EngineManager.swift 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853
  1. //
  2. // EngineManager.swift
  3. // TUIRoomKit
  4. //
  5. // Created by WesleyLei on 2022/9/22.
  6. // Copyright © 2022 Tencent. All rights reserved.
  7. //
  8. import Foundation
  9. import TUICore
  10. import Factory
  11. import RTCRoomEngine
  12. #if canImport(TXLiteAVSDK_TRTC)
  13. import TXLiteAVSDK_TRTC
  14. #elseif canImport(TXLiteAVSDK_Professional)
  15. import TXLiteAVSDK_Professional
  16. #endif
  17. class EngineManager: NSObject {
  18. static private(set) var shared = EngineManager()
  19. @WeakLazyInjected(\.conferenceStore) private var operation
  20. private(set) lazy var store: RoomStore = {
  21. let store = RoomStore()
  22. return store
  23. }()
  24. private(set) var roomEngine = TUIRoomEngine.sharedInstance()
  25. private lazy var eventDispatcher: RoomEventDispatcher = {
  26. let eventDispatcher = RoomEventDispatcher()
  27. return eventDispatcher
  28. }()
  29. private lazy var observer: TRTCObserver = {
  30. let observer = TRTCObserver()
  31. return observer
  32. }()
  33. private lazy var conferenceListObserver: ConferenceListObserver = {
  34. return ConferenceListObserver()
  35. }()
  36. private lazy var conferenceListManager: TUIConferenceListManager? = {
  37. guard let listManager = roomEngine.getExtension(extensionType: .conferenceListManager) as? TUIConferenceListManager else { return nil }
  38. return listManager
  39. }()
  40. private lazy var trtcCloudShared: TRTCCloud = {
  41. TRTCCloud.sharedInstance()
  42. }()
  43. private let takeSeatTimeOutNumber: Double = 60
  44. private let openRemoteDeviceTimeOutNumber: Double = 15
  45. private let rootRouter: RoomRouter = RoomRouter.shared
  46. private var isLoginEngine: Bool = false
  47. private let appGroupString: String = ConferenceSession.sharedInstance.implementation.appGroup
  48. private let volumeCallbackInterval: UInt = 300
  49. override private init() {
  50. super.init()
  51. }
  52. deinit {
  53. debugPrint("deinit \(self)")
  54. }
  55. func setSelfInfo(userName: String, avatarURL: String, onSuccess: @escaping TUISuccessBlock, onError: @escaping TUIErrorBlock) {
  56. store.currentUser.userName = userName
  57. store.currentUser.avatarUrl = avatarURL
  58. TUIRoomEngine.setSelfInfo(userName: userName, avatarUrl: avatarURL) {
  59. onSuccess()
  60. } onError: { code, message in
  61. onError(code, message)
  62. debugPrint("---setSelfInfo,code:\(code),message:\(message)")
  63. }
  64. }
  65. func getSelfInfo() -> TUILoginUserInfo {
  66. return TUIRoomEngine.getSelfInfo()
  67. }
  68. func createRoom(roomInfo: TUIRoomInfo, onSuccess: @escaping TUISuccessBlock, onError: @escaping TUIErrorBlock) {
  69. roomInfo.name = transferConferenceName(conferenceName: roomInfo.name)
  70. if !isLoginEngine {
  71. self.login(sdkAppId: Int(TUILogin.getSdkAppID()), userId: TUILogin.getUserID() ?? "", userSig: TUILogin.getUserSig() ?? "")
  72. { [weak self] in
  73. guard let self = self else { return }
  74. self.isLoginEngine = true
  75. self.createEngineRoom(roomInfo: roomInfo, onSuccess: onSuccess, onError: onError)
  76. } onError: { code, message in
  77. onError(code, message)
  78. }
  79. } else {
  80. createEngineRoom(roomInfo: roomInfo, onSuccess: onSuccess, onError: onError)
  81. }
  82. }
  83. func enterRoom(roomId: String, options: TUIEnterRoomOptions? = nil, enableAudio: Bool, enableVideo: Bool, isSoundOnSpeaker: Bool,
  84. onSuccess: @escaping TUIRoomInfoBlock, onError: @escaping TUIErrorBlock) {
  85. store.videoSetting.isCameraOpened = enableVideo
  86. store.audioSetting.isSoundOnSpeaker = isSoundOnSpeaker
  87. setFramework()
  88. if !isLoginEngine {
  89. self.login(sdkAppId: Int(TUILogin.getSdkAppID()), userId: TUILogin.getUserID() ?? "", userSig: TUILogin.getUserSig() ?? "")
  90. { [weak self] in
  91. guard let self = self else { return }
  92. self.isLoginEngine = true
  93. self.enterEngineRoom(roomId: roomId, options: options, enableAudio: enableAudio, onSuccess: onSuccess, onError: onError)
  94. } onError: { code, message in
  95. onError(code, message)
  96. }
  97. } else {
  98. enterEngineRoom(roomId: roomId, options: options, enableAudio: enableAudio, onSuccess: onSuccess, onError: onError)
  99. }
  100. }
  101. func exitRoom(syncWaiting: Bool = true, onSuccess: TUISuccessBlock? = nil, onError: TUIErrorBlock? = nil) {
  102. roomEngine.exitRoom(syncWaiting: syncWaiting) { [weak self] in
  103. guard let self = self else { return }
  104. self.operation?.dispatch(action: RoomResponseActions.onExitSuccess())
  105. onSuccess?()
  106. } onError: { code, message in
  107. onError?(code, message)
  108. }
  109. handleExitRoomResult()
  110. }
  111. func destroyRoom(onSuccess: TUISuccessBlock? = nil, onError: TUIErrorBlock? = nil) {
  112. roomEngine.destroyRoom { [weak self] in
  113. guard let self = self else { return }
  114. self.handleDestroyRoomResult()
  115. onSuccess?()
  116. } onError: { [weak self] code, message in
  117. guard let self = self else { return }
  118. self.handleDestroyRoomResult()
  119. onError?(code, message)
  120. }
  121. }
  122. func destroyEngineManager() {
  123. removeEngineObserver()
  124. unsubLogoutNotification()
  125. isLoginEngine = false
  126. store.reset()
  127. }
  128. func muteLocalAudio() {
  129. roomEngine.muteLocalAudio()
  130. }
  131. func unmuteLocalAudio(onSuccess:TUISuccessBlock? = nil, onError: TUIErrorBlock? = nil) {
  132. roomEngine.unmuteLocalAudio {
  133. onSuccess?()
  134. } onError: { code, message in
  135. onError?(code, message)
  136. }
  137. }
  138. func openLocalMicrophone(onSuccess: TUISuccessBlock? = nil, onError: TUIErrorBlock? = nil) {
  139. let actionBlock = { [weak self] in
  140. guard let self = self else { return }
  141. self.roomEngine.openLocalMicrophone(self.store.audioSetting.audioQuality) { [weak self] in
  142. guard let self = self else { return }
  143. self.store.audioSetting.isMicOpened = true
  144. onSuccess?()
  145. } onError: { code, message in
  146. onError?(code, message)
  147. }
  148. }
  149. if RoomCommon.checkAuthorMicStatusIsDenied() {
  150. actionBlock()
  151. } else {
  152. RoomCommon.micStateActionWithPopCompletion { granted in
  153. if granted {
  154. actionBlock()
  155. }
  156. }
  157. }
  158. }
  159. func closeLocalCamera() {
  160. store.videoSetting.isCameraOpened = false
  161. roomEngine.closeLocalCamera()
  162. }
  163. func openLocalCamera(onSuccess: TUISuccessBlock? = nil, onError: TUIErrorBlock? = nil) {
  164. let actionBlock = { [weak self] in
  165. guard let self = self else { return }
  166. self.store.videoSetting.isCameraOpened = true
  167. self.roomEngine.openLocalCamera(isFront: self.store.videoSetting.isFrontCamera, quality:
  168. self.store.videoSetting.videoQuality) {
  169. onSuccess?()
  170. } onError: { code, message in
  171. onError?(code, message)
  172. }
  173. }
  174. if RoomCommon.checkAuthorCamaraStatusIsDenied() {
  175. actionBlock()
  176. } else {
  177. RoomCommon.cameraStateActionWithPopCompletion { granted in
  178. if granted {
  179. actionBlock()
  180. }
  181. }
  182. }
  183. }
  184. func switchCamera() {
  185. store.videoSetting.isFrontCamera = !store.videoSetting.isFrontCamera
  186. roomEngine.getMediaDeviceManager().switchCamera(store.videoSetting.isFrontCamera)
  187. }
  188. func muteAllAudioAction(isMute: Bool, onSuccess: @escaping TUISuccessBlock, onError: @escaping TUIErrorBlock) {
  189. store.roomInfo.isMicrophoneDisableForAllUser = isMute
  190. roomEngine.disableDeviceForAllUserByAdmin(device: .microphone, isDisable:
  191. store.roomInfo.isMicrophoneDisableForAllUser) {
  192. onSuccess()
  193. } onError: { code, message in
  194. onError(code, message)
  195. }
  196. }
  197. func muteAllVideoAction(isMute: Bool, onSuccess: @escaping TUISuccessBlock, onError: @escaping TUIErrorBlock) {
  198. store.roomInfo.isCameraDisableForAllUser = isMute
  199. roomEngine.disableDeviceForAllUserByAdmin(device: .camera, isDisable:
  200. store.roomInfo.isCameraDisableForAllUser) {
  201. onSuccess()
  202. } onError: { code, message in
  203. onError(code, message)
  204. }
  205. }
  206. func muteAllShareScreenAction(isMute: Bool, onSuccess: TUISuccessBlock? = nil, onError: TUIErrorBlock? = nil) {
  207. roomEngine.disableDeviceForAllUserByAdmin(device: .screenSharing, isDisable: isMute) { [weak self] in
  208. guard let self = self else { return }
  209. self.store.roomInfo.isScreenShareDisableForAllUser = isMute
  210. if var roomState = self.operation?.selectCurrent(RoomSelectors.getRoomState) {
  211. roomState.isScreenShareDisableForAllUser = isMute
  212. self.operation?.dispatch(action: RoomActions.updateRoomState(payload: roomState))
  213. }
  214. onSuccess?()
  215. } onError: { code, message in
  216. onError?(code, message)
  217. }
  218. }
  219. func takeUserOnSeatByAdmin(userId: String, timeout: Double,
  220. onAccepted: @escaping TUIRequestAcceptedBlock,
  221. onRejected: @escaping TUIRequestRejectedBlock,
  222. onCancelled: @escaping TUIRequestCancelledBlock,
  223. onTimeout: @escaping TUIRequestTimeoutBlock,
  224. onError: @escaping TUIRequestErrorBlock) {
  225. roomEngine.takeUserOnSeatByAdmin(-1, userId: userId, timeout: timeout) { requestId, userId in
  226. onAccepted(requestId, userId)
  227. } onRejected: { requestId, userId, message in
  228. onRejected( requestId, userId, message)
  229. } onCancelled: { requestId, userId in
  230. onCancelled(requestId, userId)
  231. } onTimeout: { requestId, userId in
  232. onTimeout(requestId, userId)
  233. } onError: { requestId, userId, code, message in
  234. onError(requestId, userId, code, message)
  235. }
  236. }
  237. func setAudioRoute(isSoundOnSpeaker: Bool) {
  238. store.audioSetting.isSoundOnSpeaker = isSoundOnSpeaker
  239. let route: TUIAudioRoute = isSoundOnSpeaker ? .speakerphone : .earpiece
  240. roomEngine.getMediaDeviceManager().setAudioRoute(route)
  241. }
  242. func takeSeat(onAccepted: TUIRequestAcceptedBlock? = nil,
  243. onRejected: TUIRequestRejectedBlock? = nil,
  244. onCancelled: TUIRequestCancelledBlock? = nil,
  245. onTimeout: TUIRequestTimeoutBlock? = nil,
  246. onError: TUIRequestErrorBlock? = nil) -> TUIRequest {
  247. let request = self.roomEngine.takeSeat(-1, timeout: takeSeatTimeOutNumber) { [weak self] requestId, userId in
  248. guard let self = self else { return }
  249. self.store.currentUser.isOnSeat = true
  250. self.store.selfTakeSeatRequestId = nil
  251. onAccepted?(requestId, userId)
  252. } onRejected: { [weak self] requestId, userId, message in
  253. guard let self = self else { return }
  254. self.store.selfTakeSeatRequestId = nil
  255. onRejected?(requestId, userId, message)
  256. } onCancelled: { [weak self] requestId, userId in
  257. guard let self = self else { return }
  258. self.store.selfTakeSeatRequestId = nil
  259. onCancelled?(requestId, userId)
  260. } onTimeout: { [weak self] requestId, userId in
  261. guard let self = self else { return }
  262. self.store.selfTakeSeatRequestId = nil
  263. onTimeout?(requestId, userId)
  264. } onError: { [weak self] requestId, userId, code, message in
  265. guard let self = self else { return }
  266. self.store.selfTakeSeatRequestId = nil
  267. onError?(requestId, userId, code, message)
  268. }
  269. store.selfTakeSeatRequestId = request.requestId
  270. return request
  271. }
  272. func cancelTakeSeatRequest() {
  273. guard let requestId = store.selfTakeSeatRequestId else { return }
  274. cancelRequest(requestId)
  275. store.selfTakeSeatRequestId = nil
  276. }
  277. func fetchRoomInfo(roomId: String ,onSuccess: TUIRoomInfoBlock? = nil, onError: TUIErrorBlock? = nil) {
  278. roomEngine.fetchRoomInfo(roomId: roomId, roomType: .conference) { [weak self] roomInfo in
  279. guard let self = self, let roomInfo = roomInfo else { return }
  280. if roomId == self.store.roomInfo.roomId {
  281. self.store.initialRoomInfo(roomInfo)
  282. }
  283. onSuccess?(roomInfo)
  284. } onError: { code, message in
  285. onError?(code, message)
  286. debugPrint("fetchRoomInfo,code:\(code), message:\(message)")
  287. }
  288. }
  289. func setLocalVideoView(_ view: UIView?) {
  290. roomEngine.setLocalVideoView(view: view)
  291. }
  292. func changeUserRole(userId: String, role: TUIRole, onSuccess: @escaping TUISuccessBlock, onError: @escaping TUIErrorBlock) {
  293. roomEngine.changeUserRole(userId: userId, role: role, onSuccess: onSuccess, onError: onError)
  294. }
  295. func responseRemoteRequest(_ requestId: String, agree: Bool, onSuccess: TUISuccessBlock? = nil, onError: TUIErrorBlock? = nil) {
  296. roomEngine.responseRemoteRequest(requestId, agree: agree) {
  297. onSuccess?()
  298. } onError: { code, message in
  299. onError?(code, message)
  300. }
  301. }
  302. func getUserInfo(_ userId: String, onSuccess: @escaping TUIUserInfoBlock, onError: @escaping TUIErrorBlock) {
  303. roomEngine.getUserInfo(userId, onSuccess: onSuccess, onError: onError)
  304. }
  305. func stopScreenCapture() {
  306. roomEngine.stopScreenCapture()
  307. }
  308. func setVideoEncoder(videoQuality: TUIVideoQuality? = nil, bitrate: Int? = nil, fps: Int? = nil) {
  309. let param = TUIRoomVideoEncoderParams()
  310. store.videoSetting.videoQuality = videoQuality ?? store.videoSetting.videoQuality
  311. param.videoResolution = store.videoSetting.videoQuality
  312. store.videoSetting.videoBitrate = bitrate ?? store.videoSetting.videoBitrate
  313. param.bitrate = store.videoSetting.videoBitrate
  314. store.videoSetting.videoFps = fps ?? store.videoSetting.videoFps
  315. param.fps = store.videoSetting.videoFps
  316. roomEngine.updateVideoQualityEx(streamType: .cameraStream, params: param)
  317. }
  318. func cancelRequest(_ requestId: String, onSuccess: TUISuccessBlock? = nil, onError: TUIErrorBlock? = nil) {
  319. roomEngine.cancelRequest(requestId) {
  320. onSuccess?()
  321. } onError: { code, message in
  322. onError?(code, message)
  323. }
  324. }
  325. func leaveSeat(onSuccess: TUISuccessBlock? = nil, onError: TUIErrorBlock? = nil) {
  326. roomEngine.leaveSeat {
  327. onSuccess?()
  328. } onError: { code, message in
  329. onError?(code, message)
  330. }
  331. }
  332. func startScreenCapture() {
  333. roomEngine.startScreenCapture(appGroup: appGroupString)
  334. }
  335. func stopPlayRemoteVideo(userId: String, streamType: TUIVideoStreamType) {
  336. roomEngine.stopPlayRemoteVideo(userId: userId, streamType: streamType)
  337. }
  338. func setRemoteVideoView(userId: String, streamType: TUIVideoStreamType, view: UIView?) {
  339. roomEngine.setRemoteVideoView(userId: userId, streamType: streamType, view: view)
  340. }
  341. func startPlayRemoteVideo(userId: String, streamType: TUIVideoStreamType, onSuccess: TUISuccessBlock? = nil,
  342. onLoading: TUIPlayOnLoadingBlock? = nil, onError: TUIPlayOnErrorBlock? = nil) {
  343. roomEngine.startPlayRemoteVideo(userId: userId, streamType: streamType, onPlaying: { _ in
  344. guard let onSuccess = onSuccess else { return }
  345. onSuccess()
  346. }, onLoading: { userId in
  347. guard let onLoading = onLoading else { return }
  348. onLoading(userId)
  349. }, onError: { userId, code, message in
  350. guard let onError = onError else { return }
  351. onError(userId, code, message)
  352. })
  353. }
  354. func setAudioCaptureVolume(_ captureVolume: Int) {
  355. store.audioSetting.captureVolume = captureVolume
  356. trtcCloudShared.setAudioCaptureVolume(captureVolume)
  357. }
  358. func setAudioPlayoutVolume(_ playVolume: Int) {
  359. store.audioSetting.playVolume = playVolume
  360. trtcCloudShared.setAudioPlayoutVolume(playVolume)
  361. }
  362. func enableAudioVolumeEvaluation(isVolumePrompt: Bool) {
  363. store.audioSetting.volumePrompt = isVolumePrompt
  364. let volumeEvaluateParams = TRTCAudioVolumeEvaluateParams()
  365. volumeEvaluateParams.interval = isVolumePrompt ? volumeCallbackInterval : 0
  366. trtcCloudShared.enableAudioVolumeEvaluation(isVolumePrompt, with: volumeEvaluateParams)
  367. }
  368. func closeRemoteDeviceByAdmin(userId: String, device: TUIMediaDevice, onSuccess: TUISuccessBlock? = nil, onError: TUIErrorBlock? = nil) {
  369. roomEngine.closeRemoteDeviceByAdmin(userId: userId, device: device) {
  370. onSuccess?()
  371. } onError: { code, message in
  372. onError?(code, message)
  373. }
  374. }
  375. func openRemoteDeviceByAdmin(userId: String, device: TUIMediaDevice,
  376. onAccepted: TUIRequestAcceptedBlock? = nil,
  377. onRejected: TUIRequestRejectedBlock? = nil,
  378. onCancelled: TUIRequestCancelledBlock? = nil,
  379. onTimeout: TUIRequestTimeoutBlock? = nil,
  380. onError: TUIRequestErrorBlock? = nil) {
  381. roomEngine.openRemoteDeviceByAdmin(userId: userId, device: device, timeout: openRemoteDeviceTimeOutNumber, onAccepted: { requestId, userId in
  382. onAccepted?(requestId, userId)
  383. }, onRejected: { requestId, userId, message in
  384. onRejected?(requestId, userId, message)
  385. }, onCancelled: { requestId, userId in
  386. onCancelled?(requestId, userId)
  387. }, onTimeout: { requestId, userId in
  388. onTimeout?(requestId, userId)
  389. }) { requestId, userId, code, message in
  390. onError?(requestId, userId, code, message)
  391. }
  392. }
  393. func disableSendingMessageByAdmin(userId: String, isDisable: Bool, onSuccess: TUISuccessBlock? = nil, onError: TUIErrorBlock? = nil) {
  394. roomEngine.disableSendingMessageByAdmin(userId: userId, isDisable: isDisable) {
  395. onSuccess?()
  396. } onError: { code, message in
  397. onError?(code, message)
  398. }
  399. }
  400. func kickUserOffSeatByAdmin(userId: String, onSuccess: TUISuccessBlock? = nil, onError: TUIErrorBlock? = nil) {
  401. roomEngine.kickUserOffSeatByAdmin(-1, userId: userId) {
  402. onSuccess?()
  403. } onError: { code, message in
  404. onError?(code, message)
  405. }
  406. }
  407. func kickRemoteUserOutOfRoom(userId: String, onSuccess: TUISuccessBlock? = nil, onError: TUIErrorBlock? = nil) {
  408. roomEngine.kickRemoteUserOutOfRoom(userId) {
  409. onSuccess?()
  410. } onError: { code, message in
  411. onError?(code, message)
  412. }
  413. }
  414. func initUserList(onSuccess: TUISuccessBlock? = nil, onError: TUIErrorBlock? = nil) {
  415. self.getUserList(nextSequence: 0, localUserList: []) { [weak self] in
  416. guard let self = self else { return }
  417. if self.store.roomInfo.isSeatEnabled {
  418. self.getSeatList {
  419. onSuccess?()
  420. } onError: { code, message in
  421. onError?(code, message)
  422. }
  423. } else {
  424. onSuccess?()
  425. }
  426. self.updateScreenStreamUsers()
  427. self.updateDisableMessageUsers()
  428. } onError: { code, message in
  429. onError?(code, message)
  430. }
  431. }
  432. func updateVideoQuality(quality: TUIVideoQuality) {
  433. roomEngine.updateVideoQuality(quality)
  434. }
  435. func enableGravitySensor(enable: Bool) {
  436. roomEngine.enableGravitySensor(enable: enable)
  437. }
  438. func setVideoResolutionMode(streamType: TUIVideoStreamType, resolutionMode: TUIResolutionMode) {
  439. roomEngine.setVideoResolutionMode(streamType: streamType, resolutionMode: resolutionMode)
  440. }
  441. func changeRaiseHandNoticeState(isShown: Bool) {
  442. store.isShownRaiseHandNotice = isShown
  443. }
  444. func updateSeatApplicationList() {
  445. roomEngine.getSeatApplicationList { [weak self] list in
  446. guard let self = self else { return }
  447. self.store.setInviteSeatList(list: list)
  448. } onError: { code, message in
  449. debugPrint("getSeatApplicationList,code:\(code),message:\(message)")
  450. }
  451. }
  452. func changeUserNameCard(userid: String, nameCard: String, onSuccess: TUISuccessBlock? = nil, onError: TUIErrorBlock? = nil) {
  453. roomEngine.changeUserNameCard(userId: userid, nameCard: nameCard) {
  454. onSuccess?()
  455. } onError: { code, message in
  456. onError?(code, message)
  457. }
  458. }
  459. }
  460. // MARK: - Private
  461. extension EngineManager {
  462. private func login(sdkAppId: Int, userId: String, userSig: String, onSuccess: @escaping TUISuccessBlock, onError: @escaping TUIErrorBlock) {
  463. V2TIMManager.sharedInstance().initSDK(Int32(sdkAppId), config: V2TIMSDKConfig())
  464. store.currentUser.userId = userId
  465. TUIRoomEngine.login(sdkAppId: sdkAppId, userId: userId, userSig: userSig) { [weak self] in
  466. guard let self = self else { return }
  467. self.isLoginEngine = true
  468. onSuccess()
  469. } onError: { code, message in
  470. onError(code, message)
  471. }
  472. }
  473. private func createEngineRoom(roomInfo: TUIRoomInfo, onSuccess: @escaping TUISuccessBlock, onError: @escaping TUIErrorBlock) {
  474. guard !store.isEnteredRoom else {
  475. if store.roomInfo.roomId == roomInfo.roomId {
  476. RoomVideoFloatView.dismiss()
  477. onSuccess()
  478. } else {
  479. onError(.failed, .inAnotherRoomText)
  480. }
  481. return
  482. }
  483. self.store.roomInfo = roomInfo
  484. self.roomEngine.createRoom(roomInfo) {
  485. onSuccess()
  486. } onError: { [weak self] code, message in
  487. guard let self = self else { return }
  488. self.destroyEngineManager()
  489. onError(code, message)
  490. }
  491. }
  492. private func transferConferenceName(conferenceName: String?) -> String {
  493. if let confName = conferenceName, !confName.isEmpty {
  494. return confName
  495. }
  496. let selfInfo = TUIRoomEngine.getSelfInfo()
  497. let name: String = selfInfo.userName.isEmpty ? selfInfo.userId : selfInfo.userName
  498. return localizedReplace(.quickConferenceText, replace: name)
  499. }
  500. private func enterEngineRoom(roomId: String, options: TUIEnterRoomOptions? = nil, enableAudio: Bool, onSuccess: @escaping TUIRoomInfoBlock, onError: @escaping TUIErrorBlock) {
  501. guard !store.isEnteredRoom else {
  502. if store.roomInfo.roomId == roomId {
  503. onSuccess(store.roomInfo)
  504. } else {
  505. onError(.failed, .inAnotherRoomText)
  506. }
  507. return
  508. }
  509. if let options = options {
  510. roomEngine.enterRoom(roomId, roomType: .conference, options: options) { [weak self] roomInfo in
  511. guard let self = self else { return }
  512. guard let roomInfo = roomInfo else { return }
  513. self.handleEnterRoomResult(roomInfo: roomInfo, enableAudio: enableAudio, onSuccess: onSuccess, onError: onError)
  514. } onError: { [weak self] code, message in
  515. guard let self = self else { return }
  516. self.destroyEngineManager()
  517. onError(code, message)
  518. }
  519. } else {
  520. roomEngine.enterRoom(roomId) { [weak self] roomInfo in
  521. guard let self = self else { return }
  522. guard let roomInfo = roomInfo else { return }
  523. self.handleEnterRoomResult(roomInfo: roomInfo, enableAudio: enableAudio, onSuccess: onSuccess, onError: onError)
  524. } onError: { [weak self] code, message in
  525. guard let self = self else { return }
  526. self.destroyEngineManager()
  527. onError(code, message)
  528. }
  529. }
  530. }
  531. private func handleEnterRoomResult(roomInfo: TUIRoomInfo, enableAudio: Bool, onSuccess: @escaping TUIRoomInfoBlock, onError: @escaping TUIErrorBlock) {
  532. //Update the room entry data stored
  533. addEngineObserver()
  534. store.initialRoomInfo(roomInfo)
  535. store.initialRoomCurrentUser()
  536. //Initialize user list
  537. initUserList()
  538. //Initialize video settings
  539. initLocalVideoState()
  540. subLogoutNotification()
  541. updateSeatApplicationList()
  542. if !isNeededAutoTakeSeat() {
  543. operateLocalMicrophone(enableAudio: enableAudio)
  544. updateCameraState()
  545. store.initalEnterRoomMessage()
  546. onSuccess(roomInfo)
  547. } else {
  548. autoTakeSeatForOwner { [weak self] in
  549. guard let self = self else { return }
  550. self.operateLocalMicrophone(enableAudio: enableAudio)
  551. self.updateCameraState()
  552. self.store.initalEnterRoomMessage()
  553. onSuccess(roomInfo)
  554. } onError: { [weak self] code, message in
  555. guard let self = self else { return }
  556. self.destroyEngineManager()
  557. onError(code, message)
  558. }
  559. }
  560. }
  561. private func updateCameraState() {
  562. if store.roomInfo.isSeatEnabled && !store.currentUser.isOnSeat {
  563. store.videoSetting.isCameraOpened = false
  564. return
  565. }
  566. operateLocalCamera()
  567. }
  568. private func isNeededAutoTakeSeat() -> Bool {
  569. return store.roomInfo.isSeatEnabled && store.currentUser.userId == store.roomInfo.ownerId
  570. }
  571. private func autoTakeSeatForOwner(onSuccess: @escaping TUISuccessBlock, onError: @escaping TUIErrorBlock) {
  572. _ = self.takeSeat() { _,_ in
  573. onSuccess()
  574. } onError: { _, _, code, message in
  575. if code == .alreadyInSeat {
  576. onSuccess()
  577. } else {
  578. onError(code, message)
  579. }
  580. }
  581. }
  582. private func isPushLocalAudioStream(enableAudio: Bool) -> Bool {
  583. if !enableAudio {
  584. return false
  585. }
  586. if store.roomInfo.isMicrophoneDisableForAllUser, store.currentUser.userId != store.roomInfo.ownerId {
  587. return false
  588. }
  589. if store.roomInfo.isSeatEnabled, store.currentUser.userId != store.roomInfo.ownerId {
  590. return false
  591. }
  592. return true
  593. }
  594. private func operateLocalMicrophone(enableAudio: Bool ,onSuccess: TUISuccessBlock? = nil, onError: TUIErrorBlock? = nil) {
  595. if isPushLocalAudioStream(enableAudio: enableAudio) {
  596. openLocalMicrophone()
  597. } else if RoomCommon.checkAuthorMicStatusIsDenied() {
  598. muteLocalAudio()
  599. openLocalMicrophone()
  600. }
  601. }
  602. private func operateLocalCamera() {
  603. let openLocalCameraActionBlock = { [weak self] in
  604. guard let self = self else { return }
  605. setLocalVideoView(nil)
  606. openLocalCamera()
  607. }
  608. if store.videoSetting.isCameraOpened && !store.roomInfo.isCameraDisableForAllUser {
  609. if RoomCommon.checkAuthorCamaraStatusIsDenied() {
  610. openLocalCameraActionBlock()
  611. } else {
  612. RoomCommon.cameraStateActionWithPopCompletion { granted in
  613. if granted {
  614. openLocalCameraActionBlock()
  615. }
  616. }
  617. }
  618. }
  619. }
  620. private func initLocalVideoState() {
  621. setVideoParam()
  622. enableGravitySensor(enable: true)
  623. let resolutionMode: TUIResolutionMode = isLandscape ? .landscape : .portrait
  624. setVideoResolutionMode(streamType: .cameraStream, resolutionMode: resolutionMode)
  625. setVideoResolutionMode(streamType: .cameraStreamLow, resolutionMode: resolutionMode)
  626. }
  627. private func setVideoParam() {
  628. setVideoEncoder(videoQuality: store.videoSetting.videoQuality, bitrate: store.videoSetting.videoBitrate,
  629. fps: store.videoSetting.videoFps)
  630. }
  631. private func getUserList(nextSequence: Int, localUserList: [UserEntity], onSuccess: @escaping TUISuccessBlock, onError: @escaping TUIErrorBlock) {
  632. roomEngine.getUserList(nextSequence: nextSequence) { [weak self] list, nextSequence in
  633. guard let self = self else { return }
  634. var localUserList = localUserList
  635. list.forEach { userInfo in
  636. if userInfo.userName.isEmpty {
  637. userInfo.userName = userInfo.userId
  638. }
  639. let userModel = UserEntity()
  640. userModel.update(userInfo: userInfo)
  641. localUserList.append(userModel)
  642. }
  643. if nextSequence != 0 {
  644. self.getUserList(nextSequence: nextSequence, localUserList: localUserList, onSuccess: onSuccess, onError: onError)
  645. } else {
  646. self.store.attendeeList = localUserList
  647. onSuccess()
  648. if !self.store.roomInfo.isSeatEnabled {
  649. EngineEventCenter.shared.notifyUIEvent(key: .TUIRoomKitService_RenewVideoSeatView, param: [:])
  650. }
  651. EngineEventCenter.shared.notifyUIEvent(key: .TUIRoomKitService_RenewUserList, param: [:])
  652. EngineEventCenter.shared.notifyEngineEvent(event: .onGetUserListFinished, param: [:])
  653. }
  654. } onError: { code, message in
  655. onError(code, message)
  656. debugPrint("getUserList:code:\(code),message:\(message)")
  657. }
  658. }
  659. private func updateScreenStreamUsers() {
  660. let hasScreenStreamUsers = store.attendeeList.filter({ $0.hasScreenStream })
  661. let hasScreenStreamUserIdArray: [String] = hasScreenStreamUsers.map { $0.userId }
  662. let hasScreenStreamUserIdSet: Set<String> = Set(hasScreenStreamUserIdArray)
  663. operation?.dispatch(action: UserActions.updateHasScreenStreamUsers(payload: hasScreenStreamUserIdSet))
  664. }
  665. private func updateDisableMessageUsers() {
  666. let disableMessageUsers = store.attendeeList.filter({ $0.disableSendingMessage })
  667. let disableMessageUserIdArray: [String] = disableMessageUsers.map { $0.userId }
  668. let disableMessageUserIdSet: Set<String> = Set(disableMessageUserIdArray)
  669. operation?.dispatch(action: UserActions.updateDisableMessageUsers(payload: disableMessageUserIdSet))
  670. }
  671. private func getSeatList(onSuccess: @escaping TUISuccessBlock, onError: @escaping TUIErrorBlock) {
  672. roomEngine.getSeatList { [weak self] seatList in
  673. guard let self = self else { return }
  674. self.store.initialSeatList(seatList: seatList)
  675. self.store.initialOffSeatList()
  676. onSuccess()
  677. } onError: { code, message in
  678. onError(code, message)
  679. debugPrint("getSeatList:code:\(code),message:\(message)")
  680. }
  681. }
  682. private func addEngineObserver() {
  683. roomEngine.addObserver(eventDispatcher)
  684. trtcCloudShared.addDelegate(observer)
  685. conferenceListManager?.addObserver(conferenceListObserver)
  686. }
  687. private func removeEngineObserver() {
  688. roomEngine.removeObserver(eventDispatcher)
  689. trtcCloudShared.removeDelegate(observer)
  690. conferenceListManager?.removeObserver(conferenceListObserver)
  691. }
  692. private func subLogoutNotification() {
  693. NotificationCenter.default.addObserver(self, selector: #selector(handleLogout),
  694. name: NSNotification.Name.TUILogoutSuccess, object: nil)
  695. }
  696. private func unsubLogoutNotification() {
  697. NotificationCenter.default.removeObserver(self, name: NSNotification.Name.TUILogoutSuccess, object: nil)
  698. }
  699. @objc private func handleLogout() {
  700. destroyEngineManager()
  701. }
  702. private func handleDestroyRoomResult() {
  703. let param: [String : Any] = [
  704. "roomInfo" : store.roomInfo,
  705. "reason" : ConferenceFinishedReason.finishedByOwner
  706. ]
  707. destroyEngineManager()
  708. EngineEventCenter.shared.notifyEngineEvent(event: .onDestroyedRoom, param: param)
  709. }
  710. private func handleExitRoomResult() {
  711. let param: [String : Any] = [
  712. "roomInfo" : store.roomInfo,
  713. "reason" : ConferenceExitedReason.exitedBySelf
  714. ]
  715. destroyEngineManager()
  716. EngineEventCenter.shared.notifyEngineEvent(event: .onExitedRoom, param: param)
  717. }
  718. }
  719. // MARK: - TUIExtensionProtocol
  720. extension EngineManager: TUIExtensionProtocol {
  721. func onGetExtensionInfo(_ key: String, param: [AnyHashable: Any]?) -> [AnyHashable: Any]? {
  722. guard let param = param else {
  723. return [:]
  724. }
  725. guard param["roomId"] as? String != nil else {
  726. return [:]
  727. }
  728. if key == gRoomEngineKey {
  729. return [key: roomEngine]
  730. } else if key == gRoomInfoKey {
  731. return [key: store.roomInfo]
  732. } else if key == gLocalUserInfoKey {
  733. return [key: store.currentUser]
  734. } else {
  735. return [:]
  736. }
  737. }
  738. }
  739. // MARK: - setFramework
  740. extension EngineManager {
  741. fileprivate static let TUIRoomKitFrameworkValue = 1
  742. fileprivate static let TUIRoomKitComponentValue = 18
  743. fileprivate static let IMComponentValue = 19
  744. fileprivate static let TUIRoomKitLanguageValue = 3
  745. private func setFramework() {
  746. let componentValue = store.isImAccess ? EngineManager.IMComponentValue : EngineManager.TUIRoomKitComponentValue
  747. let jsonStr = """
  748. {
  749. "api":"setFramework",
  750. "params":{
  751. "framework":\(EngineManager.TUIRoomKitFrameworkValue),
  752. "component":\(componentValue),
  753. "language":\(EngineManager.TUIRoomKitLanguageValue)
  754. }
  755. }
  756. """
  757. TUIRoomEngine.callExperimentalAPI(jsonStr: jsonStr)
  758. }
  759. }
  760. private extension String {
  761. static var inAnotherRoomText: String {
  762. localized("You are already in another conference")
  763. }
  764. static var quickConferenceText: String {
  765. localized("xx's quick conference")
  766. }
  767. }