RoomEventDispatcher.swift 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  1. //
  2. // RoomEventDispatcher.swift
  3. // TUIRoomKit
  4. //
  5. // Created by janejntang on 2023/8/14.
  6. //
  7. import Foundation
  8. import RTCRoomEngine
  9. import Factory
  10. class RoomEventDispatcher: NSObject {
  11. var engineManager: EngineManager {
  12. EngineManager.shared
  13. }
  14. var store: RoomStore {
  15. engineManager.store
  16. }
  17. var roomInfo: TUIRoomInfo {
  18. store.roomInfo
  19. }
  20. var currentUser: UserEntity {
  21. store.currentUser
  22. }
  23. deinit {
  24. debugPrint("deinit")
  25. }
  26. // MARK: - private property.
  27. @WeakLazyInjected(\.conferenceStore) private var operation
  28. }
  29. extension RoomEventDispatcher: TUIRoomObserver {
  30. // MARK: - Room event callback
  31. func onAllUserMicrophoneDisableChanged(roomId: String, isDisable: Bool) {
  32. roomInfo.isMicrophoneDisableForAllUser = isDisable
  33. let param = [
  34. "roomId" : roomId,
  35. "isDisable" : isDisable,
  36. ] as [String : Any]
  37. EngineEventCenter.shared.notifyEngineEvent(event: .onAllUserMicrophoneDisableChanged, param: param)
  38. }
  39. func onAllUserCameraDisableChanged(roomId: String, isDisable: Bool) {
  40. roomInfo.isCameraDisableForAllUser = isDisable
  41. let param = [
  42. "roomId" : roomId,
  43. "isDisable" : isDisable,
  44. ] as [String : Any]
  45. EngineEventCenter.shared.notifyEngineEvent(event: .onAllUserCameraDisableChanged, param: param)
  46. }
  47. func onSendMessageForAllUserDisableChanged(roomId: String, isDisable: Bool) {
  48. roomInfo.isMessageDisableForAllUser = isDisable
  49. }
  50. func onRoomDismissed(roomId: String, reason: TUIRoomDismissedReason) {
  51. let param: [String : Any] = [
  52. "roomInfo" : roomInfo,
  53. "reason" : ConferenceFinishedReason.finishedByOwner,
  54. ]
  55. EngineEventCenter.shared.notifyEngineEvent(event: .onRoomDismissed, param: param)
  56. }
  57. func onKickedOutOfRoom(roomId: String, reason: TUIKickedOutOfRoomReason, message: String) {
  58. let kickedReason: ConferenceExitedReason = switch reason {
  59. case .byAdmin:
  60. .exitedByAdminKickOut
  61. case .byLoggedOnOtherDevice:
  62. .exitedByJoinedOnOtherDevice
  63. case .byServer:
  64. .exitedByServerKickOut
  65. default:
  66. .exitedByAdminKickOut
  67. }
  68. let param: [String : Any] = [
  69. "roomInfo" : roomInfo,
  70. "reason" : kickedReason,
  71. ]
  72. EngineEventCenter.shared.notifyEngineEvent(event: .onKickedOutOfRoom, param: param)
  73. }
  74. func onRoomNameChanged(roomId: String, roomName: String) {
  75. roomInfo.name = roomName
  76. }
  77. // MARK: - User event callback in the room
  78. func onRemoteUserEnterRoom(roomId: String, userInfo: TUIUserInfo) {
  79. store.remoteUserEnterRoom(userInfo: userInfo)
  80. let param = [
  81. "roomId" : roomId,
  82. "userInfo" : userInfo,
  83. ] as [String : Any]
  84. EngineEventCenter.shared.notifyEngineEvent(event: .onRemoteUserEnterRoom, param: param)
  85. }
  86. func onRemoteUserLeaveRoom(roomId: String, userInfo: TUIUserInfo) {
  87. store.remoteUserLeaveRoom(userInfo: userInfo)
  88. let param = [
  89. "roomId" : roomId,
  90. "userInfo" : userInfo,
  91. ] as [String : Any]
  92. EngineEventCenter.shared.notifyEngineEvent(event: .onRemoteUserLeaveRoom, param: param)
  93. }
  94. func onUserVideoStateChanged(userId: String, streamType: TUIVideoStreamType, hasVideo: Bool, reason: TUIChangeReason) {
  95. userVideoStateChanged(userId: userId, streamType: streamType, hasVideo: hasVideo, reason: reason)
  96. let param = [
  97. "userId" : userId,
  98. "streamType" : streamType,
  99. "hasVideo" : hasVideo,
  100. "reason" : reason,
  101. ] as [String : Any]
  102. EngineEventCenter.shared.notifyEngineEvent(event: .onUserVideoStateChanged, param: param)
  103. }
  104. func onUserAudioStateChanged(userId: String, hasAudio: Bool, reason: TUIChangeReason) {
  105. userAudioStateChanged(userId: userId, hasAudio: hasAudio, reason: reason)
  106. let param = [
  107. "userId" : userId,
  108. "hasAudio" : hasAudio,
  109. "reason" : reason,
  110. ] as [String : Any]
  111. EngineEventCenter.shared.notifyEngineEvent(event: .onUserAudioStateChanged, param: param)
  112. }
  113. func onUserVoiceVolumeChanged(volumeMap: [String : NSNumber]) {
  114. userVoiceVolumeChanged(volumeMap: volumeMap)
  115. EngineEventCenter.shared.notifyEngineEvent(event: .onUserVoiceVolumeChanged, param: volumeMap)
  116. }
  117. func onUserScreenCaptureStopped(reason: Int) {
  118. userScreenCaptureStopped()
  119. EngineEventCenter.shared.notifyUIEvent(key: .TUIRoomKitService_SomeoneSharing, param: ["userId":currentUser.userId, "hasVideo": false])
  120. }
  121. func onSeatListChanged(seatList: [TUISeatInfo], seated seatedList: [TUISeatInfo], left leftList: [TUISeatInfo]) {
  122. seatListChanged(seatList: seatList,seated: seatedList, left: leftList)
  123. let param = [
  124. "seatList": seatList,
  125. "seated": seatedList,
  126. "left": leftList,
  127. ] as [String : Any]
  128. EngineEventCenter.shared.notifyEngineEvent(event: .onSeatListChanged, param: param)
  129. }
  130. func OnSendMessageForUserDisableChanged(roomId: String, userId: String, isDisable muted: Bool) {
  131. store.updateUserDisableSendingMessage(userId: userId, isDisable: muted)
  132. let param = [
  133. "roomId": roomId,
  134. "userId": userId,
  135. "muted": muted,
  136. ] as [String : Any]
  137. EngineEventCenter.shared.notifyEngineEvent(event: .onSendMessageForUserDisableChanged, param: param)
  138. }
  139. // MARK: - Signaling request related callbacks
  140. func onRequestReceived(request: TUIRequest) {
  141. requestReceived(request: request)
  142. EngineEventCenter.shared.notifyEngineEvent(event: .onRequestReceived, param: ["request": request,])
  143. }
  144. func onRequestCancelled(request: TUIRequest, operateUser: TUIUserInfo) {
  145. store.deleteTakeSeatRequest(requestId: request.requestId)
  146. }
  147. func onRequestProcessed(request: TUIRequest, operateUser: TUIUserInfo) {
  148. store.deleteTakeSeatRequest(requestId: request.requestId)
  149. }
  150. func onKickedOffSeat(seatIndex: Int, operateUser: TUIUserInfo) {
  151. let param = [
  152. "userId": operateUser.userId,
  153. ] as [String : Any]
  154. EngineEventCenter.shared.notifyEngineEvent(event: .onKickedOffSeat, param: param)
  155. }
  156. func onKickedOffLine(message: String) {
  157. kickedOffLine()
  158. let param: [String : Any] = [
  159. "roomInfo" : roomInfo,
  160. "reason" : ConferenceExitedReason.exitedByKickedOutOfLine,
  161. ]
  162. EngineEventCenter.shared.notifyEngineEvent(event: .onKickedOffLine, param: param)
  163. }
  164. func onUserSigExpired() {
  165. let param: [String : Any] = [
  166. "roomInfo" : roomInfo,
  167. "reason" : ConferenceExitedReason.exitedByUserSigExpired,
  168. ]
  169. EngineEventCenter.shared.notifyEngineEvent(event: .onUserSigExpired, param: param)
  170. }
  171. func onUserInfoChanged(userInfo: TUIUserInfo, modifyFlag: TUIUserInfoModifyFlag) {
  172. if modifyFlag.contains(.nameCard) {
  173. store.changeUserName(userId: userInfo.userId, userName: userInfo.nameCard)
  174. } else if modifyFlag.contains(.userRole) {
  175. userRoleChanged(userId: userInfo.userId, userRole: userInfo.userRole)
  176. }
  177. let param = [
  178. "userInfo": userInfo,
  179. "modifyFlag": modifyFlag,
  180. ] as [String : Any]
  181. EngineEventCenter.shared.notifyEngineEvent(event: .onUserInfoChanged, param: param)
  182. }
  183. func onScreenShareForAllUserDisableChanged(roomId: String, isDisable: Bool) {
  184. roomInfo.isScreenShareDisableForAllUser = isDisable
  185. guard let operation = operation else { return }
  186. var roomState = operation.selectCurrent(RoomSelectors.getRoomState)
  187. roomState.isScreenShareDisableForAllUser = isDisable
  188. operation.dispatch(action: RoomActions.updateRoomState(payload: roomState))
  189. }
  190. }
  191. extension RoomEventDispatcher {
  192. private func seatListChanged(seatList: [TUISeatInfo], seated: [TUISeatInfo], left leftList: [TUISeatInfo]) {
  193. store.updateLeftSeatList(leftList: leftList)
  194. store.updateSeatedList(seatList: seated)
  195. }
  196. private func userAudioStateChanged(userId: String, hasAudio: Bool, reason: TUIChangeReason) {
  197. if userId == currentUser.userId {
  198. EngineEventCenter.shared.notifyUIEvent(key: .TUIRoomKitService_CurrentUserHasAudioStream, param: ["hasAudio": hasAudio, "reason": reason])
  199. currentUser.hasAudioStream = hasAudio
  200. }
  201. guard let userModel = store.attendeeList.first(where: { $0.userId == userId }) else { return }
  202. userModel.hasAudioStream = hasAudio
  203. EngineEventCenter.shared.notifyUIEvent(key: .TUIRoomKitService_RenewUserList, param: [:])
  204. }
  205. private func userVideoStateChanged(userId: String, streamType: TUIVideoStreamType, hasVideo: Bool, reason: TUIChangeReason) {
  206. switch streamType {
  207. case .screenStream:
  208. if userId == currentUser.userId {
  209. currentUser.hasScreenStream = hasVideo
  210. }
  211. if let userModel = store.attendeeList.first(where: { $0.userId == userId }) {
  212. userModel.hasScreenStream = hasVideo
  213. }
  214. EngineEventCenter.shared.notifyUIEvent(key: .TUIRoomKitService_SomeoneSharing, param: ["userId": userId, "hasVideo": hasVideo])
  215. guard let operation = operation else { return }
  216. var hasScreenStreamUsers = operation.selectCurrent(UserSelectors.getHasScreenStreamUsers)
  217. if hasVideo {
  218. hasScreenStreamUsers.insert(userId)
  219. } else {
  220. hasScreenStreamUsers.remove(userId)
  221. }
  222. operation.dispatch(action: UserActions.updateHasScreenStreamUsers(payload: hasScreenStreamUsers))
  223. case .cameraStream:
  224. if userId == currentUser.userId {
  225. EngineEventCenter.shared.notifyUIEvent(key: .TUIRoomKitService_CurrentUserHasVideoStream,
  226. param: ["hasVideo": hasVideo, "reason": reason])
  227. currentUser.hasVideoStream = hasVideo
  228. store.videoSetting.isCameraOpened = hasVideo
  229. }
  230. guard let userModel = store.attendeeList.first(where: { $0.userId == userId }) else { return }
  231. userModel.hasVideoStream = hasVideo
  232. EngineEventCenter.shared.notifyUIEvent(key: .TUIRoomKitService_RenewUserList, param: [:])
  233. default: break
  234. }
  235. }
  236. private func userRoleChanged(userId: String, userRole: TUIRole) {
  237. RoomKitLog.info("\(#file)","\(#line)","userRoleChanged, userId: \(userId), userRole: \(userRole)")
  238. RoomKitLog.info("\(#file)","\(#line)","current uerInfo, userId: \(currentUser.userId), onSeat: \(currentUser.isOnSeat)")
  239. let isSelfRoleChanged = userId == currentUser.userId
  240. let isRoomOwnerChanged = userRole == .roomOwner
  241. if let userInfo = store.attendeeList.first(where: { $0.userId == userId }) {
  242. userInfo.userRole = userRole
  243. EngineEventCenter.shared.notifyUIEvent(key: .TUIRoomKitService_RenewUserList, param: ["userRole": userRole])
  244. }
  245. if isSelfRoleChanged {
  246. store.currentUser.userRole = userRole
  247. EngineEventCenter.shared.notifyUIEvent(key: .TUIRoomKitService_CurrentUserRoleChanged, param: ["userRole": userRole])
  248. if let operation = operation {
  249. var selfInfo = operation.selectCurrent(UserSelectors.getSelfInfo)
  250. selfInfo.userRole = userRole
  251. operation.dispatch(action: UserActions.updateSelfInfo(payload: selfInfo))
  252. } else {
  253. RoomKitLog.error("\(#file)","\(#line)","conference store resolve error!")
  254. }
  255. }
  256. if isRoomOwnerChanged {
  257. EngineManager.shared.fetchRoomInfo(roomId: roomInfo.roomId) { _ in
  258. EngineEventCenter.shared.notifyUIEvent(key: .TUIRoomKitService_RoomOwnerChanged, param: ["owner": userId])
  259. }
  260. }
  261. if checkAutoTakeSeatForOwner(userId: userId, userRole: userRole) {
  262. let _ = engineManager.takeSeat()
  263. }
  264. if checkAutoSendingMessageForOwner(userId: userId, userRole: userRole) {
  265. engineManager.disableSendingMessageByAdmin(userId: userId, isDisable: false)
  266. }
  267. if isSelfRoleChanged, userRole != .generalUser {
  268. engineManager.updateSeatApplicationList()
  269. }
  270. }
  271. private func checkAutoTakeSeatForOwner(userId: String, userRole: TUIRole) -> Bool {
  272. let isSelfRoleChanged = userId == currentUser.userId
  273. let isRoomOwnerChanged = userRole == .roomOwner
  274. return isSelfRoleChanged && isRoomOwnerChanged && roomInfo.isSeatEnabled && !currentUser.isOnSeat
  275. }
  276. private func checkAutoSendingMessageForOwner(userId: String, userRole: TUIRole) -> Bool {
  277. let isSelfRoleChanged = userId == currentUser.userId
  278. let isRoomOwnerChanged = userRole == .roomOwner
  279. return isSelfRoleChanged && isRoomOwnerChanged && currentUser.disableSendingMessage
  280. }
  281. private func requestReceived(request: TUIRequest) {
  282. switch request.requestAction {
  283. case .takeSeat:
  284. store.addInviteSeatUser(request: request)
  285. default: break
  286. }
  287. }
  288. private func userVoiceVolumeChanged(volumeMap: [String : NSNumber]) {
  289. for (userId, volume) in volumeMap {
  290. guard let userModel = store.attendeeList.first(where: { $0.userId == userId}) else { continue }
  291. userModel.userVoiceVolume = volume.intValue
  292. }
  293. }
  294. private func userScreenCaptureStopped() {
  295. currentUser.hasScreenStream = false
  296. guard let userModel = store.attendeeList.first(where: { $0.userId == currentUser.userId }) else { return }
  297. userModel.hasScreenStream = false
  298. guard let operation = operation else { return }
  299. var hasScreenStreamUsers = operation.selectCurrent(UserSelectors.getHasScreenStreamUsers)
  300. hasScreenStreamUsers.remove(currentUser.userId)
  301. operation.dispatch(action: UserActions.updateHasScreenStreamUsers(payload: hasScreenStreamUsers))
  302. }
  303. private func kickedOffLine() {
  304. engineManager.destroyEngineManager()
  305. }
  306. }