@hysc/meeting 6.0.0 → 6.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (298) hide show
  1. package/esm/boom-core/src/BoomCore/BCClient/clientEventType.d.ts +428 -0
  2. package/esm/boom-meeting/src/BMChat/BMChatVM.d.ts +26 -0
  3. package/esm/boom-meeting/src/BMRoom/BMRoomVM.d.ts +317 -0
  4. package/esm/boom-meeting/src/BMRoom/RoomEvent.d.ts +1 -0
  5. package/esm/boom-meeting/src/BMStream/BMStreamModel.d.ts +305 -0
  6. package/esm/boom-meeting/src/BMStream/BMStreamModelVM.d.ts +260 -0
  7. package/esm/boom-meeting/src/BMUser/BMUser.d.ts +156 -0
  8. package/esm/boom-meeting/src/BMUser/BMUserVM.d.ts +177 -0
  9. package/esm/boom-meeting/src/audioPlay/AudioPlay.d.ts +31 -0
  10. package/esm/boom-meeting/src/bjy-common/function/debounce.d.ts +9 -0
  11. package/esm/boom-meeting/src/bjy-common/function/getErrorMessage.d.ts +1 -0
  12. package/esm/boom-meeting/src/bjy-common/function/isDef.d.ts +1 -0
  13. package/esm/boom-meeting/src/bjy-common/function/isUndef.d.ts +1 -0
  14. package/esm/boom-meeting/src/bjy-common/function/throttling.d.ts +9 -0
  15. package/esm/boom-meeting/src/bjy-common/function/toNumber.d.ts +1 -0
  16. package/esm/boom-meeting/src/bjy-common/type/api.d.ts +66 -0
  17. package/esm/boom-meeting/src/bjy-common/type/options.d.ts +7 -0
  18. package/esm/boom-meeting/src/bjy-common/type/type.d.ts +90 -0
  19. package/esm/boom-meeting/src/bjy-common/util/CustomEvent.d.ts +30 -0
  20. package/esm/boom-meeting/src/bjy-common/util/Emitter.d.ts +57 -0
  21. package/esm/boom-meeting/src/bjy-common/util/NextTask.d.ts +28 -0
  22. package/esm/boom-meeting/src/bjy-common/util/Sleep.d.ts +14 -0
  23. package/esm/boom-meeting/src/bjy-common/util/Timer.d.ts +13 -0
  24. package/esm/boom-meeting/src/bjy-common/util/array.d.ts +96 -0
  25. package/esm/boom-meeting/src/bjy-common/util/browser.d.ts +6 -0
  26. package/esm/boom-meeting/src/bjy-common/util/holder.d.ts +6 -0
  27. package/esm/boom-meeting/src/bjy-common/util/keypath.d.ts +41 -0
  28. package/esm/boom-meeting/src/bjy-common/util/logger.d.ts +42 -0
  29. package/esm/boom-meeting/src/bjy-common/util/network.d.ts +4 -0
  30. package/esm/boom-meeting/src/bjy-common/util/object.d.ts +83 -0
  31. package/esm/boom-meeting/src/bjy-common/util/os.d.ts +14 -0
  32. package/esm/boom-meeting/src/error/errorMap.d.ts +70 -0
  33. package/esm/boom-meeting/src/handleEvent/attachEvents.d.ts +48 -0
  34. package/esm/boom-meeting/src/handleEvent/brtcNetEvent.d.ts +9 -0
  35. package/esm/boom-meeting/src/handleEvent/customMessageEvent.d.ts +2 -0
  36. package/esm/boom-meeting/src/handleEvent/handleParticipantEvent.d.ts +24 -0
  37. package/esm/boom-meeting/src/handleEvent/handleRoomEvent.d.ts +20 -0
  38. package/esm/boom-meeting/src/handleEvent/messageEvent.d.ts +5 -0
  39. package/esm/boom-meeting/src/handleEvent/pullUser.d.ts +7 -0
  40. package/esm/boom-meeting/src/handleEvent/roomErrEvent.d.ts +9 -0
  41. package/esm/boom-meeting/src/handleEvent/streamEvent.d.ts +22 -0
  42. package/esm/boom-meeting/src/type/customStats.d.ts +123 -0
  43. package/esm/boom-meeting/src/type/index.d.ts +9 -0
  44. package/esm/boom-meeting/src/type/stream.d.ts +15 -0
  45. package/esm/boom-meeting/src/type/user.d.ts +9 -0
  46. package/esm/boom-meeting/src/util/PackLoss.d.ts +7 -0
  47. package/esm/boom-meeting/src/util/Privileges.d.ts +20 -0
  48. package/esm/boom-meeting/src/util/ReportCollector.d.ts +22 -0
  49. package/esm/boom-meeting/src/util/Stutter.d.ts +19 -0
  50. package/esm/boom-meeting/src/util/base64.d.ts +4 -0
  51. package/esm/boom-meeting/src/util/checkPermissions.d.ts +1 -0
  52. package/esm/boom-meeting/src/util/checkSystemRequirements.d.ts +1 -0
  53. package/esm/boom-meeting/src/util/devices.d.ts +2 -0
  54. package/esm/boom-meeting/src/util/formatUserId.d.ts +2 -0
  55. package/esm/boom-meeting/src/util/is.d.ts +70 -0
  56. package/esm/boom-meeting/src/util/peerToPeerProbe.d.ts +9 -0
  57. package/esm/boom-meeting/src/util/request.d.ts +45 -0
  58. package/esm/boom-meeting/src/util/roomUtils.d.ts +9 -0
  59. package/esm/index.js +29 -0
  60. package/esm/index.js.map +7 -0
  61. package/esm/src/BMChat/BMChatVM.d.ts +26 -0
  62. package/esm/src/BMChat/BMMessageInfo.d.ts +31 -0
  63. package/esm/src/BMRoom/BMLiveVM.d.ts +35 -0
  64. package/esm/src/BMRoom/BMRoom.d.ts +705 -0
  65. package/esm/src/BMRoom/BMRoomInfo.d.ts +215 -0
  66. package/esm/src/BMRoom/BMRoomVM.d.ts +317 -0
  67. package/esm/src/BMRoom/RoomEvent.d.ts +1 -0
  68. package/esm/src/BMStream/BMSpeaker.d.ts +26 -0
  69. package/esm/src/BMStream/BMStreamModel.d.ts +305 -0
  70. package/esm/src/BMStream/BMStreamModelVM.d.ts +260 -0
  71. package/esm/src/BMStream/getHTMLMediaStreamOptions.d.ts +35 -0
  72. package/esm/src/BMStream/sortStream.d.ts +30 -0
  73. package/esm/src/BMUser/BMUser.d.ts +156 -0
  74. package/esm/src/BMUser/BMUserVM.d.ts +177 -0
  75. package/esm/src/SingletonQueue/SingletonQueue.d.ts +26 -0
  76. package/esm/src/audioPlay/AudioPlay.d.ts +31 -0
  77. package/esm/src/bjy-common/function/debounce.d.ts +9 -0
  78. package/esm/src/bjy-common/function/execute.d.ts +9 -0
  79. package/esm/src/bjy-common/function/getErrorMessage.d.ts +1 -0
  80. package/esm/src/bjy-common/function/isDef.d.ts +1 -0
  81. package/esm/src/bjy-common/function/isNative.d.ts +1 -0
  82. package/esm/src/bjy-common/function/isUndef.d.ts +1 -0
  83. package/esm/src/bjy-common/function/nextTick.d.ts +2 -0
  84. package/esm/src/bjy-common/function/throttling.d.ts +9 -0
  85. package/esm/src/bjy-common/function/toNumber.d.ts +1 -0
  86. package/esm/src/bjy-common/function/toString.d.ts +1 -0
  87. package/esm/src/bjy-common/type/api.d.ts +66 -0
  88. package/esm/src/bjy-common/type/options.d.ts +7 -0
  89. package/esm/src/bjy-common/type/type.d.ts +90 -0
  90. package/esm/src/bjy-common/util/CustomEvent.d.ts +30 -0
  91. package/esm/src/bjy-common/util/Emitter.d.ts +57 -0
  92. package/esm/src/bjy-common/util/NextTask.d.ts +28 -0
  93. package/esm/src/bjy-common/util/Sleep.d.ts +14 -0
  94. package/esm/src/bjy-common/util/Timer.d.ts +13 -0
  95. package/esm/src/bjy-common/util/array.d.ts +96 -0
  96. package/esm/src/bjy-common/util/browser.d.ts +6 -0
  97. package/esm/src/bjy-common/util/constant.d.ts +50 -0
  98. package/esm/src/bjy-common/util/holder.d.ts +6 -0
  99. package/esm/src/bjy-common/util/is.d.ts +49 -0
  100. package/esm/src/bjy-common/util/keypath.d.ts +41 -0
  101. package/esm/src/bjy-common/util/logger.d.ts +42 -0
  102. package/esm/src/bjy-common/util/network.d.ts +4 -0
  103. package/esm/src/bjy-common/util/object.d.ts +83 -0
  104. package/esm/src/bjy-common/util/os.d.ts +14 -0
  105. package/esm/src/bjy-common/util/string.d.ts +102 -0
  106. package/esm/src/constants.d.ts +129 -0
  107. package/esm/src/error/RTCError.d.ts +20 -0
  108. package/esm/src/error/errorMap.d.ts +70 -0
  109. package/esm/src/error/errorType.d.ts +96 -0
  110. package/esm/src/handleEvent/attachEvents.d.ts +48 -0
  111. package/esm/src/handleEvent/brtcNetEvent.d.ts +9 -0
  112. package/esm/src/handleEvent/customMessageEvent.d.ts +2 -0
  113. package/esm/src/handleEvent/handleParticipantEvent.d.ts +24 -0
  114. package/esm/src/handleEvent/handleRoomEvent.d.ts +20 -0
  115. package/esm/src/handleEvent/messageEvent.d.ts +5 -0
  116. package/esm/src/handleEvent/pullUser.d.ts +7 -0
  117. package/esm/src/handleEvent/roomErrEvent.d.ts +9 -0
  118. package/esm/src/handleEvent/streamEvent.d.ts +22 -0
  119. package/esm/src/index.d.ts +2 -0
  120. package/esm/src/logger/logger.d.ts +86 -0
  121. package/esm/src/type/customStats.d.ts +123 -0
  122. package/esm/src/type/index.d.ts +9 -0
  123. package/esm/src/type/stream.d.ts +15 -0
  124. package/esm/src/type/user.d.ts +9 -0
  125. package/esm/src/util/PackLoss.d.ts +7 -0
  126. package/esm/src/util/Pqueue.d.ts +62 -0
  127. package/esm/src/util/Privileges.d.ts +20 -0
  128. package/esm/src/util/ReportCollector.d.ts +22 -0
  129. package/esm/src/util/Stutter.d.ts +19 -0
  130. package/esm/src/util/Thread.d.ts +12 -0
  131. package/esm/src/util/base64.d.ts +4 -0
  132. package/esm/src/util/checkPermissions.d.ts +1 -0
  133. package/esm/src/util/checkSystemRequirements.d.ts +1 -0
  134. package/esm/src/util/constant.d.ts +67 -0
  135. package/esm/src/util/devices.d.ts +2 -0
  136. package/esm/src/util/emitter.d.ts +43 -0
  137. package/esm/src/util/formatUserId.d.ts +2 -0
  138. package/esm/src/util/is.d.ts +70 -0
  139. package/esm/src/util/peerToPeerProbe.d.ts +9 -0
  140. package/esm/src/util/request.d.ts +45 -0
  141. package/esm/src/util/roomUtils.d.ts +9 -0
  142. package/esm/src/util/sortUtils.d.ts +10 -0
  143. package/esm/src/util/util.d.ts +78 -0
  144. package/esm/utils/BoomError.d.ts +19 -0
  145. package/esm/utils/ErrorTypes.d.ts +139 -0
  146. package/esm/utils/index.d.ts +9 -0
  147. package/package.json +16 -12
  148. package/umd/boom-core/src/BoomCore/BCClient/clientEventType.d.ts +428 -0
  149. package/umd/boom-meeting/src/BMChat/BMChatVM.d.ts +26 -0
  150. package/umd/boom-meeting/src/BMRoom/BMRoomVM.d.ts +317 -0
  151. package/umd/boom-meeting/src/BMRoom/RoomEvent.d.ts +1 -0
  152. package/umd/boom-meeting/src/BMStream/BMStreamModel.d.ts +305 -0
  153. package/umd/boom-meeting/src/BMStream/BMStreamModelVM.d.ts +260 -0
  154. package/umd/boom-meeting/src/BMUser/BMUser.d.ts +156 -0
  155. package/umd/boom-meeting/src/BMUser/BMUserVM.d.ts +177 -0
  156. package/umd/boom-meeting/src/audioPlay/AudioPlay.d.ts +31 -0
  157. package/umd/boom-meeting/src/bjy-common/function/debounce.d.ts +9 -0
  158. package/umd/boom-meeting/src/bjy-common/function/getErrorMessage.d.ts +1 -0
  159. package/umd/boom-meeting/src/bjy-common/function/isDef.d.ts +1 -0
  160. package/umd/boom-meeting/src/bjy-common/function/isUndef.d.ts +1 -0
  161. package/umd/boom-meeting/src/bjy-common/function/throttling.d.ts +9 -0
  162. package/umd/boom-meeting/src/bjy-common/function/toNumber.d.ts +1 -0
  163. package/umd/boom-meeting/src/bjy-common/type/api.d.ts +66 -0
  164. package/umd/boom-meeting/src/bjy-common/type/options.d.ts +7 -0
  165. package/umd/boom-meeting/src/bjy-common/type/type.d.ts +90 -0
  166. package/umd/boom-meeting/src/bjy-common/util/CustomEvent.d.ts +30 -0
  167. package/umd/boom-meeting/src/bjy-common/util/Emitter.d.ts +57 -0
  168. package/umd/boom-meeting/src/bjy-common/util/NextTask.d.ts +28 -0
  169. package/umd/boom-meeting/src/bjy-common/util/Sleep.d.ts +14 -0
  170. package/umd/boom-meeting/src/bjy-common/util/Timer.d.ts +13 -0
  171. package/umd/boom-meeting/src/bjy-common/util/array.d.ts +96 -0
  172. package/umd/boom-meeting/src/bjy-common/util/browser.d.ts +6 -0
  173. package/umd/boom-meeting/src/bjy-common/util/holder.d.ts +6 -0
  174. package/umd/boom-meeting/src/bjy-common/util/keypath.d.ts +41 -0
  175. package/umd/boom-meeting/src/bjy-common/util/logger.d.ts +42 -0
  176. package/umd/boom-meeting/src/bjy-common/util/network.d.ts +4 -0
  177. package/umd/boom-meeting/src/bjy-common/util/object.d.ts +83 -0
  178. package/umd/boom-meeting/src/bjy-common/util/os.d.ts +14 -0
  179. package/umd/boom-meeting/src/error/errorMap.d.ts +70 -0
  180. package/umd/boom-meeting/src/handleEvent/attachEvents.d.ts +48 -0
  181. package/umd/boom-meeting/src/handleEvent/brtcNetEvent.d.ts +9 -0
  182. package/umd/boom-meeting/src/handleEvent/customMessageEvent.d.ts +2 -0
  183. package/umd/boom-meeting/src/handleEvent/handleParticipantEvent.d.ts +24 -0
  184. package/umd/boom-meeting/src/handleEvent/handleRoomEvent.d.ts +20 -0
  185. package/umd/boom-meeting/src/handleEvent/messageEvent.d.ts +5 -0
  186. package/umd/boom-meeting/src/handleEvent/pullUser.d.ts +7 -0
  187. package/umd/boom-meeting/src/handleEvent/roomErrEvent.d.ts +9 -0
  188. package/umd/boom-meeting/src/handleEvent/streamEvent.d.ts +22 -0
  189. package/umd/boom-meeting/src/type/customStats.d.ts +123 -0
  190. package/umd/boom-meeting/src/type/index.d.ts +9 -0
  191. package/umd/boom-meeting/src/type/stream.d.ts +15 -0
  192. package/umd/boom-meeting/src/type/user.d.ts +9 -0
  193. package/umd/boom-meeting/src/util/PackLoss.d.ts +7 -0
  194. package/umd/boom-meeting/src/util/Privileges.d.ts +20 -0
  195. package/umd/boom-meeting/src/util/ReportCollector.d.ts +22 -0
  196. package/umd/boom-meeting/src/util/Stutter.d.ts +19 -0
  197. package/umd/boom-meeting/src/util/base64.d.ts +4 -0
  198. package/umd/boom-meeting/src/util/checkPermissions.d.ts +1 -0
  199. package/umd/boom-meeting/src/util/checkSystemRequirements.d.ts +1 -0
  200. package/umd/boom-meeting/src/util/devices.d.ts +2 -0
  201. package/umd/boom-meeting/src/util/formatUserId.d.ts +2 -0
  202. package/umd/boom-meeting/src/util/is.d.ts +70 -0
  203. package/umd/boom-meeting/src/util/peerToPeerProbe.d.ts +9 -0
  204. package/umd/boom-meeting/src/util/request.d.ts +45 -0
  205. package/umd/boom-meeting/src/util/roomUtils.d.ts +9 -0
  206. package/umd/index.js +29 -0
  207. package/umd/src/BMChat/BMChatVM.d.ts +26 -0
  208. package/umd/src/BMChat/BMMessageInfo.d.ts +31 -0
  209. package/umd/src/BMRoom/BMLiveVM.d.ts +35 -0
  210. package/umd/src/BMRoom/BMRoom.d.ts +705 -0
  211. package/umd/src/BMRoom/BMRoomInfo.d.ts +215 -0
  212. package/umd/src/BMRoom/BMRoomVM.d.ts +317 -0
  213. package/umd/src/BMRoom/RoomEvent.d.ts +1 -0
  214. package/umd/src/BMStream/BMSpeaker.d.ts +26 -0
  215. package/umd/src/BMStream/BMStreamModel.d.ts +306 -0
  216. package/umd/src/BMStream/BMStreamModelVM.d.ts +259 -0
  217. package/umd/src/BMStream/getHTMLMediaStreamOptions.d.ts +35 -0
  218. package/umd/src/BMStream/sortStream.d.ts +30 -0
  219. package/umd/src/BMUser/BMUser.d.ts +156 -0
  220. package/umd/src/BMUser/BMUserVM.d.ts +177 -0
  221. package/umd/src/SingletonQueue/SingletonQueue.d.ts +26 -0
  222. package/umd/src/audioPlay/AudioPlay.d.ts +31 -0
  223. package/umd/src/bjy-common/function/debounce.d.ts +9 -0
  224. package/umd/src/bjy-common/function/execute.d.ts +9 -0
  225. package/umd/src/bjy-common/function/getErrorMessage.d.ts +1 -0
  226. package/umd/src/bjy-common/function/isDef.d.ts +1 -0
  227. package/umd/src/bjy-common/function/isNative.d.ts +1 -0
  228. package/umd/src/bjy-common/function/isUndef.d.ts +1 -0
  229. package/umd/src/bjy-common/function/nextTick.d.ts +2 -0
  230. package/umd/src/bjy-common/function/throttling.d.ts +9 -0
  231. package/umd/src/bjy-common/function/toNumber.d.ts +1 -0
  232. package/umd/src/bjy-common/function/toString.d.ts +1 -0
  233. package/umd/src/bjy-common/type/api.d.ts +66 -0
  234. package/umd/src/bjy-common/type/options.d.ts +7 -0
  235. package/umd/src/bjy-common/type/type.d.ts +90 -0
  236. package/umd/src/bjy-common/util/CustomEvent.d.ts +30 -0
  237. package/umd/src/bjy-common/util/Emitter.d.ts +57 -0
  238. package/umd/src/bjy-common/util/NextTask.d.ts +28 -0
  239. package/umd/src/bjy-common/util/Sleep.d.ts +14 -0
  240. package/umd/src/bjy-common/util/Timer.d.ts +13 -0
  241. package/umd/src/bjy-common/util/array.d.ts +96 -0
  242. package/umd/src/bjy-common/util/browser.d.ts +6 -0
  243. package/umd/src/bjy-common/util/constant.d.ts +50 -0
  244. package/umd/src/bjy-common/util/holder.d.ts +6 -0
  245. package/umd/src/bjy-common/util/is.d.ts +49 -0
  246. package/umd/src/bjy-common/util/keypath.d.ts +41 -0
  247. package/umd/src/bjy-common/util/logger.d.ts +42 -0
  248. package/umd/src/bjy-common/util/network.d.ts +4 -0
  249. package/umd/src/bjy-common/util/object.d.ts +83 -0
  250. package/umd/src/bjy-common/util/os.d.ts +14 -0
  251. package/umd/src/bjy-common/util/string.d.ts +102 -0
  252. package/umd/src/constants.d.ts +129 -0
  253. package/umd/src/error/RTCError.d.ts +20 -0
  254. package/umd/src/error/errorMap.d.ts +70 -0
  255. package/umd/src/error/errorType.d.ts +96 -0
  256. package/umd/src/handleEvent/attachEvents.d.ts +47 -0
  257. package/umd/src/handleEvent/brtcNetEvent.d.ts +9 -0
  258. package/umd/src/handleEvent/customMessageEvent.d.ts +2 -0
  259. package/umd/src/handleEvent/handleParticipantEvent.d.ts +24 -0
  260. package/umd/src/handleEvent/handleRoomEvent.d.ts +20 -0
  261. package/umd/src/handleEvent/messageEvent.d.ts +5 -0
  262. package/umd/src/handleEvent/pullUser.d.ts +7 -0
  263. package/umd/src/handleEvent/roomErrEvent.d.ts +9 -0
  264. package/umd/src/handleEvent/streamEvent.d.ts +22 -0
  265. package/umd/src/index.d.ts +2 -0
  266. package/umd/src/logger/logger.d.ts +86 -0
  267. package/umd/src/type/customStats.d.ts +123 -0
  268. package/umd/src/type/index.d.ts +9 -0
  269. package/umd/src/type/stream.d.ts +12 -0
  270. package/umd/src/type/user.d.ts +9 -0
  271. package/umd/src/util/PackLoss.d.ts +7 -0
  272. package/umd/src/util/Pqueue.d.ts +62 -0
  273. package/umd/src/util/Privileges.d.ts +20 -0
  274. package/umd/src/util/ReportCollector.d.ts +22 -0
  275. package/umd/src/util/Stutter.d.ts +19 -0
  276. package/umd/src/util/Thread.d.ts +12 -0
  277. package/umd/src/util/base64.d.ts +4 -0
  278. package/umd/src/util/checkPermissions.d.ts +1 -0
  279. package/umd/src/util/checkSystemRequirements.d.ts +1 -0
  280. package/umd/src/util/constant.d.ts +67 -0
  281. package/umd/src/util/devices.d.ts +2 -0
  282. package/umd/src/util/emitter.d.ts +43 -0
  283. package/umd/src/util/formatUserId.d.ts +2 -0
  284. package/umd/src/util/is.d.ts +70 -0
  285. package/umd/src/util/peerToPeerProbe.d.ts +9 -0
  286. package/umd/src/util/request.d.ts +45 -0
  287. package/umd/src/util/roomUtils.d.ts +9 -0
  288. package/umd/src/util/sortUtils.d.ts +10 -0
  289. package/umd/src/util/util.d.ts +78 -0
  290. package/umd/utils/BoomError.d.ts +19 -0
  291. package/umd/utils/ErrorTypes.d.ts +139 -0
  292. package/umd/utils/index.d.ts +9 -0
  293. package/dist/esm/index.js +0 -6
  294. package/dist/esm/index.js.map +0 -1
  295. package/dist/index.d.mts +0 -4099
  296. package/dist/index.d.ts +0 -4099
  297. package/dist/index.js +0 -6
  298. package/dist/index.js.map +0 -1
package/dist/index.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/index.ts","../src/BMRoom/BMRoom.ts","../src/error/RTCError.ts","../src/logger/logger.ts","../src/handleEvent/attachEvents.ts","../src/util/constant.ts","../src/BMUser/BMUser.ts","../src/constants.ts","../src/util/emitter.ts","../src/util/sortUtils.ts","../src/BMUser/BMUserVM.ts","../src/bjy-common/util/constant.ts","../src/bjy-common/util/is.ts","../src/bjy-common/util/string.ts","../src/bjy-common/function/toString.ts","../src/bjy-common/function/isNative.ts","../src/bjy-common/function/nextTick.ts","../src/util/util.ts","../src/util/Thread.ts","../src/BMChat/BMMessageInfo.ts","../src/handleEvent/handleParticipantEvent.ts","../src/util/roomUtils.ts","../src/handleEvent/streamEvent.ts","../src/handleEvent/handleRoomEvent.ts","../src/handleEvent/messageEvent.ts","../src/handleEvent/roomErrEvent.ts","../src/handleEvent/customMessageEvent.ts","../src/util/Pqueue.ts","../src/BMRoom/BMRoomVM.ts","../src/BMChat/BMChatVM.ts","../src/BMStream/BMStreamModel.ts","../src/BMStream/BMSpeaker.ts","../src/BMStream/sortStream.ts","../src/BMStream/BMStreamModelVM.ts","../src/BMStream/getHTMLMediaStreamOptions.ts","../src/BMRoom/BMRoomInfo.ts","../package.json","../src/BMRoom/BMLiveVM.ts","../src/handleEvent/brtcNetEvent.ts","../src/SingletonQueue/SingletonQueue.ts","../src/audioPlay/AudioPlay.ts"],"sourcesContent":["import BoomMeetingSDK from './BMRoom/BMRoom'\nimport { BoomError, Logger } from \"@hysc/utils\"\n\nexport default BoomMeetingSDK\nexport { Logger }\n// @ts-ignore\nwindow.BoomMeeting = BoomMeetingSDK\n\n// @ts-ignore\nwindow.BoomError = BoomError\n\n// @ts-ignore\nwindow.BOOMLogger = Logger\n","import BoomCore, {\n checkSystemSupport,\n createStream,\n enumAudioInputDevices,\n enumAudioOutputDevices,\n enumVideoDevices,\n getPermissions\n} from \"@hysc/core\";\nimport BoomError from \"../error/RTCError\";\nimport * as errorType from \"../error/errorType\";\nimport { attachEvents, MessageType } from \"../handleEvent/attachEvents\";\nimport BMRoomVM, { AudioProfileInfo } from \"./BMRoomVM\";\nimport BMUserVM from \"../BMUser/BMUserVM\";\nimport { SingleLocalStream, SingleRemoteStream, SingleStreamDeviceOption } from \"../type\";\nimport type { SubscribeOptions } from '@hysc/brtc'\n\nimport BMChatVM from \"../BMChat/BMChatVM\";\nimport BMStreamModelVM, { transShareScreen2User } from \"../BMStream/BMStreamModelVM\";\nimport type { Device, VideoProfile, AudioHint } from \"@hysc/brtc\";\nimport BMRoomInfo from \"./BMRoomInfo\";\nimport { BehaviorSubject, Subject } from \"rxjs\";\nimport BoomEmitter from \"../util/emitter\";\nimport {\n ADD_AUDIO_PLAY,\n ADD_PULL_USER,\n BIND_BIG_ELEMENT,\n BIND_ELEMENT,\n HANDLE_STREAM_CONNECT_ERROR,\n MANUAL_SUBSCRIPTION,\n RECEIVE_SUBSCRIBE_MESSAGE,\n SET_VOLUME,\n STREAM_SUFFIX_SCREEN,\n UNSUBSCRIBE_STREAM\n} from \"../constants\";\nimport BMStreamModel, { ConnectErrorMessage, SubscribeMessage } from \"../BMStream/BMStreamModel\";\nimport { streamPullQueue } from \"../util/Pqueue\";\nimport BMUser from \"../BMUser/BMUser\";\nimport PackageJson from \"../../package.json\";\nimport * as logger from \"../logger/logger\";\nimport {Logger, LOGLEVEL } from \"@hysc/utils\";\n\nimport {\n BMCameraNotAuthError,\n BMCameraOccupyError,\n BMCreateStreamError,\n BmLeaveError,\n BMMicNotAuthError,\n BMMicOccupyError,\n BmSetAudioOffError,\n BmSetMsgOffError,\n BmSetVideoOffError, BMShareStreamConnectError,\n BMStreamConnectError,\n BMStreamReconnectFailed,\n BMStreamReconnectSuccess,\n BmUpdateCustomStatsError,\n getStreamError,\n RepeatJoinError\n} from \"@hysc/utils\";\nimport BMLiveVM from \"./BMLiveVM\";\nimport { debounce, isNumber, toNumber } from \"lodash-es\";\nimport { addBrtcNetEvent } from \"../handleEvent/brtcNetEvent\";\nimport { checkStreamIsNormal, handleReconnectedStream, handleShareStreamFailed } from \"../handleEvent/streamEvent\";\nimport SingletonQueue, { PullItem } from \"../SingletonQueue/SingletonQueue\";\nimport { isShareStream } from \"../util/roomUtils\";\nimport { NETWORK_ERROR_QUEUE } from \"../handleEvent/roomErrEvent\";\nimport AudioPlay from \"../audioPlay/AudioPlay\";\n\ninterface BMRoomProps {\n initDevices: boolean\n}\n\ninterface MediaPermission {\n microphone: boolean,\n camera: boolean,\n screen: boolean\n}\n\nexport let _selfSortType = 1\n\nconst subscribeOptions: SubscribeOptions = { audio: true, video: true, streamType: 'small', videoEnable: true, audioEnable: true }\n\nexport let autoPlayAudio = true\n\nexport default class BMRoom {\n public roomVM: BMRoomVM | null = null //房间 视图模型\n public userVM!: BMUserVM\n public chatVM!: BMChatVM\n public bmStreamVm: BMStreamModelVM\n public observes: any\n public boomCore: BoomCore\n public videoDevices: Device[] = []\n public audioDevices: Device[] = []\n public audioOutputDevices: Device[] = []\n public selectVideoDevice: Device | null = null\n public selectAudioDevice: Device | null = null\n public selectAudioOutputDevice: Device | null = null\n public streamQueue = new SingletonQueue()\n\n /**\n * 这个参数是和业务相关的功能,业务上的参会者列表是可以配置的,如果设置了只展示一列,那么所有的用户都要存储\n * 在commonUserList中\n */\n public userListColumns: number = 1\n\n /**\n * 排序规则 1 是标品排序, 2 是中移排序\n */\n public sortType: number = 1\n\n /**\n * brtc断网重连的时候,所有的订阅和播放相关的处理,都不需要\n */\n public BRTCConnectFailed = false\n\n /**\n * 本端推流失败次数\n */\n public pubFailedNum = 0\n\n public streamConnectedErrorQueue: Array<ConnectErrorMessage> = []\n\n /**\n * 会议模式\n * 1 会议\n * 2 直播\n */\n public conferenceMode: 1 | 2 = 1\n /**\n * 是不是大房间\n */\n public isBig = false\n\n public selectVideoDeviceWatcher = new BehaviorSubject(this.selectVideoDevice)\n public selectAudioDeviceWatcher = new BehaviorSubject(this.selectAudioDevice)\n public selectAudioOutputDeviceWatcher = new BehaviorSubject(this.selectAudioOutputDevice)\n\n public audioDevicesWatcher = new Subject<Device[]>()\n public videoDevicesWatcher = new Subject<Device[]>()\n public audioOutputDevicesWatcher = new Subject<Device[]>()\n public raiseHandleRespWatcher = new Subject<{ raiseHandsType: 0 | 1 | 2 | 3, raiseHands: boolean }>()\n public enableAudienceSpeakingWatcher = new Subject<boolean>()\n\n public mediaPermission: MediaPermission = {\n microphone: true,\n camera: true,\n screen: true\n }\n\n public videoProfile: VideoProfile = '360p'\n public audioProfile: AudioProfileInfo | null = null\n\n public voiceMode: AudioHint = ''\n\n public setVoiceMode(mode: AudioHint) {\n this.voiceMode = mode\n }\n\n /**\n * brtc断网重连要给端上事件响应,所有端上把流单独做处理的,需要在收到这个事件之后,重新处理所有的effect\n */\n public streamWSReconnectWatcher = new Subject<boolean>()\n\n /**\n * bloud断网重连的时候的提示\n */\n public bloudWSReconnectWatcher = new Subject<boolean>()\n\n public netConnecting = true\n public netConnectingWatcher = new Subject<boolean>()\n\n // 有没有sync room的权限,这个问题主要处理bloud里面ws onopen传递出去的事件,\n // 断网重连的话 onopen会触发reconnected 事件,这个事件后面会跟着调用syncRoom\n // syncRoom失败的话,再重新调用,会产生死循环\n hasSyncPermission: boolean = true\n\n /**\n * 会控底层相关处理, 比如是否取消自动拉流\n */\n private meetingControlOptions = {\n cancelAutoPull: false\n }\n // 设为焦点主屏的用户id\n forceId: string = ''\n\n\n /**\n * bloud brtc 断网重连的处理\n * networkState 记录网络状态\n * handleReconnectedStream 防抖函数,当双方有连接断网重连之后,会执行这个方法\n *\n * brtc 的sync-room 之后,本地会把所有的stream都销毁,清空,然后统一走一遍查询处理\n * 绑定新的stream,这么做简单粗暴处理所有的brtc流,防止流重复问题i\n */\n networkState = {\n bloud: true,\n brtc: true\n }\n\n brtcNetEnableWatcher = new Subject<boolean>()\n public autoPlayAudio = true\n audioPlayer!: AudioPlay\n private pubFailedTimer: NodeJS.Timeout | null = null\n\n public get isSingleColumns() {\n return this.userListColumns === 1\n }\n\n /**\n * 传递信息用的,主要是用于message信令往上层业务发送消息\n */\n public messageWatcher = new BehaviorSubject<any>({\n type: MessageType.INIT,\n status: false,\n isNotCancelRootReport: false\n })\n\n public roomInfo\n public localUser\n // 直播拉流处理\n public bmLiveVM: BMLiveVM;\n\n // 是否在等候室\n public isInWaitRoom = false\n\n public shouldPlayAudio = true\n\n constructor({ initDevices }: BMRoomProps = { initDevices: true }) {\n\n Logger.setLogLevel(LOGLEVEL.INFO)\n\n logger.info(`\n******************************************************************************\n* 欢迎使用 BoomMeeting(${PackageJson.version}) Web SDK\n******************************************************************************\n `)\n\n Logger.info('this is formatted by hysc/logger module')\n\n const emitter = BoomEmitter.getInstance()\n this.localUser = new BMUser({}, true)\n this.roomInfo = new BMRoomInfo()\n this.roomInfo.bindRoom(this)\n this.bmLiveVM = new BMLiveVM(this)\n\n this.bmStreamVm = new BMStreamModelVM().initWithRoom(this)\n this.boomCore = new BoomCore({})\n\n emitter!.on(RECEIVE_SUBSCRIBE_MESSAGE, event => {\n this.handleSubMessage(event)\n })\n\n emitter!.on(HANDLE_STREAM_CONNECT_ERROR, event => {\n this.handleStreamConnectError(event)\n })\n\n emitter!.on(ADD_PULL_USER, (event) => {\n this.addUser2Queue(event)\n })\n\n /**\n * 手动订阅流\n */\n emitter!.on(MANUAL_SUBSCRIPTION, event => {\n this.manualSubscribeStreamModel(event.stream)\n })\n\n emitter!.on(UNSUBSCRIBE_STREAM, event => {\n this.handleUnsubscribe(event.stream)\n })\n\n emitter!.on(BIND_ELEMENT, event => {\n this.handleStreamBindElement(event.stream)\n })\n\n emitter!.on(BIND_BIG_ELEMENT, event => {\n this.handleStreamBindBigElement(event.stream)\n })\n\n emitter!.on(SET_VOLUME, event => {\n this.audioPlayer?.setVolume(event.streamId, event.volume)\n })\n\n emitter!.on(ADD_AUDIO_PLAY, event => {\n const sm = event.stream.stream\n if (sm && !sm.isLocalStream()) {\n if (!this.audioPlayer.playMap.has(sm)) {\n this.audioPlayer.addStream(sm as SingleRemoteStream)\n }\n }\n })\n\n // 网络情况检测\n window.addEventListener('offline', () => {\n this.netConnecting = false\n this.netConnectingWatcher.next(false)\n })\n window.addEventListener('online', () => {\n this.netConnecting = true\n this.netConnectingWatcher.next(true)\n NETWORK_ERROR_QUEUE.forEach(fn => {\n fn()\n })\n NETWORK_ERROR_QUEUE.clear()\n\n this.handleReprocessStreamError()\n })\n\n if (window.navigator.mediaDevices) {\n // 有媒体设备接入/拔出的监听\n if (initDevices) {\n window.navigator.mediaDevices.ondevicechange = async () => {\n await this.initDevices()\n await this.handleMediaDevicesChange()\n }\n this.initDevices()\n }\n }\n\n this.streamQueue.setQueueProcessor(this.queueProcessor)\n\n this.brtcNetEnableWatcher.subscribe(v => {\n if (v) {\n this.handleReprocessStreamError()\n }\n })\n this.bloudWSReconnectWatcher.subscribe(v => {\n if (v) {\n this.handleReprocessStreamError()\n }\n })\n }\n\n /**\n * 是否自动播放声音\n * @param value\n */\n setAutoPlayAudio(value: boolean) {\n this.autoPlayAudio = value\n autoPlayAudio = value\n }\n\n setMediaPermission(permission: MediaPermission) {\n this.mediaPermission = {\n ...this.mediaPermission,\n ...permission\n }\n logger.info('current media permission is ', '', '', [JSON.stringify(this.mediaPermission)])\n }\n\n /**\n * 是否应该播放声音\n * @param value\n */\n setShouldPlayAudio(value: boolean) {\n this.shouldPlayAudio = value\n }\n\n handleReprocessStreamError = () => {\n if (this.netConnecting && this.networkState.brtc && this.networkState.bloud && this.streamConnectedErrorQueue.length) {\n logger.info('brtc 网络恢复正常,处理重推逻辑', '', '', this.streamConnectedErrorQueue)\n this.streamConnectedErrorQueue.forEach(sn => {\n this.handleStreamConnectError(sn)\n })\n this.streamConnectedErrorQueue = []\n }\n }\n\n initAudioPlayer(playerContainerId: string) {\n logger.info('init audio player')\n this.audioPlayer = new AudioPlay(playerContainerId, this)\n }\n\n /**\n * 初始化底层会控相关\n * @param options\n */\n setupMeetingControlOptions(options: any) {\n if (options) {\n this.meetingControlOptions = {\n ...this.meetingControlOptions,\n ...options\n }\n }\n }\n\n /**\n * 收到对某个流状态的订阅和取消状态\n * @private\n * @param event\n */\n private handleSubMessage(event: SubscribeMessage) {\n streamPullQueue.addQueue(\n this.handleQueueTask.bind(this, event.stream),\n `${event.stream.streamId} - 订阅流 - display ${event.stream.isDisplay} - currentDisplay - ${event.stream.isCurrentDisplay}`,\n 0,\n event.stream.nickname,\n )\n }\n\n /**\n * 设置视频分辨率, 需要在入会之前调用\n * @param profile 设置视频分辨率\n */\n public setVideoProfile(profile: VideoProfile) {\n if (!profile) {\n return\n }\n this.videoProfile = profile\n }\n\n public setUserListColumns(column: number) {\n const col = toNumber(column)\n if (isNumber(col)) {\n this.userListColumns = col\n } else {\n throw new Error('参数必须是数字')\n }\n }\n\n public setSortType(type: number) {\n const sortType = toNumber(type)\n if (sortType > 2 || sortType < 1) {\n throw new Error('排序映射只能为 2 或者 1')\n }\n this.sortType = sortType\n _selfSortType = this.sortType\n }\n\n\n /**\n * 设置声音增益的属性,回音消除 音频降噪 声音增益等\n * @param audioProfile\n */\n public setAudioProfile(audioProfile: AudioProfileInfo) {\n this.audioProfile = audioProfile\n }\n\n /**\n * 设置共享屏幕用户的brtc Sig\n * @param sig\n */\n public setSig(sig: string) {\n this.boomCore.setShareSig(sig)\n }\n\n /**\n * 初始化输入设备\n */\n async initDevices() {\n return Promise.all([\n this.enumVideoDevices().then((devices: Device[]) => {\n this.videoDevices = devices\n this.videoDevicesWatcher.next(devices)\n }),\n this.enumAudioInputDevices().then((devices: Device[]) => {\n this.audioDevices = devices\n this.audioDevicesWatcher.next(devices)\n }),\n this.enumAudioOutputDevices().then((devices: Device[]) => {\n this.audioOutputDevices = devices\n this.audioOutputDevicesWatcher.next(devices)\n }),\n ]).then(() => {\n\n let videoDevices = this.videoDevices.filter(item => item.name == this.selectVideoDevice?.name)\n const videoDevice = videoDevices[0] ? videoDevices[0] : this.filterDevice(this.videoDevices)\n if (videoDevice) {\n this.setSelectVideoDevice(videoDevice)\n }\n\n let audioDevices = this.audioDevices.filter(item => item.name == this.selectAudioDevice?.name)\n const audioDevice = audioDevices[0] ? audioDevices[0] : this.filterDevice(this.audioDevices)\n if (audioDevice) {\n this.setSelectAudioDevice(audioDevice)\n }\n\n let speakerDevices = this.audioOutputDevices.filter(item => item.name == this.selectAudioOutputDevice?.name)\n const speakerDevice = speakerDevices[0] ? speakerDevices[0] : this.filterDevice(this.audioOutputDevices)\n if (speakerDevice) {\n this.setSelectSpeakerDevice(speakerDevice)\n }\n\n return {\n videoDevices: this.videoDevices,\n audioDevices: this.audioDevices,\n audioOutputDevices: this.audioOutputDevices,\n selectVideoDevice: this.selectVideoDevice,\n selectAudioDevice: this.selectAudioDevice,\n selectAudioOutputDevice: this.selectAudioOutputDevice,\n }\n })\n }\n\n /**\n * 筛选出默认选中的设备,如果没有,选择第一个\n * @param devices\n */\n private filterDevice(devices: Device[]) {\n const device = devices.filter(item => item.default)[0]\n if (device) {\n return device\n } else {\n return devices[0]\n }\n }\n\n /**\n * 处理用户设备变化之后的逻辑\n */\n private handleMediaDevicesChange = debounce(async () => {\n // 当前选中的设备不是default: true的\n // if (!this.selectAudioDevice?.default) {\n const audioDevice = this.filterDevice(this.audioDevices)\n await this.bmStreamVm.changeAudioInput(audioDevice)\n // }\n // if (!this.selectAudioOutputDevice?.default) {\n const device = this.filterDevice(this.audioOutputDevices)\n await this.bmStreamVm.changeSpeaker(device, true)\n // }\n }, 1000)\n\n public setSelectAudioDevice(device: Device) {\n if (this.selectAudioDevice?.deviceId !== device.deviceId) {\n logger.info('setSelectAudioDevice', '', '', ['deviceId =>', device.deviceId, 'name =>', device.name])\n this.selectAudioDevice = device\n this.selectAudioDeviceWatcher.next(device)\n }\n }\n\n public setSelectVideoDevice(device: Device) {\n if (this.selectVideoDevice?.deviceId !== device.deviceId) {\n logger.info('setSelectVideoDevice', '', '', ['deviceId =>', device.deviceId, 'name =>', device.name])\n this.selectVideoDevice = device\n this.selectVideoDeviceWatcher.next(device)\n }\n }\n\n public setSelectSpeakerDevice(device: Device) {\n if (this.selectAudioOutputDevice?.deviceId !== device.deviceId) {\n logger.info('setSelectSpeakerDevice', '', '', ['deviceId =>', device.deviceId, 'name =>', device.name])\n this.selectAudioOutputDevice = device\n this.selectAudioOutputDeviceWatcher.next(device)\n }\n }\n\n /**\n * 事件相关 observes执行subscribe, 即执行observes,并添加回调\n * @param observeName observe名称\n * @param subscribeParam subscribe的参数\n */\n public observe(observeName: string, subscribeParam: any) {\n return this.observes[observeName].subscribe(subscribeParam)\n }\n /**\n * 加入一个音视频通话房间(初始化房间对象)\n * 进房代表开始一个音视频通话会话,这时候 SDK 会监听远端用户进房退房情况,若有远端用户进房并且发布流,本地会收到 'stream-added' 事件。\n * 进房后用户可以通过 publish() 发布本地流,本地流发布成功后远端用户就会收到相应 'stream-added' 事件通知从而完成一个双向的音视频通话连接。\n *\n * @param {Object} props room创建所需属性\n * @param {String} props.roomId 房间号\n * @param {Number} props.userId 用户id\n * @param {String} props.host 会议内的请求地址\n * @param {String} props.getProxiesUrl 获取ws请求地址的路径\n * @param {String} props.secret 房间密码\n * @param {Boolean} props.create 是否执行房间的创建, 默认为自适应, 有房间则创建, 没房间则不创建\n * @param {String} props.customToken 用户token\n * @param {Number} props.limit 人数最大值\n * @param {Number} props.brtcAppId\n * @param {String} props.collection 数据上报地址\n * @param {Object} props.userinfo 用户信息\n * @param {Number} props.userinfo.cver 客户端版本\n * @param {String} props.userinfo.nickname 用户昵称\n * @param {String} props.userinfo.avatar 用户头像\n * @param {String} props.userinfo.pos 客户端类型\n * @param {Number} props.type //1:单一模式, 2:混合模式\n * @param {String} props.name //房间名\n * @example\n * {\n room: '111111',//房间号\n host: 'https://v3test.boom.cn',//会议内的请求地址\n getProxiesUrl: '/api/conference/v1/auth/token',//获取ws地址的路径\n secret: '',//房间密码\n type: 1,\n nickname: 'zzy',\n collection: '',//数据上报地址\n token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJsb2dpbiIsImlhdCI6MTY1MDA5ODkwMSwibmJmIjoxNjUwMDk4OTAxLCJqdGkiOiIiLCJzdWIiOjk4NSwicHJ2IjoiODdlN2UxYmVlMjcyMmJmMzk4NjQxN2IzMzUxZTVmMjYzODQwY2ExYyIsImF0dHIiOjAsImJkIjowfQ.b-J9TnmjOzaVUJeY83tY_d1rdu_ELAWx8iH3odBN5kE',//用户token\n userinfo: {\n userId: 985,//用户id\n pos: 'web',\n nickname: 'zzy',//用户昵称\n avatar: '',//用户头像\n }\n }\n */\n public async join(props: any) {\n const brtc_host = props.brtc_host\n if (brtc_host) {\n this.setCustomUrl(brtc_host)\n }\n\n try {\n if (this.boomCore.client) {\n logger.error('重复 join,请先调用 destroy')\n return Promise.reject(RepeatJoinError)\n }\n this.conferenceMode = props.roomType\n this.isBig = props.is_big\n\n logger.info('========================', 'join info', props.userId, ['roomId: ', props.room, ' roomType: ', props.roomType, ' roomName: ', props.name])\n\n this.localUser.setup(props.userId, props.userinfo, props.nickname)\n this.bmStreamVm.createStreamModel(this.localUser)\n this.userVM = new BMUserVM(this.boomCore, this.localUser, this)\n if (this.isBig) {\n this.userVM.commTimer = 1000\n }\n this.roomVM = new BMRoomVM(\n this.boomCore,\n this.userVM,\n this.roomInfo,\n )\n this.roomVM.initWithRoom(this)\n this.chatVM = new BMChatVM(this.boomCore, this.userVM, this)\n this._attachEvents()\n\n await this.boomCore.join(props).catch((bcError: any) => {\n return Promise.reject(bcError)\n })\n\n this.roomInfo.setup(this.boomCore.getRoomInfo())\n for (let key in this.observes) {\n this.observe(key, () => { })\n }\n this.bmStreamVm.startSpeakerDetector()\n this.roomInfo.setlock((this.boomCore.client as any)!.lock)\n\n addBrtcNetEvent(this.boomCore)\n } catch (error: any) {\n logger.error('join room error', '', '', [JSON.stringify(error)])\n return Promise.reject(error)\n }\n }\n\n /**\n * 离开房间\n * @returns\n */\n public async leave() {\n try {\n this.pubFailedTimer && clearTimeout(this.pubFailedTimer)\n this.pubFailedNum = 0\n BoomEmitter.removeEmitter()\n autoPlayAudio = true\n this.audioPlayer?.destroy()\n this.bmStreamVm.clearCache()\n if (this.bmStreamVm.canvasTimer) {\n clearTimeout(this.bmStreamVm.canvasTimer)\n }\n const result = await this.boomCore.leave().catch(() => {\n logger.error('bloud离会失败')\n })\n for (let key in this.observes) {\n this.observes[key]?.unsubscribe()\n }\n this.observes = {} //清空observes\n return result\n } catch (error) {\n logger.error('leave room error', '', '', [JSON.stringify(error)])\n return Promise.reject(BmLeaveError(JSON.stringify(error)))\n }\n }\n\n /**\n * 释放房间,会议结束时调用\n */\n public async releaseRoom() {\n await this.boomCore.releaseRoom()\n }\n\n\n /**\n * 启动录制\n * @param {String} opts.filename - 录制文件名\n * @param {Object} opts.capture - 采集属性\n * @param {Number} opts.capture.width - 宽度\n * @param {Number} opts.capture.height - 高度\n * @param {Number} opts.capture.fps - 帧率\n * @param {Number} opts.record - 编码属性\n * @param {Number} opts.record.bitrate - 编码码率\n * @param {String|undefined} opts.record.format - 编码格式\n * @return {boolean}\n */\n public async startRecord(opts: any) {\n return await this.bmStreamVm.startRecord(opts)\n }\n\n /**\n * 停止录制\n */\n public async stopRecord() {\n return await this.bmStreamVm.stopRecord()\n }\n\n /**\n * 启用下一个录制分片\n * @param filename - 下一分片文件名\n */\n public async sliceRecord(filename: string) {\n return await this.bmStreamVm.sliceRecord(filename)\n }\n\n // 关闭房间\n public close() {\n this.bmStreamVm.clearCache()\n this.boomCore.close()\n }\n\n /**\n * 开关对端摄像头\n * @param status true:开,false:关\n * @param uid 用户id\n */\n public async setRemoteVideoEnable(status: boolean, uid: string) {\n await this.roomVM!.setRemoteVideoEnable(status, uid).catch(err => {\n return Promise.reject(err)\n })\n }\n\n /**\n * 开关对端麦克风(现在还不知道怎么实现, 未找到实现逻辑)\n * @param status true:开,false:关\n * @param uid 用户id\n * @param isNotCancelRootReport 当打开麦克风时, 是否不取消音频权限申请\n */\n public async setRemoteAudioEnable(status: boolean, uid: string, isNotCancelRootReport: boolean | undefined) {\n await this.roomVM!.setRemoteAudioEnable(status, uid, isNotCancelRootReport).catch(err => {\n return Promise.reject(err)\n })\n }\n\n /**\n * 开关本地摄像头\n * @param status true:开,false:关\n * @param videoTrack\n */\n public async setLocalVideoEnable(status: boolean, videoTrack?: MediaStreamTrack) {\n await this.bmStreamVm!.setLocalVideoEnable(status, videoTrack).catch(err => {\n return Promise.reject(err)\n })\n }\n /**\n * 开关本地麦克风\n * @param status true:开,false:关\n */\n public async setLocalAudioEnable(status: boolean) {\n await this.bmStreamVm!.setLocalAudioEnable(status).catch(err => {\n return Promise.reject(err)\n })\n }\n /**\n * 开关本地麦克风\n * @param status true:开,false:关\n */\n public async setLocalSpeakerEnable(status: boolean) {\n await this.bmStreamVm!.muteSpeaker(status).catch(err => {\n return Promise.reject(err)\n })\n }\n\n // 绑定监听\n private _attachEvents() {\n this.observes = attachEvents(\n this.boomCore,\n this.userVM,\n this.bmStreamVm,\n this.chatVM,\n this,\n )\n }\n\n /**\n * 创建本地流\n * @param options\n * @param sid\n */\n public async createSingleLocalStream(\n options: {\n video: boolean\n audio: boolean\n videoSource?: MediaStreamTrack\n audioSource?: MediaStreamTrack\n } = { video: true, audio: true },\n sid: string,\n ): Promise<SingleLocalStream> {\n const initOptions: SingleStreamDeviceOption = {\n video: options.video,\n audio: options.audio,\n cameraId: this.selectVideoDevice?.deviceId,\n microphoneId: this.selectAudioDevice?.deviceId,\n sourceType: 'camera'\n }\n\n if (options.videoSource) {\n initOptions.videoSource = options.videoSource\n }\n\n if (options.audioSource) {\n initOptions.audioSource = options.audioSource\n }\n\n\n initOptions.echoCancellation = true\n initOptions.noiseSuppression = true\n initOptions.autoGainControl = true\n\n if (this.voiceMode) {\n initOptions.audioHint = this.voiceMode\n initOptions.noiseSuppression = false\n }\n\n const stream = await this.boomCore.createLocalStream(initOptions, sid).catch(e => {\n logger.error('create brtc stream error', '', '', [JSON.stringify(e), (e as any)?.message])\n return Promise.reject(getStreamError(options.video ? '摄像头' : '麦克风'))\n })\n if (options.video) {\n if (this.videoProfile === '720p') {\n stream.setVideoEncoderConfiguration({\n width: 1280,\n height: 720,\n bitrate: 1500,\n frameRate: 25\n })\n } else {\n stream.setVideoProfile(this.videoProfile)\n }\n }\n try {\n await stream.init()\n } catch (e) {\n logger.error('brtc init stream failed', '', '', [(e as any)?.message])\n if (String(e).includes('Permission denied by system')) {\n if (options.video) {\n return Promise.reject(BMCameraNotAuthError())\n } else if (options.audio) {\n return Promise.reject(BMMicNotAuthError())\n }\n } else if (String(e).includes('Could not start video source')) {\n return Promise.reject(BMCameraOccupyError())\n } else if (String(e).includes('Could not start audio source')) {\n return Promise.reject(BMMicOccupyError())\n }\n return Promise.reject(BMCreateStreamError(options.video ? '摄像头' : '麦克风'))\n }\n return stream\n }\n\n /**\n * 这个方法只是为了生成brtc的流,目的是在用户只打开音频的情况下,然后在打开视频的时候,去创建一个只有视频的track的流\n * @param options\n * @param sid\n * @returns\n */\n public async createPBSingleLocalStream(\n options: { video: boolean; audio: boolean } = { video: true, audio: true },\n sid?: string,\n ) {\n const initOptions: SingleStreamDeviceOption = {\n video: options.video,\n audio: options.audio,\n cameraId: this.selectVideoDevice?.deviceId,\n microphoneId: this.selectAudioDevice?.deviceId,\n sourceType: 'camera'\n }\n initOptions.echoCancellation = true\n initOptions.noiseSuppression = true\n initOptions.autoGainControl = true\n\n if (this.voiceMode) {\n // @ts-ignore\n initOptions.audioHint = this.voiceMode\n initOptions.noiseSuppression = false\n }\n\n const stream = await this.boomCore.createPBLocalStream(initOptions, sid).catch(e => {\n return Promise.reject(e)\n })\n if (this.videoProfile === '720p') {\n stream.setVideoEncoderConfiguration({\n width: 1280,\n height: 720,\n bitrate: 1500,\n frameRate: 25\n })\n } else {\n stream.setVideoProfile(this.videoProfile)\n }\n await stream.init()\n return stream\n }\n\n /**\n * 枚举视频输入设备\n *\n * @returns 设备列表\n */\n public enumVideoDevices = enumVideoDevices\n\n /**\n * 枚举音频输入设备\n *\n * @returns 设备列表\n */\n public enumAudioInputDevices = enumAudioInputDevices\n\n /**\n * 枚举音频输出设备\n *\n * @returns 设备列表\n */\n public enumAudioOutputDevices = enumAudioOutputDevices\n\n /**\n * 检查音视频权限\n */\n public getPermissions = getPermissions\n\n public checkSystemSupport = checkSystemSupport\n\n public createStream = createStream\n\n public participantNotice = false\n\n /**\n * 订阅远端流\n * 可通过该订阅接口指明需要订阅音频、视频或者音视频流。\n *\n * @param remoteStream 需要订阅的远端流对象,由 ‘participant-published’ 事件获得\n * @param options 订阅选项\n * @returns\n */\n public async subscribe(\n remoteStream: SingleRemoteStream,\n options?: SubscribeOptions,\n ) {\n return this.boomCore.subscribe(remoteStream, options)\n }\n\n /**\n * 取消订阅远端流\n *\n * @param remoteStream 需要取消订阅的远端流对象\n * @return\n */\n public unsubscribe(remoteStream: SingleRemoteStream) {\n return this.boomCore.unsubscribe(remoteStream).catch(e => {\n return Promise.reject(e)\n })\n }\n\n /**\n * 发布本地音视频流。\n * 该方法需要在 join() 进房后调用,一次音视频会话中只能发布一个本地流。若想发布另外一个本地流,可先通过 unpublish() 取消发布当前本地流后再发布新的本地流。\n * 在发布本地流后,可通过 removeTrack()、addTrack()、 replaceTrack() 来更新本地流中的某个音频或视频流。\n * 发布本地流后远端会收到 ‘participant-published’ 事件通知。\n *\n * @param stream 创建的本地流对象\n * @return\n */\n public publish(stream: SingleLocalStream) {\n return new Promise((resolve, reject) => {\n this.boomCore.publish(stream)\n .then(() => {\n logger.info('brtc stream publish success')\n resolve(true)\n })\n .catch(async () => {\n if (this.pubFailedNum <= 3) {\n this.pubFailedNum += 1\n this.pubFailedTimer && clearTimeout(this.pubFailedTimer)\n this.pubFailedTimer = setTimeout(() => {\n logger.error(`local publish stream failed, retry failed num: ${this.pubFailedNum}`)\n return this.publish(stream).then(resolve).catch(reject)\n }, 3000)\n } else {\n logger.error(`retry publish local stream failed, ubpublish now`)\n await this.bmStreamVm.unpublishStream()\n reject(false)\n }\n })\n })\n\n }\n\n /**\n * 取消发布本地流。\n * 取消发布本地流后远端会收到 'participant-unpublished' 事件通知。\n * 请在 leave() 退房前取消已经发布的本地流。\n *\n * @param stream 取消发布的本地流对象\n * @return\n */\n public unpublish(stream: SingleLocalStream) {\n return this.boomCore.unpublish(stream).catch(e => {\n return Promise.reject(e)\n })\n }\n /**\n * 获取userList的用户对象\n * @param userId\n */\n public getUser(userId: string) {\n return this.userVM.getUser(userId)\n }\n /**\n * 改变主持人,只有主持人权限和房间创建者可以改变主持人(房间创建者可以收回主持人)\n * @param userId\n * @param isKeep 是否保留转移人的联席主持人身份\n */\n public async changeMaster(userId: string, isKeep = false) {\n return this.roomVM?.changeMaster(userId, isKeep).catch(e => e)\n }\n /**\n * 改变联席主持人,返回设置为联席主持人的bmuser对象\n * @param userId\n * @param status true:设置成联席主持人 false:取消联席主持人身份\n * @param hasS\n */\n public async updateManager(userId: string, status: boolean, hasS: boolean = true) {\n return this.roomVM!.updateManager(userId, status, hasS).catch(e => e)\n }\n /**\n * 获取房间主持人id\n */\n public getMaster(): string {\n return this.boomCore.getMaster()\n }\n /**\n * 获取房间创建者\n */\n public getCreator(): string {\n return this.boomCore.getCreator()\n }\n /**\n * 获取房间名称\n */\n public getName(): string {\n return this.boomCore.getName()\n }\n /**\n * 踢出用户\n * @param {String} userId 用户ID\n * @param withoutBlack 是否拉进黑名单 true 可以再进来 false 进不来\n */\n public async evictUser(userId: string, withoutBlack: boolean): Promise<any> {\n await this.roomVM?.evictUser(userId, withoutBlack).catch(e => e)\n }\n /**\n * 更新用户信息\n * @param {String} target - 目标用户id\n * @param {String} info - 用户信息或者自定义的字段\n */\n public async updateUser(target: string, info: any) {\n this.roomVM?.updateUser(target, info).catch(e => e)\n }\n /**\n * 获取最新消息序列号\n */\n public getMsgSeq(): number {\n return this.boomCore.getMsgSeq()\n }\n\n /**\n * 获取限制人数\n */\n public getLimits(): number {\n return this.boomCore.getLimits()\n }\n /**\n * 是否允许房间加入成员\n * @return {Boolean}\n */\n public getSwitch(): Boolean {\n return this.boomCore.getSwitch()\n }\n /**\n * 更新token\n * @param {String} token\n */\n // public updateToken(token: string) {\n // this.client.renewToken(token)\n // }\n /**\n * 同步房间信息,在事件 room-reconnected 触发后调用\n * @return {Promise}\n */\n public syncRoom(): Promise<any> {\n return this.boomCore.syncRoom()\n }\n /**\n * 更新房间状态\n * @param {Object} options - 更新房间信息参数\n * @param {Boolean} options.audiooff - 房间是否开启全员静音,可选\n * @param {Boolean} options.selfopenaudio - 房间是否允许成员自行开启语音\n * @param {Boolean} options.videooff - 房间是否开启禁用摄像头,可选\n * @param {Boolean} options.msgoff - 房间是否开启全员禁言,可选\n * @param {Boolean} options.switch - 房间是否开启准入开关,可选\n * @param {Boolean} options.lock - 房间是否锁定\n * @param {Boolean} options.secret - 不为空时表示房间密码,为以`md5(${room}.${secret})`计算所得值为参数\n * @param {Boolean} options.waitroom - 开关等候室 false 关闭\n * @returns {Promise}\n */\n public update(options: any): Promise<any> {\n return this.boomCore.update(options)\n }\n /**\n * 获取用户列表\n * @return {BMUser[]}\n */\n public getUsers() {\n return this.userVM.userList\n }\n /**\n * 获取用户总数\n * @deprecated\n * @return {Number}\n */\n public getTotalUsers(): Number {\n return this.userVM.userList.size\n }\n /**\n * 发送消息,缓存至服务器,会生成序列号\n * 端上会收到 new-message 信令\n * @param {String} message - 待发送消息, 必须是 JSON 格式的字符串\n * @param {String|undefined} to - 如果为空,则为广播消息,不为空,则为定向到to用户的私聊消息\n */\n public sendMessage(message: string, to: string | undefined): Promise<any> {\n return this.boomCore.sendMessage(message, to)\n }\n /**\n * 发送自定义消息 可绕过 W 权限\n * @param {String} message - 待发送消息\n * @param {String|undefined} to - 如果为空,则为广播消息,不为空,则定向到to用户的消息\n */\n public customMessage(message: string, to: string | undefined): Promise<any> {\n return this.boomCore.customMessage(message, to)\n }\n /**\n * 获取指定消息列表\n * @param {Number} startSeq - 起始序列号\n * @param {Number} endSeq - 终止序列号\n * @return {Promise<>}\n */\n public getMessages(startSeq: number, endSeq: number): Promise<any> {\n return this.boomCore.getMessages(startSeq, endSeq)\n }\n /**\n * 获取本地用户对象\n * @return {BMUser}\n */\n public getLocalParticipant() {\n let localUser = this.userVM?.getLocalUser()\n if (!localUser) {\n localUser = this.localUser\n }\n return localUser\n }\n\n /**\n * 是否开启全员静音\n * @return {Boolean}\n */\n public getAudioOff(): boolean {\n return this.boomCore.getAudioOff()\n }\n\n /**\n * 是否允许自行开启语音\n */\n public getSelfOpenAudio(): boolean {\n return this.boomCore.getSelfOpenAudio()\n }\n\n /**\n * 是否开启全员禁用摄像头\n * @return {Boolean}\n */\n public getVideoOff(): boolean {\n return this.boomCore.getVideoOff()\n }\n\n /**\n * 是否开启全员禁言[禁止发送消息]\n * @return {Boolean}\n */\n public getMsgOff(): boolean {\n return this.boomCore.getMsgOff()\n }\n\n /**\n * 是否锁定房间\n * @return {Boolean}\n */\n public getLock(): boolean {\n return this.boomCore.getLock()\n }\n /**\n * 获取房间信息\n * @return {Object}\n */\n public getRoomInfo(): BMRoomInfo {\n return this.roomInfo\n }\n\n /**\n * 设置全员静音\n * @param {Boolean} audiooff - 是否静音\n * @param {Boolean} selfopenaudio - 是否允许自行开启\n * @return {Promise}\n */\n public async setAudioOff(audiooff: boolean, selfopenaudio: boolean) {\n return await this.boomCore.setAudioOff(audiooff, selfopenaudio).catch(e => {\n return Promise.reject(BmSetAudioOffError(`boomCore.setAudioOff error ${JSON.stringify(e)}`))\n })\n }\n\n /**\n * 更新房间状态\n * @param opts\n */\n public async updateRoom(opts: any) {\n return this.boomCore.client.update(opts)\n }\n\n /**\n * 设置全员禁用摄像头\n * @param {Boolean} videooff - 是否禁用摄像头\n * @return {Promise}\n */\n public setVideoOff(videooff: boolean): Promise<any> {\n return this.boomCore.setVideoOff(videooff).catch(e => {\n return Promise.reject(BmSetVideoOffError(`boomCore.setVideoOff error ${JSON.stringify(e)}`))\n })\n\n }\n\n /**\n * 设置全员禁言\n * @param {Boolean} msgoff - 是否禁言\n * @return {Promise}\n */\n public setMsgOff(msgoff: boolean): Promise<any> {\n return this.boomCore.setMsgOff(msgoff).catch(e => {\n return Promise.reject(BmSetMsgOffError(`boomCore.setMsgOff error ${JSON.stringify(e)}`))\n\n })\n }\n\n /**\n * 设置是否允许加入成员\n * @param {Boolean} switch_ - 是否开启\n */\n public setSwitch(switch_: boolean) {\n return this.boomCore.setSwitch(switch_)\n }\n\n /**\n * 设置是否锁定房间\n * @param {Boolean} lock - 是否锁定\n */\n public async setLock(lock: boolean) {\n await this.boomCore.setLock(lock)\n return this.boomCore.getLock()\n }\n /**\n * 发送聊天室消息\n * @param msg\n * @param userId\n * @param lostNet\n */\n public sendChatMessage(msg: string, userId: string | undefined, lostNet: boolean): Promise<any> {\n if (!this.chatVM) {\n throw new BoomError(\n errorType.INVALID_OPERATION,\n '未初始化chatVM, 无法发送聊天信息',\n )\n }\n return this.chatVM.sendMessage(msg, userId, lostNet)\n }\n /**\n * 获取聊天室消息\n */\n public getChatMessage() {\n if (!this.chatVM) {\n throw new BoomError(\n errorType.INVALID_OPERATION,\n '未初始化chatVM, 无法获取聊天室消息',\n )\n }\n return this.chatVM.messageList\n }\n /**\n * 获取聊天室历史消息\n */\n public async getHistoryMessage() {\n return this.chatVM.getHistoryMessage()\n }\n /**\n * 更新房间自定义属性状态\n * @param {Object} customStats - 更新自定义房间信息参数\n * @param {Boolean} customStats.layoutMode - 0/1/2, // 默认为0,0:自由模式,可随时切换;1:是使用 defaultLayout,布局内可控;2:是使用 mainLayout,主会场同内容\n * @returns {Promise}\n */\n public updateCustomStats(customStats: any): Promise<any> {\n logger.info(\"updateCustomStats\", \"\", \"\", [JSON.stringify(customStats)])\n return this.boomCore.updateCustomStats({ ...customStats, pos: 'web' }).catch(e => {\n return Promise.reject(BmUpdateCustomStatsError(`.boomCore.updateCustomStats ${JSON.stringify(e)}`))\n })\n }\n /**\n * 获取自定义属性\n */\n public getCustomStats() {\n return this.boomCore.getCustomStats()\n }\n /**\n * 获取会议时间进度,返回秒数\n */\n public getDuration(): number {\n return this.boomCore.getDuration()\n }\n /**\n * 检测目标用户是否有主持人权限\n */\n public checkUserHasMaster(userId: string): boolean {\n return this.userVM.checkUserHasMaster(userId)\n }\n public async changeNickName(userId: string, nickName: string): Promise<any> {\n await this.roomVM?.changeNickName(userId, nickName)\n }\n\n /**\n * boom-web-sdk中,会存在缓存的情况\n * 所以可能会出现设置已经不存在的窗口的值,去拉不存在的窗口的流\n * 增加一层逻辑判断去处理该情况\n */\n public streamModelExits(streamModel: BMStreamModel) {\n const uid = streamModel.userId\n return streamModel.isShare ? this.bmStreamVm.shareStreamModels.has(uid) : this.bmStreamVm.streamModels.has(uid)\n }\n\n handleQueueTask = async (streamModel: BMStreamModel, noPlayChanged = false) => {\n\n if (this.BRTCConnectFailed) {\n return\n }\n\n // 有这个字段说明是取消自动拉流\n if (!streamModel.isLocal && this.meetingControlOptions.cancelAutoPull && !streamModel.shouldPull) {\n return\n }\n\n if (!this.streamModelExits(streamModel)) {\n logger.warn(`streamModel is not exits, userId: ${streamModel.userId}, isShare: ${streamModel.isShare}, ignore`)\n return\n }\n\n\n await this.handleStreamTask(streamModel, noPlayChanged)\n }\n\n async handleStreamTask(streamModel: BMStreamModel, noPlayChanged = false) {\n if (!this.streamModelExits(streamModel)) {\n logger.warn(`streamModel is not exits, userId: ${streamModel.userId}, isShare: ${streamModel.isShare}, ignore`)\n return\n }\n\n if (streamModel.stream) {\n if (this.conferenceMode === 1) {\n // 2. 然后判断是不是本地流,只有非本地流才需要去拉流\n await this.handlePull(streamModel)\n // 3. 拉完流之后就去播放\n await this.handlePlay(streamModel, noPlayChanged)\n // 4. 大小流切换\n await this.handleChangeStreamType(streamModel)\n } else {\n await this.bmLiveVM.handlePull(streamModel)\n await this.bmLiveVM.handleChangeStreamType(streamModel)\n await this.bmLiveVM.handlePlay(streamModel, noPlayChanged)\n }\n }else {\n if (((streamModel.isDisplay || streamModel.isInBig) && streamModel.bloudStream) || streamModel.audioEnable) {\n await this.addUser2Queue({ id: streamModel.userId, isScreen: streamModel.isShare, isWeb: streamModel.isWeb })\n }\n }\n }\n\n /**\n * 处理拉流的逻辑\n * @param streamModel\n */\n public async handlePull(streamModel: BMStreamModel) {\n if (!streamModel.isLocal) {\n if (streamModel.isMixer) {\n await this.handleSubscribeSteam(streamModel)\n }\n // 3. 不是本地流,就要去看目标状态和当前状态是不是一样,如果一样就不需要去拉流了,\n // 特殊情况,如果推了流,然后在取消推流,这个时候当前状态和目标状态是一致的, 需要使用hasPulled 字段判断一下是不是拉过它的流\n if (\n streamModel.isDisplay !== streamModel.isCurrentDisplay\n || streamModel.isInBig && streamModel.pulledStreamType !== streamModel.pulledStreamGoal\n || !streamModel.hasPulled\n ) {\n logger.info(' 订阅流 => ', '订阅', streamModel.userId, [\n ' streamId => ',\n streamModel.streamId,\n ' nickname => ',\n streamModel.nickname,\n ' 是否有流 => ',\n !!streamModel.stream,\n ' isDisplay => ',\n streamModel.isDisplay,\n ' isCurrentDisplay => ',\n streamModel.isCurrentDisplay,\n ' audioEnable => ',\n streamModel.audioEnable,\n 'videoEnable => ',\n streamModel.videoEnable,\n ' hasPulled => ',\n streamModel.hasPulled,\n ' isSubscribed => ',\n (streamModel.stream as SingleRemoteStream)?.isSubscribed?.()\n ])\n // 4. 置状态 拉流\n // 当前处于展示状态,或者没在展示但是有音频流才去拉流,不然就不用拉\n streamModel.isCurrentDisplay = streamModel.isDisplay\n streamModel.checkCount = 0\n if (\n streamModel.isDisplay\n || streamModel.isInBig\n || (!streamModel.isDisplay && (streamModel.audioEnable || streamModel.stream?.getAudioOn()))\n ) {\n await this.handleSubscribeSteam(streamModel)\n } else {\n // 当前不在展示,而且没有音频流,就要取消订阅这股流, 取消订阅之前先停止播放\n await this.handleUnsubscribeStream(streamModel)\n }\n }\n }\n }\n\n /**\n * 手动订阅流的处理\n */\n manualSubscribeStreamModel(streamModel: BMStreamModel) {\n streamPullQueue.addQueue(\n this.handleStreamTask.bind(this, streamModel),\n streamModel.streamId,\n 0,\n streamModel.nickname,\n )\n }\n\n /**\n * 取消订阅流的处理\n * @param streamModel\n */\n handleUnsubscribe(streamModel: BMStreamModel) {\n streamPullQueue.addQueue(\n this.handleUnsubscribeStream.bind(this, streamModel),\n streamModel.streamId,\n 0,\n streamModel.nickname,\n )\n }\n\n /**\n * 处理streamModel绑定 element 只处理播放逻辑\n * @param sm\n */\n handleStreamBindElement(sm: BMStreamModel) {\n streamPullQueue.addQueue(\n this.handlePlay.bind(this, sm, false, false),\n `bindElement-${sm.userId}-${sm.nickname}`,\n 0,\n sm.nickname\n )\n }\n\n /**\n * 处理streamModel 绑定另一个播放器(主要是大窗口), 只处理播放逻辑\n * @param sm\n */\n handleStreamBindBigElement(sm: BMStreamModel) {\n streamPullQueue.addQueue(\n this.handlePlayInBIg.bind(this, sm),\n `bindElement-${sm.userId}-${sm.nickname}`,\n 0,\n sm.nickname\n )\n }\n\n async handleUnsubscribeStream(streamModel: BMStreamModel) {\n if (streamModel.stream) {\n if (((streamModel.stream as SingleRemoteStream)?.isSubscribed?.() || streamModel.hasPulled)) {\n logger.info('取消订阅流 => ', '取消订阅', streamModel.userId, [\n ' streamId => ',\n streamModel.streamId,\n ' nickname => ',\n streamModel.nickname,\n ' 是否有流 => ',\n !!streamModel.stream,\n ' isDisplay => ',\n streamModel.isDisplay,\n ' isCurrentDisplay => ',\n streamModel.isCurrentDisplay,\n ' audioEnable => ',\n streamModel.audioEnable,\n 'videoEnable => ',\n streamModel.videoEnable,\n ' hasPulled => ',\n streamModel.hasPulled,\n ' isSubscribed => ',\n (streamModel.stream as SingleRemoteStream)?.isSubscribed?.()\n ])\n streamModel.hasPulled = false\n streamModel.pulledStreamType = 'small'\n streamModel.isInBig = false\n try {\n streamModel.stream?.stop()\n }catch (e) {\n }\n await this.unsubscribe(streamModel.stream as SingleRemoteStream)\n .then(() => {\n if (streamModel.stream) {\n this.audioPlayer?.removeStream(streamModel.stream)\n }\n streamModel.isSubScribedWatcher.next(false)\n logger.info('取消订阅流成功', '', streamModel.userId, [streamModel.nickname, streamModel.isDisplay, streamModel.isCurrentDisplay, streamModel.stream?.getStreamId()])\n })\n .catch(() => {\n logger.error('unsubscribe error')\n })\n }\n }\n }\n\n public async handleSubscribeSteam(streamModel: BMStreamModel) {\n try {\n if (streamModel.hasPulled && (streamModel.stream as SingleRemoteStream).isSubscribed()) {\n if (streamModel.isDisplay) {\n streamModel.stream?.unmuteVideo().then(() => {\n logger.info('stream unmute video success', 'unmute-video', streamModel.userId, ['streamId => ', streamModel.streamId])\n })\n } else {\n streamModel.stream?.muteVideo().then(() => {\n logger.info('stream mute video success', 'mute-video', streamModel.userId, ['streamId => ', streamModel.streamId])\n })\n }\n } else {\n logger.info('开始订阅')\n streamModel.hasPulled = true\n await this.subscribe(streamModel.stream as SingleRemoteStream, subscribeOptions)\n .then(() => {\n // 初始化订阅之后,判断一下当前的展示状态,如果是!display,mutevideo\n logger.info('订阅流结束', '订阅', streamModel.userId, [' nickname =>', streamModel.nickname, 'streamId =>', streamModel.streamId, 'display =>', streamModel.isDisplay])\n if (!streamModel.isDisplay) {\n streamModel.stream?.muteVideo()\n }\n if (streamModel.stream && streamModel.audioEnable) {\n this.audioPlayer?.addStream(streamModel.stream as SingleRemoteStream, true)\n }\n streamModel.pullFailedNum = 0\n streamModel.isSubScribedWatcher.next(true)\n this.bmStreamVm.addToRecorder(streamModel.stream!)\n if (streamModel.isDisplay && streamModel.videoEnable) {\n checkStreamIsNormal(streamModel)\n }\n })\n .catch(e => {\n logger.error('订阅流失败', '订阅', streamModel.userId, [' nickname =>', streamModel.nickname, 'streamId =>', streamModel.streamId, ' error => ', JSON.stringify(e)])\n streamModel.hasPulled = false\n streamModel.pulledStreamType = 'small'\n streamModel.pullFailedNum += 1\n streamModel.player?.destroy()\n if (streamModel.pullFailedNum <= 3) {\n this.handlePulledFailed(streamModel)\n } else {\n // 销毁这股流,重新去查\n streamModel.pullFailedNum = 0\n const isScreen = streamModel.isShare\n try {\n streamModel.stream?.destroy()\n } catch (e) {\n }\n streamModel.updateStream(undefined, false, this.bmStreamVm)\n logger.info('subscribe stream failed, need to reQuery stream', '', streamModel.userId, ['streamId =>', streamModel.streamId, 'hasStream => ', !!streamModel.stream, 'isWeb => ', streamModel.isWeb, 'isScreen => ', isScreen, 'bloudStreamState =>', JSON.stringify(streamModel.bloudStream)])\n if (streamModel.bloudStream) {\n this.addUser2Queue({ id: streamModel.userId, isWeb: streamModel.isWeb, isScreen: isScreen })\n }\n }\n })\n\n }\n } catch (e) {\n streamModel.hasPulled = false\n streamModel.pulledStreamType = 'small'\n console.error('订阅流失败', '', streamModel.userId, streamModel.nickname, '错误 =>', e)\n }\n }\n\n /**\n * 处理大小流切换\n * @param streamModel\n */\n public async handleChangeStreamType(streamModel: BMStreamModel) {\n if (!streamModel.isLocal) {\n if (streamModel.pulledStreamType !== streamModel.pulledStreamGoal && (streamModel.stream as SingleRemoteStream)?.isSubscribed()) {\n if ((streamModel.stream as SingleRemoteStream)?.isSubscribed() || streamModel.hasPulled) {\n logger.info('大小流切换 => ', '切换大小流', streamModel.userId, [\n ' streamId => ',\n streamModel.streamId,\n ' nickname => ',\n streamModel.nickname,\n ' 是否有流 => ',\n !!streamModel.stream,\n ' pulledStreamType =>',\n streamModel.pulledStreamType,\n ' pulledStreamGoal =>',\n streamModel.pulledStreamGoal\n ])\n // 8. 如果不一致,就置状态然后切换大小流\n streamModel.pulledStreamType = streamModel.pulledStreamGoal\n await this.boomCore.brtcClient!.setRemoteVideoStreamType((streamModel.stream as SingleRemoteStream), streamModel.pulledStreamGoal).catch((e: any) => {\n logger.error('大小流切换失败', '', streamModel.userId, ['error => ', JSON.stringify(e)])\n })\n logger.info('大小流切换结束', '', streamModel.userId, ['nickname =>', streamModel.nickname, ' isInBig => ', streamModel.isInBig, ' pulledStreamGoal => ', streamModel.pulledStreamGoal, 'pulledStreamType => ', streamModel.pulledStreamType])\n }\n }\n }\n }\n\n /**\n * 处理播放相关的逻辑\n * @param streamModel\n * @param noPlayChanged\n * @param shouldPlayBig\n */\n public async handlePlay(streamModel: BMStreamModel, noPlayChanged: boolean, shouldPlayBig = true) {\n if (!this.streamModelExits(streamModel)) {\n return\n }\n\n if (streamModel.isLocal) {\n if (!streamModel.isShare) {\n if (!noPlayChanged) {\n await streamModel.play()\n await streamModel.playInBig()\n }\n }\n } else {\n if ((streamModel.hasPulled || (streamModel?.stream as SingleRemoteStream)?.isSubscribed())) {\n if (!noPlayChanged || streamModel.isShare) {\n await streamModel.play()\n }\n if (streamModel.stream) {\n if (streamModel.audioEnable) {\n // audio 可能不存在,手动订阅流的操作端都没有初始化audioPlayer\n if (!this.audioPlayer?.playMap.has(streamModel.stream)) {\n this.audioPlayer?.addStream(streamModel.stream as SingleRemoteStream)\n }\n }\n }\n if (shouldPlayBig) {\n await this.handlePlayInBIg(streamModel)\n }\n }\n }\n }\n\n public async handlePlayInBIg(streamModel: BMStreamModel) {\n if (this.streamModelExits(streamModel)) {\n await streamModel.playInBig()\n }\n }\n\n /**\n * 处理brtc订阅这股流失败的处理\n * @param streamModel\n */\n private handlePulledFailed(streamModel: BMStreamModel) {\n const sId = streamModel.userId\n\n const exists = streamModel.isShare\n ? this.bmStreamVm.shareStreamModels.has(sId)\n : this.bmStreamVm.streamModels.has(sId)\n\n if (!exists) {\n return\n }\n\n streamPullQueue.addQueue(\n this.handleQueueTask.bind(this, streamModel),\n streamModel.streamId,\n 0,\n streamModel.nickname,\n )\n }\n\n /**\n * 处理流出现connect-error的逻辑,本地流需要重新推流,远端流需要重新拉流\n * @param event\n */\n private async handleStreamConnectError(event: ConnectErrorMessage) {\n const { stream: streamModel, isLocal } = event\n logger.info('handleStreamConnectError', '', '', ['nickname =>', streamModel.nickname, 'streamId => ', streamModel.streamId, 'isShare =>', streamModel.isShare, 'isLocal => ', isLocal])\n // 流出现connect-error的情况下,删除这股流的播放\n if (streamModel.stream) {\n this.audioPlayer?.removeStream(streamModel.stream)\n }\n if (isLocal) {\n if (streamModel.stream) {\n if (!streamModel.isShare) {\n this.bmStreamVm.localStreamConnectErrorWatcher.next(BMStreamConnectError())\n } else {\n this.bmStreamVm.localShareError.next(BMShareStreamConnectError())\n }\n if (this.netConnecting && this.networkState.brtc && this.networkState.bloud) {\n if (!streamModel.isShare) {\n logger.info('brtc 网络正常,重新推流')\n if (streamModel.stream) {\n await this.republishLocalStream(streamModel.stream as SingleLocalStream)\n }\n } else {\n logger.info('Local share stream has problem, now ,republish')\n handleShareStreamFailed(this, this.bmStreamVm)\n }\n } else {\n logger.error(`brtc 网络还没恢复,等恢复了在重新推流 `, '', streamModel.userId, ['nickname =>', streamModel.nickname, 'streamId => ', streamModel.streamId, 'isShare =>', streamModel.isShare])\n this.streamConnectedErrorQueue.push(event)\n }\n }\n } else {\n if (this.netConnecting && this.networkState.brtc) {\n streamModel.hasPulled = false\n streamModel.pulledStreamType = 'small'\n streamPullQueue.addQueue(\n this.handleQueueTask.bind(this, streamModel),\n streamModel.streamId,\n 0,\n streamModel.nickname,\n )\n } else {\n logger.error(`brtc 网络还没恢复,等恢复了在重新拉流 `, '', streamModel.userId, ['nickname =>', streamModel.nickname])\n this.streamConnectedErrorQueue.push(event)\n }\n }\n }\n\n republishLocalStream = debounce(async (stream: SingleLocalStream) => {\n const audioEnable = stream.getAudioOn() || false\n const videoEnable = stream.getVideoOn() || false\n logger.info('republish local stream ', '', '', [audioEnable, videoEnable])\n if (audioEnable || videoEnable) {\n await this.publish(stream as SingleLocalStream)\n .then(async () => {\n this.bmStreamVm.bloudStream = null\n await this.bmStreamVm.publishBloudStream(audioEnable, videoEnable)\n logger.info('local stream connect error, and republish success, bloud stream republish success', '', '', ['audio =>', audioEnable, ' video => ', videoEnable])\n this.bmStreamVm.localStreamConnectErrorWatcher.next(BMStreamReconnectSuccess(audioEnable, videoEnable))\n })\n .catch(() => {\n logger.info('local stream connect error, and republish failed', '', '', ['audio =>', audioEnable, ' video => ', videoEnable])\n // @ts-ignore\n this.bmStreamVm.localStreamConnectErrorWatcher.next(BMStreamReconnectFailed());\n })\n }\n }, 1000)\n\n /**\n * 设置用户禁止/允许发言\n * @param bmUser\n * @param status\n */\n public toggleAudienceSpeaking(bmUser: BMUser, status: boolean) {\n bmUser.permission.setAudio(status)\n this.updateUser(bmUser.userId, {\n permission: bmUser.permission.get(),\n })\n }\n\n /**\n * 更新用户的嘉宾身份 true 设置为嘉宾 false 设置为普通参会者\n * S -> permission\n * 普通参会者缺少S权限,嘉宾有S权限\n * @param user\n * @param status\n */\n public async updateUserIsGuest(user: BMUser, status: boolean) {\n user.permission.setSubscribe(status)\n await this.updateUser(user.userId, {\n permission: user.permission.get(),\n })\n }\n /**\n * 联席主持人设置嘉宾的操作\n * @param userId\n */\n public managerChangeToGuest(userId: string) {\n this.userVM!.managerChangeToGuest(userId)\n }\n\n /**\n * 将用户移动到等候室\n * @param target 用户id\n * @param toWait 是否移动到等候室\n * @param autoJoin 是否自动准入\n */\n moveUserRoom(target: string, toWait: boolean = false, autoJoin: boolean = false): Promise<any> {\n return this.boomCore.client!.moveUserRoom(target, toWait, autoJoin)\n }\n\n /**\n * 获取业务端是否开启参会者进入/离开直播通知\n * @param status\n */\n public getParticipantNotice(status: boolean) {\n this.participantNotice = status\n }\n\n /**\n *私有化部署url地址\n * @param url\n */\n public setCustomUrl(url: string) {\n this.boomCore.setCustomUrl(url)\n }\n\n /**\n * 重推本地流,在收到brtc的code 4001 之后,说明本地掉线了\n * 需要重新推本地流\n */\n async handleRePushSelf() {\n const localStream = this.getLocalParticipant()?.getMainStreamModel()?.stream as SingleLocalStream\n if (localStream) {\n await this.republishLocalStream(localStream)\n }\n }\n\n /**\n * 重拉远端流\n */\n handleResetOtherStreamStatus() {\n logger.info('brtc sync-room-completed')\n this.audioPlayer.clear()\n this.bmStreamVm.streamModels.forEach(m => {\n if (!m.isLocal) {\n m.hasPulled = false\n m.pulledStreamType = 'small'\n try {\n m.stream && m.stream.stop()\n m.stream?.destroy()\n }catch (e) {\n }\n m.updateStream(undefined, false, this.bmStreamVm)\n }\n })\n this.bmStreamVm.shareStreamModels.forEach(m => {\n if (!m.isLocal) {\n m.hasPulled = false\n m.pulledStreamType = 'small'\n const user = m.getUser()\n try {\n m.stream?.stop()\n m.stream?.destroy()\n }catch (e) {\n }\n user.removeStream(`${m.userId}${STREAM_SUFFIX_SCREEN}`)\n }\n })\n this.bmStreamVm.shareStreamModels.clear()\n this.bmStreamVm.shareStreamModelsWatcher.next(Array.from(this.bmStreamVm.shareStreamModels.values()))\n this.networkState.brtc = true\n setTimeout(() => {\n this.brtcNetEnableWatcher.next(true)\n this.streamWSReconnectWatcher.next(true)\n }, 2000)\n handleReconnectedStream(this)\n }\n\n async addUser2Queue(pullItem: PullItem) {\n\n if (pullItem.force) {\n this.processUser(new Map([[pullItem.id, pullItem]]))\n }\n\n if (pullItem.isScreen) {\n this.streamQueue.addUsers([pullItem])\n } else {\n const sm = this.bmStreamVm.streamModels.get(pullItem.id)\n if (sm && !sm.isLocal) {\n if (!sm.stream) {\n if (sm && (sm.bloudStream?.audio || (sm.bloudStream && sm.isDisplay))) {\n this.streamQueue.addUsers([pullItem])\n }\n }\n }\n }\n }\n\n processUser = async (uIds: Map<string, PullItem>) => {\n const realNeedQuery: Set<string> = new Set()\n uIds.forEach(u => {\n if (u.isScreen) {\n const shareStreamModel = this.bmStreamVm.getShareStreamModelByUId(u.id)\n if (!shareStreamModel || !shareStreamModel.stream) {\n if (u.isWeb) {\n realNeedQuery.add(`${u.id}_screen`)\n } else {\n realNeedQuery.add(u.id)\n }\n }\n } else {\n let user = this.bmStreamVm.streamModels.get(u.id)\n if (user && !user.stream) {\n realNeedQuery.add(u.id)\n }\n }\n })\n logger.info('brtc query streams', '', '', ['queryIds => ', JSON.stringify(Array.from(realNeedQuery))])\n if (realNeedQuery.size) {\n try {\n const streams: SingleRemoteStream[] = await this.queryBrtcStreams(Array.from(realNeedQuery))\n if (streams && streams.length) {\n const streamInfo = streams.map(s => [s.getUserId(), s.getStreamId()])\n logger.info('brtc query streams result', '', '', ['streamInfo =>', JSON.stringify(streamInfo)])\n if (streams) {\n this.handleAddStreams(streams)\n }\n }\n }catch (e) {\n logger.error('query stream error', '', '', [JSON.stringify(e)])\n }\n }\n }\n\n queueProcessor = debounce(this.processUser, 500, { maxWait: 1000 })\n\n async queryBrtcStreams(uids: string[]) {\n return await this.boomCore.brtcClient!.queryUsers(uids)\n }\n\n\n handleAddStreams(streams: SingleRemoteStream[]) {\n streams.forEach(s => {\n if (isShareStream(s)) {\n const sm = this.bmStreamVm.shareStreamModels.get(transShareScreen2User(s.getUserId().toString()))\n if (!sm || (sm && !sm.stream)) {\n this.bmStreamVm.remoteStreamPublished(s)\n }\n } else {\n const sm = this.bmStreamVm.streamModels.get(s.getUserId().toString())\n if (sm && !sm.stream) {\n this.bmStreamVm.remoteStreamPublished(s)\n }\n }\n })\n }\n\n\n async getForceUser(forceId: string) {\n const { users } = await this.boomCore.queryUsers([forceId])\n this.userVM.addBcUsersMap(users, true)\n this.userVM.getForceUserWatcher.next(true)\n }\n\n getVersion() {\n return PackageJson.version\n }\n}\n","import * as is from '../util/is'\nimport { BoomErrorMessage } from './errorMap'\n\nexport default class BoomError extends Error {\n\n // 这个类的实例不能使用 instanceOf 来判断(可能是 bable 的 bug) =_=| ,自己写一个函数来判断\n static instanceOf(error: any): boolean {\n return !!(error && error.BoomErrorFlag)\n }\n\n private BoomErrorFlag: boolean\n\n private code: number\n\n private eName?: string\n\n\n private error: any\n\n /**\n * @internal\n * @param code \n * @param name \n * @param message \n */\n constructor(code: number, message?: any, error?: any, name?: string) {\n super()\n //this.RTCType = getWebRTCType()\n this.code = code\n this.error = error\n this.BoomErrorFlag = true\n\n\n\n this.eName = name //|| (BoomErrorMessage[this.code] ? BoomErrorMessage[this.code].name : 'BRTCError')\n this.message = message //`[code: ${this.code}] [error_name: ${this.eName}] ${message || 'unkown'}`\n }\n\n /**\n * 获取错误码\n * \n * @returns 错误码\n */\n public getCode(): number {\n return this.code\n }\n}","// import * as is from './is'\nimport RTCError from '../error/RTCError'\n\n\n\n/**\n * debug 级别\n */\nexport const DEBUG = 1\n/**\n * info 级别\n */\nexport const INFO = 2\n/**\n * info 级别\n */\n// export const CALL = 3\n/**\n * warn 级别\n */\nexport const WARN = 3\n/**\n * error 级别\n */\nexport const ERROR = 4\n/**\n * 关闭所有日志\n */\nexport const CLOSE = 5\n/**\n * fatal 级别\n * @internal\n */\nexport const FATAL = 6\n\n\n/**\n * @internal\n * 是否上传\n */\nlet enableUpload: boolean = false\n\n/**\n * @internal\n */\nconst EMPTY_FUNCTION = function () {\n /** BRTC */\n}\n\n/**\n * 当前是否是源码调试,如果开启了代码压缩,empty function 里的注释会被干掉\n * \n * @internal\n */\nconst level = /BRTC/.test(EMPTY_FUNCTION.toString()) ? DEBUG : WARN\n\n/**\n * 格式化日志\n * \n * @internal\n * @param level \n * @param msg \n * @param tag \n * @param userId \n */\nfunction formatLog(level: string, msg: string, tag?: string, userId?: any) {\n let info: Array<any> = []\n // if (is.number(getWebRTCType())) {\n // info.push(getWebRTCType())\n // }\n if (tag) {\n info.push(tag)\n }\n if (userId) {\n info.push(userId)\n }\n return `[${new Date().toLocaleTimeString('chinese', { hour12: false })}] <${level}> [${info.join('|')}] ${msg}`\n}\n\n/**\n * 全局调试开关\n * \n * @internal\n */\nfunction getLevel() {\n if (window) {\n const logLevel = (window as any)['BRTC_LOG_LEVEL']\n if (logLevel >= DEBUG && logLevel <= FATAL) {\n return logLevel as number\n }\n }\n return level\n}\n\n/**\n * 设置日志输出级别\n * \n * @param level 日志输出级别\n */\nexport function setLevel(level: number): void {\n (window as any)['BRTC_LOG_LEVEL'] = level\n\n}\n\n/**\n * 打印 debug 日志\n *\n * @param msg 日志内容\n */\nexport function debug(msg: string, tag?: string, userId?: any, args: any = []): void {\n args.unshift(formatLog('DEBUG', msg, tag, userId))\n console.log(...args)\n}\n\n/**\n * 打印 info 日志\n *\n * @param msg 日志内容\n */\nexport function info(msg: string, tag?: string, userId?: any, args: any = []): void {\n args.unshift(formatLog('INFO', msg, tag, userId))\n console.log(...args)\n}\n\n/**\n * 打印 call 日志\n *\n * @param msg\n * @param args\n */\n// export function call(msg: string, tag?: string, args?: any): void {\n// if (nativeConsole && getLevel() <= CALL) {\n// args.unshift(formatLog('INFO', msg, tag))\n// nativeConsole.log.apply(nativeConsole.log, args)\n// }\n// }\n\n/**\n * 打印 warn 日志\n *\n * @param msg 日志内容\n */\nexport function warn(msg: string, tag?: string, userId?: any, args: any = []): void {\n args.unshift(formatLog('WARN', msg, tag, userId))\n console.log(...args)\n}\n\n/**\n * 打印 error 日志\n *\n * @param msg 日志内容\n */\nexport function error(msg: string, tag?: string, userId?: any, args: any = []): void {\n args.unshift(formatLog('ERROR', msg, tag, userId))\n console.log(...args)\n}\n\n/**\n * 致命错误,中断程序\n *\n * @param msg 日志内容\n */\nexport function fatal(code: number, name?: string, message?: string): void {\n throw new RTCError(code, name, message)\n}\n\n/**\n * 打开日志上传\n * \n */\nexport function enableUploadLog(): void {\n enableUpload = true\n}\n\n/**\n * 关闭日志上传\n * \n */\nexport function disableUploadLog(): void {\n enableUpload = false\n}\n\nexport const LogMap = {\n [DEBUG]: debug,\n [INFO]: info,\n // [CALL]: call,\n [WARN]: warn,\n [ERROR]: error\n}","import BoomCore from '@hysc/core'\nimport * as logger from '../logger/logger'\nimport BMStreamModelVM from \"../BMStream/BMStreamModelVM\";\nimport BMRoom from '../BMRoom/BMRoom'\nimport BMUserVM from \"../BMUser/BMUserVM\"\nimport BMChatVM from '../BMChat/BMChatVM'\nimport { BehaviorSubject } from 'rxjs'\nimport {\n handleChangeMaster,\n handleEvict,\n handleLeaveUsers,\n handleMoveUserRoom,\n handleParticipantJoin,\n handleParticipantLeft,\n handleUpdateUser,\n handleUserRejoined\n} from \"./handleParticipantEvent\";\nimport {\n handleBloudRoomReconnected,\n handleBloudRoomReconnecting, handleBloudRoomSync,\n handleBrtcRoomReconnected,\n handleBrtcRoomReconnecting,\n handleInitJoinRoomUsers,\n handleRoomConnected,\n handleRoomUpdated\n} from \"./handleRoomEvent\";\nimport { handleCustomMessage, handleSendMessage } from \"./messageEvent\"\nimport { handleBloudError, handleBRTCRoomError, NETWORK_ERROR_QUEUE, reconnectBRTCShareWS } from \"./roomErrEvent\";\nimport {\n handleBloudStreamPubAUpdate, handleBloudStreamPublished,\n handleBloudStreamUnPublished, handleBloudStreamUpdated, handleShareStreamFailed, handleStreamPublished\n} from \"./streamEvent\";\nimport { handleCustomStats } from \"./customMessageEvent\";\nimport { eventQueue } from \"../util/Pqueue\";\nimport { sleep } from \"../util/Thread\";\nimport { BMShareStreamReconnectFailed } from \"@hysc/utils\";\nimport type { StreamCustomInfo } from '@hysc/bloud/src/core/Room'\nimport { BloudEvents, BrtcEvents as BRTCEvents, CustomEvents as CustomEvent} from '@hysc/utils';\n\n/**\n * 收到消息信令的集合\n */\nexport enum MessageType {\n /**\n * 初始化watcher用\n */\n INIT = 'init',\n /**\n * 收到远端控制本地摄像头的消息\n */\n VIDEO_FORCE_CHANGE = 'video-force-change',\n /**\n * 收到远端控制本地麦克风的消息\n */\n AUDIO_FORCE_CHANGE = 'audio-force-change',\n}\n\n\nexport interface BloudStreamEventState {\n userId: string\n streamId: string\n isScreen: boolean\n video: boolean\n audio: boolean\n customInfo?: StreamCustomInfo\n}\n\nexport interface BloudStreamState {\n video: boolean\n audio: boolean\n isScreen: boolean\n customInfo?: StreamCustomInfo\n}\n\nexport interface BloudUnPubEvent {\n userId: string\n streamId: string\n isScreen: boolean\n}\n\nexport type Observes = {\n [k: string]: BehaviorSubject<any>\n}\n\nexport function attachEvents(boomCore: BoomCore, userVM: BMUserVM, bmStreamVm: BMStreamModelVM, chatVM: BMChatVM, bmRoom: BMRoom) {\n logger.info('attachEvents init')\n // @ts-ignore\n let observes: Observes = {}\n\n // ================================= 自定义事件 =========================================== //\n boomCore.on('toggle-screen-share', () => {\n logger.error('share stream video track ended, now unpublish share stream')\n // @ts-ignore\n bmStreamVm.localShareError.next(BMShareStreamReconnectFailed())\n bmStreamVm.toggleShareScreen(false, undefined).then(() => { })\n })\n\n boomCore.on('client-banned', async () => {\n await bmRoom.boomCore.leaveShare()\n })\n\n boomCore.on('share-brtc-error', async (data: any) => {\n const code = data.getCode()\n if (code === 4002) {\n try {\n logger.info('brtc share client disconnected, reconnecting')\n await boomCore.shareBrtcClient!.leave('room_close')\n reconnectBRTCShareWS(boomCore)\n .then(async () => {\n logger.info('brtc share client reconnected, retry repub share stream')\n await sleep(1000)\n if (boomCore.shareScreenStream) {\n const audioEnable = boomCore.shareScreenStream.getAudioOn()\n const videoEnable = boomCore.shareScreenStream.getVideoOn()\n boomCore.shareBrtcClient!.publish(boomCore.shareScreenStream)\n boomCore.createAndPubBloudShareStream(audioEnable, videoEnable)\n }\n })\n .catch(e => {\n throw new Error('共享屏幕重新入会失败')\n })\n } catch (e) {\n bmStreamVm.toggleShareScreen(false, undefined)\n .then(() => { })\n .catch(err => {\n logger.error('共享发生错误退会失败', '', '', [JSON.stringify(err)])\n })\n }\n }\n })\n\n // ================================ 自定义事件 结束 ======================================== //\n\n let allEvents: string[] = []\n\n allEvents = allEvents.concat(Object.values(BloudEvents))\n allEvents = allEvents.concat(Object.values(BRTCEvents))\n allEvents = allEvents.concat(Object.values(CustomEvent))\n\n // 遍历所有的event 给observes 添加初始事件\n allEvents.forEach(event => {\n observes[event] = new BehaviorSubject(null)\n })\n\n // 遍历所有的event 绑定对应的监听事件\n allEvents.forEach(eventKey => {\n switch (eventKey) {\n /** ================================================== brtc 事件 ================================================== */\n\n // 自己推流以后的事件 stream-published\n case BRTCEvents.STREAM_PUBLISHED:\n boomCore.on(BRTCEvents.STREAM_PUBLISHED, (event: any) => {\n eventQueue.addQueue(handleStreamPublished.bind(null, event, bmStreamVm, bmRoom, observes), BRTCEvents.STREAM_PUBLISHED)\n })\n break\n\n case BRTCEvents.BRTC_SYNC_ROOM_COMPLETED:\n boomCore.on(BRTCEvents.BRTC_SYNC_ROOM_COMPLETED, async (data: any) => {\n eventQueue.addQueue(bmRoom.handleResetOtherStreamStatus.bind(bmRoom), BRTCEvents.BRTC_SYNC_ROOM_COMPLETED)\n })\n break\n\n case CustomEvent.BRTC_SHARE_SYNC_ROOM_COMPLETED:\n boomCore.on(CustomEvent.BRTC_SHARE_SYNC_ROOM_COMPLETED, () => {\n logger.info('brtc share client sync completed, retry publish share stream')\n eventQueue.addQueue(handleShareStreamFailed.bind(null, bmRoom, bmStreamVm), CustomEvent.BRTC_SHARE_SYNC_ROOM_COMPLETED)\n })\n break\n\n case BRTCEvents.BRTC_ROOM_ROCONNECTING:\n boomCore.on(BRTCEvents.BRTC_ROOM_ROCONNECTING, (data: any) => {\n eventQueue.addQueue(handleBrtcRoomReconnecting.bind(null, data, bmRoom, observes), BRTCEvents.BRTC_ROOM_ROCONNECTING)\n })\n break\n\n case BRTCEvents.BRTC_ROOM_RECONNECTED:\n boomCore.on(BRTCEvents.BRTC_ROOM_RECONNECTED, async (data: any) => {\n eventQueue.addQueue(handleBrtcRoomReconnected.bind(null, data, bmRoom, observes), BRTCEvents.BRTC_ROOM_RECONNECTED)\n })\n break\n\n // brtc 以相同用户被顶\n case BRTCEvents.CLIENT_BANNED:\n boomCore.on(BRTCEvents.CLIENT_BANNED, (data: any) => {\n logger.info('brtc client banned')\n handleUserRejoined(observes, data)\n })\n break\n\n\n // brtc error\n case BRTCEvents.ERROR:\n boomCore.on(BRTCEvents.ERROR, async (data: any) => {\n if (bmRoom.netConnecting) {\n eventQueue.addQueue(handleBRTCRoomError.bind(null, data, bmRoom, boomCore, bmStreamVm, observes), BRTCEvents.ERROR)\n } else {\n // 断网了,然后,网络没恢复的时候brtc就报错了,这个时候存一下相关状态,等到网络恢复在重新去调用brtc 的join\n // 防止网络还没连上呢,就一直join\n NETWORK_ERROR_QUEUE.add(handleBRTCRoomError.bind(null, data, bmRoom, boomCore, bmStreamVm, observes))\n }\n })\n break\n\n /** ================================================== brtc 事件 结束 ================================================== **/\n\n /** ================================================== bloud 事件 ================================================== **/\n\n case BloudEvents.SYNC_FAILED:\n boomCore.on(BloudEvents.SYNC_FAILED, (data: any) => {\n logger.error('bloud sync failed, leave room')\n observes[BloudEvents.TIMEOUT].next(data)\n })\n break\n\n // 房间建立连接\n case BloudEvents.ROOM_CONNECTED:\n boomCore.on(BloudEvents.ROOM_CONNECTED, async (data: any) => handleRoomConnected(data, bmRoom, userVM, observes))\n break\n\n case CustomEvent.JOIN_READY:\n boomCore.on(CustomEvent.JOIN_READY, () => handleInitJoinRoomUsers(bmRoom))\n break\n\n //有人加入\n case BloudEvents.PARTICIPANT_JOINED:\n boomCore.on(BloudEvents.PARTICIPANT_JOINED, async (data: any) => {\n if (!bmRoom.isInWaitRoom) {\n eventQueue.addQueue(handleParticipantJoin.bind(null, data, userVM, bmStreamVm, boomCore, chatVM, observes), BloudEvents.PARTICIPANT_JOINED)\n }\n })\n break\n\n //有人离开\n case BloudEvents.PARTICIPANT_LEFT:\n boomCore.on(BloudEvents.PARTICIPANT_LEFT, (data: { userId: string, mode: number }) => {\n if (!bmRoom.isInWaitRoom) {\n // @ts-ignore\n eventQueue.addQueue(handleParticipantLeft.bind(null, data, userVM, bmRoom, observes, bmStreamVm, boomCore, chatVM), BloudEvents.PARTICIPANT_LEFT)\n }\n })\n break\n\n case BloudEvents.LEAVE_USERS:\n boomCore.on(BloudEvents.LEAVE_USERS, (data: any) => eventQueue.addQueue(handleLeaveUsers.bind(null, data, userVM, bmRoom, observes, bmStreamVm, boomCore, chatVM), BloudEvents.LEAVE_USERS))\n break\n\n //主持人改变\n case BloudEvents.CHANGE_MASTER:\n boomCore.on(BloudEvents.CHANGE_MASTER, (data: any) => {\n eventQueue.addQueue(handleChangeMaster.bind(null, data, userVM, bmRoom, observes, bmStreamVm), BloudEvents.CHANGE_MASTER)\n })\n break\n\n // 聊天\n case BloudEvents.SEND_MESSAGE:\n boomCore.on(BloudEvents.SEND_MESSAGE, (msg: any) => {\n eventQueue.addQueue(handleSendMessage.bind(null, msg, userVM, chatVM, observes), BloudEvents.SEND_MESSAGE)\n })\n break\n\n //接收到新消息\n case BloudEvents.CUSTOM_MESSAGE:\n boomCore.on(BloudEvents.CUSTOM_MESSAGE, (msg: any) => {\n eventQueue.addQueue(handleCustomMessage.bind(null, msg, bmRoom, observes), BloudEvents.CUSTOM_MESSAGE)\n })\n break\n\n // 踢出用户,所有人都会收到这个信令\n case BloudEvents.EVICTED:\n boomCore.on(BloudEvents.EVICTED, async (data: { userId: string }) => {\n // @ts-ignore\n eventQueue.addQueue(handleEvict.bind(null, data, userVM, bmStreamVm, bmRoom, observes), BloudEvents.EVICTED)\n })\n break\n\n // 用户信息被改变, 这里不要调vloud的getMaster,因为不准\n case BloudEvents.UPDATE_USER:\n boomCore.on(BloudEvents.UPDATE_USER, (data: any) => {\n eventQueue.addQueue(handleUpdateUser.bind(null, data, userVM, bmRoom, bmStreamVm, observes), BloudEvents.UPDATE_USER)\n })\n break\n\n // 房间状态被改变\n case BloudEvents.UPDATE_STATS:\n boomCore.on(BloudEvents.UPDATE_STATS, (data: any) => {\n eventQueue.addQueue(handleRoomUpdated.bind(null, data, bmRoom), BloudEvents.UPDATE_STATS)\n })\n break\n\n // custom-stats改变\n case BloudEvents.UPDATE_CUSTOM_STATS:\n boomCore.on(BloudEvents.UPDATE_CUSTOM_STATS, (data: any) => {\n eventQueue.addQueue(handleCustomStats.bind(null, data, bmRoom, observes), BloudEvents.UPDATE_CUSTOM_STATS)\n })\n break\n\n case BloudEvents.TIMEOUT:\n boomCore.on(BloudEvents.TIMEOUT, (data: any) => {\n eventQueue.addQueue(handleBloudError.bind(null, bmRoom, boomCore, bmStreamVm, data, observes), BloudEvents.TIMEOUT)\n })\n break\n\n // 用户被顶掉\n case BloudEvents.USER_REJOINED:\n boomCore.on(BloudEvents.USER_REJOINED, (data: any) => {\n logger.info('bloud user rejoined')\n handleUserRejoined(observes, data)\n })\n break\n\n // bloud reconnecting\n case BloudEvents.RECONNECTING:\n boomCore.on(BloudEvents.RECONNECTING, (data: any) => {\n eventQueue.addQueue(handleBloudRoomReconnecting.bind(null, data, bmRoom, observes), BloudEvents.RECONNECTING)\n })\n break\n\n // bloud room reconnected\n case BloudEvents.RECONNECTED:\n boomCore.on(BloudEvents.RECONNECTED, async (data: any) => {\n eventQueue.addQueue(handleBloudRoomReconnected.bind(null, data, bmRoom, observes), BloudEvents.RECONNECTED)\n })\n break\n\n // bloud sync room\n case BloudEvents.ROOM_SYNCED:\n boomCore.on(BloudEvents.ROOM_SYNCED, async (data: any) => {\n eventQueue.addQueue(handleBloudRoomSync.bind(null, data, userVM, bmRoom, bmStreamVm, observes), BloudEvents.ROOM_SYNCED)\n })\n break\n\n // bloud stream event\n case BloudEvents.STREAM_PUBLISHED:\n boomCore.on(BloudEvents.STREAM_PUBLISHED, async (data: BloudStreamEventState) => {\n eventQueue.addQueue(handleBloudStreamPublished.bind(null, data, bmStreamVm, observes), BloudEvents.STREAM_PUBLISHED)\n })\n break\n\n case BloudEvents.STREAM_REMOVED:\n boomCore.on(BloudEvents.STREAM_REMOVED, async (data: BloudUnPubEvent) => {\n eventQueue.addQueue(handleBloudStreamUnPublished.bind(null, data, bmStreamVm, observes), BloudEvents.STREAM_REMOVED)\n })\n break\n\n case BloudEvents.UPDATE_STREAM:\n boomCore.on(BloudEvents.UPDATE_STREAM, async (data: BloudStreamState) => {\n eventQueue.addQueue(handleBloudStreamUpdated.bind(null, data, bmStreamVm, observes), BloudEvents.UPDATE_STREAM)\n })\n\n case BloudEvents.STREAM_UPDATE:\n boomCore.on(BloudEvents.STREAM_UPDATE, async (data: BloudStreamEventState) => {\n eventQueue.addQueue(handleBloudStreamPubAUpdate.bind(null, data, bmStreamVm), BloudEvents.STREAM_UPDATE)\n })\n break\n\n // 本地用户等候室相关信令\n case BloudEvents.MOVE_USER_ROOM:\n boomCore.on(BloudEvents.MOVE_USER_ROOM, async (data: any) => {\n eventQueue.addQueue(handleMoveUserRoom.bind(null, bmRoom, userVM, data, observes), BloudEvents.MOVE_USER_ROOM)\n })\n break\n\n /** ================================================== bloud 事件结束 ================================================== **/\n\n default:\n boomCore.on(eventKey, (data: any) => observes[eventKey].next(data))\n break\n }\n })\n // @ts-ignore\n return observes\n}\n\n","/**\n * @file 为了压缩,定义的常量\n * @author zhaogaoxing\n */\n\nexport const TRUE = true\nexport const FALSE = false\nexport const NULL = null\nexport const UNDEFINED = void 0\nexport const MINUS_ONE = -1\n\nexport const RAW_TRUE = 'true'\nexport const RAW_FALSE = 'false'\nexport const RAW_NULL = 'null'\nexport const RAW_UNDEFINED = 'undefined'\n\nexport const RAW_THIS = 'this'\nexport const RAW_VALUE = 'value'\nexport const RAW_LENGTH = 'length'\nexport const RAW_FUNCTION = 'function'\nexport const RAW_WILDCARD = '*'\nexport const RAW_DOT = '.'\nexport const RAW_SLASH = '/'\nexport const RAW_TAG = 'tag'\n\nexport const KEYPATH_PARENT = '..'\nexport const KEYPATH_CURRENT = RAW_THIS\n\n/**\n * Single instance for window in browser\n */\nexport const WINDOW = typeof window !== RAW_UNDEFINED ? window : UNDEFINED\n\n/**\n * Single instance for document in browser\n */\nexport const DOCUMENT = typeof document !== RAW_UNDEFINED ? document : UNDEFINED\n\n/**\n * Single instance for global in nodejs or browser\n */\nexport const GLOBAL = typeof global !== RAW_UNDEFINED ? global : WINDOW\n\n\n/**\n * Single instance for noop function\n */\nexport const EMPTY_FUNCTION = function () {\n /** bjy-util */\n}\n\n/**\n * 空对象,很多地方会用到,比如 `a || EMPTY_OBJECT` 确保是个对象\n */\nexport const EMPTY_OBJECT = Object.freeze({})\n\n/**\n * 空数组\n */\nexport const EMPTY_ARRAY = Object.freeze([])\n\n/**\n * 空字符串\n */\nexport const EMPTY_STRING = ''\n\n\n\nexport const WEBRTC_TYPE_VLOUD = 0\n\nexport const WEBRTC_TYPE_TENCENT = 1\n\nexport const PRODUCTION = 'production'\n\nexport const BETA = 'beta'\n\nexport const DEVELOPMENT = 'development'\n\nexport const LOGGER_TAG_CLIENT = 'c'\n\nexport const LOGGER_TAG_STREAM = 's'\n\nexport const LOGGER_TAG_SIGNAL = 'g'\n\nexport const LOGGER_TAG_PLAYER = 'p'\n\nexport const MEDIA_TYPE_CAMERA = 'videoinput'\n\nexport const MEDIA_TYPE_MIC = 'audioinput'\n\nexport const MEDIA_TYPE_SPEAKER = 'audiooutput'\n\nexport const ROOM_CHANNEL_TYPE_WS = 0\n\nexport const ROOM_CHANNEL_TYPE_DC = 1\n\nexport const SING_MODE = 1\nexport const MIX_MODE = 2","import BMStreamModel from '../BMStream/BMStreamModel'\nimport { BehaviorSubject } from 'rxjs'\nimport { BCUser } from \"@hysc/core\"\nimport { CHANG_IS_GUEST, RAISE_HAND, SIGNAL_SUFFIX, STREAM_SUFFIX_SCREEN, USER_SORT_NUM_CHANGE } from \"../constants\"\nimport BoomEmitter from '../util/emitter'\nimport BMRoom from '../BMRoom/BMRoom'\nimport * as logger from '../logger/logger'\nimport { getSortNum } from \"../util/sortUtils\"\n\nexport type Operation = 'none' | 'getMaster' | 'getManager' | 'removeMaster' | 'getGuest' | 'removeGuest' | 'removeManager' | 'changeNickName' | 'speakerEnable' | 'changeShare' | 'updateUser' | 'raiseHandsVideo' | 'raiseHandsAudio' | 'audienceEnableSpeaking' | 'inBackground' | 'raiseHand'\n\ninterface IUserActionWatcher {\n operation: Operation\n user: BMUser\n}\n\ninterface UserInfo {\n avatar: string,\n jointime: number,\n nickname: string,\n pos: string,\n userId: string,\n status?: {\n audioRaiseHands: boolean,\n videoRaiseHands: boolean\n }\n}\n\nexport interface RaiseHandInfo {\n status: 'raiseHandsAudio' | 'raiseHandsVideo' | 'raiseHand'\n user: BMUser\n}\n\nexport default class BMUser {\n /**\n * 用户id\n */\n public userId: string\n /**\n * 用户信息\n */\n public userInfo: UserInfo\n public nickName: string //昵称\n public isMaster: boolean //是否为主持人\n public isManager: boolean //是否为联席主持人\n public mirror!: boolean //镜像\n public isLocal!: boolean //是否是本地用户\n public isToupingma!: boolean //是否有投屏码\n public hasMultiple!: boolean //是否有多路流\n public isCreate: boolean //这个人是不是这个房间的创建者\n public hasShare: boolean //当前人是否在屏幕共享\n public audienceEnableSpeaking: boolean //当前人是观众时是否允许发言\n /** 头像 */\n public avatar: string\n private streamModels = new Map<string, BMStreamModel>() //流列表\n public permission: any //权限对象\n /**\n * 监听器, 监听返回对象属性\n * @property {string} operation\n * 'getManager':获得管理员权限/成为联席主持人\n * 'getMaster':成为主持人\n * 'removeManager':取消管理员权限/取消联席主持人\n * 'removeMaster':取消主持人\n * 'changeNickName':改变昵称\n * 'speakerEnable':扬声器开关状态改变\n * 'changeShare': 是否在屏幕共享\n * 'raiseHandsVideo': 是否视频举手\n * 'raiseHandsAudio': 是否音频举手\n * 'raiseHand':\b单纯的举手\n * @property {BMUser} user\n */\n public watcher: BehaviorSubject<IUserActionWatcher>\n\n /**\n * 排序\n */\n public sortNum: number = 100\n\n /**\n * 举手相关\n */\n public raiseVideoHands = false\n public raiseAudioHands = false\n public raiseHand = false\n public isAudience = false\n /**\n * 是不是普通参会者\n */\n isCommonUser: boolean = false\n /**\n * 如果改用户是移动端, 该值用于判断这个用户是否在后台\n */\n public inBackground = false\n public raiseHandTime: number = 0\n\n /**\n * 是不是web端入会\n */\n public get isWeb() {\n return !!(this.userInfo.pos && (this.userInfo.pos.includes('web') || this.userInfo.pos.includes('pc')))\n }\n\n constructor(user: any, isLocal = false) {\n this.userId = user.userId\n this.userInfo = user.userInfo\n this.nickName = user.nickname\n this.isMaster = !!user.isMaster\n this.isManager = !!user.isManager\n this.isToupingma = !!user.isToupingma\n this.isLocal = isLocal\n this.hasMultiple = !!user.hasMultiple\n this.isCreate = !!user.isCreate\n this.hasShare = !!user.hasShare\n this.avatar = user.userInfo?.avatar\n this.permission = user.permission\n this.raiseAudioHands = !!user.raiseAudioHands\n this.raiseVideoHands = !!user.raiseVideoHands\n this.raiseHand = !!user.raiseHand\n this.isAudience = !!user.isAudience\n this.isCommonUser = !!user.isCommonUser\n this.inBackground = !!user.inBackground\n this.audienceEnableSpeaking = !!user.audienceEnableSpeaking\n this.raiseHandTime = user.raiseHandTime || 0\n const defaultValue = { operation: 'none', user: this } as IUserActionWatcher\n this.watcher = new BehaviorSubject<IUserActionWatcher>(defaultValue) //权限监听\n this.updateSortNum(false)\n }\n\n setup(userId: string, userinfo: UserInfo, nickname: string) {\n this.isLocal = true\n this.userId = userId\n this.userInfo = userinfo\n if (nickname) {\n this.nickName = nickname\n } else {\n this.nickName = userinfo.nickname\n }\n this.avatar = userinfo.avatar\n }\n\n public getMainStreamModel() {\n return this.streamModels.get(this.userId)\n }\n\n public get nickname() {\n return this.nickName\n }\n\n public getShareStreamModel() {\n return this.streamModels.get(`${this.userId}${STREAM_SUFFIX_SCREEN}`)\n }\n /**\n * 获取用户麦克风开启状态\n */\n get audioEnable() {\n const model = this.getMainStreamModel()\n if (model) {\n return model!._audio_enable\n } else {\n return false\n }\n }\n\n get isMixer() {\n return this.userId.includes('-mixer-')\n }\n\n /**\n * 获取用户视频开启状态\n */\n get videoEnable() {\n const model = this.getMainStreamModel()\n if (model) {\n return model!._video_enable\n } else {\n return false\n }\n }\n\n get isSharing() {\n let isShare = false\n for (let stream of this.streamModels.values()) {\n if (stream.isShare) {\n isShare = true\n break\n }\n }\n return isShare\n }\n\n /**\n * 是否是信号源\n */\n get isSignal() {\n return !!this.userId?.startsWith(SIGNAL_SUFFIX)\n }\n\n /**\n * 检测当前用户是否有主持人权限\n */\n public checkLocalHasMaster() {\n return this.isMaster || this.isManager\n }\n\n /**\n * 给用户添加流\n * @param streamId\n * @param stream 流\n */\n public addStream(streamId: string, stream: BMStreamModel) {\n this.streamModels.set(streamId, stream)\n this.watcher.next({\n operation: 'changeShare',\n user: this,\n })\n }\n\n /**\n * 删除流\n * @param streamId\n */\n public removeStream(streamId: string) {\n this.streamModels.delete(streamId)\n if (streamId.includes(STREAM_SUFFIX_SCREEN)) {\n logger.info('删除的是共享屏幕的流:', '', '', ['streamId =>', streamId])\n }\n setTimeout(() => {\n this.watcher.next({\n operation: 'changeShare',\n user: this,\n })\n }, 400)\n }\n /**\n * 获取用户id\n */\n public getID() {\n return this.userId\n }\n /**\n * 获取用户昵称\n */\n public getNickName() {\n return this.nickName\n }\n /**\n * 获取用户信息\n */\n public getUserInfo() {\n return this.userInfo\n }\n /**\n * 获取用户流信息\n */\n public getStreams() {\n return this.streamModels\n }\n /**\n * updateUserInfo更新用户信息(除了isMaster,isMaster是通过change-master事件改变的)\n * @param bcUser\n * @param participant\n * @param bmRoom\n * @returns\n */\n public updateUserInfo(bcUser: BCUser, participant: any = {}, bmRoom: BMRoom) {\n const customInfo = participant?.params?.customInfo\n const updateKeys = customInfo?.updateKeys || []\n let isRaiseHand = false\n\n let status: Operation = 'none';\n logger.info('updateUserInfo =>', 'updateUser', bcUser.userId, ['updateKeys', updateKeys.toString(), 'permission', bcUser.permission?.permission, 'isMaster =>', this.isMaster, 'isManager =>', this.isManager])\n\n if (this.nickName !== bcUser.nickname) {\n status = 'changeNickName'\n }\n\n //取消联席主持人的判断\n if (!this.isMaster && this.isManager && !bcUser.permission.getManage()) {\n status = 'removeManager'\n this.isManager = false\n }\n //成为联席主持人的判断\n if (!this.isMaster && !this.isManager && bcUser.permission.getManage() && updateKeys.indexOf('changeMaster') == -1) {\n status = 'getManager'\n this.isManager = true;\n }\n if (bcUser.userinfo.pos) {\n this.userInfo = bcUser.userinfo\n } else {\n const pos = this.userInfo.pos\n this.userInfo = bcUser.userinfo\n this.userInfo.pos = pos // pos 任何时候都不应该给赋值冲掉.\n }\n if (updateKeys.includes(\"changeMaster\") || updateKeys.includes(\"permission\")) {\n bcUser.permission = participant.getPermission()\n }\n\n // 举手处理\n // 音频举手\n if (updateKeys.includes('raiseHandsAudio')) {\n this.raiseAudioHands = customInfo.raiseHandsAudio\n status = 'raiseHandsAudio'\n BoomEmitter.emitter!.emit(RAISE_HAND, { status: 'raiseHandsAudio', user: this })\n isRaiseHand = true\n }\n\n //视频举手\n if (updateKeys.includes('raiseHandsVideo')) {\n this.raiseVideoHands = customInfo.raiseHandsVideo\n status = 'raiseHandsVideo'\n BoomEmitter.emitter!.emit(RAISE_HAND, { status: 'raiseHandsVideo', user: this })\n isRaiseHand = true\n }\n // 单纯的举手\n if (updateKeys.includes('raiseHand')) {\n this.raiseHand = customInfo.raiseHand\n this.raiseHandTime = customInfo.raiseHandTime\n status = 'raiseHand'\n BoomEmitter.emitter!.emit(RAISE_HAND, { status: 'raiseHand', user: this })\n isRaiseHand = true\n }\n if (bmRoom.conferenceMode !== 1 && this.isAudience && updateKeys.includes('permission')) {\n // 观众允许发言\n if (participant.params?.customInfo?.permission.indexOf('A') !== -1) {\n bmRoom.enableAudienceSpeakingWatcher.next(true)\n this.audienceEnableSpeaking = true\n status = 'audienceEnableSpeaking'\n bmRoom.bmLiveVM.handleAudienceEnable()\n }\n // 观众禁止发言\n if (participant.params?.customInfo?.permission.indexOf('A') === -1) {\n bmRoom.enableAudienceSpeakingWatcher.next(false)\n this.audienceEnableSpeaking = false\n status = 'audienceEnableSpeaking'\n bmRoom.bmLiveVM.handleAudienceDisable()\n }\n\n\n }\n if (updateKeys.includes('inBackground')) {\n status = 'inBackground'\n this.inBackground = customInfo.inBackground\n }\n\n this.nickName = bcUser.nickname\n this.permission = bcUser.permission\n\n\n let preIsGuest = !this.isCommonUser\n this.isCommonUser = !bcUser.permission.getSubscribe()\n if (preIsGuest !== !this.isCommonUser) {\n logger.info(`身份有发生过变化,从${preIsGuest ? '嘉宾' : '普通参会者'} => ${this.isCommonUser ? '普通参会者' : '嘉宾'}`)\n BoomEmitter.emitter!.emit(CHANG_IS_GUEST, { user: this, isGuest: !this.isCommonUser, preIsGuest: preIsGuest })\n }\n if (status) {\n this.watcher.next({\n operation: status,\n user: this,\n })\n }\n if (!isRaiseHand || (isRaiseHand && !this.isLocal)) {\n this.updateSortNum(true)\n }\n }\n\n /** 是否有管理权限, 是主持人或联席主持人之一 */\n public hasManager() {\n return this.isManager || this.isMaster\n }\n\n /** 获取用户后面的身份标识 */\n public getNicknameSuffix() {\n let nickNameSuffix = ''\n if (this.isLocal && this.isMaster) {\n nickNameSuffix = '(我、主持人)'\n } else if (this.isLocal && this.isManager) {\n nickNameSuffix = '(我、联席主持人)'\n } else if (this.isLocal) {\n nickNameSuffix = '(我)'\n } else if (this.isMaster) {\n nickNameSuffix = '(主持人)'\n } else if (this.isManager) {\n nickNameSuffix = '(联席主持人)'\n } else if (this.isSharing && !this.isToupingma) {\n nickNameSuffix = '的共享屏幕'\n } else if (this.isSharing && this.isToupingma) {\n nickNameSuffix = '(仅共享屏幕)'\n }\n return nickNameSuffix\n }\n\n /**\n * 更新当前用户的排序\n */\n public updateSortNum(force:boolean = true, shouldDelay = false) {\n let sortNum = getSortNum(this)\n this.setSortNum(sortNum, force, shouldDelay)\n }\n\n setSortNum(sortNum: number, force: boolean, shouldDelay: boolean) {\n if (this.sortNum === sortNum) {\n return\n }else {\n this.sortNum = sortNum\n if (force) {\n BoomEmitter.emitter!.emit(USER_SORT_NUM_CHANGE, {isCommon: this.isCommonUser, shouldDelay})\n }\n }\n }\n}\n","/**\n * @name: constants\n * @author: yangliye\n * @date: 2022-04-27 10:39\n * @description:constants\n * @update: 2022-04-27 10:39\n */\n\n/**\n * 标品排序规则\n */\nexport enum MODEL_SORT_ENUM_STAND {\n SCREEN_MASTER,\n SCREEN_MANAGER_AUDIO_VIDEO,\n SCREEN_MANAGER_AUDIO,\n SCREEN_MANAGER_VIDEO,\n SCREEN_MANAGER,\n SCREEN_GUEST_AUDIO_VIDEO,\n SCREEN_GUEST_AUDIO,\n SCREEN_GUEST_VIDEO,\n SCREEN_GUEST,\n SCREEN_COMMONUSER_AUDIO_VIDEO,\n SCREEN_COMMONUSER_AUDIO,\n SCREEN_COMMONUSER_VIDEO,\n SCREEN_OTHER,\n MASTER,\n LOCAL,\n MANAGER_AUDIO_VIDEO,\n MANAGER_AUDIO,\n MANAGER_VIDEO,\n MANAGER,\n RAISE_HAND,\n RAISE_AUDIO,\n RAISE_VIDEO,\n GUEST_AUDIO_VIDEO,\n GUEST_AUDIO,\n GUEST_VIDEO,\n GUEST,\n SIGNAL,\n COMMONUSER_AUDIO_VIDEO,\n COMMONUSER_AUDIO,\n COMMONUSER_VIDEO,\n OTHER\n}\n\n/**\n * 中移排序规则\n */\nexport enum MODEL_SORT_ENUM_ZY {\n SCREEN,\n RAISE_AUDIO,\n RAISE_VIDEO,\n LOCAL,\n MASTER_AUDIO_VIDEO,\n MANAGER_AUDIO_VIDEO,\n AUDIO_VIDEO,\n MASTER_AUDIO,\n MANAGER_AUDIO,\n AUDIO,\n MASTER_VIDEO,\n MANAGER_VIDEO,\n VIDEO,\n MASTER,\n MANAGER,\n GUEST,\n COMMON_USER,\n SIGNAL,\n OTHER\n}\n\nexport enum STREAM_TYPE {\n /**\n * 大流\n */\n SUB_MAIN,\n /**\n * 小流\n */\n SINGLE,\n /**\n * 屏幕共享流\n */\n SHARE,\n /**\n * 其他\n */\n OTHER\n}\n\n\nexport const STREAM_SUFFIX_LOW = 'LowQuality';\n\nexport const TOUPINGMA = '_toupingma';\n\nexport const STREAM_SUFFIX_SCREEN = '_screen';\n\nexport const MOBILE_STREAM_SUFFIX_SCREEN = 'screen-';\n\nexport const SIGNAL_SUFFIX = 'xinhao_'\n\nexport const IGNORE_USERS_PREFIX = ['record#', 'robot_', 'stt_']\n\n\nexport const STREAM_SUFFIX_HDMI = '_hdmi';\n\nexport const STREAM_CONTAIN_MIXER = '-mixer-';\n\nexport const STREAM_CONTAIN_RTMP_MIXER = '-rtmpmixer-';\n\n/**\n * 接受到传递过来的收到订阅信息的信令\n */\nexport const RECEIVE_SUBSCRIBE_MESSAGE = 'sub-message'\n\n\n/**\n * 用户的排序改变\n */\nexport const USER_SORT_NUM_CHANGE = 'user-sort-num-change'\n\n/**\n * 收到业务端bindDom的事件信息,主要是处理播放逻辑的功能\n */\nexport const BIND_ELEMENT = 'bind-element'\n\n/**\n * 流监听到connect-error的处理\n */\nexport const HANDLE_STREAM_CONNECT_ERROR = 'stream-connect-error'\n\n/**\n * 举手相关的处理\n */\nexport const RAISE_HAND = 'raise-hand'\n\nexport const MANUAL_SUBSCRIPTION = 'manual-subscription'\n\n/**\n * 手动订阅模式取消订阅流\n */\nexport const UNSUBSCRIBE_STREAM = 'unsubscribe-stream'\n\n/**\n * 用户的嘉宾身份会发生变化,从嘉宾变为普通参会者,或者从普通参会者变为嘉宾\n */\nexport const CHANG_IS_GUEST = 'change-is-guest'\n\nexport const BIND_BIG_ELEMENT = 'bind-big-element'\n\nexport const NO_CONTAINER = 'no-container'\n\nexport const MODEL_SORT_NUM_CHANGE = 'model-sort-num-change'\n\nexport const ADD_PULL_USER = 'add-pull-user'\n\nexport const SET_VOLUME = 'set-volume'\n\nexport const ADD_AUDIO_PLAY = 'add-audio-play'","/**\n * @name: emitter\n * @author: yangliye\n * @date: 2022-05-24 15:15\n * @description:emitter\n * @update: 2022-05-24 15:15\n */\nimport mitt, { Emitter } from \"mitt\";\nimport { ConnectErrorMessage, NoPlayerContainer, SubscribeMessage } from \"../BMStream/BMStreamModel\";\nimport {\n ADD_AUDIO_PLAY,\n ADD_PULL_USER,\n BIND_BIG_ELEMENT,\n BIND_ELEMENT,\n CHANG_IS_GUEST,\n HANDLE_STREAM_CONNECT_ERROR,\n MANUAL_SUBSCRIPTION,\n MODEL_SORT_NUM_CHANGE,\n NO_CONTAINER,\n RAISE_HAND,\n RECEIVE_SUBSCRIBE_MESSAGE,\n SET_VOLUME,\n UNSUBSCRIBE_STREAM,\n USER_SORT_NUM_CHANGE\n} from \"../constants\";\nimport { RaiseHandInfo } from \"../BMUser/BMUser\";\nimport { ChangeIsGuest } from \"../BMUser/BMUserVM\";\nimport { PullItem } from \"../SingletonQueue/SingletonQueue\";\n\nexport type UserSortType = {\n isCommon: boolean\n shouldDelay: boolean\n}\n\nexport type VolumeInfo = {\n streamId: string\n volume: number\n}\n\ntype Events = {\n [RECEIVE_SUBSCRIBE_MESSAGE]: SubscribeMessage,\n [USER_SORT_NUM_CHANGE]: UserSortType,\n [HANDLE_STREAM_CONNECT_ERROR]: ConnectErrorMessage,\n [RAISE_HAND]: RaiseHandInfo,\n [UNSUBSCRIBE_STREAM]: SubscribeMessage,\n [MANUAL_SUBSCRIPTION]: SubscribeMessage,\n [CHANG_IS_GUEST]: ChangeIsGuest,\n [BIND_ELEMENT]: SubscribeMessage,\n [BIND_BIG_ELEMENT]: SubscribeMessage,\n [NO_CONTAINER]: NoPlayerContainer,\n [MODEL_SORT_NUM_CHANGE]: null\n [ADD_PULL_USER]: PullItem,\n [SET_VOLUME]: VolumeInfo,\n [ADD_AUDIO_PLAY]: SubscribeMessage\n}\n\nexport default class BoomEmitter {\n static emitter: Emitter<Events> | undefined = undefined\n\n static getInstance() {\n if (!BoomEmitter.emitter) {\n BoomEmitter.emitter = mitt()\n }\n return BoomEmitter.emitter\n }\n\n static removeEmitter = () => {\n BoomEmitter.emitter?.off(RECEIVE_SUBSCRIBE_MESSAGE)\n BoomEmitter.emitter?.off(USER_SORT_NUM_CHANGE)\n BoomEmitter.emitter?.off(HANDLE_STREAM_CONNECT_ERROR)\n BoomEmitter.emitter?.off(RAISE_HAND)\n BoomEmitter.emitter?.off(UNSUBSCRIBE_STREAM)\n BoomEmitter.emitter?.off(MANUAL_SUBSCRIPTION)\n BoomEmitter.emitter?.off(CHANG_IS_GUEST)\n BoomEmitter.emitter?.off(BIND_ELEMENT)\n BoomEmitter.emitter?.off(BIND_BIG_ELEMENT)\n BoomEmitter.emitter?.off(NO_CONTAINER)\n BoomEmitter.emitter?.off(MODEL_SORT_NUM_CHANGE)\n BoomEmitter.emitter?.off(ADD_PULL_USER)\n BoomEmitter.emitter?.off(SET_VOLUME)\n BoomEmitter.emitter?.off(ADD_AUDIO_PLAY)\n BoomEmitter.emitter = undefined\n }\n\n}","/**\n * @name: sortUtils\n * @author: yangliye\n * @date: 2023-02-22 18:17\n * @description:sortUtils\n * @update: 2023-02-22 18:17\n */\nimport BMUser from \"../BMUser/BMUser\";\nimport { MODEL_SORT_ENUM_STAND, MODEL_SORT_ENUM_ZY } from \"../constants\";\nimport { _selfSortType } from \"../BMRoom/BMRoom\";\n\nexport function getSortNum(user: BMUser) {\n if (_selfSortType === 2) {\n return sortZY(user)\n } else {\n return sortStand(user)\n }\n}\n\nfunction sortStand(user: BMUser) {\n let sortNum = MODEL_SORT_ENUM_STAND.OTHER\n // 共享\n if (user.isSharing) {\n if (user.isMaster) {\n sortNum = MODEL_SORT_ENUM_STAND.SCREEN_MASTER\n }\n else if (user.isManager && user.audioEnable && user.videoEnable) {\n sortNum = MODEL_SORT_ENUM_STAND.SCREEN_MANAGER_AUDIO_VIDEO\n }\n else if (user.isManager && user.audioEnable) {\n sortNum = MODEL_SORT_ENUM_STAND.SCREEN_MANAGER_AUDIO\n }\n else if (user.isManager && user.videoEnable) {\n sortNum = MODEL_SORT_ENUM_STAND.SCREEN_MANAGER_VIDEO\n }\n else if (user.isManager) {\n sortNum = MODEL_SORT_ENUM_STAND.SCREEN_MANAGER\n }\n else if (!user.isCommonUser) {\n if (user.audioEnable && user.videoEnable) {\n sortNum = MODEL_SORT_ENUM_STAND.SCREEN_GUEST_AUDIO_VIDEO\n }\n else if (user.audioEnable) {\n sortNum = MODEL_SORT_ENUM_STAND.SCREEN_GUEST_AUDIO\n }\n else if (user.videoEnable) {\n sortNum = MODEL_SORT_ENUM_STAND.SCREEN_GUEST_VIDEO\n }\n else {\n sortNum = MODEL_SORT_ENUM_STAND.SCREEN_GUEST\n }\n }\n else if (user.audioEnable && user.videoEnable) {\n sortNum = MODEL_SORT_ENUM_STAND.SCREEN_COMMONUSER_AUDIO_VIDEO\n }\n else if (user.audioEnable) {\n sortNum = MODEL_SORT_ENUM_STAND.SCREEN_COMMONUSER_AUDIO\n }\n else if (user.videoEnable) {\n sortNum = MODEL_SORT_ENUM_STAND.SCREEN_COMMONUSER_VIDEO\n }\n else {\n sortNum = MODEL_SORT_ENUM_STAND.SCREEN_OTHER\n }\n return sortNum\n }\n else if (user.isMaster) {\n sortNum = MODEL_SORT_ENUM_STAND.MASTER\n }\n else if (user.isLocal) {\n sortNum = MODEL_SORT_ENUM_STAND.LOCAL\n }\n // 联席\n else if (user.isManager) {\n if (user.audioEnable && user.videoEnable) {\n sortNum = MODEL_SORT_ENUM_STAND.MANAGER_AUDIO_VIDEO\n }\n else if (user.audioEnable) {\n sortNum = MODEL_SORT_ENUM_STAND.MANAGER_AUDIO\n }\n else if (user.videoEnable) {\n sortNum = MODEL_SORT_ENUM_STAND.MANAGER_VIDEO\n }\n else {\n sortNum = MODEL_SORT_ENUM_STAND.MANAGER\n }\n }\n // 举手\n else if (user.raiseHand) {\n sortNum = MODEL_SORT_ENUM_STAND.RAISE_HAND\n }\n // 音视频举手排序不动\n // else if (user.raiseAudioHands) {\n // sortNum = MODEL_SORT_ENUM_STAND.RAISE_AUDIO\n // }\n // else if (user.raiseVideoHands) {\n // sortNum = MODEL_SORT_ENUM_STAND.RAISE_VIDEO\n // }\n // 嘉宾\n else if (!user.isCommonUser) {\n if (user.audioEnable && user.videoEnable) {\n sortNum = MODEL_SORT_ENUM_STAND.GUEST_AUDIO_VIDEO\n }\n else if (user.audioEnable) {\n sortNum = MODEL_SORT_ENUM_STAND.GUEST_AUDIO\n }\n else if (user.videoEnable) {\n sortNum = MODEL_SORT_ENUM_STAND.GUEST_VIDEO\n }else {\n sortNum = MODEL_SORT_ENUM_STAND.GUEST\n }\n }\n // 信号源\n else if (user.isSignal) {\n sortNum = MODEL_SORT_ENUM_STAND.SIGNAL\n }\n\n // 普通参会者\n else if (user.isCommonUser) {\n if (user.audioEnable && user.videoEnable) {\n sortNum = MODEL_SORT_ENUM_STAND.COMMONUSER_AUDIO_VIDEO\n }\n else if (user.audioEnable) {\n sortNum = MODEL_SORT_ENUM_STAND.COMMONUSER_AUDIO\n }\n else if (user.videoEnable) {\n sortNum = MODEL_SORT_ENUM_STAND.COMMONUSER_VIDEO\n }\n else {\n sortNum = MODEL_SORT_ENUM_STAND.OTHER\n }\n }\n return sortNum\n}\n\nfunction sortZY(user: BMUser) {\n let sortNum\n if (user.isToupingma) {\n sortNum = MODEL_SORT_ENUM_ZY.SCREEN\n }\n else if (user.raiseHand) {\n sortNum = MODEL_SORT_ENUM_STAND.RAISE_HAND\n }\n else if (user.raiseAudioHands) {\n sortNum = MODEL_SORT_ENUM_ZY.RAISE_AUDIO\n }\n else if (user.raiseVideoHands) {\n sortNum = MODEL_SORT_ENUM_ZY.RAISE_VIDEO\n }\n else if (user.isLocal) {\n sortNum = MODEL_SORT_ENUM_ZY.LOCAL\n }\n else if (user.isMaster && user.audioEnable && user.videoEnable) {\n sortNum = MODEL_SORT_ENUM_ZY.MASTER_AUDIO_VIDEO\n }\n else if (user.isManager && user.audioEnable && user.videoEnable) {\n sortNum = MODEL_SORT_ENUM_ZY.MANAGER_AUDIO_VIDEO\n }\n else if (user.audioEnable && user.videoEnable) {\n sortNum = MODEL_SORT_ENUM_ZY.AUDIO_VIDEO\n }\n else if (user.isMaster && user.audioEnable) {\n sortNum = MODEL_SORT_ENUM_ZY.MASTER_AUDIO\n }\n else if (user.isManager && user.audioEnable) {\n sortNum = MODEL_SORT_ENUM_ZY.MANAGER_AUDIO\n }\n else if (user.audioEnable) {\n sortNum = MODEL_SORT_ENUM_ZY.AUDIO\n }\n else if (user.isMaster && user.videoEnable) {\n sortNum = MODEL_SORT_ENUM_ZY.MASTER_VIDEO\n }\n else if (user.isManager && user.videoEnable) {\n sortNum = MODEL_SORT_ENUM_ZY.MANAGER_VIDEO\n }\n else if (user.videoEnable) {\n sortNum = MODEL_SORT_ENUM_ZY.VIDEO\n }\n else if (user.isMaster) {\n sortNum = MODEL_SORT_ENUM_ZY.MASTER\n }\n else if (user.isManager) {\n sortNum = MODEL_SORT_ENUM_ZY.MANAGER\n }\n else if (user.isCommonUser) {\n sortNum = MODEL_SORT_ENUM_ZY.COMMON_USER\n }\n else if (user.isSignal) {\n sortNum = MODEL_SORT_ENUM_ZY.SIGNAL\n }\n else {\n sortNum = MODEL_SORT_ENUM_ZY.GUEST\n }\n return sortNum\n}","import BCClient from '@hysc/core'\nimport BoomError from '../error/RTCError'\nimport * as errorType from '../error/errorType'\nimport * as logger from '../logger/logger'\nimport * as constant from '../util/constant'\nimport BMUser, { Operation } from \"./BMUser\"\nimport { BCUser } from \"@hysc/core\"\nimport BMRoom from '../BMRoom/BMRoom'\nimport { BehaviorSubject } from \"rxjs\"\nimport { UpdateMasterType } from '../type'\nimport { getIsCommonUser, getIsManager, getIsMaster, sortUsers } from \"../util/util\"\nimport { CHANG_IS_GUEST, SIGNAL_SUFFIX, USER_SORT_NUM_CHANGE } from \"../constants\"\nimport BoomEmitter, { UserSortType } from \"../util/emitter\";\nimport BMStreamModel from \"../BMStream/BMStreamModel\"\nimport { sleep } from \"../util/Thread\"\nimport { debounce } from \"lodash-es\"\nimport { PullItem } from \"../SingletonQueue/SingletonQueue\";\n/**\n * 往业务端返回的时候,需要把这些用户过滤掉\n */\nexport const ignoreUserId = ['-mixer-', '-rtmpmixer-', 'record#', 'robot_', 'stt_']\n\nexport interface ChangeIsGuest {\n user: BMUser,\n preIsGuest: boolean\n isGuest: boolean\n}\n\n/**\n * bloud 一页用户拉取数量\n */\nexport const BLOUD_PAGE_SIZE = 500\n/**\n * 嘉宾及以上身份用户\n */\nexport const PERMISSION_NOT_COMMON = 'RWPSAVMO,RWPSAVM,RWPSAV'\n\nexport default class BMUserVM {\n public userList: Map<string, BMUser> = new Map()\n public audiencesList: Map<string, BMUser> = new Map()\n public signalList: Map<string, BMUser> = new Map()\n public commonUserList: Map<string, BMUser> = new Map()\n\n public boomCore: BCClient\n public room: BMRoom\n public userListWatcher: BehaviorSubject<BMUser[]> = new BehaviorSubject(Array.from(this.userList.values()))\n public audiencesListWatcher: BehaviorSubject<BMUser[]> = new BehaviorSubject(Array.from(this.audiencesList.values()))\n public commonUserListWatcher: BehaviorSubject<BMUser[]> = new BehaviorSubject(Array.from(this.commonUserList.values()))\n public signalListWatcher = new BehaviorSubject(Array.from(this.signalList.values()))\n public masterUserWatcher = new BehaviorSubject<BMUser | null>(null)\n public getForceUserWatcher = new BehaviorSubject<boolean>(false)\n\n public localUser: BMUser\n\n public commTimer = 200\n\n constructor(boomCore: BCClient, localUser: BMUser, room: BMRoom) {\n this.boomCore = boomCore\n this.localUser = localUser\n this.room = room\n\n if (!BoomEmitter.emitter) {\n logger.error('init boom emitter error')\n }\n\n BoomEmitter.emitter!.on(CHANG_IS_GUEST, this.handleUserRoleChange.bind(this))\n BoomEmitter.emitter!.on(USER_SORT_NUM_CHANGE, this.updateSortByType)\n }\n\n\n public async handleUserRoleChange(info: ChangeIsGuest) {\n const { user, isGuest, preIsGuest } = info\n const isBigRoom = this.room?.roomInfo.isBigRoom\n logger.info('handleUserRoleChange', '', user.userId, ['isGuest =>', isGuest, 'preIsGuest =>', preIsGuest, 'isBigRoom =>', isBigRoom])\n\n const isOnlyOneColumn = this.room?.userListColumns === 1\n if (!isOnlyOneColumn) {\n if (preIsGuest) {\n this.userList.delete(user.userId)\n } else {\n this.commonUserList.delete(user.userId)\n }\n\n if (isGuest) {\n this.userList.set(user.userId, user)\n } else {\n this.commonUserList.set(user.userId, user)\n }\n }\n\n // 大房间处理\n if (isBigRoom) {\n if (isGuest) {\n if (user.isLocal) {\n await this.initUsers()\n }\n } else {\n const localIsCommonUser = this.room?.getLocalParticipant().isCommonUser\n if (user.isLocal) {\n this.handleUnSubCommonUser()\n this.handleCommonUserChange()\n this.commonUserList.set(user.userId, user)\n }\n if (localIsCommonUser) {\n const streamModel = user.getMainStreamModel()\n if (streamModel) {\n streamModel.unSubscribeStream()\n }\n if (!user.isLocal) {\n this.commonUserList.delete(user.userId)\n }\n }\n }\n }\n this.updateAllSort()\n }\n\n /**\n * 添加用户, 并返回已添加的用户对象\n * @param bcUser bcUser对象\n */\n public addUser(bcUser: BCUser): BMUser | null {\n const user = this.getUser(bcUser.userId)\n if (user) {\n logger.info(\n '该用户已经加入房间',\n constant.LOGGER_TAG_CLIENT,\n bcUser.userId,\n )\n this.updateUser(user, bcUser)\n //获取用户是不是主持人\n return null\n }\n let bmUser\n if (this.boomCore.userId == bcUser.userId) {\n this.updateUser(this.localUser, bcUser)\n bmUser = this.localUser\n } else {\n bmUser = this.toBMUser(bcUser)\n }\n\n if (this.room?.userListColumns === 1) {\n this.commonUserList.set(bmUser.userId, bmUser)\n } else {\n // 观众处理\n if (bmUser.isAudience) {\n this.audiencesList.set(bmUser.userId, bmUser)\n }\n else if (bmUser.isSignal) {\n this.signalList.set(bmUser.userId, bmUser)\n }\n else if (bmUser.isCommonUser) {\n this.commonUserList.set(bmUser.userId, bmUser)\n }\n else {\n this.userList.set(bmUser.userId, bmUser)\n }\n }\n return bmUser\n }\n /**\n * 移除用户\n * @param userId 用户id\n */\n public removeUser(userId: string) {\n let foundUser = this.userList.delete(userId)\n if (!foundUser) {\n foundUser = this.signalList.delete(userId)\n }\n if (!foundUser) {\n foundUser = this.audiencesList.delete(userId)\n }\n if (!foundUser) {\n foundUser = this.commonUserList.delete(userId)\n }\n if (!foundUser) {\n logger.warn(\n `userList中未找到该用户, 移除无效`,\n constant.LOGGER_TAG_CLIENT,\n userId,\n )\n }\n return foundUser\n }\n\n /**\n * 获取用户视频开启状态\n * @param userId 用户id\n */\n public videoEnable(userId: string) {\n const user = this.getUser(userId)\n if (user) {\n return user.videoEnable\n } else {\n throw new BoomError(errorType.USER_NOT_EXIT, '用户不存在')\n }\n }\n\n /**\n * 获取用户音频开启状态\n * @param userId\n */\n audioEnable(userId: string) {\n const user = this.getUser(userId)\n if (user) {\n return user.audioEnable\n } else {\n throw new BoomError(errorType.USER_NOT_EXIT, '用户不存在')\n }\n }\n\n /**\n * 检测用户是不是主持人\n * @param {string} userId 用户id\n */\n public checkIsMaster(userId: any) {\n if (!userId) return false\n const masterId = this.boomCore.getMaster()\n if (!masterId) return false\n return masterId === userId\n }\n /**\n * 检测当前用户是否有主持人权限\n */\n public checkLocalHasMaster() {\n return this.localUser.isMaster || this.localUser.isManager\n }\n /**\n * 检测目标用户是否有主持人权限\n */\n public checkUserHasMaster(userId: string): boolean {\n const user = this.userList.get(userId)\n if (user) {\n return user.permission.getManage()\n }\n return false\n }\n /**\n * 根据用户id获取user对象\n * @param {string} userId\n */\n public getUser(userId: string) {\n let bmUser\n if (userId?.startsWith(SIGNAL_SUFFIX)) {\n bmUser = this.signalList.get(userId)\n } else {\n bmUser = this.userList.get(userId)\n }\n if (!bmUser) {\n bmUser = this.commonUserList.get(userId)\n }\n if (!bmUser) {\n bmUser = this.audiencesList.get(userId)\n }\n return bmUser\n }\n\n async getAllUsers(pageIndex: number, allUsers: Map<string, BCUser>, permission = '', useNew = false) {\n let users\n if (useNew) {\n let { users: usersInRoom, total } = await this.boomCore.getUsersList(pageIndex, permission, BLOUD_PAGE_SIZE)\n users = usersInRoom\n }else {\n let { users: usersInRoom, total } = await this.boomCore.getUsers(pageIndex, permission, BLOUD_PAGE_SIZE)\n users = usersInRoom\n }\n users.forEach(u => {\n allUsers.set(u.userId, u)\n })\n }\n\n /**\n * 刚加入房间时初始化人数\n */\n public async initUserList(usersInRoom: Map<string, BCUser>) {\n const localUser = usersInRoom.get(this.localUser.userId)\n if (localUser) {\n const user = this.addUser(localUser)\n if (!this.room?.bmStreamVm.getStreamModelByUId(localUser.userId)) {\n const bmuser = this.getUser(localUser.userId)\n if (bmuser) {\n this.room?.bmStreamVm.createStreamModel(bmuser)\n }else {\n logger.error('there is no local streamModel exits, and create failed!!!')\n }\n }\n\n if (user?.isMaster) {\n this.masterUserWatcher.next(user)\n }\n }\n\n usersInRoom.delete(this.localUser.userId)\n\n if (usersInRoom && usersInRoom.size > 0) {\n this.addBcUsersMap(usersInRoom)\n }\n }\n\n addBcUsersMap(users: Map<string, BCUser>, forceGetStream = false) {\n users.forEach(bcUser => {\n this.addBCUser(bcUser, forceGetStream)\n })\n }\n\n addBCUser = (bcUser: BCUser, forceGetStream = false) => {\n const user = this.addUser(bcUser)\n const sm = this.room!.bmStreamVm.streamModels.get(bcUser.userId)\n if (!sm) {\n const bmUser = this.getUser(bcUser.userId)\n if (bmUser) {\n this.room!.bmStreamVm.createStreamModel(bmUser)\n }else {\n logger.error(`there is no user named ${bcUser.userId}, and create streamModel failed!!!`)\n }\n }\n\n // 处理 bloud的流,看看是查brtc流,还是绑定bloud的流\n {\n const sm = this.room!.bmStreamVm.streamModels.get(bcUser.userId)\n if (sm) {\n if(bcUser.stream.size) {\n bcUser.stream.forEach(async s => {\n const {video_enable, audio_enable, customInfo } = s\n if(s.screen) {\n this.room.bmStreamVm.shareBloudStateMap.set(bcUser.userId, { audio: audio_enable, video: video_enable, customInfo, userId: bcUser.userId, streamId: s.getID(), isScreen: true })\n const item: PullItem = {id: sm.userId, isScreen: true, isWeb: sm.isWeb}\n if (forceGetStream) {\n const map = new Map()\n map.set(bcUser.userId, item)\n await this.room?.processUser(map)\n }else {\n this.room?.addUser2Queue(item)\n }\n }else {\n if (sm) {\n sm.updateBloudStream({ video: video_enable, audio: audio_enable, isScreen: s.screen, customInfo }, this.room!.bmStreamVm)\n if (forceGetStream) {\n const item: PullItem = {id: sm.userId, isScreen: false, isWeb: sm.isWeb}\n const map = new Map()\n map.set(bcUser.userId, item)\n this.room?.processUser(map)\n }\n }\n }\n })\n }else {\n if (sm.bloudStream) {\n sm.updateBloudStream(undefined, this.room!.bmStreamVm)\n }\n this.room?.bmStreamVm.removeShareStreamModelByUId(bcUser.userId)\n }\n }\n }\n\n if (user && user.isMaster) {\n this.masterUserWatcher.next(user)\n }\n user?.updateSortNum(false)\n return user\n }\n\n\n /**\n * 改变userList中的主持人,返回改变后的主持人用户对象,该方法只在change-master中调用, 不对外暴露\n * @param userId\n * @param oldMasterId\n * @param isKeep\n */\n public updateMaster(userId: string, oldMasterId: string, isKeep: boolean): UpdateMasterType {\n // 更改主持人\n const master = this.getUser(userId)\n if (master) {\n if (master.isManager) {\n master.isManager = false\n }\n master.isMaster = true\n master.updateSortNum()\n }\n\n // 更改原主持人\n const oldMaster = this.getUser(oldMasterId)\n if (oldMaster) {\n oldMaster.isMaster = false\n if (isKeep) {\n oldMaster.isManager = true\n }\n oldMaster.updateSortNum()\n }\n\n if (!master && !oldMaster) {\n logger.error(\n `未找到该用户, updateMaster未生效`,\n constant.LOGGER_TAG_CLIENT,\n userId,\n ['masterId => ', userId, 'oldMasterId => ', oldMasterId]\n )\n }\n return {\n master: master,\n oldMaster: oldMaster,\n }\n }\n /**\n * 联席主持人设置嘉宾的操作\n * @param userId\n */\n public managerChangeToGuest(userId: string) {\n const bmUser = this.getUser(userId)\n if (bmUser) {\n if (bmUser.isManager) {\n bmUser.permission.setManage(false)\n bmUser.permission.setSubscribe(true)\n this.boomCore.updateUser(userId, {\n customInfo: {\n permission: bmUser.permission.get(),\n },\n })\n bmUser.watcher.next({\n operation: 'getGuest',\n user: bmUser,\n })\n this.updateAllSort()\n }else {\n logger.error(\n `该用户不是管理员,无法设置为嘉宾`,\n constant.LOGGER_TAG_CLIENT,\n userId,\n )\n }\n } else {\n logger.error(\n `未找到该用户, managerChangeToGuest未生效`,\n constant.LOGGER_TAG_CLIENT,\n userId,\n )\n }\n return bmUser\n }\n\n /**\n * 改变联席主持人,返回设置为联席主持人的bmuser对象\n * @param userId\n * @param status true:设置成联席主持人 false:取消联席主持人身份\n * @param hasS\n * @returns\n */\n public updateManager(userId: string, status: boolean, hasS: boolean = true): BMUser {\n const bmUser = this.getUser(userId)\n if (bmUser) {\n //设置用户的permission的权限字段\n bmUser.permission.setManage(status)\n // 如果是设置/取消联席主持人身份, 则还要把嘉宾身份设置/撤销\n bmUser.permission.setSubscribe(status)\n //更新用户信息, 设置权限\n this.boomCore.updateUser(userId, {\n customInfo: {\n permission: bmUser.permission.get(),\n },\n })\n bmUser.watcher.next({\n operation: status ? 'getManager' : 'removeManager',\n user: bmUser,\n })\n this.updateAllSort()\n } else {\n logger.error(\n `userList中未找到该用户, updateManager未生效`,\n constant.LOGGER_TAG_CLIENT,\n userId,\n )\n }\n return bmUser!\n }\n /**\n * 获取我自己\n */\n public getLocalUser(): BMUser {\n return this.localUser\n }\n\n public updateUser(bmUser: BMUser, bcUser: BCUser) {\n\n /**\n * 本地用户如果断网重连,重新走join的时候,会走到updateUser里面\n * 如果之前该用户存在,这个时候如果身份变化,不会在update-user信令里面收到,得把身份变化告诉端上\n */\n const nextIsMaster = this.checkIsMaster(bcUser.userId)\n const nextIsManager = ((bcUser.permission?.getManage() || getIsManager(bcUser.permission?.permission)) && !(bcUser.permission?.getOwn() || getIsMaster(bcUser.permission?.permission)))\n\n let operation: Operation = 'none'\n\n const currentIsMaster = bmUser.isMaster\n const currentIsManager = bmUser.isManager\n\n if (currentIsManager !== nextIsManager) {\n if(nextIsManager) {\n operation = 'getManager'\n }else {\n operation = 'removeManager'\n }\n }\n\n if (operation !== 'none') {\n setTimeout(() => {\n bmUser.watcher.next({\n operation,\n user: bmUser\n })\n }, 10)\n }\n\n if (currentIsMaster !== nextIsMaster) {\n if (nextIsMaster) {\n operation = 'getMaster'\n }else {\n operation = 'removeMaster'\n }\n }\n\n if (operation !== 'none') {\n setTimeout(() => {\n bmUser.watcher.next({\n operation,\n user: bmUser\n })\n }, 100)\n }\n\n // raiseHand\n const currentRaiseHand = bmUser.raiseHand\n const nextRaiseHand = bcUser.customInfo.raiseHand\n if (currentRaiseHand !== nextRaiseHand) {\n if (!nextRaiseHand && currentRaiseHand) {\n this.room.roomInfo.removeSimpleRaiseHandUser(bmUser.userId)\n }\n setTimeout(() => {\n bmUser.watcher.next({\n operation: 'raiseHand',\n user: bmUser\n })\n }, 300)\n }\n\n // raiseVideoHand\n const currentVideoRaiseHand = bmUser.raiseVideoHands\n const nextVideoRaiseHand = bcUser.customInfo.raiseHandsVideo\n if (currentVideoRaiseHand !== nextVideoRaiseHand) {\n if (!nextVideoRaiseHand && currentVideoRaiseHand) {\n this.room.roomInfo.removeVideoRaiseHandUser(bmUser.userId)\n }\n setTimeout(() => {\n bmUser.watcher.next({\n operation: 'raiseHandsVideo',\n user: bmUser\n })\n }, 300)\n }\n // raiseAudioHand\n const currentAudioRaiseHand = bmUser.raiseAudioHands\n const nextAudioRaiseHand = bcUser.customInfo.raiseHandsAudio\n if (currentAudioRaiseHand !== nextAudioRaiseHand) {\n if (!nextAudioRaiseHand && currentAudioRaiseHand) {\n this.room.roomInfo.removeRaiseHandUser(bmUser.userId)\n }\n setTimeout(() => {\n bmUser.watcher.next({\n operation: 'raiseHandsAudio',\n user: bmUser\n })\n }, 300)\n }\n\n\n const currentNickname = bmUser.nickname\n const nextNickname = bcUser.nickname\n if (currentNickname !== nextNickname) {\n setTimeout(() => {\n bmUser.watcher.next({\n operation: 'changeNickName',\n user: bmUser\n })\n }, 300)\n }\n\n bmUser.userInfo = bcUser.userinfo\n bmUser.nickName = bcUser.nickname\n bmUser.userId = bcUser.userId\n bmUser.permission = bcUser.permission\n bmUser.avatar = bcUser.userinfo.avatar\n bmUser.isToupingma = bcUser.userinfo.pos.includes('_toupingma')\n bmUser.raiseHand = nextRaiseHand\n bmUser.isMaster = nextIsMaster\n bmUser.isCreate = this.boomCore.getCreator() === bcUser.userId\n bmUser.isAudience = !bcUser.permission.getAudio()\n bmUser.isCommonUser = !bcUser.permission.getSubscribe()\n bmUser.isManager = nextIsManager\n bmUser.inBackground = !!bcUser?.customInfo?.inBackground\n bmUser.updateSortNum()\n }\n\n updateLocalUserPermission(permission: string) {\n const localUser = this.getLocalUser()\n localUser.isMaster = getIsMaster(permission)\n localUser.isManager = !getIsMaster(permission) && getIsManager(permission)\n localUser.isCommonUser = getIsCommonUser(permission)\n localUser.watcher.next({\n operation: 'none',\n user: localUser\n })\n }\n\n /**\n * bcUser变成BMUser\n * @param bcUser\n * @returns\n */\n public toBMUser(bcUser: BCUser) {\n let userMsg: any = {}\n userMsg.userInfo = bcUser.userinfo\n userMsg.nickname = bcUser.nickname\n userMsg.userId = bcUser.userId\n userMsg.streamModels = []\n userMsg.permission = bcUser.permission\n userMsg.stream = bcUser.stream\n userMsg.isToupingma = !!(bcUser.userinfo.pos && bcUser.userinfo.pos.includes('_toupingma'))\n //获取用户是不是主持人\n userMsg.isMaster = this.checkIsMaster(userMsg.userId)\n userMsg.isAudience = !bcUser.permission.getAudio()\n userMsg.isCommonUser = !bcUser.permission.getSubscribe() || getIsCommonUser(bcUser.permission.permission)\n userMsg.raiseAudioHands = bcUser.customInfo.raiseHandsAudio\n userMsg.raiseVideoHands = bcUser.customInfo.raiseHandsVideo\n userMsg.raiseHand = bcUser.customInfo.raiseHand\n userMsg.raiseHandTime = bcUser.customInfo.raiseHandTime\n userMsg.inBackground = bcUser.customInfo.inBackground\n userMsg.isCreate = this.boomCore.getCreator() === bcUser.userId\n //获取用户该用户是不是本地用户;\n let localUser = this.boomCore.getLocalParticipant()\n if (!localUser) {\n throw new BoomError(\n errorType.INVALID_PARAMETER,\n 'BCUserVM addUser时未找到本地用户',\n )\n }\n if (localUser.getID() == userMsg.userId) {\n userMsg.isLocal = true\n }\n\n if ((userMsg.permission?.getManage() || getIsManager(userMsg.permission?.permission)) && !userMsg.isMaster) {\n userMsg.isManager = true\n }\n return new BMUser(userMsg, userMsg.isLocal)\n }\n\n private sortUsers() {\n return sortUsers(Array.from(this.userList.values()))\n }\n\n private sortAudiences() {\n return sortUsers(Array.from(this.audiencesList.values()))\n }\n\n private sortCommonUsers() {\n return sortUsers(Array.from(this.commonUserList.values()))\n }\n\n private sortSignalUsers() {\n return sortUsers(Array.from(this.signalList.values()))\n }\n\n private static filterUsers(users: BMUser[]) {\n return users\n .filter(user => !ignoreUserId.some(ignore => user.userId.includes(ignore)))\n }\n\n /**\n * 排序变化之后的处理逻辑\n */\n updateAllSort = () => {\n this.updateUserSort()\n this.updateCommonUserSort()\n }\n\n updateSortByType = (userType: UserSortType) => {\n if (this.room?.isSingleColumns || userType.isCommon) {\n if (this.room?.isBig && userType.shouldDelay) {\n this.updateDelayCommonUserSort();\n } else {\n this.updateCommonUserSort();\n }\n } else {\n this.updateUserSort();\n }\n }\n\n\n updateUserSort = debounce(() => {\n const users = this.sortUsers()\n this.userListWatcher.next(BMUserVM.filterUsers(users))\n }, 200, {maxWait: 1000})\n\n updateCommonUserSort = debounce(() => {\n const commonUsers = this.sortCommonUsers()\n this.commonUserListWatcher.next(BMUserVM.filterUsers(commonUsers))\n }, this.commTimer, {maxWait: 12 * 1000})\n\n updateDelayCommonUserSort = debounce(() => {\n const commonUsers = this.sortCommonUsers()\n this.commonUserListWatcher.next(BMUserVM.filterUsers(commonUsers))\n }, 120 * 1000, {maxWait: 120 * 1000})\n\n updateAudienceUserSort = () => {\n const audiencesUsers = this.sortAudiences()\n this.audiencesListWatcher.next(BMUserVM.filterUsers(audiencesUsers))\n }\n\n updateSignalUserSort = () => {\n const signalUsers = this.sortSignalUsers()\n this.signalListWatcher.next(signalUsers)\n }\n\n /**\n * 初始化所有的用户\n */\n async initUsers() {\n const total = await this.getTotalUserNumber()\n logger.info(`initUsers total users num: ${total}`)\n const pullCount = Math.ceil(total / BLOUD_PAGE_SIZE)\n let pullPage = 0\n const localIsCommonUser = this.localUser.isCommonUser\n\n// ==== 制作一个队列用来存储拉取bloud用户的方法,当入会之后 根据身份不同去拉取所有用户, 对应 ==== //\n const pullQueue: any[] = []\n const loop = async (pullPage: number) => {\n if (pullPage < pullCount) {\n await this.transBloudUsers(pullPage - 1)\n }\n }\n const pullBloudUsers = async (pullQueue: Array<() => void>) => {\n for (const f of pullQueue) {\n await f()\n await sleep(50)\n }\n }\n// ============================================================================ //\n\n // 嘉宾及以上,拉取全量用户,普通参会者,只拉取嘉宾及以上用户\n // 大房间,普通参会者只查嘉宾及以上身份的人\n if (localIsCommonUser && this.room?.isBig) {\n this.commonUserList.set(this.localUser.userId, this.localUser)\n await this.transBloudUsers(-1, PERMISSION_NOT_COMMON, true)\n }\n // 其他情况,查所有人\n else {\n while (pullPage < pullCount) {\n pullQueue.push(loop.bind(null, pullPage))\n pullPage += 1\n }\n pullBloudUsers(pullQueue)\n }\n }\n\n /**\n * 把bloud用户转化为当前的BMUser 和创建对应的BMStreamModel\n * @param page\n * @param permission\n * @param useNew 是否使用getUsersList\n */\n transBloudUsers = async (page: number, permission = '', useNew = false, failedNum = 0) => {\n const allUsers = new Map<string, BCUser>()\n await this.getAllUsers(page, allUsers, permission, useNew).catch(() => {\n if(failedNum < 3) {\n logger.error('get bloud user error, retry')\n failedNum += 1\n this.transBloudUsers(page, permission, useNew, failedNum)\n return\n }else {\n logger.error('get current page of bloud users after 10 times final failed', '', '', [' page ', page, ' permission ', permission])\n return;\n }\n })\n await this.initUserList(allUsers)\n allUsers.clear()\n let raiseHandsUsers: BMUser[] = []\n for (let user of this.userList.values()) {\n if (user.raiseVideoHands || user.raiseAudioHands || user.raiseHand) {\n raiseHandsUsers.push(user)\n }\n }\n for (let user of this.commonUserList.values()) {\n if (user.raiseVideoHands || user.raiseAudioHands || user.raiseHand) {\n raiseHandsUsers.push(user)\n }\n }\n for (let user of this.commonUserList.values()) {\n if (user.raiseVideoHands || user.raiseAudioHands) {\n raiseHandsUsers.push(user)\n }\n }\n this.room!.roomInfo.setRaiseHandsList(raiseHandsUsers)\n\n // 触发一次updateSort 给端上初始化数据\n this.updateAllSort()\n this.room!.bmStreamVm.updateModelSort()\n }\n\n\n\n /**\n * 本地嘉宾用户降级为普通参会者之后要取消拉流\n */\n handleUnSubCommonUser() {\n this.commonUserList.forEach(user => {\n const streamModel = user.getMainStreamModel()\n if (streamModel?.hasPulled) {\n streamModel.unSubscribeStream()\n }\n })\n }\n\n handleCommonUserChange() {\n let newBMStreamModels = new Map<string, BMStreamModel>()\n this.room!.bmStreamVm.streamModels.forEach(sm => {\n if (!sm.getUser().isCommonUser || sm.isLocal) {\n newBMStreamModels.set(sm.userId, sm)\n }\n })\n this.room!.bmStreamVm.streamModels = newBMStreamModels\n this.commonUserList.clear()\n }\n\n async getUsers(page: number, pageSize: number, permission = 'RWPAV') {\n const { users, total } = await this.boomCore.getUsers(page, permission, pageSize)\n const userList: BMUser[] = []\n users.forEach(bcUser => {\n const user = this.toBMUser(bcUser)\n userList.push(user)\n })\n\n return { userList, total }\n }\n\n async getUsersList(page: number, pageSize: number, permission = '', waitRoom = false) {\n const { users, total, pageIndex } = await this.boomCore.getUsersList(page, permission, pageSize, waitRoom)\n const userList: BMUser[] = []\n users.forEach(bcUser => {\n const user = this.toBMUser(bcUser)\n userList.push(user)\n })\n if (waitRoom) {\n if (this.room?.roomInfo.totalWaitRoomUserWatcher.value !== total) {\n this.room?.roomInfo.totalWaitRoomUserWatcher.next(total)\n }\n }\n\n return { userList, total, pageIndex }\n }\n\n async getTotalUserNumber(): Promise<number> {\n const getUsers = async () => {\n const { total } = await this.boomCore.getUsers(0, '', 1)\n return total\n }\n\n const init = (resolve: (value: number) => void ) => {\n getUsers()\n .then(r => {\n resolve(r)\n })\n .catch(e => {\n logger.error('getTotalUserNumber error', '', '', [JSON.stringify(e)])\n init(resolve)\n })\n }\n\n return new Promise(async (resolve, reject) => {\n init(resolve)\n })\n }\n\n clearUsers() {\n this.userList.clear()\n this.commonUserList.clear()\n this.audiencesList.clear()\n this.signalList.clear()\n }\n /**\n * 参会者列表搜索(嘉宾及以上才能搜索)\n * @param searchTxt 搜索文本\n * @param pageSize 一页几个\n * @param waitRoom 是否是等候室用户\n */\n public async searchUsers(searchTxt: string, pageSize: number) {\n try {\n const { users } = await this.boomCore.searchUsers(searchTxt, pageSize, false)\n let userList: BMUser[] = [], commonUserList: BMUser[] = []\n users.forEach(u => {\n const user = this.userList.get(u.userId)\n if (user) {\n userList.push(user)\n return\n }\n const cUser = this.commonUserList.get(u.userId)\n if (cUser) {\n commonUserList.push(cUser)\n }\n })\n\n return { userList, commonUserList }\n } catch (err: any) {\n return Promise.reject(new BoomError(errorType.LOCAL_ERROR, 'boomCore.searchUsers发生错误:' + err?.message))\n }\n }\n\n /**\n * 查找等候室用户\n * @param searchTxt\n * @param pageSize\n */\n async searchWaitRoomUsers(searchTxt: string, pageSize: number) {\n try {\n const { users } = await this.boomCore.searchUsers(searchTxt, pageSize, true)\n const searUsers: BMUser[] = []\n users.forEach(u => {\n const user = this.toBMUser(u)\n searUsers.push(user)\n })\n return searUsers\n }catch (e) {\n return Promise.reject(new BoomError(errorType.LOCAL_ERROR, 'search wait room users error'))\n }\n }\n}","/**\n * 为了压缩,定义的常量\n */\nexport const TRUE = true\nexport const FALSE = false\nexport const NULL = null\nexport const UNDEFINED = void 0\nexport const MINUS_ONE = -1\n\nexport const RAW_TRUE = 'true'\nexport const RAW_FALSE = 'false'\nexport const RAW_NULL = 'null'\nexport const RAW_UNDEFINED = 'undefined'\n\nexport const RAW_THIS = 'this'\nexport const RAW_VALUE = 'value'\nexport const RAW_LENGTH = 'length'\nexport const RAW_FUNCTION = 'function'\nexport const RAW_WILDCARD = '*'\nexport const RAW_DOT = '.'\nexport const RAW_SLASH = '/'\nexport const RAW_TAG = 'tag'\n\nexport const KEYPATH_PARENT = '..'\nexport const KEYPATH_CURRENT = RAW_THIS\n\n/**\n * Single instance for window in browser\n */\nexport const WINDOW = typeof window !== RAW_UNDEFINED ? window : UNDEFINED\n\n/**\n * Single instance for document in browser\n */\nexport const DOCUMENT = typeof document !== RAW_UNDEFINED ? document : UNDEFINED\n\n/**\n * Single instance for global in nodejs or browser\n */\nexport const GLOBAL = typeof global !== RAW_UNDEFINED ? global : WINDOW\n\n\n/**\n * Single instance for noop function\n */\nexport const EMPTY_FUNCTION = function () {\n /** bjy-common */\n}\n\n/**\n * 空对象,很多地方会用到,比如 `a || EMPTY_OBJECT` 确保是个对象\n */\nexport const EMPTY_OBJECT = Object.freeze({})\n\n/**\n * 空数组\n */\nexport const EMPTY_ARRAY = Object.freeze([])\n\n/**\n * 空字符串\n */\nexport const EMPTY_STRING = ''\n\n","import * as constant from './constant'\n\n/**\n * Check if value is a function.\n *\n * @param value\n * @return\n */\nexport function func(value: any): boolean {\n return typeof value === constant.RAW_FUNCTION\n}\n\n/**\n * Check if value is an array.\n *\n * @param value\n * @return\n */\nexport function array(value: any): boolean {\n return Array.isArray(value)\n}\n\n/**\n * Check if value is an object.\n *\n * @param value\n * @return\n */\nexport function object(value: any): boolean {\n // 低版本 IE 会把 null 当作 object\n return value !== constant.NULL && typeof value === 'object'\n}\n\n/**\n * Check if value is a string.\n *\n * @param value\n * @return\n */\nexport function string(value: any): boolean {\n return typeof value === 'string'\n}\n\n/**\n * Check if value is a number.\n *\n * @param value\n * @return\n */\nexport function number(value: any): boolean {\n return typeof value === 'number' && !isNaN(value)\n}\n\n/**\n * Check if value is boolean.\n *\n * @param value\n * @return\n */\nexport function boolean(value: any): boolean {\n return typeof value === 'boolean'\n}\n\n/**\n * Check if value is numeric.\n *\n * @param value\n * @return\n */\nexport function numeric(value: any): boolean {\n return number(value)\n || (string(value) && !isNaN(parseFloat(value)) && isFinite(value))\n}\n","import * as is from './is'\nimport * as constant from './constant'\n\nconst camelizePattern = /-([a-z])/gi,\n\nhyphenatePattern = /\\B([A-Z])/g,\n\ncapitalizePattern = /^[a-z]/,\n\ncamelizeCache: Record<string, string> = {},\n\nhyphenateCache: Record<string, string> = {},\n\ncapitalizeCache: Record<string, string> = {}\n\n/**\n * 连字符转成驼峰\n *\n * @param str\n * @return 驼峰格式的字符串\n */\nexport function camelize(str: string): string {\n if (!camelizeCache[str]) {\n camelizeCache[str] = str.replace(\n camelizePattern,\n function ($0, $1) {\n return upper($1)\n }\n )\n }\n return camelizeCache[str]\n}\n\n/**\n * 驼峰转成连字符\n *\n * @param str\n * @return 连字符格式的字符串\n */\nexport function hyphenate(str: string): string {\n if (!hyphenateCache[str]) {\n hyphenateCache[str] = str.replace(\n hyphenatePattern,\n function ($0, $1) {\n return '-' + lower($1)\n }\n )\n }\n return hyphenateCache[str]\n}\n\n/**\n * 首字母大写\n *\n * @param str\n * @return\n */\nexport function capitalize(str: string): string {\n if (!capitalizeCache[str]) {\n capitalizeCache[str] = str.replace(\n capitalizePattern,\n upper\n )\n }\n return capitalizeCache[str]\n}\n\n/**\n * 清除两侧空白符\n *\n * @param str\n * @return 清除两侧空白符的字符串\n */\nexport function trim(str: any): string {\n return falsy(str)\n ? constant.EMPTY_STRING\n : str.trim()\n}\n\n/**\n * 截取字符串\n *\n * @param str\n * @param start\n * @param end\n * @return\n */\nexport function slice(str: string, start: number, end?: number): string {\n return is.number(end)\n ? start === end\n ? constant.EMPTY_STRING\n : str.slice(start, end)\n : str.slice(start)\n}\n\n/**\n * 获取子串的起始位置\n *\n * @param str\n * @param part\n * @param start\n * @return\n */\nexport function indexOf(str: string, part: string, start?: number): number {\n return str.indexOf(part, start !== constant.UNDEFINED ? start : 0)\n}\n\n/**\n * 获取子串的起始位置\n *\n * @param str\n * @param part\n * @param end\n * @return\n */\nexport function lastIndexOf(str: string, part: string, end?: number): number {\n return str.lastIndexOf(part, end !== constant.UNDEFINED ? end : str.length)\n}\n\n/**\n * str 是否以 part 开头\n *\n * @param str\n * @param part\n * @return\n */\nexport function startsWith(str: string, part: string): boolean {\n return indexOf(str, part) === 0\n}\n\n/**\n * str 是否以 part 结束\n *\n * @param str\n * @param part\n * @return\n */\nexport function endsWith(str: string, part: string): boolean {\n const offset = str.length - part.length\n return offset >= 0 && lastIndexOf(str, part) === offset\n}\n\n/**\n * 获取某个位置的字符\n */\nexport function charAt(str: string, index?: number): string {\n return str.charAt(index || 0)\n}\n\n/**\n * 获取某个位置的字符编码\n */\nexport function codeAt(str: string, index?: number): number {\n return str.charCodeAt(index || 0)\n}\n\n/**\n * 大写格式\n */\nexport function upper(str: string): string {\n return str.toUpperCase()\n}\n\n/**\n * 小写格式\n */\nexport function lower(str: string): string {\n return str.toLowerCase()\n}\n\n/**\n * str 是否包含 part\n *\n * @param str\n * @param part\n * @return 是否包含\n */\nexport function has(str: string, part: string): boolean {\n return indexOf(str, part) >= 0\n}\n\n/**\n * 判断长度大于 0 的字符串\n *\n * @param str\n * @return\n */\nexport function falsy(str: any): boolean {\n return !is.string(str) || !str.length\n}\n","import * as constant from '../util/constant'\n\nexport default function (target: any, defaultValue?: string): string {\n return target != constant.NULL && target.toString\n ? target.toString()\n : defaultValue !== constant.UNDEFINED\n ? defaultValue as string\n : constant.EMPTY_STRING\n}\n","import * as is from '../util/is'\nimport * as string from '../util/string'\nimport toString from './toString'\n\nexport default function (target: any): boolean {\n return is.func(target)\n && string.has(toString(target), '[native code]')\n}","import * as constant from '../util/constant'\nimport isNative from './isNative'\n\ndeclare const setImmediate: Function\n\nlet nextTick: Function\n\n// IE (10+) 和 node\nif (typeof setImmediate === constant.RAW_FUNCTION && isNative(setImmediate)) {\n nextTick = setImmediate\n}\n// 用 MessageChannel 去做 setImmediate 的 polyfill\n// 原理是将新的 message 事件加入到原有的 dom events 之后\n// 兼容性 IE10+ 和其他标准浏览器\nif (typeof MessageChannel === constant.RAW_FUNCTION && isNative(MessageChannel)) {\n nextTick = function (fn: any) {\n const channel = new MessageChannel()\n channel.port1.onmessage = fn\n channel.port2.postMessage(1)\n }\n}\nelse {\n nextTick = setTimeout\n}\n\nexport default nextTick\n","import execute from '../bjy-common/function/execute'\nimport nextTick from '../bjy-common/function/nextTick'\nimport BMUser from '../BMUser/BMUser'\nimport BMStreamModel from '../BMStream/BMStreamModel'\nimport { MODEL_SORT_ENUM_STAND } from \"../constants\";\n\nexport const notGetTalkInterval = 5 * 60 * 1000 //没有得到新的聊天时间的间隔\n/**\n * 生成唯一 id\n *\n * @internal\n * @returns id\n */\nexport function generateUUID(): string {\n let d = new Date().getTime()\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {\n let r = (d + Math.random() * 16) % 16 | 0\n d = Math.floor(d / 16)\n return (c == 'x' ? r : (r & 0x3) | 0x8).toString(16)\n })\n}\n\n/**\n * 将函数回调转换为 Promise\n *\n * @internal\n * @typeParam T 回调结果类型\n * @typeParam This 函数执行上下文\n * @param fn 回调函数\n * @param args 函数执行参数\n * @param ctx 函数执行上下文\n * @param hasResolve 是否有成功回调\n * @returns 回调结果\n */\nexport function callbackToPromise<T, This>(\n fn: any,\n args: any[],\n ctx: any,\n hasResolve: boolean = true,\n): Promise<T | void> {\n return new Promise((resolve, reject) => {\n if (hasResolve) {\n args.push(function (data: T) {\n resolve(data)\n })\n }\n args.push(function (error: any) {\n reject(error)\n })\n\n execute(fn, ctx, args)\n\n if (!hasResolve) {\n nextTick(() => {\n resolve()\n })\n }\n })\n}\n\nlet audioContext: AudioContext\n\n/**\n * 创建 AudioContext\n *\n * @internal\n * @returns AudioContext\n */\nexport function getAudioContext(): AudioContext {\n if (audioContext) {\n return audioContext\n }\n let AudioContext = window.AudioContext || (window as any).webkitAudioContext\n audioContext = new AudioContext()\n return audioContext\n}\n\n/**\n * 创建 AudioMeter\n *\n * @internal\n * @param audioContext\n * @param clipLevel\n * @param averaging\n * @param clipLag\n * @returns ScriptProcessorNode\n */\nexport function createAudioMeter(\n audioContext: AudioContext,\n clipLevel: number = 0.98,\n averaging: number = 0.95,\n clipLag: number = 750,\n): ScriptProcessorNode {\n const processor: any = audioContext.createScriptProcessor(2048, 1, 1)\n\n processor.onaudioprocess = (event: any) => {\n const buf = event.inputBuffer.getChannelData(0)\n const bufLength = buf.length\n let sum = 0\n let x: number\n\n // Do a root-mean-square on the samples: sum up the squares...\n for (let i = 0; i < bufLength; i++) {\n x = buf[i]\n if (Math.abs(x) >= processor.clipLevel) {\n processor.clipping = true\n processor.lastClip = window.performance.now()\n }\n sum += x * x\n }\n\n // ... then take the square root of the sum.\n const rms = Math.sqrt(sum / bufLength)\n\n // Now smooth this out with the averaging factor applied\n // to the previous sample - take the max here because we\n // want \"fast attack, slow release.\"\n processor.volume = Math.max(rms, processor.volume * processor.averaging)\n }\n\n processor.clipping = false\n processor.lastClip = 0\n processor.volume = 0\n processor.clipLevel = clipLevel\n processor.averaging = averaging\n processor.clipLag = clipLag\n\n // this will have no effect, since we don't copy the input to the output,\n // but works around a current Chrome bug.\n processor.connect(audioContext.destination)\n\n processor.checkClipping = () => {\n if (!processor.clipping) return false\n if (processor.lastClip + processor.clipLag < window.performance.now())\n processor.clipping = false\n return processor.clipping\n }\n\n processor.shutdown = () => {\n processor.disconnect()\n audioContext.close()\n processor.onaudioprocess = null\n }\n return processor\n}\n\n/**\n * 放置 AudioMeter\n *\n * @internal\n * @param stream\n * @param mediaStream\n */\nexport function createVolumeMeter(\n stream: any,\n audioTrack: MediaStreamTrack,\n): void {\n if (stream._volumeMeter) {\n stream._volumeMeter.disconnect()\n }\n if (audioTrack && audioTrack.kind === 'audio') {\n let mediaStream = new MediaStream()\n mediaStream.addTrack(audioTrack)\n let audioContext = getAudioContext()\n let mediaStreamSource = audioContext.createMediaStreamSource(mediaStream)\n stream._volumeMeter = createAudioMeter(audioContext)\n mediaStreamSource.connect(stream._volumeMeter)\n }\n\n stream.getAudioLevel = () => {\n if (stream._volumeMeter) {\n return stream._volumeMeter.volume\n }\n return 0\n }\n}\n\n/**\n * 解析 vloud 流数据\n *\n * @internal\n * @param streamDeviceOption\n * @param streamCodecOption\n * @returns 解析结果\n */\nexport function parseVloudStreamOptions(\n streamDeviceOption: any,\n streamCodecOption: any,\n): Object {\n if (streamDeviceOption.audioSource || streamDeviceOption.videoSource) {\n return {\n audio: !!streamDeviceOption.audioSource,\n video: !!streamDeviceOption.videoSource,\n }\n } else if (streamDeviceOption.screen) {\n return {\n audio: !!streamDeviceOption.audio,\n video: true,\n screen: true,\n fps: streamCodecOption.frameRate,\n }\n } else {\n return {\n audio: !!streamDeviceOption.audio,\n video: !!streamDeviceOption.video,\n }\n }\n}\n\nexport function timestamp(): number {\n return Math.floor(new Date().getTime() / 1000)\n}\n\nexport async function resumeContext() {\n if (audioContext) {\n await audioContext.resume()\n }\n}\n\nexport function getEmptyVloudStats(): any {\n return {\n bandwidth: {\n upload: 0,\n download: 0,\n },\n bitrate: {\n audio: {\n upload: 0,\n download: 0,\n },\n video: {\n upload: 0,\n download: 0,\n },\n },\n packetLoss: {\n audio: {\n upload: 0,\n download: 0,\n },\n video: {\n upload: 0,\n download: 0,\n },\n },\n resolution: {\n width: 0,\n height: 0,\n },\n framerate: 0,\n audioLevel: 0,\n transport: [\n {\n ip: '',\n type: '',\n localIp: '',\n localCandidateType: '',\n remoteCandidateType: '',\n networkType: '',\n rtt: 0,\n },\n ],\n quality: {\n audio: {\n jitter: 0,\n interruptionCount: 0,\n interruptionDuration: 0,\n },\n video: {\n jitter: 0,\n interruptionCount: 0,\n interruptionDuration: 0,\n },\n },\n statistics: {\n audio: {\n bytesReceived: 0,\n bytesSent: 0,\n packetsReceived: 0,\n packetsSent: 0,\n packetsLost: 0,\n },\n video: {\n bytesReceived: 0,\n bytesSent: 0,\n packetsReceived: 0,\n packetsSent: 0,\n packetsLost: 0,\n framesEncoded: 0,\n framesDecoded: 0,\n framesSent: 0,\n },\n bweforvideo: {\n availableReceiveBandwidth: 0,\n availableSendBandwidth: 0,\n retransmitBitrate: 0,\n transmitBitrate: 0,\n targetEncBitrate: 0,\n },\n },\n cpu: {\n appCpu: 0,\n systemCpu: 0,\n },\n }\n}\n\nexport function timestampMillisecond(diffNTP: number = 0): number {\n return new Date().getTime() + diffNTP\n}\n\n/**\n * 处理时间戳\n * @param {number} timeStamp\n * @returns {string} 12:09\n */\nexport function handleTime(timeStamp: number): string {\n let listDate = new Date(timeStamp)\n let currentDate = new Date()\n let month =\n listDate.getMonth() + 1 < 10\n ? '0' + (listDate.getMonth() + 1)\n : listDate.getMonth() + 1\n let date =\n listDate.getDate() < 10 ? '0' + listDate.getDate() : listDate.getDate()\n let hours =\n listDate.getHours() < 10 ? '0' + listDate.getHours() : listDate.getHours()\n let minute =\n listDate.getMinutes() < 10\n ? '0' + listDate.getMinutes()\n : listDate.getMinutes()\n if (currentDate.setHours(0, 0, 0, 0) == listDate.setHours(0, 0, 0, 0)) {\n return hours + ':' + minute\n } else {\n return month + '月' + date + '日' + ' ' + hours + ':' + minute\n }\n}\nexport function sortUsers(list: BMUser[]) {\n return list.sort((a, b) => {\n if (a.sortNum === MODEL_SORT_ENUM_STAND.RAISE_HAND && b.sortNum === MODEL_SORT_ENUM_STAND.RAISE_HAND) {\n return a.raiseHandTime - b.raiseHandTime\n }else {\n return a.sortNum - b.sortNum\n }\n })\n}\n\nexport function sortStreamModels(list: BMStreamModel[]) {\n return list.sort((a, b) => {\n if (a.sortNum !== b.sortNum) {\n return b.sortNum - a.sortNum\n } else {\n return Number(a.getUser().isCommonUser) - Number(b.getUser().isCommonUser)\n }\n })\n}\n\n/**\n * 根据权限判断是不是普通参会者\n * @param permission\n */\nexport function getIsCommonUser(permission: string) {\n return !getPermission(permission, 's')\n}\n\nexport function getIsManager(permission: string) {\n return getPermission(permission, 'm')\n}\nexport function getIsMaster(permission: string) {\n return getPermission(permission, 'o')\n}\nexport function getPermission(permission: string, p: string) {\n return permission.toLowerCase().includes(p)\n}","/**\n * @name: Thread\n * @author: yangliye\n * @date: 2023-05-06 15:33\n * @description:Thread\n * @update: 2023-05-06 15:33\n */\n\n/**\n * 休眠 ms\n * @param ms\n */\nexport function sleep(ms: number) {\n return new Promise(resolve => setTimeout(resolve, ms))\n}\n","import { handleTime } from '../util/util'\n\ninterface IMessageInfo {\n userId?: string\n message: string\n role?: string\n isLocal?: boolean\n avatar?: string\n nickName?: string\n sendTime?: number\n isMeetingNotice?: boolean,\n to?: string | undefined\n isDanger?: boolean\n seq?: number,\n failed?: boolean\n}\n\n// 聊天室\nexport default class BMMessageInfo {\n public userId?: any //用户id\n public message!: string //消息内容\n public time: string //发送消息时间\n public timeStamp: number //发送消息的时间戳\n public role?: string //角色??\n public isLocal?: boolean //是否为本地用户\n public avatar?: any //头像\n public nickName?: any\n public isMeetingNotice: boolean = false\n public to: string | undefined\n public isDanger :boolean | undefined\n public seq : number | undefined\n public failed: boolean | undefined\n\n constructor(props: IMessageInfo) {\n this.userId = props.userId\n this.message = props.message\n\n this.role = props.role\n this.isLocal = props.isLocal\n this.avatar = props.avatar\n this.nickName = props.nickName\n this.to = props.to\n this.isDanger = props.isDanger\n this.seq = props.seq\n this.failed = props.failed\n\n let isMeetingNotice = false\n if (props.isMeetingNotice) {\n isMeetingNotice = true\n }\n this.isMeetingNotice = isMeetingNotice\n if (props.sendTime) {\n this.timeStamp = props.sendTime\n this.time = handleTime(this.timeStamp)\n } else {\n this.timeStamp = new Date().getTime()\n this.time = handleTime(this.timeStamp)\n }\n }\n}\n","/**\n * @name: EventHandler\n * @author: yangliye\n * @date: 2023-04-04 10:14\n * @description:EventHandler\n * @update: 2023-04-04 10:14\n */\nimport BMUserVM, { ignoreUserId } from \"../BMUser/BMUserVM\";\nimport BMMessageInfo from \"../BMChat/BMMessageInfo\";\nimport * as logger from \"../logger/logger\";\nimport * as constant from \"../util/constant\";\nimport BMRoom from \"../BMRoom/BMRoom\";\nimport BMStreamModelVM from \"../BMStream/BMStreamModelVM\";\nimport BCClient from \"@hysc/core\";\nimport BMChatVM from \"../BMChat/BMChatVM\";\nimport BoomCore from \"@hysc/core\";\nimport { getIsCommonUser } from \"../util/util\";\nimport { BCUser } from \"@hysc/core\"\nimport BMUser from \"../BMUser/BMUser\";\nimport { debounce } from \"lodash-es\";\nimport { handleInitJoinRoomUsers, handleRoomConnected } from \"./handleRoomEvent\";\nimport { MessageType } from \"./attachEvents\";\nimport { USER_REJOINED, PARTICIPANT_JOINED, CHANGE_MASTER, EVICTED, UPDATE_USER, PARTICIPANT_LEFT, CUSTOM_MESSAGE, MOVE_USER_ROOM } from '@hysc/utils/events/bloudEvents'\n\n\nexport function handleParticipantJoin(data: any, userVM: BMUserVM, bmStreamVm: BMStreamModelVM, boomCore: BoomCore, chatVM: BMChatVM, observes: any) {\n const sync = data?.participant?.params?.info.sync\n const mode = data.mode\n logger.info('用户入会', '用户入会', data.user.userId, ['sync => ', sync, 'mode =>', mode])\n const shouldDelay = userVM.room!.isBig && bmStreamVm.streamModels.size > 1000\n let hasRoleChanged = false\n if (sync) {\n let user = userVM.userList.get(data.user.userId)\n if (!user) {\n user = userVM.commonUserList.get(data.user.userId)\n }\n if (user) {\n if (user.inBackground != !!data.user?.customInfo?.inBackground) {\n user.inBackground = !!data.user?.customInfo?.inBackground\n user.watcher.next({\n operation: 'inBackground',\n user: user,\n })\n }\n return\n }\n }\n if (mode === 1 && userVM.room?.isBig) {\n userVM.commonUserList.delete(data.user.userId)\n bmStreamVm.streamModels.delete(data.user.userId)\n }\n /**\n * 服务端现在在身份变化入会异常情况下会发入会\n * 所以要做特殊处理,就是当有新人入会的时候\n * 判断一下,当前是不是能找到这个人,然后判断和之前的身份是不是不一样\n * 如果不一样 就把之前的人删了 然后重新创建新的用户\n */\n const curIsCommon = getIsCommonUser(data.user.permission.permission)\n if (curIsCommon) {\n const user = userVM.userList.get(data.user.userId)\n if (user) {\n userVM.userList.delete(data.user.userId)\n bmStreamVm.streamModels.delete(data.user.userId)\n hasRoleChanged = true\n }\n } else {\n const user = userVM.commonUserList.get(data.user.userId)\n if (!userVM.room?.isSingleColumns) {\n if (user) {\n userVM.commonUserList.delete(data.user.userId)\n bmStreamVm.streamModels.delete(data.user.userId)\n hasRoleChanged = true\n }\n }\n }\n\n let bmUser = userVM.addBCUser(data.user)\n if (bmUser) {\n if (bmUser.inBackground != !!data.user?.customInfo?.inBackground) {\n bmUser.inBackground = !!data.user?.customInfo?.inBackground\n bmUser.watcher.next({\n operation: 'inBackground',\n user: bmUser,\n })\n }\n\n let shouldIgnore = false\n ignoreUserId.forEach(suffix => {\n if (bmUser?.userId.includes(suffix)) {\n shouldIgnore = true\n }\n })\n\n if (hasRoleChanged) {\n userVM.updateAllSort()\n } else {\n // 入会的是普通参会者,就更新普通参会者列表,是嘉宾就更新嘉宾列表\n if (userVM.room?.isSingleColumns) {\n userVM.updateCommonUserSort()\n } else {\n if (bmUser) {\n if (bmUser.isCommonUser) {\n if (shouldDelay) {\n userVM.updateDelayCommonUserSort()\n } else {\n userVM.updateCommonUserSort()\n }\n } else {\n userVM.updateUserSort()\n }\n } else {\n userVM.updateAllSort()\n }\n }\n }\n\n bmStreamVm.updateModelSort()\n if (!shouldIgnore) {\n if (data.mode !== 1) {\n const message = new BMMessageInfo({\n isMeetingNotice: true,\n userId: bmUser.userId,\n message:\n bmUser.nickName +\n `加入${boomCore.roomType == 2 ? '直播' : '会议'}`,\n })\n chatVM.addMessage(message, true)\n }\n observes[PARTICIPANT_JOINED].next({\n user: bmUser,\n mode,\n data\n })\n }\n }\n}\n\nexport function handleLeaveUsers(data: any, userVM: BMUserVM, bmRoom: BMRoom, observes: any, bmStreamVm: BMStreamModelVM, boomCore: BCClient, chatVM: BMChatVM) {\n const userIds = data.userIds\n logger.info('bloud leave users', '', '', ['userIds =>', userIds])\n if (userIds.length) {\n userIds.forEach((u: string) => {\n const user = leaveUser(u, userVM, bmRoom, bmStreamVm)\n if (user) {\n sendLeveNotification(user, boomCore, chatVM, observes, true, 0)\n }\n })\n\n // 离开的是普通参会者,就更新普通参会者列表,是嘉宾就更新嘉宾列表\n if (userVM.room?.isSingleColumns) {\n userVM.updateCommonUserSort()\n } else {\n userVM.updateAllSort()\n }\n\n bmStreamVm.updateModelSort()\n }\n}\n\nexport function handleParticipantLeft(data: any, userVM: BMUserVM, bmRoom: BMRoom, observes: any, bmStreamVm: BMStreamModelVM, boomCore: BCClient, chatVM: BMChatVM) {\n logger.info(`bloud participant left ===>${data.userId}, ${data.mode}`)\n const isPermissionChanged = data.mode === 1\n const uid: string = data.userId\n const shouldDelay = bmRoom.isBig && bmStreamVm.streamModels.size > 1000\n if (uid) {\n const removedUser = leaveUser(uid, userVM, bmRoom, bmStreamVm)\n\n // 离开的是普通参会者,就更新普通参会者列表,是嘉宾就更新嘉宾列表\n if (userVM.room?.isSingleColumns) {\n userVM.updateCommonUserSort()\n } else {\n if (removedUser) {\n if (removedUser.isCommonUser) {\n if (shouldDelay) {\n userVM.updateDelayCommonUserSort()\n } else {\n userVM.updateCommonUserSort()\n }\n } else {\n userVM.updateUserSort()\n }\n } else {\n userVM.updateAllSort()\n }\n }\n\n bmStreamVm.updateModelSort()\n if (isPermissionChanged) {\n observes[PARTICIPANT_LEFT].next({\n user: removedUser,\n mode: data.mode,\n data\n })\n return\n }\n if (removedUser) {\n sendLeveNotification(removedUser, boomCore, chatVM, observes, data.mode !== 1, data.mode)\n }\n\n } else {\n logger.warn(\n `participant-left触发=======>但是该用户信息不存在`,\n constant.LOGGER_TAG_CLIENT,\n null,\n [data.userId],\n )\n observes[PARTICIPANT_LEFT].next({\n user: data.userId,\n mode: data.mode,\n data\n })\n }\n}\n\nfunction sendLeveNotification(removedUser: BMUser, boomCore: BoomCore, chatVM: BMChatVM, observes: any, shouldNitify: boolean, mode: number) {\n let shouldIgnore = false\n ignoreUserId.forEach(suffix => {\n if (removedUser?.userId.includes(suffix)) {\n shouldIgnore = true\n }\n })\n if (!shouldIgnore) {\n if (shouldNitify) {\n const message = new BMMessageInfo({\n isMeetingNotice: true,\n userId: removedUser.userId,\n message:\n removedUser?.nickName +\n `离开${boomCore.roomType == 2 ? '直播' : '会议'}`,\n })\n chatVM.addMessage(message, true)\n }\n\n observes[PARTICIPANT_LEFT].next({\n user: removedUser,\n mode: mode\n })\n }\n}\n\nfunction leaveUser(uid: string, userVM: BMUserVM, bmRoom: BMRoom, bmStreamVm: BMStreamModelVM) {\n const removedUser = userVM.getUser(uid)\n userVM.removeUser(uid)\n bmRoom.streamQueue.removeUsers([{ id: uid, isScreen: false }, { id: uid, isScreen: true }])\n bmStreamVm.removeStreamModelByUId(uid)\n bmStreamVm.removeShareStreamModelByUId(uid)\n bmRoom.roomInfo.removeRaiseHandUser(uid)\n bmRoom.roomInfo.removeVideoRaiseHandUser(uid)\n bmRoom.roomInfo.removeSimpleRaiseHandUser(uid)\n bmStreamVm.shareBloudStateMap.delete(uid)\n return removedUser\n}\n\nexport function handleChangeMaster(data: any, userVM: BMUserVM, bmRoom: BMRoom, observes: any, bmStreamVm: BMStreamModelVM) {\n logger.info('changeMaster =>', 'changeMaster', '', ['master: => ', data.master, 'oldMaster =>', data.oldMaster])\n const masterId = data.master\n const oldMasterId = data.oldMaster\n const isKeep = data.isKeep\n if (!masterId) {\n logger.warn(\n `change-master触发=======>但是房间内找不到master`,\n constant.LOGGER_TAG_CLIENT,\n null,\n masterId,\n )\n observes[CHANGE_MASTER].next(null)\n } else {\n let users = userVM.updateMaster(masterId, oldMasterId, isKeep)\n if (users.master) {\n users.master.watcher.next({\n operation: 'getMaster',\n user: users.master,\n })\n bmRoom.userVM.masterUserWatcher.next(users.master)\n }\n if (users.oldMaster) {\n users.oldMaster.watcher.next({\n operation: 'removeMaster',\n user: users.oldMaster,\n })\n\n if (isKeep) {\n users.oldMaster.watcher.next({\n operation: 'getManager',\n user: users.oldMaster,\n })\n }\n\n }\n const oldStream = bmStreamVm.getStreamModelByUId(oldMasterId)\n const newStream = bmStreamVm.getStreamModelByUId(masterId)\n oldStream?.updateSortNum()\n newStream?.updateSortNum()\n observes[CHANGE_MASTER].next({\n master: users.master,\n oldMaster: users.oldMaster,\n data\n })\n }\n}\n\nexport function handleEvict(data: any, userVM: BMUserVM, bmStreamVm: BMStreamModelVM, bmRoom: BMRoom, observes: any) {\n const uid = data.userId\n const evictedUser = userVM.getUser(uid)\n logger.info('踢出用户 => ', 'evict ', evictedUser?.userId, ['nickname => ', evictedUser?.nickName])\n const removedUser = leaveUser(uid, userVM, bmRoom, bmStreamVm)\n // 离开的是普通参会者,就更新普通参会者列表,是嘉宾就更新嘉宾列表\n if (userVM.room?.isSingleColumns) {\n userVM.updateCommonUserSort()\n } else {\n if (removedUser) {\n if (removedUser.isCommonUser) {\n userVM.updateCommonUserSort()\n } else {\n userVM.updateUserSort()\n }\n } else {\n userVM.updateAllSort()\n }\n }\n\n bmStreamVm.updateModelSort()\n observes[EVICTED].next(data)\n}\n\nexport function handleUpdateUser(data: any, userVM: BMUserVM, bmRoom: BMRoom, bmStreamVm: BMStreamModelVM, observes: any) {\n logger.info('用户信息被改变', '', data.user?.userId)\n if (data.user?.userId) {\n let bmUser = userVM.getUser(data.user.userId)\n let streamModel = bmStreamVm.getStreamModelByUId(data.user.userId)\n if (bmUser) {\n bmUser.updateUserInfo(data.user, data.participant, bmRoom)\n } else {\n console.warn('participant-update: bmUser is null')\n }\n\n if (streamModel) {\n streamModel.updateSortNum(true)\n }\n\n observes[UPDATE_USER].next({\n bmUser: bmUser,\n params: data.participant.params,\n })\n }\n}\n\nexport function updateBMUser(allUsers: Map<string, BCUser>, bmUser: BMUser, userVm: BMUserVM) {\n const bcUser = allUsers.get(bmUser.userId)\n if (bcUser) {\n userVm.updateUser(bmUser, bcUser)\n }\n}\n\nexport const handleUserRejoined = debounce((observes: any, data: any) => {\n observes[USER_REJOINED].next(data)\n}, 1000)\n\nexport async function handleMoveUserRoom(bmRoom: BMRoom, userVM: BMUserVM, data: any, observes: any) {\n logger.info('bloud move user room', '', '', [data])\n // true 移动到等候室 false 移动到房间\n const toWait = data.toWait as boolean\n bmRoom.isInWaitRoom = toWait\n if (!toWait) {\n // 初始化房间相关信息\n const { audiooff, selfopenaudio, lock } = data.info\n if (lock !== bmRoom.roomInfo.lock) {\n bmRoom.roomInfo.setlock(lock)\n }\n if (audiooff !== bmRoom.roomInfo.audioOff || selfopenaudio !== bmRoom.roomInfo.selfopenaudio) {\n bmRoom.roomInfo.setAudioOff(audiooff, selfopenaudio)\n }\n await handleRoomConnected(data.info, bmRoom, userVM, observes, true)\n await handleInitJoinRoomUsers(bmRoom)\n observes[MOVE_USER_ROOM].next(toWait)\n } else {\n bmRoom.handleResetOtherStreamStatus()\n userVM.userList.clear()\n userVM.userListWatcher.next([])\n userVM.commonUserList.clear()\n userVM.commonUserListWatcher.next([])\n userVM.getForceUserWatcher.next(false)\n bmRoom.bmStreamVm.streamModels.clear()\n bmRoom.bmStreamVm.clearDetector()\n bmRoom.bmStreamVm.speakerWatcher.next(null)\n observes[CUSTOM_MESSAGE].next(null)\n // 重新初始化message watcher\n bmRoom.messageWatcher.next({\n type: MessageType.INIT,\n status: false,\n isNotCancelRootReport: false\n })\n bmRoom.audioPlayer.destroy()\n const localModel = bmRoom.bmStreamVm.localModel\n if (localModel) {\n bmRoom.bmStreamVm.streamModels.set(localModel.userId, localModel)\n }\n bmRoom.bmStreamVm.streamModelsWatcher.next([])\n bmRoom.bmStreamVm.shareStreamModels.clear()\n bmRoom.bmStreamVm.shareStreamModelsWatcher.next([])\n bmRoom.roomInfo.raiseHandsWatcher.next([])\n bmRoom.roomInfo.raiseVideoHandsWatcher.next([])\n bmRoom.roomInfo.raiseSimpleHandsWatcher.next([])\n observes[MOVE_USER_ROOM].next(toWait)\n // 清空attachEvents相关的监听\n Object.values(bmRoom.observes).forEach((v: any) => {\n v.next(null)\n })\n }\n}","import { SingleRemoteStream } from \"../type\";\nimport { MOBILE_STREAM_SUFFIX_SCREEN, STREAM_SUFFIX_SCREEN } from \"../constants\";\n\n/**\n * @name: roomUtils\n * @author: yangliye\n * @date: 2022-12-06 09:31\n * @description:roomUtils\n * @update: 2022-12-06 09:31\n */\nexport function isShareStream(remoteStream: SingleRemoteStream) {\n const streamId = remoteStream.getStreamId()\n const uid = remoteStream.getUserId().toString()\n return ((uid.endsWith(STREAM_SUFFIX_SCREEN)) || streamId.startsWith(MOBILE_STREAM_SUFFIX_SCREEN) || (remoteStream.getType && remoteStream.getType() === 'assist'))\n}","/**\n * @name: streamEvent\n * @author: yangliye\n * @date: 2023-04-26 10:36\n * @description:streamEvent\n * @update: 2023-04-26 10:36\n */\nimport BMStreamModel from \"../BMStream/BMStreamModel\";\nimport { SingleRemoteStream } from \"../type\";\nimport * as logger from \"../logger/logger\";\nimport BMStreamModelVM, { transShareScreen2User } from \"../BMStream/BMStreamModelVM\";\nimport { isShareStream } from \"../util/roomUtils\";\nimport { BloudStreamEventState, BloudUnPubEvent } from \"./attachEvents\";\nimport { PullItem } from \"../SingletonQueue/SingletonQueue\";\nimport BMRoom from \"../BMRoom/BMRoom\";\nimport { debounce } from \"lodash-es\";\nimport { BMShareStreamReconnectFailed, BMShareStreamReconnectSuccess, BMStreamReconnectSuccess, STREAM_PUBLISHED, STREAM_REMOVED, STREAM_UPDATE, UPDATE_STREAM } from \"@hysc/utils\";\nimport * as BRTCEvents from '@hysc/utils/events/brtcEvents';\n\nexport function checkStreamIsNormal(streamModel: BMStreamModel | undefined) {\n if (streamModel && !streamModel.isLocal) {\n const currentState = streamModel.isDisplay && (streamModel.videoEnable && streamModel.stream?.getVideoOn() && !streamModel.stream?.getVideoTrack())\n if (currentState || streamModel.audioEnable && !(streamModel.stream as SingleRemoteStream)?.isSubscribed?.()) {\n setTimeout(() => {\n const currentState = streamModel.isDisplay && (streamModel.videoEnable && streamModel.stream?.getVideoOn() && !streamModel.stream?.getVideoTrack())\n if (currentState || streamModel.audioEnable && !(streamModel.stream as SingleRemoteStream)?.isSubscribed?.()) {\n logger.warn('用户流检测,但是流订阅出现了问题,需要重新订阅', '用户流检测', streamModel.userId, [' nickname => ', streamModel.nickname, 'isDisplay =>', streamModel.isDisplay])\n streamModel.hasPulled = false\n streamModel.pulledStreamType = 'small'\n streamModel.sendMessage2Room()\n }\n }, 2 * 1000)\n }\n }\n}\n\nexport function handleStreamUpdated(event: any, bmStreamVm: BMStreamModelVM, observes: any) {\n const stream = event.stream\n let streamModel: BMStreamModel | undefined\n\n if (isShareStream(stream)) {\n streamModel = bmStreamVm.getShareStreamModelByUId(stream.getUserId())\n } else {\n streamModel = bmStreamVm.getStreamModelByUId(stream.getUserId())\n }\n\n logger.info('远端有人更新流', '远端有人更新流', stream.getUserId(), [stream.getStreamId(), 'audioOn =>', stream.getAudioOn(), 'videoOn =>', stream.getVideoOn(), 'audioEnable => ', streamModel?.audioEnable, streamModel?.stream?.getAudioOn(), 'videoEnable =>', streamModel?.videoEnable, streamModel?.stream?.getVideoOn(), 'streamId =>', stream.getStreamId()])\n\n checkStreamIsNormal(streamModel)\n}\n\nexport function handleBloudReconnectStreamEvent(bmStreamVm: BMStreamModelVM) {\n // 处理本地流的情况,当bloud重连上之后,判断一下当前流的状态,如果brtc 的流已经销毁了,同步一下bloud的状态\n const localModel = bmStreamVm.getLocalStreamModel()\n // brtc 没流了,但是bloud还有流,说明当前brtc 取消推流了\n if (localModel && !localModel?.stream) {\n if (bmStreamVm.bloudStream) {\n logger.info('brtc 已经没有流了,bloud 的流要取消掉')\n bmStreamVm.bloudStream.unpublish()\n localModel.updateBloudStream(undefined, bmStreamVm)\n bmStreamVm.bloudStream = null\n }\n }\n // brtc 有流,断网重连之后,给各个端上重新发pub\n else if (localModel && localModel.stream) {\n logger.info('brtc 流已经重推上去了,bloud要重新发推流的逻辑')\n const audioEnable = localModel.stream.getAudioOn()\n const videoEnable = localModel.stream.getVideoOn()\n bmStreamVm.publishBloudStream(audioEnable, videoEnable).then(() => {\n logger.info('brtc stream repub success bloud repub success, notify reconnect success')\n // @ts-ignore\n bmStreamVm.localStreamConnectErrorWatcher.next(BMStreamReconnectSuccess(audioEnable, videoEnable));\n })\n }\n\n // 本地共享屏幕流处理\n if (bmStreamVm.localIsShare) {\n logger.info('brtc has share stream, and bloud need to republish share stream')\n const shareStream = bmStreamVm.room?.boomCore.shareScreenStream\n if (shareStream) {\n const audioEnable = shareStream.getAudioOn()\n const videoEnable = shareStream.getVideoOn()\n try {\n bmStreamVm.room?.boomCore.createAndPubBloudShareStream(audioEnable, videoEnable)\n } catch (e) {\n logger.error('bloud 共享屏幕流,断网重连重推流失败')\n }\n }\n }\n}\n\nexport const handleReconnectedStream = debounce((bmRoom: BMRoom) => {\n if (bmRoom.networkState.bloud && bmRoom.networkState.brtc) {\n try {\n bmRoom.streamQueue.restart()\n } catch (e) {\n bmRoom.streamQueue.setQueueProcessor(bmRoom.queueProcessor)\n bmRoom.streamQueue.restart()\n }\n }\n}, 300)\n\nexport function handleStreamPublished(event: any, bmStreamVm: BMStreamModelVM, bmRoom: BMRoom, observes: any) {\n const stream = event.stream\n logger.info('本地推流', '本地推流', stream.getUserId())\n if (stream) {\n const localStreamModel = bmStreamVm.getLocalStreamModel()\n if (localStreamModel) {\n bmStreamVm.updateStreamModel(localStreamModel, stream)\n }\n observes[BRTCEvents.STREAM_PUBLISHED].next({ published: true, model: localStreamModel })\n // 处理直播的业务,本地是观众的时候,推了流,这个时候要拉取所有人的流\n if (bmRoom.conferenceMode === 1) {\n const localIsAudience = bmRoom.getLocalParticipant().isAudience\n if (localIsAudience) {\n bmStreamVm.getStreamModels().forEach(streamModel => {\n streamModel.sendMessage2Room()\n })\n }\n }\n } else {\n observes[BRTCEvents.STREAM_PUBLISHED].next({ published: false })\n }\n}\n\nexport function handleBloudStreamPublished(data: any, bmStreamVm: BMStreamModelVM, observes: any) {\n logger.info('bloud publish stream')\n handleBloudStreamPubAUpdate(data, bmStreamVm, true)\n observes[STREAM_PUBLISHED].next(data)\n}\n\nexport function handleBloudStreamPubAUpdate(data: BloudStreamEventState, bmStreamVm: BMStreamModelVM, isPublish = false) {\n logger.info('bloud stream update', '', '', [JSON.stringify(data)])\n const userId = data.userId\n const isScreen = data.isScreen\n const sm = bmStreamVm.streamModels.get(userId)\n if (sm) {\n if (!isScreen) {\n sm.updateBloudStream(data, bmStreamVm, isPublish)\n sm.getUser().updateSortNum()\n } else {\n bmStreamVm.shareBloudStateMap.set(userId, data)\n const item: PullItem = { id: userId, isWeb: sm.isWeb, isScreen: isScreen }\n bmStreamVm.room?.addUser2Queue(item)\n }\n } else {\n logger.error('bloud stream update, but can not get streamModel', '', userId)\n }\n}\n\nexport function handleBloudStreamUnPublished(data: any, bmStreamVm: BMStreamModelVM, observes: any) {\n logger.info('bloud unpublish stream', '', '', [JSON.stringify(data)])\n handleBloudStreamUnpublish(data, bmStreamVm)\n observes[STREAM_REMOVED].next(data)\n}\n\nexport function handleBloudStreamUpdated(data: any, bmStreamVm: BMStreamModelVM, observes: any) {\n logger.info('bloud stream update', '', '', [JSON.stringify(data)])\n const streamId = data.streamId\n const userId = data.userId\n const customInfo = data.params.customInfo\n let sm\n if (streamId.includes('_screen')) {\n sm = bmStreamVm.shareStreamModels.get(userId)\n } else {\n sm = bmStreamVm.streamModels.get(userId)\n }\n\n if (sm) {\n sm.updateBloudCustomInfo(customInfo)\n } else {\n logger.error('bloud stream update, but can not get streamModel', '', userId, ['streamId =>', streamId])\n }\n\n observes[UPDATE_STREAM].next(data)\n}\n\nexport function handleBloudStreamUnpublish(data: BloudUnPubEvent, bmStreamVm: BMStreamModelVM) {\n const userId = data.userId\n const isScreen = data.isScreen\n if (!isScreen) {\n const sm = bmStreamVm.streamModels.get(userId)\n if (sm) {\n sm.updateBloudStream(undefined, bmStreamVm)\n const bsm = (sm.stream as SingleRemoteStream)\n if (bsm) {\n bmStreamVm.room!.audioPlayer?.removeStream(bsm)\n bmStreamVm.remoteStreamUnpublished(bsm)\n bsm.destroy()\n }\n const item: PullItem = { id: userId, isWeb: sm.isWeb, isScreen: false }\n bmStreamVm.room?.streamQueue.removeUsers([item])\n }\n } else {\n const shareStreamModel = bmStreamVm.shareStreamModels.get(userId)\n if (shareStreamModel) {\n const bsm = shareStreamModel.stream as SingleRemoteStream\n if (bsm) {\n bsm.destroy()\n bmStreamVm.remoteStreamUnpublished(bsm)\n } else {\n bmStreamVm.removeShareStreamModelByUId(userId)\n }\n const item: PullItem = { id: userId, isWeb: shareStreamModel.isWeb, isScreen: true }\n bmStreamVm.room?.streamQueue.removeUsers([item])\n }\n }\n}\n\nexport function handleShareStreamFailed(bmRoom: BMRoom, bmStreamVm: BMStreamModelVM) {\n setTimeout(async () => {\n logger.info('handle republish share stream')\n try {\n const shareStream = bmRoom.boomCore.shareScreenStream\n if (shareStream) {\n const audioEnable = shareStream.getAudioOn()\n const videoEnable = shareStream.getVideoOn()\n await bmRoom.boomCore.shareBrtcClient!.publish(shareStream)\n bmRoom.boomCore.createAndPubBloudShareStream(audioEnable, videoEnable);\n logger.info('handle republish share stream success')\n bmStreamVm.localShareError.next(BMShareStreamReconnectSuccess())\n } else {\n logger.warn('no share stream exist, unpublish share stream, to prevent share stream state error')\n bmStreamVm.toggleShareScreen(false, undefined)\n }\n } catch (e) {\n logger.error('handle republish share stream failed , now unpublish')\n bmStreamVm.localShareError.next(BMShareStreamReconnectFailed())\n await bmStreamVm.toggleShareScreen(false, undefined)\n }\n }, 1000)\n}\n","/**\n * @name: handleRoomEvent\n * @author: yangliye\n * @date: 2023-04-25 15:16\n * @description:handleRoomEvent\n * @update: 2023-04-25 15:16\n */\nimport BMRoom from \"../BMRoom/BMRoom\";\nimport BMUserVM, { BLOUD_PAGE_SIZE, PERMISSION_NOT_COMMON } from \"../BMUser/BMUserVM\";\nimport BMStreamModelVM from \"../BMStream/BMStreamModelVM\";\nimport { BCUser } from \"@hysc/core\"\nimport * as logger from \"../logger/logger\";\nimport { handleBloudReconnectStreamEvent, handleReconnectedStream } from \"./streamEvent\";\nimport BMUser from \"../BMUser/BMUser\";\nimport { BloudEvents, BrtcEvents as BRTCEvents } from '@hysc/utils';\n\nfunction setupRoomInfo(data: any, bmRoom: BMRoom, userVM: BMUserVM) {\n const localPermission = data.permission\n const total = data.total\n if (localPermission) {\n userVM.updateLocalUserPermission(localPermission)\n }\n // 当前我是不是应该加入到等候室\n bmRoom.isInWaitRoom = data.joinwait\n // 当前房间有没有开启等候室\n const waitroom = data.waitroom\n bmRoom.roomInfo.isOpenWaitRoom.next(waitroom)\n bmRoom.roomInfo.totalUserWatcher.next(total)\n // 全员静音相关处理\n const audiooff = data.audiooff\n const selfopenaudio = data.selfopenaudio\n if (audiooff !== bmRoom.roomInfo.audioOff || selfopenaudio !== bmRoom.roomInfo.selfopenaudio) {\n if (audiooff != undefined && selfopenaudio != undefined) {\n bmRoom.roomInfo.setAudioOff(audiooff, selfopenaudio)\n }\n }\n}\n\nexport async function handleRoomConnected(data: any, bmRoom: BMRoom, userVM: BMUserVM, observes: any, shouldNotification = true) {\n logger.info('room-connected', bmRoom.getLocalParticipant().userId, 'room-connected', ['roomId =>', bmRoom.roomInfo.roomID, ' local permission => ', data.permission])\n bmRoom.forceId = data.customStats.forceOn?.user\n handleInitRoomInfo(data, bmRoom)\n setupRoomInfo(data, bmRoom, userVM)\n if (shouldNotification) {\n observes[BloudEvents.ROOM_CONNECTED].next(data)\n }\n}\n\nexport async function handleInitJoinRoomUsers(bmRoom: BMRoom) {\n logger.info('join ready init users')\n if (!bmRoom.isInWaitRoom) {\n if (bmRoom.forceId) {\n await bmRoom.getForceUser(bmRoom.forceId)\n }\n await bmRoom.userVM.initUsers()\n }\n}\n\nexport function handleRoomUpdated(data: any, bmRoom: BMRoom) {\n logger.info('update-stats ', ' ', '', ['options => ', JSON.stringify(data.options)])\n // 全员静音,和是否允许个人打开的处理\n if (data.options && data.options[0] == \"audiooff\" || data.options[1] == \"selfopenaudio\") {\n bmRoom.roomInfo.setAudioOff(\n data.room.audiooff,\n data.room.selfopenaudio\n )\n // 锁定会议的处理\n } else if (data.options && data.options[0] == \"lock\") {\n bmRoom.roomInfo.setlock(data.room.lock)\n }\n // 等候室\n else if (data.options && data.options[0] == 'waitroom') {\n bmRoom.roomInfo.isOpenWaitRoom.next(data.stats.waitroom)\n }\n}\n\nexport function handleInitRoomInfo(data: any, bmRoom: BMRoom) {\n bmRoom.roomInfo.msgSeq = data.msgSeq\n if (data.customStats) {\n bmRoom.roomInfo.initCustomStats(data.customStats)\n }\n}\n\nfunction exitUserUpdateStream(userVm: BMUserVM, u: BMUser, bcu: BCUser, bmStreamVm: BMStreamModelVM, bmRoom: BMRoom) {\n userVm.updateUser(u, bcu)\n // update stream state\n const streams = bcu.stream\n const streamModel = bmStreamVm.streamModels.get(u.userId)\n if (!streamModel) {\n logger.error('bmUserVM中存在该用户,但是bmStreamModelVM中不存在该用户,佛了')\n }\n // streams.size == 0 说明这个人,没有推流,如果本端记录这个人推流了,要把状态更新了\n if (!streams.size) {\n if (streamModel?.bloudStream) {\n streamModel.updateBloudStream(undefined, bmStreamVm)\n bmRoom.streamQueue.removeUsers([{ id: u.userId, isScreen: false }, { id: u.userId, isScreen: true }])\n }\n const shareModel = bmStreamVm.shareStreamModels.get(u.userId)\n if (shareModel && !shareModel.isLocal) {\n try {\n shareModel.stream?.destroy()\n } catch (e) {\n }\n bmStreamVm.removeShareStreamModel(shareModel)\n }\n }\n // streams.size > 1说明这个人有两股流,共享屏幕流和本人的流\n if (streams.get(`${u.userId}_screen`)) {\n bmRoom.addUser2Queue({ id: u.userId, isScreen: true, isWeb: u.isWeb })\n }\n const bsm = streams.get(u.userId)\n if (bsm) {\n streamModel?.updateBloudStream({ audio: bsm.audio_enable, video: bsm.video_enable, isScreen: false }, bmStreamVm)\n }\n}\n\nfunction addUsers(bmRoom: BMRoom, userVm: BMUserVM, users: Map<string, BCUser>, bmStreamVm: BMStreamModelVM) {\n if (bmRoom.isSingleColumns) {\n userVm.commonUserList.forEach(u => {\n const bcu = users.get(u.userId)\n if (bcu) {\n users.delete(u.userId)\n exitUserUpdateStream(userVm, u, bcu, bmStreamVm, bmRoom)\n return\n }\n\n userVm.commonUserList.delete(u.userId)\n bmStreamVm.streamModels.delete(u.userId)\n bmStreamVm.shareStreamModels.delete(u.userId)\n })\n } else {\n userVm.userList.forEach(user => {\n const bcu = users.get(user.userId)\n if (bcu) {\n // 更新用户信息,不能保证在断网重连期间,这个用户的身份有没有发生变化\n exitUserUpdateStream(userVm, user, bcu, bmStreamVm, bmRoom)\n if (user.isCommonUser) {\n userVm.userList.delete(user.userId)\n } else {\n users.delete(user.userId)\n }\n return\n }\n\n userVm.userList.delete(user.userId)\n bmStreamVm.streamModels.delete(user.userId)\n bmStreamVm.shareStreamModels.delete(user.userId)\n })\n }\n bmRoom.userVM.addBcUsersMap(users)\n}\n\nexport async function handleRoomSync(data: any, bmRoom: BMRoom, userVm: BMUserVM, bmStreamVm: BMStreamModelVM) {\n // todo diff 请求下来的用户和现有的用户,如果之前存在这个用户,保留,如果不存在,就删除\n // streamModel同理,如果存在,就保留,如果不存在,就删除\n const localUserId = bmRoom.getLocalParticipant().userId\n const { users } = await bmRoom.boomCore.queryUsers([localUserId])\n const local = users.get(localUserId)\n if (local) {\n userVm.updateUser(userVm.localUser, local)\n }\n const localIsCommonUser = bmRoom.getLocalParticipant().isCommonUser\n\n if (bmRoom.isBig && localIsCommonUser) {\n const { users } = await bmRoom.boomCore.getUsersList(0, PERMISSION_NOT_COMMON, 500)\n addUsers(bmRoom, userVm, users, bmStreamVm)\n } else {\n //\n const total = await bmRoom.userVM.getTotalUserNumber()\n const pullCount = total / BLOUD_PAGE_SIZE\n let allUsers = new Map<string, BCUser>()\n\n for (let i = 0; i < pullCount; i++) {\n let { users: usersInRoom } = await bmRoom.boomCore.getUsers(i - 1, '', BLOUD_PAGE_SIZE)\n usersInRoom.forEach(user => {\n allUsers.set(user.userId, user)\n })\n }\n\n addUsers(bmRoom, userVm, allUsers, bmStreamVm)\n }\n\n handleInitRoomInfo(data, bmRoom)\n bmRoom.userVM.updateAllSort()\n bmRoom.bmStreamVm.updateModelSort()\n}\n\nexport function handleBrtcRoomReconnecting(data: any, bmRoom: BMRoom, observes: any) {\n logger.info('brtc room reconnecting')\n bmRoom.networkState.brtc = false\n bmRoom.streamWSReconnectWatcher.next(false)\n observes[BRTCEvents.BRTC_ROOM_ROCONNECTING].next(data)\n}\n\nexport function handleBrtcRoomReconnected(data: any, bmRoom: BMRoom, observes: any) {\n logger.info('brtc room reconnected')\n bmRoom.networkState.brtc = true\n // setTimeout(() => {\n // bmRoom.brtcNetEnableWatcher.next(true)\n // }, 2000)\n handleReconnectedStream(bmRoom)\n observes[BRTCEvents.BRTC_ROOM_RECONNECTED].next(data)\n}\n\nexport function handleBloudRoomReconnecting(data: any, bmRoom: BMRoom, observes: any) {\n logger.info('bloud room reconnecting')\n bmRoom.networkState.bloud = false\n bmRoom.bloudWSReconnectWatcher.next(false)\n observes[BloudEvents.RECONNECTING].next(data)\n}\n\nexport async function handleBloudRoomReconnected(data: any, bmRoom: BMRoom, observes: any) {\n if (bmRoom.hasSyncPermission) {\n logger.info('bloud room reconnected')\n bmRoom.bloudWSReconnectWatcher.next(false)\n observes[BloudEvents.MOVE_USER_ROOM].next(null)\n await bmRoom.syncRoom()\n .then(() => {\n bmRoom.hasSyncPermission = true\n observes[BloudEvents.ROOM_CONNECTED].next(data)\n })\n .catch(e => {\n logger.error('sync room error', JSON.stringify(e))\n const code = e.code\n if (code === 43) {\n bmRoom.hasSyncPermission = false\n observes[BloudEvents.USER_REJOINED].next(e)\n return\n } else {\n bmRoom.hasSyncPermission = false\n observes[BloudEvents.TIMEOUT].next(e)\n }\n })\n } else {\n observes[BloudEvents.TIMEOUT].next(data)\n }\n}\n\nexport async function handleBloudRoomSync(data: any, userVM: BMUserVM, bmRoom: BMRoom, bmStreamVm: BMStreamModelVM, observes: any) {\n logger.info('bloud sync room completed')\n setupRoomInfo(data, bmRoom, userVM)\n await handleRoomSync(data, bmRoom, userVM, bmStreamVm)\n handleBloudReconnectStreamEvent(bmStreamVm)\n bmRoom.networkState.bloud = true\n handleReconnectedStream(bmRoom)\n bmRoom.bloudWSReconnectWatcher.next(true)\n observes[BloudEvents.ROOM_SYNCED].next(data)\n}\n","/**\n * @name: messageEvent\n * @author: yangliye\n * @date: 2023-04-25 17:53\n * @description:messageEvent\n * @update: 2023-04-25 17:53\n */\nimport * as logger from \"../logger/logger\";\nimport BMMessageInfo from \"../BMChat/BMMessageInfo\";\nimport BMUserVM from \"../BMUser/BMUserVM\";\nimport BMChatVM from \"../BMChat/BMChatVM\";\nimport { MessageType } from \"./attachEvents\";\nimport BMRoom from \"../BMRoom/BMRoom\";\nimport { BloudEvents} from \"@hysc/utils\";\n\nexport function handleSendMessage(msg: any, userVM: BMUserVM, chatVM: BMChatVM, observes: any) {\n let _msg = { ...msg }\n if (_msg.message) {\n _msg.message =\n typeof _msg.message == 'string'\n ? JSON.parse(_msg.message)\n : _msg.message\n logger.info('new-message', '', '', [' method => ', _msg.message.method])\n if (_msg.message.method === 'send-talk') {\n const isLocal = _msg.user === userVM.getLocalUser()?.userId\n const msgStr: string = _msg.message?.params?.status || ''\n const avatar: string = _msg.message?.params?.stream?.avatar\n const seq = msg.seq\n const message = new BMMessageInfo({\n userId: _msg.user, //用户id\n message: msgStr, //发送的消息内容\n isLocal: isLocal,\n avatar: avatar,\n to: _msg.to,\n seq,\n nickName: _msg.message?.params?.stream?.nickname,\n sendTime: new Date().getTime()\n })\n chatVM.addMessage(message, false)\n }\n observes[BloudEvents.SEND_MESSAGE].next(_msg)\n }\n}\n\nexport function handleCustomMessage(msg: any, bmRoom: BMRoom, observes: any) {\n let _msg = { ...msg }\n if (_msg.message) {\n _msg.message =\n typeof _msg.message == 'string'\n ? JSON.parse(_msg.message)\n : _msg.message\n logger.info('custom-message', '', '', [' method => ', _msg.message.method])\n // 远端开启/关闭本地摄像头\n if (_msg.message.method == 'video-force-change') {\n const status = _msg.message.params.status == 'enabled'\n logger.info(`远端控制本地摄像头: ${status}`)\n bmRoom.messageWatcher.next({\n type: MessageType.VIDEO_FORCE_CHANGE,\n status,\n fromUserId: _msg.user\n })\n }\n // 远端开启/关闭本地麦克风\n else if (_msg.message.method == 'audio-force-change') {\n let status\n if (_msg.message.params.status == 'checkUserAudio') {\n status = _msg.message.params.status\n } else {\n status = _msg.message.params.status == 'enabled'\n }\n logger.info(`远端控制本地麦克风: ${status}`)\n bmRoom.messageWatcher.next({\n type: MessageType.AUDIO_FORCE_CHANGE,\n status,\n fromUserId: _msg.user,\n isNotCancelRootReport: _msg.message.params?.isNotCancelRootReport\n })\n }\n // 举手相关操作处理\n else if (_msg.message.method === 'raise-hands') {\n bmRoom.raiseHandleRespWatcher.next(_msg.message.params)\n }\n // 点赞处理\n else if (_msg.message.method === 'give-like') {\n bmRoom.roomVM?.giveLikeList.push({\n userId: _msg.user, //用户id\n nickName: _msg.message?.params?.stream?.nickname,\n time: new Date().getTime(),\n type: _msg.message?.params?.stream?.type\n })\n bmRoom.roomVM?.giveLikeListWatcher.next(bmRoom.roomVM?.giveLikeList)\n }\n else if (_msg.message.method === 'resp-to-check-devices') {\n if (_msg.message?.params) {\n _msg.message.params.fromUserId = _msg.user\n }\n observes[BloudEvents.CUSTOM_MESSAGE].next(_msg)\n }\n else if (_msg.message.method === 'usercount') {\n if (_msg.message.params) {\n let total = _msg.message?.params?.total\n if (total) {\n total = Number(total)\n if (total < 0) {\n logger.warn('服务返回的usercount为负数,' + total)\n total = 0\n }\n } else {\n logger.warn('服务未返回usercount,' + total)\n total = 0\n }\n bmRoom.roomInfo.totalUserWatcher.next(total)\n }\n }\n else if (_msg.message.method === 'waitusercount') {\n if (_msg.message.params) {\n const total = _msg.message.params.total\n bmRoom.roomInfo.totalWaitRoomUserWatcher.next(total)\n }\n }\n else {\n observes[BloudEvents.CUSTOM_MESSAGE].next(_msg)\n }\n }\n}","/**\n * @name: roomErrEvent\n * @author: yangliye\n * @date: 2023-04-26 10:29\n * @description:roomErrEvent\n * @update: 2023-04-26 10:29\n */\nimport * as logger from \"../logger/logger\";\nimport BMRoom from \"../BMRoom/BMRoom\";\nimport BCClient from \"@hysc/core\";\nimport BMStreamModelVM from \"../BMStream/BMStreamModelVM\";\nimport BoomCore from \"@hysc/core\";\nimport { handleReconnectedStream } from \"./streamEvent\";\nimport { handleBloudRoomReconnected } from \"./handleRoomEvent\";\nimport { BloudEvents, BrtcEvents as BRTCEvents } from \"@hysc/utils\";\n\n// brtc reconnect failed num\nlet reconnectFailed = 0\n// bloud reconnect failed num\nlet bloudReconnectFailed = 0\n// brtc share reconnect failed num\nlet shareReconnectFailed = 0\n\nexport const NETWORK_ERROR_QUEUE: Set<(...args: any) => void> = new Set()\n\nexport async function handleBRTCRoomError(data: any, bmRoom: BMRoom, boomCore: BCClient, bmStreamVm: BMStreamModelVM, observes: any) {\n logger.error('brtc error', 'brtc error', '', [new Date().toLocaleTimeString(), JSON.stringify(data), data.getCode()])\n const code = data.getCode()\n if (code === 4002) {\n bmRoom.BRTCConnectFailed = true\n bmRoom.networkState.brtc = false\n logger.warn('brtc 信令通道错误,需要重新走入会', 'brtc error', '')\n bmRoom.streamWSReconnectWatcher.next(false)\n try {\n await boomCore.brtcClient!.leave('room_close')\n } catch (e) {\n logger.error('brtc 离会失败')\n }\n setTimeout(async () => {\n // 设置所有流状态为false\n bmRoom.handleResetOtherStreamStatus()\n await reconnectBrtcWS(boomCore, bmRoom, observes, data)\n .catch(e => {\n logger.info('brtc断网重连失败, 处理一下退会逻辑', '', '', [JSON.stringify(e)])\n observes[BRTCEvents.ERROR].next(data)\n })\n }, 1000)\n } else {\n observes[BRTCEvents.ERROR].next(data)\n }\n}\n\nasync function reconnectBrtcWS(boomCore: BoomCore, bmRoom: BMRoom, observes: any, data: any) {\n return new Promise((resolve, reject) => {\n setTimeout(() => {\n logger.info('brtc重连')\n boomCore.brtcClient!.join(boomCore.roomId, boomCore.userId, boomCore.brtcSig)\n .then(async () => {\n logger.info('brtc断网重连成功, 重新处理拉流和推流')\n bmRoom.networkState.brtc = true\n setTimeout(() => {\n bmRoom.brtcNetEnableWatcher.next(true)\n }, 2000)\n handleReconnectedStream(bmRoom)\n bmRoom.BRTCConnectFailed = false\n // 处理推拉流逻辑\n reconnectFailed = 0\n // 重推本地流逻辑\n await bmRoom.handleRePushSelf()\n bmRoom.streamWSReconnectWatcher.next(true)\n\n resolve(true)\n })\n .catch((e: any) => {\n const code = e.getCode()\n logger.info('断网重连入会失败', '', '', [e, code])\n if (reconnectFailed <= 10) {\n reconnectFailed += 1\n // @ts-ignore\n boomCore.brtcClient!.isJoinning = false\n setTimeout(() => {\n reconnectBrtcWS(boomCore, bmRoom, observes, data)\n }, 2 * 1000)\n } else {\n logger.error('brtc断网重连失败,处理一下退会')\n reconnectFailed = 0\n observes[BRTCEvents.ERROR].next(data)\n reject(false)\n }\n })\n }, 7 * 1000)\n })\n}\n\nexport async function reconnectBloud(bmRoom: BMRoom, boomCore: BoomCore, observes: any, data: any) {\n return new Promise((resolve, reject) => {\n setTimeout(() => {\n logger.info('bloud断网重连')\n boomCore.handleBloudRejoin()\n .then(() => {\n bloudReconnectFailed = 0\n bmRoom.networkState.bloud = true\n resolve(true)\n })\n .catch((e: any) => {\n logger.error(`bloud断网重连失败, 尝试次数: ${bloudReconnectFailed}`)\n if (bloudReconnectFailed <= 10) {\n bloudReconnectFailed += 1\n reconnectBloud(bmRoom, boomCore, observes, data)\n } else {\n logger.error('bloud 断网重连失败,处理退会逻辑')\n bloudReconnectFailed = 0\n observes[BloudEvents.TIMEOUT].next(data)\n reject(false)\n }\n })\n }, 7 * 1000)\n })\n}\n\nexport async function reconnectBRTCShareWS(boomCore: BoomCore) {\n return new Promise((resolve, reject) => {\n setTimeout(() => {\n logger.info('共享屏幕重连')\n boomCore.shareBrtcClient!.join(boomCore.roomId, boomCore.userId, boomCore.brtcSig)\n .then(() => {\n shareReconnectFailed = 0\n resolve(true)\n })\n .catch((e: any) => {\n const code = e.getCode()\n logger.info('共享屏幕断网重连入会失败', '', '', [e, code])\n if (shareReconnectFailed <= 3) {\n shareReconnectFailed += 1\n reconnectBRTCShareWS(boomCore)\n } else {\n logger.error('共享屏幕用户重连失败,处理一下取消共享屏幕')\n shareReconnectFailed = 0\n throw new Error('共享屏幕重连失败')\n }\n })\n }, 7 * 1000)\n })\n}\n\nexport async function handleBloudError(bmRoom: BMRoom, boomCore: BCClient, bmStreamVm: BMStreamModelVM, data: any, observes: any) {\n logger.error('network-error', 'network-error', 'local-client', ['本地链接出现问题', 'netconnectiong => ', bmRoom.netConnecting])\n if (bmRoom.netConnecting) {\n await handleBloudRoomReconnected(data, bmRoom, observes)\n } else {\n observes[BloudEvents.TIMEOUT].next(data)\n }\n // bmRoom.networkState.bloud = false\n // observes[BCEvent.MOVE_USER_ROOM].next(null)\n // reconnectBloud(bmRoom, boomCore, observes, data)\n // .then( async () => {\n // await sleep(1000)\n // await handleInitJoinRoomUsers(bmRoom)\n // handleBloudReconnectStreamEvent(bmStreamVm)\n // bmRoom.networkState.bloud = true\n // handleReconnectedStream(bmRoom)\n // })\n // .catch(() => {\n // observes[BCEvent.NETWORK_ERROR].next(data)\n // })\n}","/**\n * @name: customMessageEvent\n * @author: yangliye\n * @date: 2023-04-26 10:27\n * @description:customMessageEvent\n * @update: 2023-04-26 10:27\n */\nimport * as logger from \"../logger/logger\";\nimport BMRoom from \"../BMRoom/BMRoom\";\nimport { BloudEvents } from '@hysc/utils'\n\nexport function handleCustomStats(data: any, bmRoom: BMRoom, observes: any) {\n let updateKeys = data?.updateKeys;\n logger.info('update-custom-stats', ' ', ' ', ['updateKeys => ', JSON.stringify(updateKeys)])\n // 通知公告/文档权限/屏幕共享权限/观众聊天权限/观众点赞权限改变\n //入会时是否允许开启麦克风/入会时是否允许开启摄像头/参会者列表权限/会议中是否允许自行开启麦克风/会议中是否允许自行开启摄像头/是否允许改名/是否允许开启虚拟背景\n if (updateKeys?.includes('chatNotice') ||\n updateKeys?.includes('chatNoticeRich') ||\n updateKeys?.includes('fileUpdateLook') ||\n updateKeys?.includes('fileUpdateDown') ||\n updateKeys?.includes('fileUpdateEdit') ||\n updateKeys?.includes('fileUpdateModel') ||\n updateKeys?.includes('screenShareModel') ||\n updateKeys?.includes('onlyOnePersonShare') ||\n updateKeys?.includes('chatEnable') ||\n updateKeys?.includes('giveLikeEnable') ||\n updateKeys?.includes('cloudRecord') ||\n updateKeys?.includes('joinAudioEnable') ||\n updateKeys?.includes('joinVideoEnable') ||\n updateKeys?.includes('userListEnable') ||\n updateKeys?.includes('audioEnable') ||\n updateKeys?.includes('videoEnable') ||\n updateKeys?.includes('modifyNameEnable') ||\n updateKeys?.includes('backgroundAIEnable') ||\n updateKeys?.includes('recordEnable') ||\n updateKeys?.includes('joinMicrophoneDisable') ||\n updateKeys?.includes('joinCameraDisable') ||\n updateKeys?.includes('raiseHandEnable') ||\n updateKeys?.includes('forceOpenUserMic') ||\n updateKeys?.includes('forceOpenUserCamera') ||\n updateKeys?.includes('joinCueVoice')\n ) {\n bmRoom.roomInfo.updateOperationPermission(data.customStats)\n }\n if (updateKeys?.includes('chatNotice') ||\n updateKeys?.includes('chatNoticeRich')) {\n bmRoom.roomInfo.chatNoticeWatcher.next(data)\n }\n observes[BloudEvents.UPDATE_CUSTOM_STATS].next(data)\n}","/**\n * @ Author: zhaozhidan\n * @ Create Time: 2020-04-26 11:47:55\n * @ Modified by: zhaozhidan\n * @ Modified time: 2020-09-19 22:19:21\n * @ Description: Boom\n */\n\nimport PQueue from '@hysc/p-queue'\n\nclass Pqueue {\n private queueArray: any[]\n private isTaskPending: boolean\n private queue: PQueue\n\n constructor(maxTask: number, isStart = true) {\n this.queue = new PQueue({\n concurrency: maxTask, autoStart: isStart, carryoverConcurrencyCount: true, timeout: 3 * 1000, completeAction: (status) => {\n console.log('task complete', status)\n }\n })\n this.queueArray = []\n this.isTaskPending = isStart\n }\n\n /**\n * 添加队列\n * @param {*} fn 生成Promise函数\n * @param {String} taskId 任务标识别\n * @param {Number} priority 任务优先级\n * @param {String} nickName 要打印的值\n */\n addQueue(fn: any, taskId: string, priority = 0, nickName = '') {\n if (this.queue.isPaused) {\n this.queue.start()\n }\n // console.log(`+++++++++++ ${nickName}:${taskId}:加入队列+++++++++++`)\n let temp: any = {}\n temp.taskID = taskId\n temp.status = 'pending'\n this.queue.add(fn, { priority: priority, timeout: 3 * 1000 }, (status) => {\n temp.status = status\n if (temp.status === 'resolve' || temp.status === 'resolve-paused' || temp.status === 'resolve-timeout') {\n const index = this.queueArray.findIndex(item => temp.taskID === item.taskID)\n if (index !== -1) {\n this.queueArray.splice(index, 1)// 执行完成之后,删除.\n // console.log(`++++++++++++${nickName}:${taskId}:离开队列+++++++++++`)\n }\n }\n })\n this.queueArray.push(temp)\n }\n /**\n * 清空队列\n */\n clearQueue() {\n this.queue.clear()\n this.queueArray = []\n this.queue.onEmpty().then(res => {\n })\n this.queue.onIdle().then(res => {\n console.log('clearQueue全部完事')\n })\n }\n /**\n * 队列开始执行\n */\n startQueue() {\n this.queue.start()\n }\n\n /**\n * 暂停队列\n */\n pauseQueue() {\n this.queue.pause()\n console.log(`size:${this.size()}`)\n this.isTaskPending = false\n this.queue.onEmpty().then(res => {\n })\n this.queue.onIdle().then(res => {\n })\n return this.queueArray\n }\n /**\n * 返回队列里还未pending和执行完的任务数\n * @returns {number}\n */\n size() {\n return this.queue.size\n }\n /**\n * 返回队列里还未pending和执行完的任务数\n * @returns {number}\n */\n pending() {\n return this.queue.pending\n }\n\n /**\n * 查询任务是否结束\n */\n checkTaskStatus() {\n return this.isTaskPending\n }\n /**\n * 修改任务的状态\n */\n setTaskStatus(res: boolean) {\n this.isTaskPending = res\n }\n\n /**\n * 队列是否执行完了.\n */\n onIdle() {\n return this.queue.onIdle()\n }\n\n /**\n * 队列是否执行完了.\n */\n onEmpty() {\n return this.queue.onEmpty()\n }\n}\n\n// 拉流队列\nexport const streamPullQueue = new Pqueue(4)\n\n// 所有的任务队列\nexport const eventQueue = new Pqueue(10)","import BoomCore from \"@hysc/core\"\nimport BoomError from \"../error/RTCError\"\nimport * as errorType from \"../error/errorType\"\nimport BMRoom from \"./BMRoom\"\nimport BMUserVM from \"../BMUser/BMUserVM\"\nimport * as constant from \"../util/constant\"\nimport BMRoomInfo from \"./BMRoomInfo\"\nimport * as logger from \"../logger/logger\"\nimport {\n BmChangeAudioProfileError,\n BmChangeMasterError,\n BmChangeVideoProfileError,\n BmCheckDeviceError,\n BmEvictUserError,\n BmSetRemoteAudioEnable,\n BmSetRemoteVideoEnable,\n BmUpdateManagerError,\n BmUpdateUserError,\n updateCustomStatsError\n} from \"@hysc/utils\";\nimport { HostLayout, PartialCustomStats } from \"../type/customStats\";\nimport { Subject } from \"rxjs\";\n\n/**\n * 0 仅支持人 1 嘉宾 2 全员\n */\nexport type FilePermission = 0 | 1 | 2\ntype giveLikeItem = {\n userId: string | undefined,\n nickName: string | undefined,\n time: number,\n type: number\n}\nexport type CloudRecord = {\n recordStatus: 0 | 1 | 2,\n userId: string\n}\n\n\ntype SupportVideoProfile = '180p' | '240p' | '360p' | '480p' | '720p'\n\ntype SampleDeviceInfo = { name: string }\n\ninterface DeviceList {\n microphoneDeviceList: SampleDeviceInfo[],\n speakerDeviceList: SampleDeviceInfo[],\n videoDeviceList: SampleDeviceInfo[],\n selectVideoDevice: SampleDeviceInfo,\n selectMicrophoneDevice: SampleDeviceInfo,\n selectSpeakerDevice: SampleDeviceInfo,\n videoProfile: SupportVideoProfile,\n echoCancellation: boolean,\n noiseSuppression: boolean,\n autoGainControl: boolean,\n speakerVolume: number\n}\n\nexport interface AudioProfileInfo {\n /**\n * 音频采集设备\n */\n microphoneDevice?: SampleDeviceInfo,\n /**\n * 音频输出设备\n */\n speakerDevice?: SampleDeviceInfo,\n /**\n * 回音消除\n */\n echoCancellation?: boolean,\n /**\n * 音频降噪\n */\n noiseSuppression?: boolean,\n /**\n * 声音增益\n */\n autoGainControl?: boolean,\n /**\n * 调整扬声器音量 0 - 100\n */\n speakerVolume?: number,\n /**\n * 调整麦克风音量 0 - 100\n */\n microVolume?: number,\n\n}\n\nexport default class BMRoomVM {\n public roomInfo: BMRoomInfo\n public boomCore: BoomCore\n public userVM: BMUserVM\n public giveLikeListWatcher: Subject<Array<giveLikeItem>>;\n public giveLikeList: Array<giveLikeItem>\n private room: BMRoom | null = null\n\n public tipQueueObj: any = {}\n\n constructor(boomCore: BoomCore, userVM: any, roomInfo: BMRoomInfo) {\n this.roomInfo = roomInfo\n this.userVM = userVM\n this.boomCore = boomCore\n this.giveLikeList = []\n this.giveLikeListWatcher = new Subject<Array<giveLikeItem>>();\n }\n\n public initWithRoom(room: BMRoom) {\n this.room = room\n }\n\n /**\n * 踢出用户\n * @param {String} userId 用户ID\n * @param {boolean} withoutBlack\n */\n public async evictUser(userId: string, withoutBlack: boolean): Promise<any> {\n if (!userId) {\n return Promise.reject(BmEvictUserError('未传递用户id'))\n }\n if (!this.userVM.checkLocalHasMaster()) {\n return Promise.reject(BmEvictUserError('只有主持人权限才能踢出用户'))\n }\n if (this.userVM.checkIsMaster(userId)) {\n return Promise.reject(BmEvictUserError('主持人不能被踢出'))\n }\n try {\n await this.boomCore.evictUser(userId, withoutBlack)\n } catch (error) {\n return Promise.reject(BmEvictUserError(`踢出用户失败${JSON.stringify(error)}`))\n }\n }\n\n /**\n * 更新用户信息,端上会收到 participant-update 信令\n * @param userId\n * @param info\n */\n public async updateUser(userId: string, info: any) {\n if (!userId) {\n return Promise.reject(BmUpdateUserError('未传递目标用户id'))\n }\n if (!info) {\n return Promise.reject(BmUpdateUserError('info为空,请写入要更新的信息'))\n }\n await this.boomCore.updateUser(userId, {\n customInfo: info,\n }).catch(e => {\n return Promise.reject(BmUpdateUserError(`boomCore updateUser出错 ${JSON.stringify(e)}`))\n })\n }\n\n /**\n * 改变主持人\n * @param {String} userId 用户ID\n * @param isKeep\n */\n public async changeMaster(userId: string, isKeep: boolean): Promise<any> {\n if (!userId) {\n return Promise.reject(BmChangeMasterError('未传递主持人id'))\n }\n if (this.userVM.checkLocalHasMaster() || this.userVM.getUser(userId)?.isCreate) {\n try {\n await this.boomCore.changeMaster(userId, isKeep)\n }catch (e) {\n return Promise.reject(BmChangeMasterError(`boomCore changeMaster error ${e}`))\n }\n } else {\n console.error(\n `该用户没有管理员权限, 无法改变主持人`,\n constant.LOGGER_TAG_CLIENT,\n userId,\n )\n return Promise.reject(BmChangeMasterError('您没有管理员权限, 无法改变主持人'))\n }\n }\n\n public async updateManager(userId: string, status: boolean, hasS: boolean = true) {\n if (!userId) {\n return Promise.reject(BmUpdateManagerError('未传递联席主持人id'))\n }\n if (this.userVM.checkLocalHasMaster()) {\n return this.userVM.updateManager(userId, status, hasS)\n } else {\n console.error(\n `该用户没有管理员权限, 无法改变联席主持人`,\n constant.LOGGER_TAG_CLIENT,\n userId,\n )\n return Promise.reject(BmUpdateManagerError('该用户没有管理员权限, 无法改变主持人'))\n }\n }\n\n /**\n * 改变昵称 需要调用http请求\n * @param {String} userId 用户ID\n * @param {String} nickName 用户ID\n */\n public async changeNickName(userId: string, nickName: string): Promise<any> {\n const nickInfo = { nickname: nickName }\n await this.updateUser(userId, nickInfo)\n }\n\n /**\n * 主持人send-message\n * @param message 发送的消息\n * @param uid 指定的userId\n */\n async sendMessageWithMaster(message: any, uid?: string) {\n if (!this.userVM.checkLocalHasMaster()) {\n return Promise.reject(BmSetRemoteAudioEnable('您不是主持人,没有该权限'))\n }\n if (uid) {\n let user = this.userVM.getUser(uid)\n if (!user) {\n return Promise.reject(BmSetRemoteAudioEnable(`uid: ${uid} 未找到用户`))\n }\n }\n try {\n await this.boomCore.customMessage(JSON.stringify(message), uid)\n } catch (err) {\n return Promise.reject(err)\n }\n }\n\n /**\n * 开关对端麦克风-信令发送\n * @param status true:开,false:关\n * @param uid 用户id\n * @param isNotCancelRootReport 当打开麦克风时, 是否不取消音频权限申请\n */\n public async setRemoteAudioEnable(status: boolean, uid: string, isNotCancelRootReport: boolean | undefined) {\n let _status: any = status ? 'enabled' : 'disabled'\n if (_status == 'enabled' && isNotCancelRootReport) {\n _status = 'checkUserAudio'\n }\n let message = {\n domain: 'room-control',\n method: 'audio-force-change',\n params: {\n status: _status,\n isNotCancelRootReport: isNotCancelRootReport,\n fromUserId: this.boomCore.getLocalParticipant().getID(),\n },\n }\n this.sendMessageWithMaster(message, uid).catch(err => {\n return Promise.reject(BmSetRemoteAudioEnable(`boomCore.sendMessage发生错误 ${err}`))\n })\n }\n\n /**\n * 开关对端摄像头-信令发送\n * @param status true:开,false:关\n * @param uid 用户id\n */\n public async setRemoteVideoEnable(status: boolean, uid: string) {\n let message = {\n domain: 'room-control',\n method: 'video-force-change',\n params: {\n status: status ? 'enabled' : 'disabled',\n fromUserId: this.boomCore.getLocalParticipant().getID(),\n },\n }\n\n this.sendMessageWithMaster(message, uid).catch(err => {\n return Promise.reject(BmSetRemoteVideoEnable(`boomCore.sendMessage发生错误 ${err}`))\n })\n }\n\n\n /**\n * 关闭对端共享屏幕\n * @param uid 用户id\n */\n public async closeRemoteShare(uid: string) {\n let message = {\n domain: 'room-control',\n method: 'close-remote-share',\n params: {\n fromUserId: this.boomCore.getLocalParticipant().getID(),\n },\n }\n this.sendMessageWithMaster(message, uid).catch(err => {\n return Promise.reject(BmSetRemoteAudioEnable(`boomCore.sendMessage发生错误 ${err}`))\n })\n }\n /**\n * 提醒用户\n * @param uid 用户id\n * @param uid msg\n */\n public async tipUser(uid: string, msg: string, richMsg: object, time: any) {\n\n let message = {\n domain: 'room-control',\n method: 'tip-user',\n params: {\n fromUserId: this.boomCore.getLocalParticipant().getID(),\n message: msg,\n richMsg\n },\n }\n if (time) {\n this.tipQueueObj[uid] = setTimeout(() => {\n this.sendMessageWithMaster(message, uid)\n }, ((time.minutes || 0) * 60 * 1000) + ((time.seconds || 0) * 1000))\n } else {\n this.sendMessageWithMaster(message, uid).catch(e => {\n return Promise.reject(BmSetRemoteAudioEnable(`boomCore.sendMessage发生错误 ${JSON.stringify(e)}`))\n })\n }\n\n }\n\n /**\n * 举手相关操作\n * @param type 视频还是音频举手 audio/video\n * @param raise 举手还是放下举手 true/false\n */\n public async raiseHands(type: 'audio' | 'video' | 'raiseHand', raise: boolean) {\n const localUserId = this.room?.getLocalParticipant().getID()!\n let raiseInfo: any = {}\n if (type === 'raiseHand') {\n raiseInfo['raiseHand'] = raise\n raiseInfo['raiseHandTime'] = Math.floor(new Date().getTime() / 1000)\n } else {\n raiseInfo[type === 'audio' ? 'raiseHandsAudio' : 'raiseHandsVideo'] = raise\n }\n\n await this.updateUser(localUserId, raiseInfo)\n }\n\n /**\n * 主持人处理举手操作\n * @param raiseHandsType 0 音视频 1 音频 2 视频 3 单纯的举手\n * @param raiseHands true 同意 false 拒绝\n * @param uid 指定的用户Id\n * @description 如果不指定用户ID就是广播处理所有的举手的人员\n */\n public async handleRaiseHands(raiseHandsType: 0 | 1 | 2 | 3, raiseHands: boolean, uid?: string) {\n let message = {\n domain: 'user-control',\n method: 'raise-hands',\n params: {\n raiseHandsType,\n raiseHands\n },\n }\n try {\n if (uid) {\n await this.boomCore.customMessage(JSON.stringify(message), uid)\n } else {\n const audioRaiseHands = this.room?.roomInfo.raiseHandsWatcher.getValue()\n const videoRaiseHands = this.room?.roomInfo.raiseVideoHandsWatcher.getValue()\n const simpleHands = this.room?.roomInfo.raiseSimpleHandsWatcher.getValue()\n if (raiseHandsType === 0) {\n audioRaiseHands?.forEach(user => {\n this.boomCore.customMessage(JSON.stringify(message), user.userId)\n })\n videoRaiseHands?.forEach(user => {\n this.boomCore.customMessage(JSON.stringify(message), user.userId)\n })\n }\n if (raiseHandsType === 1) {\n audioRaiseHands?.forEach(user => {\n this.boomCore.customMessage(JSON.stringify(message), user.userId)\n })\n }\n if (raiseHandsType === 2) {\n videoRaiseHands?.forEach(user => {\n this.boomCore.customMessage(JSON.stringify(message), user.userId)\n })\n }\n if (raiseHandsType === 3) {\n simpleHands?.forEach(user => {\n this.boomCore.customMessage(JSON.stringify(message), user.userId)\n })\n }\n }\n } catch (err) {\n return Promise.reject(new BoomError(errorType.LOCAL_ERROR, 'boomCore.sendMessage发生错误'))\n }\n }\n\n /**\n * 更新自定义属性 updateCustomStats\n * @param stats\n * @param {boolean} replace 是否替换原数据\n */\n private async updateCustomStats(stats: PartialCustomStats, replace: boolean = false) {\n await this.boomCore.updateCustomStats(stats, replace).catch(e => {\n return Promise.reject(updateCustomStatsError(`${JSON.stringify(stats)} - ${JSON.stringify(e)}`))\n })\n }\n\n /**\n * 发送聊天公告\n * @param notice\n */\n public async sendChatNotice(notice: string, richNotice: object, showTipNotice: boolean) {\n await this.updateCustomStats({\n chatNotice: notice,\n chatNoticeRich: richNotice,\n showTipNotice: showTipNotice\n }).catch(e => e)\n }\n\n /**\n * 是否允许点赞\n * @param enable 0 不允许 1 允许\n */\n public async giveLikeEnable(enable: 0 | 1) {\n await this.updateCustomStats({ giveLikeEnable: enable }).catch(e => e)\n }\n\n /**\n * 入会自动静音配置 0 关闭 1 开启自动静音 2 超过6个人入会自动静音\n * @param enable\n */\n public async changeAutoMute(enable: 0 | 1 | 2) {\n return this.updateCustomStats({ autoMute: enable })\n }\n\n /**\n * 允许成员接收进入/离开会议通知配置 0 关闭 1 开启自动静音\n * @param enable\n */\n public async allUserReceiveJoinLeaveMessages(enable: 0 | 1) {\n return this.updateCustomStats({ allUserReceiveJoinLeaveMessages: enable })\n }\n /**\n * 成员入会时给主持人播放提示音配置 0 关闭 1 开启自动静音\n * @param enable\n */\n public async userJoinMasterVoice(enable: 0 | 1) {\n return this.updateCustomStats({ userJoinMasterVoice: enable })\n }\n\n /**\n * 观众点赞(走customMessage)\n * @param type 1:点赞, 2:送花, 3:爱心, 4: 鼓掌, 5: 喝彩\n */\n public async userGiveLike(type: 1 | 2 | 3 | 4 | 5) {\n // send talk message\n let sendTime = new Date().getTime()\n let message: any = {\n domain: 'room-control',\n method: 'give-like',\n params: {\n stream: {\n user: this.userVM.localUser.userId,\n avatar: this.userVM.localUser.avatar,\n sendTime: sendTime,\n nickname: this.userVM.localUser.nickName,\n type: type || 1\n },\n // status: '赞',\n },\n }\n let localUser = this.userVM.getLocalUser()\n try {\n await this.boomCore.customMessage(JSON.stringify(message), undefined)\n this.giveLikeList.push({\n userId: this.room?.getLocalParticipant().userId, //用户id\n nickName: this.room?.getLocalParticipant().nickName,\n time: new Date().getTime(),\n type\n })\n this.giveLikeListWatcher.next(this.giveLikeList)\n } catch (err) {\n logger.error(\n err as any,\n constant.LOGGER_TAG_CLIENT,\n localUser?.userId,\n )\n throw new BoomError(\n errorType.CLIENT_BANNED,\n `用户点赞==>sendMessage出错`,\n )\n }\n }\n /**\n * 聊天是否可用\n * @param enable 0 不允许 1 允许 2仅主持人 3嘉宾\n */\n public async chatEnable(enable: 0 | 1 | 2 | 3) {\n await this.updateCustomStats({ chatEnable: enable }).catch(e => e)\n }\n\n /**\n * 入会时是否允许开启麦克风\n * @param enable 0全员 1嘉宾 2仅主持人 3全员禁止\n */\n public async joinAudioEnable(enable: 0 | 1 | 2 | 3) {\n await this.updateCustomStats({ joinAudioEnable: enable }).catch(e => e)\n }\n\n /**\n * 入会时是否允许开启摄像头\n * @param enable 0全员 1嘉宾 2仅主持人 3全员禁止\n */\n public async joinVideoEnable(enable: 0 | 1 | 2 | 3) {\n await this.updateCustomStats({ joinVideoEnable: enable }).catch(e => e)\n }\n\n /**\n * 参会者列表权限\n * @param enable 0全员 1嘉宾 2仅主持人\n */\n public async userListEnable(enable: 0 | 1 | 2) {\n await this.updateCustomStats({ userListEnable: enable }).catch(e => e)\n }\n\n /**\n * 会议中是否允许开麦克风\n * @param enable 0全员 1嘉宾 2仅主持人\n */\n public async audioEnable(enable: 0 | 1 | 2) {\n await this.updateCustomStats({ audioEnable: enable }).catch(e => e)\n }\n\n /**\n * 会议中是否允许开启摄像头\n * @param enable 0全员 1嘉宾 2仅主持人\n */\n public async videoEnable(enable: 0 | 1 | 2) {\n await this.updateCustomStats({ videoEnable: enable }).catch(e => e)\n }\n\n /**\n * 是否允许自行改名\n * @param enable 0全员 1嘉宾\n */\n public async modifyNameEnable(enable: 0 | 1 | 2) {\n await this.updateCustomStats({ modifyNameEnable: enable }).catch(e => e)\n }\n\n /**\n * 是否允许开启虚拟背景\n * @param enable 0全员 1嘉宾 2仅主持人\n */\n public async backgroundAIEnable(enable: 0 | 1 | 2) {\n await this.updateCustomStats({ backgroundAIEnable: enable }).catch(e => e)\n }\n\n /**\n * 强制开启对方视频\n * @param enable true开启 false关闭\n */\n public async forceOpenUserCamera(enable: true | false) {\n await this.updateCustomStats({ forceOpenUserCamera: enable }).catch(e => e)\n }\n\n\n /**\n * 强制开启对方音频\n * @param enable true开启 false关闭\n */\n public async forceOpenUserMic(enable: true | false) {\n await this.updateCustomStats({ forceOpenUserMic: enable }).catch(e => e)\n }\n\n /**\n * 入会提示音设置\n * @param enable 0关闭 1开启\n */\n public async joinCueVoice(enable: 0 | 1) {\n await this.updateCustomStats({ joinCueVoice: enable }).catch(e => e)\n }\n\n /**\n * 是否全员可录制\n * @param enable 0全员 1嘉宾 2仅主持人\n */\n public async recordEnable(enable: 0 | 1 | 2) {\n await this.updateCustomStats({ recordEnable: enable }).catch(e => e)\n }\n /**\n * 是否全员可录制\n * @param enable 0禁止全员举手 1嘉宾可举手 2全员可举手\n */\n public async raiseHandEnable(enable: 0 | 1 | 2) {\n await this.updateCustomStats({ raiseHandEnable: enable }).catch(e => e)\n }\n\n /**\n * 入会麦克风禁用\n * @param enable 0全员禁止使用 1嘉宾和学员不可使用 2不开启\n */\n public async joinMicrophoneDisable(enable: 0 | 1 | 2) {\n await this.updateCustomStats({ joinMicrophoneDisable: enable }).catch(e => e)\n }\n\n /**\n * 入会摄像头禁用\n * @param enable 0全员禁止使用 1嘉宾和学员不可使用 2不开启\n */\n public async joinCameraDisable(enable: 0 | 1 | 2) {\n await this.updateCustomStats({ joinCameraDisable: enable }).catch(e => e)\n }\n\n /**\n * 上传文档权限\n * @param permission 0 仅支持人 1 嘉宾 2 全员\n */\n public async changeFileUpdateModelPermission(permission: FilePermission) {\n await this.updateCustomStats({ fileUpdateModel: permission }).catch(e => e)\n }\n\n public async changeFileUpdateLookPermission(permission: FilePermission) {\n await this.updateCustomStats({ fileUpdateLook: permission }).catch(e => e)\n }\n\n public async changeFileUpdateDownPermission(permission: FilePermission) {\n await this.updateCustomStats({ fileUpdateDown: permission }).catch(e => e)\n }\n\n public async changeFileUpdateEditPermission(permission: FilePermission) {\n await this.updateCustomStats({ fileUpdateEdit: permission }).catch(e => e)\n }\n\n /**\n * 共享屏幕权限\n * @param permission 0全员可共享 1允许嘉宾共享 2仅主持人可共享\n */\n public async changeScreenShareModelPermission(permission: 0 | 1 | 2) {\n await this.updateCustomStats({ screenShareModel: permission }).catch(e => e)\n }\n /**\n * 是否仅一人共享权限\n * @param permission 1: 是 2: 否\n */\n public async changeOnlyOnePersonSharePermission(permission: 0 | 1) {\n await this.updateCustomStats({ onlyOnePersonShare: permission }).catch(e => e)\n }\n\n /**\n * 设为焦点主屏\n * @param {string} userid 设为焦点主屏的userId\n */\n public async setForceOnUser(userid: string) {\n await this.updateCustomStats({ forceOn: { user: userid } }).catch(e => e)\n }\n\n /**\n * 主持人上报布局状态\n * @param layoutData\n * @param replace\n */\n async updateHostLayout(layoutData: HostLayout, replace: boolean = false) {\n if (!this.userVM.checkLocalHasMaster()) {\n logger.info('您不是主持人,没有该上报权限', constant.LOGGER_TAG_CLIENT)\n } else {\n return this.updateCustomStats({ from: { fromTag: 'masterId' }, hostLayout: layoutData }, replace)\n }\n\n\n }\n\n async checkDevices(userId: string): Promise<void> {\n const message = {\n domain: 'user-control',\n method: 'check-devices',\n params: {\n fromUserId: this.boomCore.getLocalParticipant().getID(),\n },\n }\n this.sendMessageWithMaster(message, userId).catch(err => {\n return Promise.reject(BmCheckDeviceError(`检测对方设备send-message发生错误: ${err}`))\n })\n }\n\n async resp2CheckDevices(deviceList: DeviceList, userId: string): Promise<void> {\n const message = {\n domain: 'user-control',\n method: 'resp-to-check-devices',\n params: {\n ...deviceList,\n fromUserId: this.boomCore.getLocalParticipant().getID(),\n }\n }\n if (!userId) {\n return Promise.reject(BmCheckDeviceError(`响应设备检测: uid: ${userId} 未找到用户`))\n }\n\n try {\n await this.boomCore.customMessage(JSON.stringify(message), userId)\n } catch (err) {\n return Promise.reject(BmCheckDeviceError(`响应响应设备检测send-message发生错误 ${err}`))\n }\n }\n\n /**\n * 调节对方的视频分辨率\n * @param {SupportVideoProfile} videoInfo 调节对方视频信息\n * @param {string} userId\n */\n async changeRemoteVideoProfile(videoInfo: { profile: SupportVideoProfile, videoDevice: SampleDeviceInfo }, userId: string): Promise<any> {\n const message = {\n domain: 'user-control',\n method: 'change-video-profile',\n params: {\n ...videoInfo,\n fromUserId: this.boomCore.getLocalParticipant().getID(),\n }\n }\n\n this.sendMessageWithMaster(message, userId).catch(err => {\n return Promise.reject(BmChangeVideoProfileError(`调节对方的视频分辨率send-message发生错误: ${err}`))\n })\n }\n\n /**\n * 设置完本地的视频分辨率之后,给对方响应\n * @param {boolean} status 设置是否成功\n * @param {string} userId\n */\n async resp2ChangeRemoteVideoProfile(status: boolean, userId: string, profile: string): Promise<any> {\n const message = {\n domain: 'user-control',\n method: 'resp-to-change-video-profile',\n params: {\n status,\n profile,\n fromUserId: this.boomCore.getLocalParticipant().getID(),\n }\n }\n if (!userId) {\n return Promise.reject(BmChangeVideoProfileError(`响应调节视频分辨率: uid: ${userId} 未找到用户`))\n }\n\n try {\n await this.boomCore.customMessage(JSON.stringify(message), userId)\n } catch (err) {\n return Promise.reject(BmChangeVideoProfileError(`响应调节视频分辨率send-message发生错误 ${err}`))\n }\n }\n\n /**\n * 调节远端的音频参数\n * @param {Object} profileInfo\n * @param uid\n */\n async changeRemoteAudioProfile(profileInfo: AudioProfileInfo, uid: string): Promise<any> {\n const message = {\n domain: 'user-control',\n method: 'change-audio-profile',\n params: {\n microphoneDevice: profileInfo.microphoneDevice,\n speakerDevice: profileInfo.speakerDevice,\n echoCancellation: profileInfo.echoCancellation,\n noiseSuppression: profileInfo.noiseSuppression,\n autoGainControl: profileInfo.autoGainControl,\n speakerVolume: profileInfo.speakerVolume,\n microVolume: profileInfo.microVolume,\n fromUserId: this.boomCore.getLocalParticipant().getID(),\n },\n }\n this.sendMessageWithMaster(message, uid).catch(err => {\n return Promise.reject(BmChangeAudioProfileError(`调节音频send-message发生错误 ${JSON.stringify(err)}`))\n })\n }\n\n /**\n * 响应调节远端音频的结果\n * @param status\n * @param uid\n */\n async resp2ChangeRemoteAudioProfile(status: boolean, uid: string): Promise<any> {\n const message = {\n domain: 'user-control',\n method: 'resp-to-change-audio-profile',\n params: {\n status,\n fromUserId: this.boomCore.getLocalParticipant().getID(),\n },\n }\n\n if (!uid) {\n return Promise.reject(BmChangeAudioProfileError(`响应调节音频: uid: ${uid} 未找到用户`))\n }\n\n try {\n await this.boomCore.customMessage(JSON.stringify(message), uid)\n } catch (err) {\n return Promise.reject(BmChangeAudioProfileError(`响应调节音频send-message发生错误 ${err}`))\n }\n }\n}\n","import BCClient from '@hysc/core'\nimport BoomError from '../error/RTCError'\nimport * as errorType from '../error/errorType'\nimport * as logger from '../logger/logger'\nimport * as constant from '../util/constant'\nimport BMMessageInfo from './BMMessageInfo'\nimport { BehaviorSubject, Subject } from \"rxjs\";\nimport { notGetTalkInterval } from '../util/util'\nimport BMUserVM from '../BMUser/BMUserVM'\nimport BMRoom from '../BMRoom/BMRoom'\nimport { debounce } from \"lodash-es\";\n// 聊天室\nexport default class BMChatVM {\n public messageList: Array<BMMessageInfo> = []\n public boomCore: BCClient\n public userVM: BMUserVM\n public bmRoom: BMRoom\n public messageListWatcher: BehaviorSubject<Array<BMMessageInfo>> //消息监听器\n public hasDangerMessageWatcher = new Subject<boolean>()\n\n constructor(boomCore: BCClient, userVM: BMUserVM, bmRoom: BMRoom) {\n this.boomCore = boomCore;\n this.userVM = userVM;\n this.bmRoom = bmRoom\n this.messageListWatcher = new BehaviorSubject(this.messageList) //权限监听\n }\n /**\n * 发送聊天消息\n * @param talkMsg 聊天信息\n */\n public async sendMessage(talkMsg: string, userId: string | undefined, lostNet: boolean) {\n let _talkMsg = talkMsg.replace(/(^\\s*)|(\\s*$)/g, '')\n // send talk message\n let sendTime = new Date().getTime()\n let message: any = {\n domain: 'room-control',\n method: 'send-talk',\n params: {\n stream: {\n user: this.userVM.localUser.userId,\n avatar: this.userVM.localUser.avatar,\n sendTime: sendTime,\n nickname: this.userVM.localUser.nickName,\n },\n status: _talkMsg,\n },\n }\n let localUser = this.userVM.getLocalUser()\n try {\n let isDanger = false\n let seq: number | undefined\n let failed = lostNet\n if (!failed) {\n await this.boomCore.sendMessage(JSON.stringify(message), userId)\n .then(r => {\n seq = r.seq\n })\n .catch(e => {\n logger.warn('sendmessage 出错', '', localUser?.userId, [e])\n if (e && e.code === 39) {\n isDanger = true\n this.hasDangerMessageWatcher.next(true)\n }\n })\n }\n\n const messageInfo = new BMMessageInfo({\n userId: localUser?.userId,\n message: _talkMsg,\n isLocal: localUser?.isLocal,\n avatar: localUser?.avatar,\n nickName: localUser?.nickName,\n sendTime: sendTime,\n to: userId,\n isDanger,\n seq,\n failed\n })\n this.addMessage(messageInfo, false)\n if (failed) {\n return Promise.reject(messageInfo)\n } else {\n return Promise.resolve()\n }\n } catch (err) {\n logger.error(\n err as any,\n constant.LOGGER_TAG_CLIENT,\n localUser?.userId,\n )\n throw new BoomError(\n errorType.CLIENT_BANNED,\n `发送聊天消息==>sendMessage出错`,\n )\n }\n }\n\n public addMessage(info: BMMessageInfo, isParticipantNotice: boolean) {\n //let bmMessageInfo = new BMMessageInfo(info)\n // console.log('addMessage=====>', info)\n if (isParticipantNotice && !this.bmRoom.participantNotice) {\n return\n }\n if (\n this.messageList.length == 0 ||\n info.timeStamp -\n this.messageList[this.messageList.length - 1].timeStamp >=\n notGetTalkInterval\n ) {\n // 如果没有消息或者消息间隔大于5分钟就会出现时间提示\n const message = new BMMessageInfo({\n isMeetingNotice: true,\n message: '',\n })\n this.messageList.push(message)\n }\n\n this.messageList.push(info)\n this.notificationMessageList()\n //return bmMessageInfo\n }\n\n notificationMessageList = debounce(() => {\n this.messageListWatcher.next(this.messageList)\n }, 500)\n\n public updateMessageListWatcher(messageList: Array<BMMessageInfo>) {\n this.messageList = messageList\n this.messageListWatcher.next(this.messageList)\n }\n\n /**\n * 获取历史消息\n */\n public async getHistoryMessage() {\n const respMsgs = await this.boomCore.getMessages(0, this.boomCore.getMsgSeq())\n let userInfoArr: BMMessageInfo[] = []\n respMsgs.items.forEach((msgData: any) => {\n if (msgData.private || msgData.to) {\n return false\n }\n if (msgData.msg.length == 0 || msgData.msg.indexOf('{') == -1) {\n return false\n }\n const msgObj = JSON.parse(msgData.msg)\n if (msgObj.method != 'send-talk') {\n return false\n }\n const seq = msgData.seq\n let content = msgObj.params\n let userId = content.stream.user ? content.stream.user : msgData.userId\n let userInfo = {\n nickName: content.stream.nickname,\n content: content.status,\n timeStamp: new Date().getTime(),\n userId\n }\n const message = new BMMessageInfo({\n userId: userId,\n message: content.status,\n nickName: content.stream.nickname,\n isLocal: userId == this.userVM.localUser.userId,\n avatar: content.stream.avatar,\n sendTime: content.stream.sendTime,\n seq\n })\n userInfoArr.push(message)\n })\n return Promise.resolve(userInfoArr)\n // 插入到头部\n //this.messageList.splice(0, 0, ...userInfoArr)\n //this.messageListWatcher.next(this.messageList)\n }\n}\n","import { SingleRemoteStream, SingleStream } from \"../type\"\nimport { SubscribeOptions } from \"@hysc/brtc\"\nimport BMUser from \"../BMUser/BMUser\"\nimport {\n ADD_AUDIO_PLAY,\n ADD_PULL_USER,\n BIND_BIG_ELEMENT,\n BIND_ELEMENT,\n HANDLE_STREAM_CONNECT_ERROR,\n MANUAL_SUBSCRIPTION,\n MODEL_SORT_NUM_CHANGE,\n NO_CONTAINER,\n RECEIVE_SUBSCRIBE_MESSAGE, SET_VOLUME,\n STREAM_SUFFIX_SCREEN,\n STREAM_TYPE,\n UNSUBSCRIBE_STREAM,\n} from \"../constants\"\nimport { BehaviorSubject, Subject } from \"rxjs\"\nimport BoomEmitter from \"../util/emitter\"\nimport { Player } from \"@hysc/core\"\nimport * as logger from \"../logger/logger\"\nimport BMStreamModelVM from \"./BMStreamModelVM\"\nimport BMSpeaker from \"./BMSpeaker\"\nimport { debounce } from \"lodash-es\";\nimport { getGuestSort, getLocalSort, getManagerSort, getMasterSort } from \"./sortStream\"\nimport { BloudStreamState } from \"../handleEvent/attachEvents\"\nimport type { StreamCustomInfo } from '@hysc/bloud/src/core/Room'\n\n/**\n * @name: BMStreamModel\n * @author: yangliye\n * @date: 2022-04-25 11:14\n * @description:BMStreamModel\n * @update: 2022-04-25 11:14\n */\n\ntype StreamType = 'big' | 'small'\n\nexport interface SubscribeMessage {\n stream: BMStreamModel\n}\n\nexport interface ConnectErrorMessage {\n stream: BMStreamModel,\n isLocal: boolean\n}\n\nexport interface NoPlayerContainer {\n type: 'share' | 'normal',\n container: 'small' | 'big',\n id: string\n}\n\n/**\n * 播放器状态\n */\nenum PlayerState {\n NO_CONTAINER,\n NO_PLAYING,\n PLAYING,\n}\n\nconst namespace = `.streammodel${Math.random()}`\n\nexport default class BMStreamModel {\n private user: BMUser\n private _stream: SingleStream | undefined\n public bloudStream: BloudStreamState | undefined\n\n /**\n * 流类型\n */\n public streamType: number = STREAM_TYPE.OTHER\n\n public pullFailedNum = 0\n\n\n public _video_enable = false\n public _audio_enable = false\n\n public videoEnableWatcher = new BehaviorSubject(this._video_enable)\n public audioEnableWatcher = new BehaviorSubject(this._audio_enable)\n // 流有没有更新\n public streamUpdateWatcher = new Subject<boolean>()\n\n public isSubScribedWatcher = new Subject<boolean>()\n\n public playStateChangeWatcher = new Subject<BMStreamModel>()\n /**\n * 找不到播放器,说明当前的streamModel可能是销毁重建的,或者是业务上绑定失败的,这个时候给端上一个提示,让他重新绑定一下播放器\n */\n public noContainerWatcher = new Subject<boolean>()\n\n public noBigContainerWatcher = new Subject<boolean>()\n\n // 音量\n public audioLevelWatcher = new Subject<number>()\n\n public isCurrentDisplay = false\n /**\n * 当前窗口是不是在展示中目标状态\n */\n public isDisplay = false\n public isDisplayObserve = new Subject<boolean>()\n\n //当前是否在大窗\n public isInBig = false\n public isInBigObserve = new Subject<boolean>()\n\n //记录是否拉取了音视频流\n public _hasPulled = false\n playerId: string = ''\n\n\n /**\n * 手动拉流配置, 默认是false, 如果是走手动拉流,设置成true,说明拉他的流\n * shouldPull 是否应该拉\n */\n shouldPull = false\n\n get hasPulled() {\n return this._hasPulled\n }\n\n set hasPulled(value) {\n this._hasPulled = value\n }\n\n /**\n * 当前拉取的是大流还是小流\n */\n public _pulledStreamType: StreamType = 'small'\n\n get pulledStreamType() {\n return this._pulledStreamType\n }\n\n set pulledStreamType(type) {\n this._pulledStreamType = type\n }\n\n /**\n * 要拉取的流的目标状态\n */\n public pulledStreamGoal: StreamType = 'small'\n\n bigPlayerId: string = ''\n player: Player | undefined | null\n isPlayingBig: boolean = false\n\n /**\n * 是否静音了扬声器,brtc不会处理业务上静音的逻辑,所以需要自己处理\n * 如果静音了,就把所有的流都重新静音播放一遍\n */\n public muted = false\n private checkVideoTimer: NodeJS.Timeout | null = null\n public checkCount = 0\n private checkFailedCount = 0\n\n /**\n * streamModel的唯一标识,用来给业务绑定播放容器\n */\n public get uuid() {\n if (this.isShare) {\n return `${this.userId}_share`\n }\n else {\n return this.userId\n }\n }\n\n public get isAudience() {\n return this.user.isAudience\n }\n\n /**\n * 因为直播模式中,观众默认是不展示的,只有开麦以后才会展示\n * 所以这个地方要判断一下\n */\n public get canShow() {\n if (this.isAudience) {\n return this.audioEnable || this.videoEnable;\n } else {\n return true\n }\n }\n\n public changeMute(mute: boolean) {\n if (this.muted !== mute) {\n this.muted = mute\n this.handleSpeakerChange()\n }\n }\n\n public handleSpeakerChange() {\n if (!this.isLocal) {\n if (this.muted) {\n (this.stream as SingleRemoteStream)?.setAudioVolume(0)\n } else {\n (this.stream as SingleRemoteStream)?.setAudioVolume(1)\n }\n }\n }\n\n /**\n * 排序数字\n * 窗口的排序使用二进制运算进行了优化,为了提高运行速度牺牲了一部分代码可读性\n */\n public sortNum = -1\n\n public get isToupingma() {\n return this.user.isToupingma\n }\n\n public get isMixer() {\n return this.user.isMixer\n }\n\n get isSignal() {\n return this.user.isSignal\n }\n\n /**\n * 初始化展示的model\n * @param user\n * @param stream\n */\n constructor(user: BMUser, stream?: SingleStream) {\n this.user = user\n this.updateUser(user)\n this._stream = stream\n // 存储的用户身份的映射列表,用来优化排序处理逻辑\n this.isDisplayObserve.subscribe(display => {\n this.handleDisplayChange(display)\n })\n this.isInBigObserve.subscribe(display => {\n this.handleIsInBig(display)\n })\n this.updateSortNum(false)\n }\n\n /**\n * 生成订阅信息\n */\n public genReceiveSubMsg() {\n let subscribeOptions: SubscribeOptions | null = null\n if (this.isDisplay) {\n subscribeOptions = {\n audio: true,\n video: true,\n streamType: 'small',\n }\n } else {\n subscribeOptions = {\n audio: true,\n video: false,\n streamType: 'small',\n }\n }\n return subscribeOptions\n }\n\n /**\n * display属性改变调整\n * @private\n */\n private handleDisplayChange = (display: boolean) => {\n if (this.isDisplay === display) {\n return\n }\n this.isDisplay = display\n this.stream?.stop()\n if (!this.isDisplay) {\n this.checkVideoTimer && clearTimeout(this.checkVideoTimer)\n this.checkVideoTimer = null\n this.checkCount = 0\n // this.isInBig = false\n this.pulledStreamType = 'small'\n }\n this.sendMessage2Room()\n }\n\n /**\n * 处理当前窗口是不是在大窗的逻辑\n * @param display\n * @private\n */\n private handleIsInBig(display: boolean) {\n if (this.isInBig === display) {\n return\n }\n this.isInBig = display\n logger.info('isInBig change', '', this.userId, ['streamId =>', this.streamId, 'isInBig => ', display])\n if (this.isInBig) {\n this.pulledStreamGoal = 'big'\n } else {\n this.pulledStreamGoal = 'small'\n }\n\n this.sendMessage2Room()\n\n if (this.isShare) {\n if (!this.isInBig) {\n this.checkVideoTimer && clearTimeout(this.checkVideoTimer)\n this.checkVideoTimer = null\n this.checkCount = 0\n }\n }\n }\n\n /**\n * 设置是否打开摄像头状态\n * @param enable\n * @private\n */\n public setVideoEnable(enable: boolean) {\n if (this._video_enable !== enable) {\n this._video_enable = enable\n this.videoEnableWatcher.next(enable)\n }\n }\n\n /**\n * 设置是否打开麦克风状态\n * @param enable\n * @private\n */\n public setAudioEnable(enable: boolean) {\n if (this._audio_enable !== enable) {\n this._audio_enable = enable\n this.audioEnableWatcher.next(enable)\n }\n }\n\n /**\n * 更新当前streamModel中的流\n * @param stream\n * @param needReProcess\n * @param bmStreamVm\n */\n updateStream(stream: SingleStream | undefined, needReProcess: boolean = true, bmStreamVm: BMStreamModelVM) {\n if (this._stream) {\n this._stream.off(namespace)\n }\n this._stream = stream\n if (stream) {\n // this.streamType = stream.type\n const hasVideo = stream.getVideoOn()\n const hasAudio = stream.getAudioOn()\n logger.info('更新用户的流', 'updateStream', stream?.getUserId(), ['nickname =>', this.nickname, 'audioOn', hasAudio, 'videoOn', hasVideo, 'streamId', stream.getStreamId()])\n if (hasAudio) {\n // 添加语音激励相关处理\n if (!this.isShare) {\n bmStreamVm.addToDetector(new BMSpeaker(this.user, stream))\n }\n // 添加对音量的控制\n this.collectAudioLevel()\n }\n\n stream.on('player-state-changed'+namespace, this.onPlayerStateChange)\n stream.on('connect-error'+namespace, this.handleStreamConnectError)\n stream.on('stream-connection-error'+namespace, this.handleStreamConnectError)\n\n // 添加拉流的处理逻辑\n if (needReProcess) {\n this.sendMessage2Room()\n }\n } else {\n this.hasPulled = false\n this.pulledStreamType = 'small'\n this.streamType = STREAM_TYPE.OTHER\n }\n }\n\n /**\n * 更新bloud的stream,设置流状态\n * @param streamState\n * @param bmStreamVM\n * @param forceSearch\n */\n updateBloudStream(streamState: BloudStreamState | undefined, bmStreamVM: BMStreamModelVM, forceSearch = false) {\n let videoChanged = false\n let audioChanged = false\n if (streamState) {\n this.bloudStream = { audio: streamState.audio, video: streamState.video, isScreen: streamState.isScreen }\n\n if (streamState.customInfo) {\n if (!this.bloudStream.customInfo || this.bloudStream.customInfo?.volume !== streamState.customInfo.volume) {\n if (!Number.isNaN(streamState.customInfo.volume)) {\n this.setRemoteAudioLevel(streamState.customInfo.volume)\n }\n }\n this.bloudStream.customInfo = streamState.customInfo\n }\n\n if (this.stream) {\n if (this.bloudStream.audio) {\n if (!this.isShare) {\n bmStreamVM.addToDetector(new BMSpeaker(this.user, this.stream))\n this.collectAudioLevel()\n }\n }else {\n bmStreamVM.removeFromDetector(this.stream.getStreamId())\n }\n }\n\n if (this.bloudStream.video !== this._video_enable) {\n videoChanged = true\n }\n\n if (this.bloudStream.audio != this._audio_enable) {\n audioChanged = true\n }\n\n this.setVideoEnable(this.bloudStream.video)\n this.setAudioEnable(this.bloudStream.audio)\n\n // 收到bloud重推流的信令,需要将brtc的流销毁,然后重新去query\n if (forceSearch) {\n try {\n this.stream?.destroy()\n }catch (e) {\n\n }\n if (this.stream) {\n bmStreamVM.room!.audioPlayer?.removeStream(this.stream)\n }\n this.updateStream(undefined, false, bmStreamVM)\n this._stream = undefined\n }\n\n if (audioChanged && !this.audioEnable && this.stream) {\n bmStreamVM.room!.audioPlayer?.removeStream(this.stream)\n }\n\n // 添加是否查询这股流的逻辑判断\n if (this.bloudStream.audio || (this.bloudStream && this.isDisplay)) {\n if (!this.stream || forceSearch) {\n BoomEmitter.emitter!.emit(ADD_PULL_USER, {id: this.userId, isWeb: this.isWeb, isScreen: this.isShare})\n }else {\n if (!this.isLocal) {\n if (!this.hasPulled || !(this.stream as SingleRemoteStream).isSubscribed()) {\n this.sendMessage2Room()\n }\n }\n if (videoChanged) {\n this.sendMessage2Room()\n }\n\n if (!this.isLocal && audioChanged && this.audioEnable && (this.stream as SingleRemoteStream).isSubscribed()) {\n BoomEmitter.getInstance().emit(ADD_AUDIO_PLAY, {stream: this})\n }\n }\n }\n }else {\n this.bloudStream = undefined\n this.setVideoEnable(false)\n this.setAudioEnable(false)\n if (this.stream) {\n bmStreamVM.removeFromDetector(this.stream.getStreamId())\n }\n }\n this.updateSortNum(true)\n this.streamUpdateWatcher.next(true)\n }\n\n public updateBloudCustomInfo(customInfo: StreamCustomInfo) {\n if (this.bloudStream) {\n if (!this.bloudStream.customInfo || this.bloudStream.customInfo?.volume !== customInfo.volume) {\n if (!Number.isNaN(customInfo.volume)) {\n this.setRemoteAudioLevel(customInfo.volume)\n }\n }\n this.bloudStream.customInfo = customInfo\n\n }else {\n logger.error('updateBloudCustomInfo, but bloudStream is undefined', '', '', ['userId =>', this.userId])\n }\n }\n\n private onPlayerStateChange = (state: any) => {\n if (state.type === 'error' && state.reason && state.reason.name === 'NotAllowedError') {\n logger.info('播放失败, 需要调用 resume 方法')\n // this.stream?.resume()\n this.playStateChangeWatcher.next(this)\n }\n if (state.state === 'PAUSED' || state.reason === 'pause') {\n // logger.info('播放器状态发生变化, paused', '播放状态', this.userId, [state])\n if (this.player) {\n this.player?.resume()\n }\n this.stream?.resume()\n }\n }\n\n public handleStreamConnectError = () => {\n logger.info('流出现的connect-error userId', '', this.userId, ['streamId ==>', this.streamId, 'nickname =>', this.nickname, 'isLocal => ', this.isLocal])\n if (this.isLocal) {\n BoomEmitter.emitter!.emit(HANDLE_STREAM_CONNECT_ERROR, { stream: this, isLocal: true })\n } else {\n BoomEmitter.emitter!.emit(HANDLE_STREAM_CONNECT_ERROR, { stream: this, isLocal: false })\n }\n }\n\n /**\n * 获取当前的streamId\n */\n public get streamId() {\n if (this._stream) {\n return this._stream.getStreamId()\n } else {\n return this.userId\n }\n }\n\n public get bStreamId() {\n if (this.isShare) {\n return `${this.userId}_screen`\n }else {\n return this.userId\n }\n }\n\n /**\n * 获取当前窗口绑定的用户id\n */\n public get userId() {\n return this.user.userId\n }\n\n /**\n * 获取当前的流对象\n */\n public get stream() {\n return this._stream\n }\n\n /**\n * 是否是本地流\n */\n public get isLocal() {\n return this.user.isLocal\n }\n\n /**\n * 是否是屏幕共享的流\n */\n public get isShare() {\n if (this.stream) {\n if (this.user.isWeb) {\n return this.stream?.getUserId().toString()?.endsWith(STREAM_SUFFIX_SCREEN)\n } else {\n return !!(\n this.stream &&\n (this.stream as SingleRemoteStream).getType &&\n (this.stream as SingleRemoteStream).getType() === 'assist'\n )\n }\n }else {\n return !!this.bloudStream?.isScreen\n }\n }\n\n get isWeb() {\n return this.user.isWeb\n }\n\n /**\n * 当前音频是否开启\n */\n public get audioEnable() {\n return this._audio_enable\n }\n\n /**\n * 当前视频是否开启\n */\n public get videoEnable() {\n return this._video_enable\n }\n\n private get brtcPlayerId() {\n return `player_${this.stream!.getStreamId()}`\n }\n\n private get selfPlayerId() {\n return `player_${this.stream!.getStreamId()}_big_container`\n }\n\n /**\n * 获取当前流绑定的用户昵称\n */\n public get nickname() {\n if (this.user.isToupingma) {\n return `${this.user.nickName}(的投屏)`\n } else if (this.streamId?.includes(STREAM_SUFFIX_SCREEN)) {\n return `${this.user.nickName}(的屏幕共享)`\n }\n return this.user.nickName\n }\n\n /**\n * 获取流的麦克风音量\n */\n public get audioLevel() {\n return this._stream?.getAudioLevel() || 0\n }\n\n public getUser() {\n return this.user\n }\n /**\n * 设置远端流的播放声音\n * @param volume\n */\n public setRemoteAudioLevel(volume: number) {\n if (this.isLocal) {\n throw new Error('不能设置本地流的音量')\n }\n BoomEmitter.emitter!.emit(SET_VOLUME, {streamId: this.streamId, volume})\n }\n\n /**\n * 获取流的传输信息\n */\n public getStats() {\n return this._stream?.getStats()\n }\n\n /**\n * BIND_ELEMENT 事件\n * @param eleId\n */\n public bindElement = (eleId: string) => {\n this.playerId = eleId\n this.emitBindElement()\n }\n\n public bindBigElement = (eleId: string) => {\n this.bigPlayerId = eleId\n this.emitBindBigElement()\n }\n\n public sendMessage2Room = debounce(() => {\n BoomEmitter.emitter!.emit(RECEIVE_SUBSCRIBE_MESSAGE, { stream: this })\n }, 300)\n\n public emitBindElement = debounce(() => {\n BoomEmitter.emitter!.emit(BIND_ELEMENT, { stream: this })\n }, 50)\n\n public emitBindBigElement = debounce(() => {\n BoomEmitter.emitter!.emit(BIND_BIG_ELEMENT, { stream: this })\n }, 50)\n\n\n /**\n * 当前是不是正在播放\n * @param containerId sdk绑定播放器容器id\n * @param playerContainerId 播放器创建的容器id\n */\n currentIsPlaying = (containerId: string): PlayerState => {\n // this.playerId\n const container = document.getElementById(containerId)\n if (!container) {\n return PlayerState.NO_CONTAINER\n }\n let canGetPlayer: boolean\n let playerNum: number\n let failedPlayerNum = 0\n\n const players = Array.from(container.children)\n canGetPlayer = players.length > 0\n playerNum = players.length\n players.forEach(player => {\n if (player.children.length === 0) {\n failedPlayerNum += 1;\n (player as HTMLElement).style.display = 'none'\n container.removeChild(player)\n }\n })\n if (canGetPlayer && playerNum > failedPlayerNum) {\n return PlayerState.PLAYING\n }\n return PlayerState.NO_PLAYING\n }\n\n /**\n * 播放当前流\n */\n public play = async () => {\n const stream = this.stream\n if (stream) {\n if (this.isDisplay && this.videoEnable) {\n const playerState =this.currentIsPlaying(this.playerId)\n\n if (playerState === PlayerState.NO_CONTAINER) {\n logger.warn('找不到播放器容器', 'stream play', this.userId, ['流 id =>', this.streamId, 'nickname =>', this.nickname, 'playerId =>', this.playerId])\n if (!this.playerId) {\n BoomEmitter.emitter!.emit(NO_CONTAINER, { type: this.isShare ? 'share' : 'normal', id: this.userId, container: 'small' })\n }\n }\n else if (playerState === PlayerState.NO_PLAYING) {\n try {\n await stream.play(this.playerId, { backgroundColor: '#202020', fit: 'contain', audio: false })\n logger.info('远端流播放结束', this.userId, this.streamId, [this.nickname])\n this.checkSmallVideo()\n } catch (e) {\n stream.stop()\n setTimeout(() => {\n logger.error('播放小流失败, 尝试重新播放', '播放', this.userId, [this.streamId, this.stream, 'error => ', JSON.stringify(e)])\n this.play()\n }, 2 * 1000)\n }\n }\n } else {\n try {\n this.stream?.stop()\n }catch (e) {\n }\n }\n }\n }\n\n /**\n * 在大窗口播放该流的时候调用这个方法\n */\n public playInBig = async () => {\n const stream = this.stream\n if (stream) {\n const playState = this.currentIsPlaying(this.bigPlayerId)\n // 大流的播放逻辑\n if (this.isInBig && this.videoEnable && this.bigPlayerId) {\n if (playState === PlayerState.NO_CONTAINER) {\n logger.warn('找不到 bigPlayerId', '大流播放', this.userId, ['流 id =>', this.streamId])\n if (!this.bigPlayerId) {\n BoomEmitter.emitter!.emit(NO_CONTAINER, { type: this.isShare ? 'share' : 'normal', id: this.userId, container: 'big' })\n }\n }\n else if (playState === PlayerState.NO_PLAYING) {\n this.player?.destroy()\n this.player = null\n this.initBigPlayer()\n if (this.player) {\n await (this.player as Player).play(stream)\n this.isPlayingBig = true\n this.checkBigVideo()\n }\n logger.info('远端流大流播放结束', this.userId, this.streamId, [this.nickname])\n }\n } else {\n this.player?.destroy()\n this.player = null\n this.isPlayingBig = false\n }\n }\n }\n\n private initBigPlayer() {\n try {\n if (this.bigPlayerId) {\n const videoId = document.querySelector<HTMLDivElement>(\n `#${this.bigPlayerId}`,\n )!\n\n if (!videoId) {\n console.error('播放大流失败,找不到大流容器', this.userId, this.streamId, this.bigPlayerId)\n }\n\n if (!this.player && videoId) {\n this.player = new Player(videoId, { fit: 'contain' })\n this.player.on('player-state-changed', (data: any) => {\n if (this.stream) {\n logger.info('big player state change', '', '', [JSON.stringify(data)])\n if (data.type === 'error' && data.reason && data.reason.name === 'NotAllowedError') {\n this.playStateChangeWatcher.next(this)\n }\n if (data.state === 'PAUSED') {\n this.player?.resume()\n }\n }\n })\n }\n }\n } catch (error: any) {\n logger.error('初始化大窗口的播放器失败', this.userId, this.streamId, error.message)\n }\n }\n\n /**\n * 停止播放当前流\n */\n public stop() {\n this._stream?.stop()\n }\n\n /**\n * 销毁当前流\n */\n public destroy() {\n this._stream?.destroy()\n }\n\n /**\n * 获取当前流是否正在播放\n */\n public isPlaying() {\n return this._stream?.isPlaying()\n }\n\n /**\n * 重新播放\n */\n public replay() {\n return this._stream?.replay()\n }\n\n /**\n * 恢复播放音视频\n * 在某些版本浏览器上移动传入 play() 的 div 容器可能会导致音视频播放器进入 ‘PAUSED’ 状态,此时 需要调用该接口恢复播放。\n * 由于浏览器自动播放策略的限制,在 play() 返回 PLAY_NOT_ALLOWED 错误后需要引导用户通过手势 调用该接口恢复播放\n *\n * @returns\n */\n public resume() {\n this._stream?.resume()\n this.player?.resume()\n }\n\n /**\n * 是否有音频流\n */\n public hasAudio() {\n return this._stream?.hasAudio() || false\n }\n\n /**\n * 是否有视频流\n */\n public hasVideo() {\n return this._stream?.hasVideo() || false\n }\n\n /**\n * 更新当前model的用户信息\n * @param user\n */\n public updateUser(user: BMUser) {\n this.user = user\n const pos = this.user.userInfo.pos\n if (!pos) {\n this.streamType = STREAM_TYPE.SINGLE\n return\n }\n if (pos.includes('web') || pos.includes('pc')) {\n this.streamType = STREAM_TYPE.SUB_MAIN\n } else if (pos.includes('_toupingma')) {\n this.streamType = STREAM_TYPE.SHARE\n } else {\n this.streamType = STREAM_TYPE.SINGLE\n }\n }\n\n\n public updateSortNum(force: boolean = true) {\n const sortNum = this.getSortNum()\n this.setSortNum(sortNum, force)\n }\n\n setSortNum(sortNum: number, force: boolean) {\n if (this.sortNum === sortNum) {\n return\n }else {\n this.sortNum = sortNum\n }\n if (force) {\n BoomEmitter.emitter!.emit(MODEL_SORT_NUM_CHANGE, null)\n // 音视频状态发生变化,用户排序也要发生变化, 这个东西要调整的地方是,如果是普通参会者,大房间,超过1000人,应该走delay的逻辑\n this.user.updateSortNum(true)\n }\n }\n\n\n getSortNum() {\n if (this.user.isMaster) {\n return getMasterSort(this.audioEnable, this.videoEnable)\n }\n else if (this.user.isLocal) {\n return getLocalSort(this.audioEnable, this.videoEnable)\n }\n else if (this.user.isManager) {\n return getManagerSort(this.audioEnable, this.videoEnable);\n }\n else {\n return getGuestSort(this.audioEnable, this.videoEnable);\n }\n }\n\n\n /**\n * 启动音频音量检测\n */\n collectAudioLevel = () => {\n if (this.stream) {\n this.stream.off('audio-level' + namespace, this.handleAudioLevel)\n this.stream.on('audio-level' + namespace, this.handleAudioLevel)\n }else {\n logger.warn('collection audio level but not have brtc stream')\n }\n }\n\n private handleAudioLevel = (level: number) => {\n this.audioLevelWatcher.next(level)\n }\n\n public checkSmallVideo() {\n if (this.videoEnable) {\n if (this.stream) {\n if (!this.isShare) {\n const canGetContainer = !!document.getElementById(this.playerId)\n if (canGetContainer) {\n const smallElement = `video_${this.stream!.getStreamId()}`\n const canGetSmallElement = !!document.getElementById(smallElement)\n if (canGetSmallElement) {\n this.checkVideoDecodeFrame(smallElement)\n return\n }\n else {\n logger.error('stream is display, but no video element, should replay now')\n // 存在设置了 isdisplay 但是不用小窗口播放的问题,这块逻辑后续优化\n this.play()\n }\n }\n }\n\n }\n }\n }\n\n public checkBigVideo = debounce(() => {\n if (this.videoEnable) {\n if (this.stream) {\n const bigElement = `video_${this.stream!.getStreamId()}_big`\n if (!this.isShare && this.isDisplay && this.playerId) {\n // 检测小窗口的视频是不是正常播放的\n const canGetBigElement = !!document.getElementById(bigElement)\n if (this.isInBig) {\n if ( canGetBigElement) {\n this.checkVideoDecodeFrame(bigElement)\n return\n } else {\n logger.error('stream is playing in big, but no video element, replay now')\n this.playInBig()\n }\n }\n\n }\n\n // 大窗口的播放容器\n if (this.isShare && this.isInBig && this.bigPlayerId) {\n this.checkVideoDecodeFrame(bigElement)\n }\n }\n }\n }, 2000)\n\n /**\n * 播放黑窗处理,主要是做一个容错处理,又可能这股流拉下来或者存在订阅就出现问题的情况\n * 播放时黑窗的,这个时候需要,检测,然后重新拉流\n * @param videoContainer\n */\n private checkVideoDecodeFrame(videoContainer: string) {\n const container = document.getElementById(videoContainer) as HTMLVideoElement\n this.checkVideoTimer && clearTimeout(this.checkVideoTimer)\n if (!container) {\n logger.info('黑帧检测没有播放容器', this.userId, '', ['streamId =>', this.streamId, 'isShare =>', this.isShare, 'playerId =>', this.playerId, 'bigPlayerId =>', this.bigPlayerId, 'isDisplay => ', this.isDisplay, 'isInbig =>', this.isInBig])\n if (this.isShare && this.isInBig && this.bigPlayerId) {\n logger.warn('share stream has no video player, retry play')\n this.playInBig()\n }\n return\n }\n this.checkVideoTimer = setTimeout(() => {\n // getVideoPlaybackQuality 这个api在低于chrome80版本一下不能用, webkitDecodedFrameCount这个api被废弃了\n const data = (container?.getVideoPlaybackQuality && container?.getVideoPlaybackQuality()?.totalVideoFrames || 0)\n if (container && !container.getVideoPlaybackQuality) {\n this.checkVideoTimer && clearTimeout(this.checkVideoTimer)\n return\n }\n if (data > 0) {\n clearTimeout(this.checkVideoTimer!)\n this.checkFailedCount = 0\n return\n } else {\n if (this.checkCount > 10) {\n logger.error('检测超过了十次,还没有视频流,需要重新拉取', '黑帧检测', this.userId, ['streamId =>', this.streamId, 'nickname =>', this.nickname, 'videoContainer => ', videoContainer])\n this.checkVideoTimer && clearTimeout(this.checkVideoTimer)\n this.checkVideoTimer = null\n this.checkCount = 0\n this.checkFailedCount += 1\n // 十秒钟都没有检测通过,则证明这个人当前在展示的视频流有问题,需要重新拉流\n if (this.checkFailedCount <= 3) {\n this.hasPulled = false\n this.pulledStreamType = 'small'\n this._stream?.off(namespace)\n try {\n this._stream?.destroy()\n }catch (e) {\n\n }\n this._stream = undefined\n this.sendMessage2Room()\n }\n return\n }\n this.checkCount += 1\n this.checkVideoDecodeFrame(videoContainer)\n }\n }, 200)\n }\n\n /**\n * 发送订阅该流的请求\n */\n subscribeStream() {\n this.shouldPull = true\n BoomEmitter.emitter!.emit(MANUAL_SUBSCRIPTION, { stream: this })\n }\n\n unSubscribeStream() {\n this.shouldPull = false\n BoomEmitter.emitter!.emit(UNSUBSCRIBE_STREAM, { stream: this })\n }\n\n checkStreamIsPlaying = debounce(() => {\n if (this.isDisplay && this.videoEnable) {\n if (!this.stream) {\n return\n }\n const container = document.getElementById(this.playerId)\n if (!container) {\n return\n }\n const isPlaying = this.currentIsPlaying(this.playerId) === PlayerState.NO_PLAYING\n if (!isPlaying) {\n logger.error(`${this.userId} - ${this.nickname}: current is ${this.isDisplay}, but there is no player, try play again`)\n this.play()\n }\n }\n }, 1000)\n\n /**\n * 取消流的播放\n * @param type big: 大窗口 small: 小窗口 all: 全部\n */\n unAttach(type: 'big' | 'small' | 'all') {\n logger.info('unattach stream play', '', this.userId, ['streamId =>', this.streamId, 'nickname =>', this.nickname, 'type =>', type])\n if (type === 'all') {\n this.stream?.stop()\n this.player?.destroy()\n }\n else if (type === 'big') {\n this.player?.destroy()\n }\n else if (type === 'small') {\n this.stream?.stop()\n }\n }\n}\n","import BMUser from '../BMUser/BMUser'\nimport { SingleStream } from '../type'\n\n/**\n * @name: BMSpeaker\n * @author: liuxinghai\n * @date: 2022-06-07 11:41\n * @description:BMSpeaker\n * 适配 brtc 流对象到 bloud 流对象接口,\n * 用户辅助采用 bloud SpeakerDetector 做说话人检测\n * @date: 2022-06-07 11:41\n */\n\nexport default class BMSpeaker {\n public user: BMUser\n public stream: SingleStream\n\n constructor(user: BMUser, stream: SingleStream) {\n this.user = user\n this.stream = stream\n }\n\n /**\n * 获取对象 ID 标识,此处使用流 ID 标识\n * @returns\n */\n getID() {\n return this.stream.getStreamId()\n }\n\n /**\n * 获取用户 BMUser 对象\n * @returns\n */\n getUser(): BMUser {\n return this.user\n }\n}","/**\n * @name: sortStream\n * @author: yangliye\n * @date: 2023-04-18 11:40\n * @description:sortStream\n * @update: 2023-04-18 11:40\n */\nexport function getMasterSort(a: boolean, v: boolean) {\n return 16 | ~~a << 1 | ~~v\n}\n\n/**\n * 12 - 15\n */\nexport function getLocalSort(a: boolean, v: boolean) {\n return 12 | ~~a << 1 | ~~v\n}\n\n/**\n * 8 - 11\n * @param a\n * @param v\n */\nexport function getManagerSort(a: boolean, v: boolean) {\n return 8 | ~~a << 1 | ~~v\n}\n\n\n/**\n * 取值范围 4 - 7\n * @param a\n * @param v\n */\nexport function getGuestSort(a: boolean, v: boolean) {\n return 4 | ~~a << 1 | ~~v\n}\n\n/**\n * 取值范围 0 - 3\n * @param a\n * @param v\n */\nexport function getCommonSort(a: boolean, v: boolean) {\n return ~~a << 1 | ~~v\n}\n","/**\n * @name: BMStreamModelVM\n * @author: yangliye\n * @date: 2022-04-27 15:25\n * @description:BMStreamModelVM\n * @update: 2022-04-27 15:25\n * @description\n * 这个模块的功能是去管理展示窗口的处理逻辑,主要包括创建streamModel,更新streamModel(主要是流相关信息的更新,和用户更新)\n * 创建streamModel的操作:\n * 初始化整个流程是根据bloud的用户来创建的\n * 然后在根据brtc里面流的信息来更新对应的streamModel\n * bloud的用户和brtc的流信息是根据uid来进行关联。\n *\n * 共享屏幕用户做了特殊处理,因为web端共享屏幕和移动端共享屏幕处理逻辑不一样\n */\n\nimport BMStreamModel, { NoPlayerContainer } from \"./BMStreamModel\"\nimport BMUser from \"../BMUser/BMUser\"\nimport { SingleLocalStream, SingleRemoteStream, SingleStream } from \"../type\"\nimport BMRoom from \"../BMRoom/BMRoom\"\nimport {\n MOBILE_STREAM_SUFFIX_SCREEN,\n MODEL_SORT_NUM_CHANGE,\n NO_CONTAINER,\n STREAM_SUFFIX_SCREEN,\n STREAM_TYPE\n} from \"../constants\"\nimport { BehaviorSubject, Subject } from \"rxjs\"\nimport {BoomError} from \"@hysc/utils\"\nimport * as errorType from \"../error/errorType\"\nimport type { Device } from \"@hysc/brtc\"\nimport { debounce } from \"lodash-es\"\nimport BMSpeaker from \"./BMSpeaker\"\nimport BoomEmitter from \"../util/emitter\"\nimport { sortStreamModels } from \"../util/util\"\nimport {\n BMCameraNotAuthError,\n BMCreateStreamError, BMMicNotAuthError,\n BMOpenCameraError,\n BMOpenMicroError,\n BmSetLocalAudioEnable,\n BmSetLocalSpeakerEnable,\n BmSetLocalVideoEnable, BMStreamDisconnectedError, BmSyncStreamFailError,\n getStreamError\n} from \"@hysc/utils\"\nimport { ignoreUserId } from \"../BMUser/BMUserVM\"\nimport * as logger from \"../logger/logger\"\nimport { ShareMediaOptions } from \"@hysc/core\"\nimport { getHTMLMediaStreamOptions, getMediaStreamInfo, Result } from \"./getHTMLMediaStreamOptions\"\nimport { isShareStream } from \"../util/roomUtils\"\nimport { BloudStream } from \"@hysc/core\"\nimport type { StreamCustomInfo } from '@hysc/bloud/src/core/Room'\nimport { BloudStreamEventState } from \"../handleEvent/attachEvents\"\n\nexport function transShareScreen2User(userId: string) {\n return userId.split('_')[0]\n}\n\nconst namespace = `.streammuteevent${Math.random()}`\n\nexport default class BMStreamModelVM {\n\n public streamModels: Map<string, BMStreamModel> = new Map()\n /**\n * 因为投屏码用户进来以后,他是不在小窗口展示的,所以要把投屏的用户过滤掉给业务的展示\n */\n public streamModelsWatcher = new BehaviorSubject(BMStreamModelVM.filterStreamModels(this.sortStreamModels()))\n\n public shareStreamModels = new Map<string, BMStreamModel>()\n public shareStreamModelsWatcher = new BehaviorSubject(Array.from(this.shareStreamModels.values()))\n\n public localStreamErrorWatcher = new Subject<string>()\n\n public localModel: BMStreamModel | null = null\n public room: BMRoom | null = null\n public bloudStream: BloudStream | null = null\n public brtcStream: SingleLocalStream | undefined\n /**\n * 后面打开摄像头存储的流,主要是关闭摄像头的时候得把它清除掉\n */\n public videoStream: SingleLocalStream | null = null\n public audioStream: SingleLocalStream | null = null\n public audioStats = false\n public videoStats = false\n\n /**\n * 本地是否在屏幕共享\n */\n public localIsShare: boolean = false\n public isShareWatcher = new Subject<boolean>()\n\n public _speaker_enable = true\n public speakerEnableWatcher = new BehaviorSubject(this._speaker_enable)\n /**\n * 混流\n */\n public mixStreamModelWatcher = new BehaviorSubject<BMStreamModel | null>(null)\n\n public canvasTimer: NodeJS.Timeout | null = null\n\n\n private _recorder: any\n private _isRecording = false\n private _slicingRecord = false\n public isRecordingWatcher = new BehaviorSubject(this._isRecording)\n\n private _speaker: BMUser | null = null\n private _speakerDetector: any\n private _speakers = new Map<string, BMSpeaker>()\n public speakerWatcher = new BehaviorSubject(this._speaker)\n\n\n /**\n * 窗口没有播放容器的错误处理\n */\n noContainerWatcher = new Subject<BMStreamModel>()\n\n /**\n * 窗口没有大窗口播放容器的错误处理\n */\n noBigContainerWatcher = new Subject<BMStreamModel>()\n\n localStreamConnectErrorWatcher = new Subject<BoomError>()\n\n /**\n * 共享屏幕相关错误\n * 包括,共享客户端错误\n * 共享屏幕流错误\n */\n localShareError = new Subject<BoomError>()\n\n /**\n * 共享屏幕流是单独处理的逻辑,不是先创建streamModel然后在去查流,而是先去查流,在创建streamModel\n */\n public shareBloudStateMap = new Map<string, BloudStreamEventState>()\n\n constructor() {\n this.createCanvas()\n setTimeout(() => {\n this.canvasDisplay()\n }, 100)\n\n BoomEmitter.emitter!.on(MODEL_SORT_NUM_CHANGE, this.updateModelSort)\n BoomEmitter.emitter!.on(NO_CONTAINER, this.handleNoContainer)\n }\n\n private static filterStreamModels(streamModels: BMStreamModel[]) {\n return streamModels\n .filter(item => !item.isToupingma)\n .filter(item => !ignoreUserId.some(ignore => item.userId.includes(ignore)))\n .filter(item => item.canShow)\n }\n\n\n public initWithRoom(room: BMRoom) {\n this.room = room\n return this\n }\n\n /**\n * 设置扬声器是否打开\n * @param enable\n * @private\n */\n private setSpeakerEnable(enable: boolean) {\n if (this._speaker_enable !== enable) {\n this.room!.audioPlayer?.mute(!enable)\n this._speaker_enable = enable\n this.speakerEnableWatcher.next(enable)\n }\n }\n\n\n public getStreamModels(): Array<BMStreamModel> {\n return Array.from(this.streamModels.values())\n }\n\n /**\n * 获取streamModel\n * @param userId 用户Id\n * @returns\n */\n public getStreamModelByUId(userId: string) {\n return this.streamModels.get(userId)\n }\n\n public getShareStreamModelByUId(userId: string) {\n return this.shareStreamModels.get(userId)\n }\n\n public getLocalStreamModel() {\n return this.localModel\n }\n\n public createStreamModel(user: BMUser, stream?: SingleStream): BMStreamModel {\n // 先创建streamModel\n const newStreamModel = new BMStreamModel(user, undefined)\n // 然后更新流\n if (stream) {\n newStreamModel.updateStream(stream, true, this)\n }\n\n // 更新静音状态\n // newStreamModel.changeMute(!this._speaker_enable)\n\n if (newStreamModel.isShare) {\n user.addStream(`${user.userId}${STREAM_SUFFIX_SCREEN}`, newStreamModel)\n this.addShareStreamModel(newStreamModel)\n }\n else {\n user.addStream(user.userId, newStreamModel)\n this.addStreamModel(newStreamModel)\n }\n return newStreamModel\n }\n\n public addStreamModel(streamModel: BMStreamModel) {\n if (!streamModel) return\n\n if (streamModel.isLocal) {\n if (!this.localModel) {\n this.localModel = streamModel\n this.streamModels.set(this.localModel.userId, this.localModel)\n }\n }else {\n this.streamModels.set(streamModel.userId, streamModel)\n }\n }\n\n public addShareStreamModel(streamModel: BMStreamModel) {\n if (!streamModel) return\n if (streamModel.isLocal) {\n return\n }\n this.shareStreamModels.set(streamModel.userId, streamModel)\n this.shareStreamModelsWatcher.next(Array.from(this.shareStreamModels.values()))\n }\n\n public removeStreamModel(streamModel: BMStreamModel) {\n if (!streamModel) return\n const user = streamModel.getUser()\n this.streamModels.delete(streamModel.userId)\n user.removeStream(streamModel.userId)\n }\n\n public removeShareStreamModelByUId(uid: string) {\n const streamModel = this.shareStreamModels.get(uid)\n if (streamModel) {\n try {\n streamModel.stream?.stop()\n streamModel.stream?.destroy()\n }catch (e) {\n\n }\n if (streamModel.audioEnable) {\n if (streamModel.stream) {\n this.room?.audioPlayer?.removeStream(streamModel.stream as SingleRemoteStream)\n }\n }\n this.removeShareStreamModel(streamModel)\n }\n }\n\n public removeShareStreamModel(streamModel: BMStreamModel) {\n if (!streamModel) return\n const user = streamModel.getUser()\n this.shareStreamModels.delete(streamModel.userId)\n user.removeStream(`${streamModel.userId}${STREAM_SUFFIX_SCREEN}`)\n user.updateSortNum(true)\n this.shareStreamModelsWatcher.next(Array.from(this.shareStreamModels.values()))\n }\n\n /**`\n * 通过用户id删除streamModel\n * @param userId\n * @returns\n */\n public removeStreamModelByUId(userId: string) {\n const streamModel = this.getStreamModelByUId(userId)\n if (streamModel) {\n if (streamModel.stream) {\n this.removeFromDetector(streamModel.streamId)\n try {\n streamModel.stream.stop()\n streamModel.stream.destroy()\n }catch (e) {\n }\n }\n if (streamModel.audioEnable) {\n if (streamModel.stream) {\n this.room?.audioPlayer?.removeStream(streamModel.stream as SingleRemoteStream)\n }else {\n this.room?.audioPlayer.removeStreamByUid(userId)\n }\n }\n\n this.removeStreamModel(streamModel)\n }\n return streamModel\n }\n\n remoteStreamPublished(stream: SingleRemoteStream) {\n const streamId = stream.getStreamId()\n const userId = stream.getUserId().toString()\n let streamModel = this.getStreamModelByUId(userId)\n let realUserId\n if (!streamModel) {\n // streamModel 不存在,就是web端的共享屏幕用户, 或者是投屏\n // 投屏码的userId,共享屏幕的userId要进行处理,移动端投屏会有多个 stream,getType\n realUserId = transShareScreen2User(String(userId))\n streamModel = this.getStreamModelByUId(realUserId)\n }\n\n if (streamModel) {\n // web端共享屏幕是userId_screen, 移动端共享屏幕是通过stream.getType() 判断辅流\n if (isShareStream(stream)) {\n let ssm: BMStreamModel | undefined\n if (realUserId) {\n ssm = this.shareStreamModels.get(realUserId)\n }\n if (ssm) {\n if (ssm.isLocal) {\n return\n }\n ssm.hasPulled = false\n ssm.pulledStreamType = 'small'\n ssm.updateStream(stream, true, this)\n this.shareStreamModelsWatcher.next(Array.from(this.shareStreamModels.values()))\n }\n else {\n // 创建共享屏幕的窗口\n const streamModelShare = this.createStreamModel(streamModel.getUser(), stream)\n const videoEnable = stream.getVideoOn()\n const audioEnable = stream.getAudioOn()\n const shareState = this.shareBloudStateMap.get(streamModel.userId)\n if (shareState) {\n streamModelShare.updateBloudStream({audio: shareState.audio, video: shareState.video, isScreen: true, customInfo: shareState.customInfo}, this)\n }else {\n streamModelShare.updateBloudStream({audio: audioEnable, video: videoEnable, isScreen: true}, this)\n }\n streamModelShare.streamType = STREAM_TYPE.SHARE\n }\n }\n // 正常用户推流\n else {\n streamModel.hasPulled = false\n streamModel.pulledStreamType = 'small'\n this.updateStreamModel(streamModel, stream)\n }\n\n /**\n * 混流处理\n */\n if (streamModel.getUser().isMixer) {\n this.mixStreamModelWatcher.next(streamModel!)\n }\n // 设置这股流的播放的扬声器\n this.changeSingleStreamSpeaker(streamModel).catch(e => {\n logger.error('设置单股流的扬声器的播放出现了问题', '设置播放音量', streamModel?.userId)\n })\n } else {\n logger.error('brtc有人推流了,但是找不到对应的streamModel, 找不到对应的用户', '', userId, ['streamId => ', streamId, 'type =>', stream.getType && stream.getType()])\n }\n }\n\n /**\n * 有人取消流触发,有人取消流之后brtc底层会把流销毁掉,除了流Id和userId,其他的信息都不稳定能取到\n * @param stream\n * @returns\n */\n remoteStreamUnpublished(stream: SingleRemoteStream) {\n let streamModel: BMStreamModel | undefined\n const userId = stream.getUserId().toString()\n const streamId = stream.getStreamId()\n let isShare = false\n // 这边传入的是userId,那么web端传入的就是userId_screen, 那么肯定就在streamModels里面找不到,就需要去share里面找\n if (userId.includes(STREAM_SUFFIX_SCREEN)) {\n // 额外处理一层逻辑,web端的共享屏幕流也是进来一个新用户,所以也会走到这里的逻辑处理\n const realUid = transShareScreen2User(String(userId))\n if (realUid == this.room?.getLocalParticipant()?.userId) {\n logger.info('本地用户取消共享屏幕', '取消共享屏幕', userId)\n this.localModel!.getUser().removeStream(userId)\n return\n }\n streamModel = this.getShareStreamModelByUId(realUid)\n isShare = true\n\n } else if (streamId.startsWith(MOBILE_STREAM_SUFFIX_SCREEN) || (stream.getType && stream.getType() === 'assist')) {\n // 接下来处理移动端的共享屏幕的情况\n streamModel = this.getShareStreamModelByUId(userId)\n isShare = true\n } else {\n // 否则就是普通的流\n streamModel = this.getStreamModelByUId(userId)!\n }\n this.removeFromDetector(streamId)\n this.removeFromRecorder(stream)\n if (!streamModel) {\n logger.error('brtc有人取消推流 但是找不到对应的streamModel', '取消推流', userId, [streamId])\n return\n }\n\n // 判断当前的streamModel上面的stream和取消推流收到的这股流是不是同一个\n const ssid = streamModel.stream?.getStreamId()\n if (ssid !== streamId) {\n logger.error('当前取消推流的和当前绑定的不是同一股流', '', userId, ['streamId =>', streamId, 'streamModel.streamId', ssid])\n return\n }\n // 远端有人取消推流之后,将拉流状态设置为false\n streamModel.hasPulled = false\n streamModel.pulledStreamType = 'small'\n // 共享屏幕的流,要删除这个用户\n if (isShare || streamModel.streamType === STREAM_TYPE.SHARE) {\n streamModel.updateStream(undefined, true, this)\n this.removeShareStreamModel(streamModel)\n return\n }\n // 非共享屏幕的流,需要更新流为空\n streamModel.updateStream(undefined, true, this)\n return streamModel\n }\n\n sortStreamModels() {\n return sortStreamModels(Array.from(this.streamModels.values()))\n }\n\n updateStreamModel(streamModel: BMStreamModel, stream: SingleStream) {\n streamModel.updateStream(stream, true, this)\n }\n\n updateShareStreamModel(streamModel: BMStreamModel, stream: SingleStream) {\n streamModel.updateStream(stream, true, this)\n }\n\n /**\n * 开关本地摄像头\n * @param status true:开,false:关\n * @param videoTrack 开启美颜之后,需要传递这个参数,携带美颜之后的videoTrack\n */\n public async setLocalVideoEnable(status: boolean, videoTrack?: MediaStreamTrack) {\n if (!this.room?.networkState.brtc || !this.room.netConnecting) {\n logger.error('断网期间开本地摄像头,不与响应')\n return\n }\n if (!this.room.mediaPermission.camera) {\n return Promise.reject(BMCameraNotAuthError())\n }\n const localModel = this.getLocalStreamModel();\n logger.info(`开关本地摄像头, 状态 => ${status}`, '本地用户', localModel?.userId)\n if (localModel) {\n if (status) {\n // 需要判断一下是canvas的Stream还是video的Stream\n if (localModel?.stream) {\n if (!videoTrack) {\n const videoTrack = localModel.stream.getVideoTrack()\n if ((videoTrack as CanvasCaptureMediaStreamTrack).constructor.name === 'CanvasCaptureMediaStreamTrack') {\n const videoTrack = await this.createVideoStream().catch(e => {\n return Promise.reject(e)\n })\n const res = await (localModel.stream as SingleLocalStream).replaceTrack(videoTrack)\n .then(() => {\n logger.info('replace video track success')\n })\n .catch(e => {\n logger.error('本地视频流更换视频流失败', '', '', JSON.stringify(e))\n this.handleStreamUpdateFailed()\n return Promise.reject(BMOpenCameraError())\n })\n }\n }\n // 传了美颜的videoTrack之后,替换videoTrack就行\n else {\n await (localModel.stream as SingleLocalStream).replaceTrack(videoTrack).catch(e => {\n logger.error('美颜 videoTrack replace 失败', '', '', JSON.stringify(e))\n })\n }\n\n const res = await localModel.stream.unmuteVideo()\n if(res) {\n logger.info('brtc unmute video success')\n }else {\n logger.error('brtc unmuteVideo失败')\n this.handleStreamUpdateFailed()\n return Promise.reject(BMOpenCameraError())\n }\n await this.bloudStream!.setVideoEnabled(true)\n .then(() => {\n // 设置状态,然后抛发videoEnable的状态\n localModel.updateStream(localModel.stream, true, this)\n localModel.updateBloudStream({video: true, audio: localModel.audioEnable, isScreen: false}, this)\n // 本地在大窗口的时候,这个是防止大窗口黑屏做的兼容处理\n localModel.playInBig()\n })\n .catch((e: any) => {\n logger.error('bloud unmuteVideo失败', '本地用户', '', [JSON.stringify(e)])\n this.handleStreamUpdateFailed()\n })\n\n } else {\n // 如果没有stream,就需要创建stream,创建一个brtc的stream,为了推流,创建一个bloud stream,为了同步状态,主要给管理后台用\n await this.createStreamAndPublish(false, true, localModel, videoTrack).catch(e => {\n logger.error('开启本地摄像头失败', '', '', [JSON.stringify(e)])\n this.localModel?.stream?.destroy()\n if (this.bloudStream?.published) {\n this.bloudStream.unpublish()\n }\n this.localModel?.updateStream(undefined, true, this)\n this.localModel?.updateBloudStream(undefined, this)\n return Promise.reject(e)\n })\n }\n } else {\n const stream = localModel.stream as SingleLocalStream\n if (stream) {\n await this.muteOrUnpublishStream('video', true, localModel).catch(e => {\n logger.error('关闭本地摄像头失败', '', '', [e])\n return Promise.reject(BmSetLocalVideoEnable(e))\n })\n }\n }\n }\n }\n\n /**\n * brtc流更新状态失败,这个时候重新推流\n */\n async handleStreamUpdateFailed() {\n logger.error('brtc unmute stream failed, now unpublish')\n await this.unpublishStream()\n }\n /**\n * 开关本地麦克风\n * @param status true:开,false:关\n */\n public async setLocalAudioEnable(status: boolean) {\n if (!this.room?.networkState.brtc || !this.room.netConnecting) {\n logger.error('断网期间开本地麦克风,不与响应')\n return\n }\n if (!this.room.mediaPermission.microphone) {\n return Promise.reject(BMMicNotAuthError())\n }\n const localModel = this.getLocalStreamModel();\n logger.info(`开关本地麦克风, 状态 => ${status}`, '本地用户', localModel?.userId)\n if (localModel) {\n if (status) {\n if (localModel?.stream) {\n const res = await localModel.stream.unmuteAudio()\n logger.info(`unmute local stream audio res : ${res}`)\n if(res) {\n logger.info('unmute audio success')\n }else {\n logger.error('brtc unmuteAudio失败', '本地用户', '')\n await this.handleStreamUpdateFailed()\n return Promise.reject(BMOpenMicroError())\n }\n await this.bloudStream!.setAudioEnabled(true)\n .then(() => {\n logger.info('bloud stream set audio enable')\n localModel.updateStream(localModel.stream, false, this)\n localModel.updateBloudStream({audio: true, video: localModel.videoEnable, isScreen: false}, this)\n })\n .catch((e: any) => {\n logger.error('bloud unmuteAudio失败', '本地用户', '', [JSON.stringify(e)])\n this.handleStreamUpdateFailed()\n })\n } else {\n await this.createStreamAndPublish(true, false, localModel).catch(e => {\n logger.error('开启本地麦克风失败', '', '', [e])\n this.localModel?.stream?.destroy()\n if (this.bloudStream?.published) {\n this.bloudStream.unpublish()\n }\n this.localModel?.updateStream(undefined, true, this)\n this.localModel?.updateBloudStream(undefined, this)\n return Promise.reject(e)\n })\n }\n if (localModel?.stream) {\n this.addToRecorder(localModel?.stream)\n }\n // 关闭\n } else {\n const stream = localModel.stream as SingleLocalStream\n if (stream) {\n this.removeFromRecorder(stream)\n this.removeFromDetector(stream.getStreamId())\n try {\n await this.muteOrUnpublishStream('audio', true, localModel)\n } catch (e) {\n logger.error('关闭本地麦克风失败', '', '', [JSON.stringify(e)])\n return Promise.reject(BmSetLocalAudioEnable(e as string))\n }\n }\n }\n }\n }\n\n /**\n * 该方法只是在入会的时候,同时开启音频和视频的时候使用,其他时候禁止使用该方法\n * 切换音频和视频状态请使用 setLocalAudioEnable 和 setLocalVideoEnable\n * @param audio\n * @param video\n */\n public async joinWithAudioAndAudio(audio: boolean, video: boolean) {\n logger.info('join with audio and video', 'join publish', '', [audio, video])\n const localStreamModel = this.getLocalStreamModel()\n if (localStreamModel) {\n await this.createStreamAndPublish(audio, video, localStreamModel).catch(e => {\n logger.error('join create and publish failed', '', '', [JSON.stringify(e)])\n this.localModel?.stream?.destroy()\n if (this.bloudStream?.published) {\n this.bloudStream.unpublish()\n }\n this.localModel?.updateStream(undefined, true, this)\n this.localModel?.updateBloudStream(undefined, this)\n return Promise.reject(e)\n })\n }\n\n }\n\n /**\n * 切换扬声器\n * @param device\n * @param force 是否需要强制更新\n */\n public async changeSpeaker(device: Device, force = false) {\n logger.info('change speaker', '', '', [JSON.stringify(device)])\n if (!device.deviceId) {\n throw new BoomError(errorType.LOCAL_ERROR, '切换扬声器失败!,原因: 选择的设备没有deviceId' + device?.name)\n }\n try {\n this.room!.setSelectSpeakerDevice(device)\n this.room?.audioPlayer?.setDevice(device.deviceId, force)\n } catch (error) {\n logger.error('切换扬声器失败', '', '', ['error', (error as any)?.message, JSON.stringify(error)])\n throw new BoomError(errorType.LOCAL_ERROR, '切换扬声器失败')\n }\n }\n\n /**\n * 设置单个流的扬声器\n * @param streamModel\n */\n public async changeSingleStreamSpeaker(streamModel: BMStreamModel) {\n const selectSpeakerDevice = this.room!.selectAudioOutputDevice\n if (selectSpeakerDevice) {\n if (!streamModel.isLocal) {\n if (streamModel.stream) {\n await (streamModel.stream as SingleRemoteStream).setAudioOutput(selectSpeakerDevice.deviceId)\n }\n }\n }\n }\n\n public async changeAudioInput(device: Device) {\n logger.info('change audio input device', '', '', [JSON.stringify(device)])\n const stream = this.localModel?.stream\n this.room?.setSelectAudioDevice(device)\n if (stream) {\n const ended = stream.getAudioTrack()?.readyState === 'ended'\n if (ended) {\n logger.error('try to change audio input device but audio track is ended')\n return false\n }\n this.removeFromRecorder(stream)\n await (stream as SingleLocalStream).switchDevice('audio', device.deviceId)\n this.addToRecorder(stream)\n return true\n }\n }\n\n public async changeVideoInput(device: Device) {\n logger.info('change video input device', '', '', [JSON.stringify(device)])\n const stream = this.localModel?.stream\n this.room?.setSelectVideoDevice(device)\n if (stream) {\n const ended = stream.getVideoTrack()?.readyState === 'ended'\n if (ended) {\n logger.error('try to change video input device but video track is ended')\n return false\n }\n await (stream as SingleLocalStream).switchDevice('video', device.deviceId)\n if (this.localModel?.isDisplay && this.localModel.isInBig) {\n this.localModel.playInBig()\n }\n return true\n }\n }\n /**\n * 是否静音扬声器\n * @param enable\n */\n public async muteSpeaker(enable: boolean) {\n logger.info('静音扬声器 状态 =>', '', '', ['status =>', enable])\n try {\n this.setSpeakerEnable(enable)\n } catch (e) {\n return Promise.reject(BmSetLocalSpeakerEnable(`开关扬声器失败 ${enable} error: ${JSON.stringify(e)}`))\n }\n }\n\n /**\n * 创建本地音频流\n */\n async createLocalAudioStream() {\n if (!this.room!.mediaPermission.microphone) {\n logger.error('there is no microphone permission')\n return\n }\n await this.room!.initDevices()\n if (this.room!.audioDevices.length) {\n this.audioStream?.destroy()\n this.audioStream = await this.room!.createSingleLocalStream({ video: false, audio: true }, this.localModel!.userId).catch(e => {\n logger.error('create brtc stream error', '', '', [JSON.stringify(e)])\n return Promise.reject(e)\n })\n }else {\n logger.error('there is no audio device exists')\n }\n }\n\n /**\n * 创建流并且发布\n * @param audio 是否发布音频流\n * @param video 是否发布视频流\n * @param localModel 本地的streamModel\n * @param videoTrack\n * @private\n */\n private async createStreamAndPublish(audio: boolean, video: boolean, localModel: BMStreamModel, videoTrack?: MediaStreamTrack) {\n /**\n * 现在要处理打开只打开音频的情况下,这种时候,如果调用brtc传入video,audio都为true的情况下\n * 会导致摄像头的灯是亮的\n * 处理逻辑是,使用canvas创建一个空track,然后初始化brtc流的时候传递进去,然后再打开摄像头的时候,\n * replaceTrack 把对应的video track替换掉\n */\n let canvasStream = BMStreamModelVM.getCanvasStream()\n // // 适配PC 客户端获取不到设备的问题\n await this.room!.initDevices()\n\n /**\n * brtc现在的逻辑是,如果你指定了videoSource 那么就必须要指定audioSource,所以要同时创建两个track\n */\n if (!video) {\n const videoTrack = canvasStream.getVideoTracks()[0]\n if (!this.audioStream) {\n this.audioStream = await this.room!.createSingleLocalStream({ video: false, audio: true }, localModel.userId).catch(e => {\n logger.error('create brtc stream error', '', '', [JSON.stringify(e)])\n return Promise.reject(e)\n })\n }\n const audioTrack = this.audioStream?.getAudioTrack()\n if (!audioTrack || (audioTrack && audioTrack.muted)) {\n this.audioStream?.destroy()\n this.audioStream = null\n this.localStreamErrorWatcher.next('audio')\n logger.error('麦克风设备不可用', '', '', ['muted => ?', audioTrack?.muted])\n throw getStreamError('麦克风')\n }\n\n this.brtcStream?.destroy()\n /**\n * 传入了videoSource 和 audioSource之后,video和audio配置项失效\n */\n this.brtcStream = await this.room!.createSingleLocalStream({ video: true, audio: true, videoSource: videoTrack, audioSource: audioTrack }, localModel.userId).catch(e => {\n return Promise.reject(e)\n })\n } else {\n this.brtcStream?.destroy()\n if (!this.room?.audioDevices.length) {\n logger.error('当前电脑中没有音频输入设备,重新获取')\n await this.room?.initDevices()\n }\n\n if (!this.room?.videoDevices.length) {\n logger.error('当前电脑中没有视频输入设备, 重新获取')\n await this.room?.initDevices()\n }\n\n if (this.room!.audioDevices.length > 0) {\n this.brtcStream = await this.room!.createSingleLocalStream({ video: true, audio: this.room!.mediaPermission.microphone }, localModel.userId).catch(e => {\n logger.error('create brtc audio and video stream failed', '', '', [JSON.stringify(e)])\n return Promise.reject(e)\n })\n } else {\n logger.error('没有音频输入设备,只能创建视频流')\n this.brtcStream = await this.room!.createSingleLocalStream({ video: true, audio: false }, localModel.userId).catch(e => {\n logger.error('create brtc video stream failed', '', '', [JSON.stringify(e)])\n return Promise.reject(e)\n })\n }\n }\n\n if (this.brtcStream) {\n if (!video) {\n await this.brtcStream.muteVideo()\n }\n if (!audio) {\n await this.brtcStream.muteAudio()\n }\n\n if (videoTrack) {\n await this.brtcStream.replaceTrack(videoTrack).catch(e => {\n logger.error('美颜 videoTrack replace 失败', '', '', JSON.stringify(e))\n })\n }\n\n await this.room!.publish(this.brtcStream).catch(e => {\n this.brtcStream?.destroy()\n this.localModel?.updateBloudStream(undefined, this)\n return Promise.reject(e)\n })\n this.brtcStream.on('video-track-mute'+namespace, this.muteHandler.bind(this, 'video'))\n this.brtcStream.on('video-track-ended'+namespace, this.muteHandler.bind(this, 'video'))\n this.brtcStream.on('audio-track-mute'+namespace, this.muteHandler.bind(this, 'audio'))\n this.brtcStream.on('audio-track-ended'+namespace, this.muteHandler.bind(this, 'audio'))\n await this.publishBloudStream(audio, video)\n }\n }\n\n async publishBloudStream(audio: boolean, video: boolean) {\n const localModelId = this.localModel!.userId\n\n // @ts-ignore\n this.bloudStream = this.room!.boomCore.creteBloudLocalStream({\n audio_enable: audio,\n video_enable: video\n }, localModelId)\n\n await this.bloudStream!.publish({ video_enable: video, audio_enable: audio })\n this.localModel?.updateBloudStream({video, audio, isScreen: false}, this)\n }\n\n muteHandler(type: 'video' | 'audio') {\n // 如果是走的replace track之后,有可能会触发这个事件,加个定时器去做个延迟处理\n const handleUnpublish = async () => {\n if (this.localModel?.stream) {\n await this.room?.boomCore.unpublish(this.localModel.stream as SingleLocalStream).catch(e => {\n logger.error('brtc local stream has problem and unpublish failed', '', '', [String(e)])\n })\n }\n this.localModel?.stream?.destroy()\n this.audioStream?.destroy()\n this.videoStream?.destroy()\n this.brtcStream?.destroy()\n this.brtcStream = undefined\n this.audioStream = null\n this.videoStream = null\n this.localModel?.updateStream(undefined, true, this)\n await this.bloudStream!.unpublish()\n this.bloudStream = null\n this.localModel?.updateBloudStream(undefined, this)\n }\n\n setTimeout(async () => {\n if (this.localModel?.stream) {\n const videoEnable = this.localModel?.videoEnable\n const audioEnable = this.localModel?.audioEnable\n\n if (type === 'video') {\n const muted = this.localModel.stream.getVideoTrack()?.muted\n const label = this.localModel.stream.getVideoTrack()?.label\n const enabled = this.localModel.stream.getVideoTrack()?.enabled\n const readyState = this.localModel.stream.getVideoTrack()?.readyState\n const ended = readyState === 'ended'\n logger.info('brtc video track status', '', '', [muted, enabled, readyState, label])\n if(!ended && !muted && enabled) {\n return\n }\n\n logger.info('video track has problem, now try recreate and publish')\n\n logger.error('brtc本地流出现异常,需要重新推流处理', '', '', ['videoEnable', videoEnable, 'audioEnable', audioEnable, 'type', type])\n this.localStreamConnectErrorWatcher.next(BMStreamDisconnectedError('摄像头'))\n\n if (this.localModel?.stream) {\n await this.room?.boomCore.unpublish(this.localModel.stream as SingleLocalStream).catch(e => {\n logger.error('brtc local stream has problem and unpublish failed', '', '', [String(e)])\n })\n this.localModel?.updateStream(undefined, true, this)\n this.localModel?.stream?.destroy()\n this.audioStream?.destroy()\n this.brtcStream?.destroy()\n this.brtcStream = undefined\n this.videoStream?.destroy()\n this.audioStream = null\n this.videoStream = null\n }\n\n await this.createStreamAndPublish(audioEnable, videoEnable, this.localModel).catch(async e => {\n logger.error('brtc video stream has problem and republish stream failed', '', '', [JSON.stringify(e)])\n await handleUnpublish()\n this.localStreamConnectErrorWatcher.next(BmSyncStreamFailError())\n })\n }else {\n\n logger.error('brtc本地流出现异常,需要重新推流处理', '', '', ['videoEnable', videoEnable, 'audioEnable', audioEnable, 'type', type])\n this.localStreamConnectErrorWatcher.next(BMStreamDisconnectedError('麦克风'))\n\n this.audioStream?.destroy()\n this.audioStream = null\n this.audioStream = await this.room!.createPBSingleLocalStream({video: false, audio: true})\n const audioTrack = this.audioStream?.getAudioTrack()\n if (audioTrack && !audioTrack.muted) {\n if (this.localModel.stream) {\n await (this.localModel.stream as SingleLocalStream).replaceTrack(audioTrack).catch(e => {\n logger.error('本地流出现异常, 重新创建audio stream replace 失败', '本地流出现异常', '', [JSON.stringify(e)])\n this.localStreamConnectErrorWatcher.next(BmSyncStreamFailError())\n handleUnpublish()\n })\n }\n }else {\n logger.error('recreate audio stream failed, now unpub')\n this.localStreamConnectErrorWatcher.next(BmSyncStreamFailError())\n handleUnpublish()\n }\n }\n }\n this.localStreamErrorWatcher.next(type)\n }, 1000)\n }\n\n async unpublishStream() {\n logger.info('unpublish stream')\n const localModel = this.getLocalStreamModel();\n if (localModel) {\n const stream = localModel.stream! as SingleLocalStream\n if (stream) {\n await this.room?.unpublish(stream).catch(e => {\n logger.error('brtc 取消发布失败', '取消推流', localModel.userId, [JSON.stringify(e)])\n })\n }\n try {\n this.removeFromRecorder(stream)\n stream?.destroy()\n this.videoStream?.destroy()\n this.audioStream?.destroy()\n this.brtcStream?.destroy()\n this.videoStream = null\n this.audioStream = null\n this.brtcStream = undefined\n localModel.updateStream(undefined, true, this)\n await this.bloudStream!.unpublish().catch(e => {\n logger.error('bloud unpublish stream failed', 'bloud unpublish stream', localModel.userId, [JSON.stringify(e), e?.code, e?.message])\n })\n localModel.updateBloudStream(undefined, this)\n this.bloudStream = null\n } catch (e) {\n logger.error('stream destroy failed', '取消推流', localModel.userId, [JSON.stringify(e)])\n }\n }\n }\n\n /**\n * 更改音视频状态或者取消发布\n * @param type 更改类型\n * @param mute 是否取消发布\n * @param localModel 本地的streamModel\n * @private\n */\n private async muteOrUnpublishStream(type: 'audio' | 'video', mute: boolean, localModel: BMStreamModel) {\n const stream = localModel.stream! as SingleLocalStream\n let getOn = true\n if (type === 'audio') {\n getOn = stream.getVideoOn()\n } else if (type === 'video') {\n getOn = stream.getAudioOn()\n }\n /**\n * 如果是关闭音频,首先要看一下视频是不是开着的,如果视频开着,则此时只需要mute掉音频流\n * 如果此时视频是关着的,那么就需要取消发布\n * 视频同理\n */\n if (getOn) {\n if (type === 'audio') {\n const success = await stream.muteAudio()\n if (!success) {\n // todo 如果unmute 失败, 端上没办法在重新调用unmute,因为brtc内部状态已经改了,这个时候得重新推流。。。\n logger.error('brtc muteAudio失败', '关闭本地音频', '本地')\n }\n await this.bloudStream!.setAudioEnabled(false).catch((e: any) => {\n logger.error('bloud setAudioEnabled 失败', '关闭本地音频', '本地', [JSON.stringify(e)])\n })\n // localModel.setAudioEnable(false)\n localModel.updateBloudStream({audio: false, video: true, isScreen: false}, this)\n } else if (type === 'video') {\n const canvasStream = BMStreamModelVM.getCanvasStream()\n const videoTrack = canvasStream.getVideoTracks()[0]\n try {\n await stream.replaceTrack(videoTrack)\n await stream.muteVideo()\n } catch (e) {\n logger.error('关闭本地视频失败', '关闭本地视频', '本地', [JSON.stringify(e)])\n }\n try {\n this.videoStream?.destroy()\n this.videoStream = null\n } catch (e) {\n logger.error('this.videoStream destroy failed')\n }\n await this.bloudStream!.setVideoEnabled(false).catch((e: any) => {\n logger.error('bloud setVideoEnabled 失败', '关闭本地音频', '本地', [JSON.stringify(e)])\n })\n // localModel.setVideoEnable(false)\n localModel.updateBloudStream({video: false, audio: true, isScreen: false}, this)\n }\n } else {\n await this.unpublishStream()\n }\n }\n\n public async toggleShareScreen(enable: boolean, opts: any, customShare?: Result) {\n logger.info('开关共享屏幕', '', '开关共享屏幕', ['stats => ', enable])\n if (!enable && this.room?.boomCore.shareScreenStream) {\n this.removeFromRecorder(this.room?.boomCore.shareScreenStream)\n }\n\n const voiceMode = this.room?.voiceMode\n\n await this.room!.boomCore.toggleShareScreen(enable, { audioHint: voiceMode }, customShare)\n .then(() => {\n logger.info('bmStreamVm toggleShareScreen success', '切换共享屏幕', '', ['enable =>', enable, 'options =>', JSON.stringify(opts)])\n if (enable) {\n const shareStream = this.room!.boomCore.shareScreenStream as unknown as SingleRemoteStream\n if (shareStream) {\n this.remoteStreamPublished(shareStream)\n }\n }else {\n // 取消共享屏幕的处理\n this.localModel!.getUser().removeStream(`${this.localModel!.userId}_screen`)\n this.localModel!.getUser().updateSortNum(true)\n }\n })\n .catch(e => {\n logger.error('bmStreamVm toggleShareScreen error', '切换共享屏幕', '', ['enable =>', enable, 'options =>', opts])\n return Promise.reject(e)\n })\n if (enable && this.room?.boomCore.shareScreenStream) {\n this.addToRecorder(this.room?.boomCore.shareScreenStream)\n }\n this.localIsShare = enable\n this.isShareWatcher.next(enable)\n return Promise.resolve(true)\n }\n\n public setShareScreenContentHint(contentHint: '' | 'motion' | 'detail' | 'text') {\n this.room?.boomCore.setShareScreenContentHint(contentHint)\n }\n\n updateModelSort = debounce(() => {\n const streamModels = this.sortStreamModels()\n this.streamModelsWatcher.next(BMStreamModelVM.filterStreamModels(streamModels))\n }, 200, { maxWait: 500 })\n\n handleNoContainer = (info: NoPlayerContainer) => {\n const { type, container, id } = info\n let sm: BMStreamModel | undefined\n if (type === 'share') {\n sm = this.shareStreamModels.get(id)\n }else {\n sm = this.streamModels.get(id)\n }\n\n if (sm) {\n if (container === 'small') {\n this.noContainerWatcher.next(sm)\n }else {\n this.noBigContainerWatcher.next(sm)\n }\n }\n }\n\n /**\n * 创建canvas,目的是为了捕获空track流,给brtc使用\n */\n createCanvas() {\n const canvas = document.createElement('canvas')\n canvas.id = 'tarCanvas'\n canvas.style.width = '1px'\n canvas.style.height = '1px'\n canvas.style.position = 'absolute'\n canvas.style.bottom = '0'\n document.body.appendChild(canvas)\n }\n\n private canvasDisplay() {\n let canvas = document.getElementById('tarCanvas') as HTMLCanvasElement\n if (canvas) {\n canvas.width = 640\n canvas.height = 360\n let ctx = canvas.getContext('2d')!\n\n ctx.fill()\n ctx.beginPath()\n\n ctx.fillStyle = 'rgb(0,0,0)'\n ctx.fillRect(0, 0, canvas.width, canvas.height)\n this.canvasTimer && clearTimeout(this.canvasTimer)\n\n this.canvasTimer = setTimeout(() => {\n this.canvasDisplay()\n }, 1000)\n }\n }\n\n private static getCanvasStream() {\n let canvas = document.getElementById('tarCanvas') as HTMLCanvasElement\n return canvas!.captureStream()\n }\n\n private async createVideoStream(): Promise<MediaStreamTrack> {\n // 适配PC 客户端获取不到设备的问题\n await this.room!.initDevices()\n this.videoStream?.destroy()\n this.videoStream = await this.room!.createPBSingleLocalStream({ video: true, audio: false }, this.localModel!.userId).catch(e => {\n return Promise.reject(BMCreateStreamError('视频'))\n })\n // this.videoStream?.on('video-track-mute', this.muteHandler.bind(this, 'video'))\n // this.videoStream?.on('video-track-ended', this.muteHandler.bind(this, 'video'))\n\n return this.videoStream!.getVideoTrack()!\n }\n\n /**\n * 启动录制\n * @param {String} opts.filename - 录制文件名\n * @param {Object} opts.capture - 采集属性\n * @param {Number} opts.capture.width - 宽度\n * @param {Number} opts.capture.height - 高度\n * @param {Number} opts.capture.fps - 帧率\n * @param {Number} opts.record - 编码属性\n * @param {Number} opts.record.bitrate - 编码码率\n * @param {String|undefined} opts.record.format - 编码格式\n * @return {boolean}\n */\n public async startRecord(opts: any) {\n if (this._recorder)\n return\n\n this._recorder = this.room?.boomCore.createRecorder(opts)\n\n this._recorder.on('track-ended', () => {\n this.stopRecord()\n logger.info('record ended')\n })\n this._recorder.on('started', () => {\n logger.info('record started.')\n })\n\n let success = true\n try {\n await this._recorder.start()\n this._isRecording = true\n this.isRecordingWatcher.next(true)\n\n this.shareStreamModels.forEach((mod) => {\n if (mod.stream && !mod.stream.isLocalStream() && (mod.stream as SingleRemoteStream).isSubscribed()) {\n this.addToRecorder(mod.stream)\n }\n })\n this.streamModels.forEach((mod) => {\n if (mod.stream && !mod.stream.isLocalStream() && (mod.stream as SingleRemoteStream).isSubscribed()) {\n this.addToRecorder(mod.stream)\n }\n })\n\n } catch (e) {\n let recorder = this._recorder\n this._recorder = undefined\n this._isRecording = false\n this.isRecordingWatcher.next(false)\n success = false\n await recorder.stop()\n }\n return success\n }\n\n /**\n * 添加流对象到录制器,用于音频轨道录制\n * @param stream\n */\n public addToRecorder(stream: SingleStream) {\n if (this._isRecording && !this._slicingRecord) {\n stream.on('audio-track-ended', () => {\n this.removeFromRecorder(stream)\n })\n this._recorder.addStream(stream)\n }\n }\n\n /**\n * 从录制器中删除流对象\n * @param stream\n */\n public removeFromRecorder(stream: any) {\n if (this._isRecording && !this._slicingRecord) {\n this._recorder.removeStream(stream)\n }\n }\n\n /**\n * 停止录制\n */\n public async stopRecord() {\n if (!this._recorder)\n return\n this._isRecording = false\n this.isRecordingWatcher.next(false)\n await this._recorder.stop()\n this._recorder = undefined\n }\n\n /**\n * 启用下一个录制分片\n * @param filename - 下一分片文件名\n */\n public async sliceRecord(filename: string) {\n if (!this._isRecording)\n return\n let opts = this._recorder._opts\n this._slicingRecord = true\n\n // stop current recorder\n try {\n await this._recorder.stop()\n } catch (e) {\n logger.error('stop record exception', '', '', [JSON.stringify(e)])\n }\n\n // create new recorder\n opts.filename = filename\n this._recorder = this.room?.boomCore.createRecorder(opts)\n\n this._recorder.on('track-ended', () => {\n this.stopRecord()\n logger.info('record ended.')\n })\n this._recorder.on('started', () => {\n logger.info('record started.')\n })\n\n let success = true\n try {\n await this._recorder.start()\n\n this._slicingRecord = false\n this.shareStreamModels.forEach((mod) => {\n if (mod.stream && !mod.stream.isLocalStream() && (mod.stream as SingleRemoteStream).isSubscribed()) {\n this.addToRecorder(mod.stream)\n }\n })\n this.streamModels.forEach((mod) => {\n if (mod.stream && !mod.stream.isLocalStream() && (mod.stream as SingleRemoteStream).isSubscribed()) {\n this.addToRecorder(mod.stream)\n }\n })\n\n } catch (e) {\n let recorder = this._recorder\n this._recorder = undefined\n this._isRecording = false\n this.isRecordingWatcher.next(false)\n this._slicingRecord = false\n success = false\n await recorder.stop()\n }\n return success\n }\n\n /**\n * 启动说话人检测器\n */\n public startSpeakerDetector() {\n this._speaker = null\n this._speakerDetector = this.room?.boomCore.createSpeakerDetector()\n this._speakerDetector.on('speaker', (speaker: any) => {\n let hasChanged = true\n if (speaker) {\n if (this._speaker?.getUserInfo().userId === speaker.getUser().userId) {\n hasChanged = false\n }\n this._speaker = speaker.getUser()\n } else {\n if (!this._speaker) {\n hasChanged = false\n }\n this._speaker = null\n }\n if (hasChanged) {\n logger.info('当前讲话人', '语音激励', this._speaker?.userId, ['nickname => ', this._speaker?.nickname])\n this.speakerWatcher.next(this._speaker)\n }\n })\n }\n\n public addToDetector(speaker: BMSpeaker) {\n this._speakers.set(speaker.getID(), speaker)\n if (this._speakerDetector) {\n this._speakerDetector.addStream(speaker)\n }\n }\n\n public removeFromDetector(speakerId: string) {\n let speaker = this._speakers.get(speakerId)\n if (this._speakerDetector && speaker) {\n this._speakers.delete(speakerId)\n this._speakerDetector.removeStream(speaker)\n }\n }\n\n public clearDetector() {\n const sIds: string[] = []\n this._speakers.forEach((k, i) => {\n sIds.push(i)\n })\n sIds.forEach((id) => {\n this.removeFromDetector(id)\n })\n }\n\n public async shareCustomMedia(enable: boolean, shareOptions: ShareMediaOptions) {\n return this.room?.boomCore.shareHTMLMedia(enable, shareOptions)\n }\n\n /**\n * 根据videoElement 获取内部流数据\n */\n public getHTMLMediaStream = getHTMLMediaStreamOptions\n public getMediaStream = getMediaStreamInfo\n\n /**\n * 更新流信息 会给服务端发送updateStream信令,会收到updateStream的广播\n */\n public updateBloudStreamCustomStats(uid: string, streamId: string, streamInfo: StreamCustomInfo) {\n return this.room?.boomCore.updateStream(uid, streamId, streamInfo)\n }\n\n /**\n * 布局发生变化之后去调用一下这个方法去检测所有流的播放状态\n * @param {string} status tag 用于区分是什么状态下调用的\n */\n public checkStreamStats(status: string) {\n logger.info('check stream stats', '', '', [status])\n if (this.streamModels.size < 100) {\n this.streamModels.forEach((mod) => {\n mod.checkStreamIsPlaying()\n })\n }\n }\n\n clearCache() {\n try {\n this.localModel?.stream?.destroy()\n this.videoStream?.destroy()\n this.audioStream?.destroy()\n }catch (e) {\n }\n this.streamModels.clear()\n this.shareStreamModels.clear()\n this.room?.userVM.clearUsers()\n this.shareBloudStateMap.clear()\n }\n}\n","/**\n * @name: getHTMLMediaStreamOptions\n * @author: yangliye\n * @date: 2022-09-15 14:58\n * @description:getHTMLMediaStreamOptions\n * @update: 2022-09-15 14:58\n */\n\ninterface Options {\n videoElement: HTMLVideoElement\n}\n\nexport interface Result {\n video: boolean\n audio: boolean\n videoSource: MediaStreamTrack\n audioSource: MediaStreamTrack\n width: number,\n height: number\n}\n\n/**\n * 获取video标签中的mediaStream\n * @param opts\n */\nexport function getHTMLMediaStreamOptions(opts: Options): Result | null {\n let localStream: MediaStream | null = null\n const videoElement = opts.videoElement\n const width = videoElement.offsetWidth\n const height = videoElement.offsetHeight\n if ((videoElement as any).captureStream) {\n localStream = (videoElement as any).captureStream();\n } else if ((videoElement as any).mozCaptureStream) {\n localStream = (videoElement as any).mozCaptureStream();\n }\n\n if (localStream) {\n const videoTrack = localStream.getVideoTracks()[0]\n const audioTrack = localStream.getAudioTracks()[0]\n return {\n video: !!videoTrack,\n audio: !!audioTrack,\n videoSource: videoTrack,\n audioSource: audioTrack,\n width,\n height\n }\n }\n\n return null\n}\n\nexport function getMediaStreamInfo(mediaStream: MediaStream, videoInfo: {width: number, height: number}) {\n try {\n const videoTrack = mediaStream.getVideoTracks()[0]\n const audioTrack = mediaStream.getAudioTracks()[0]\n return {\n video: !!videoTrack,\n audio: !!audioTrack,\n videoSource: videoTrack,\n audioSource: audioTrack,\n width: videoInfo.width,\n height: videoInfo.height\n }\n }catch (e) {\n console.log('获取共享音频参数有误', e)\n return null\n }\n}","/**\n * @name: BMRoomInfo\n * @author: yangliye\n * @date: 2022-05-18 13:52\n * @description:BMRoomInfo\n * @update: 2022-05-18 13:52\n */\nimport { BehaviorSubject, Subject } from 'rxjs'\nimport { audioOffWatcherValue } from '../type'\nimport BMRoom from './BMRoom'\nimport BMUser from '../BMUser/BMUser'\nimport { debounce } from 'lodash-es'\nimport BoomEmitter from '../util/emitter'\nimport { RAISE_HAND } from \"../constants\";\nimport { CloudRecord, FilePermission } from \"./BMRoomVM\";\n\ninterface OperationCustomStats {\n /**\n * 是否允许点赞 0 不可用 1可用\n */\n giveLikeEnable: 0 | 1,\n /**\n * 聊天是否可以用 0 不可用 1可用 2仅主持人 3嘉宾\n */\n chatEnable: 0 | 1 | 2 | 3,\n /**\n * 上传文档权限 设置-文档上传模式 0仅主持人 1 嘉宾 2 全员\n */\n fileUpdateModel: FilePermission,\n /**\n * 文档查看权限 设置-文档查看模式 0仅主持人 1 嘉宾 2 全员\n */\n fileUpdateLook: FilePermission,\n /**\n * 文档下载权限 设置-文档下载模式 0仅主持人 1 嘉宾 2 全员\n */\n fileUpdateDown: FilePermission,\n /**\n * 文档编辑权限 设置-文档编辑模式 0仅主持人 1 嘉宾 2 全员\n */\n fileUpdateEdit: FilePermission,\n /**\n * 共享屏幕权限 设置-屏幕共享模式 0仅主持人 1全员\n */\n screenShareModel: 0 | 1,\n /**\n * 是否仅一人共享 1:是 2:否\n */\n onlyOnePersonShare: 0 | 1,\n /**\n * 云录对象\n * recordStatus 录制状态:0=暂未开始,1=录制中,2=申请中\n * userId:开启人\n */\n cloudRecord: CloudRecord,\n /**\n * 入会时麦克风权限 0全员 1嘉宾 2主持人\n */\n joinAudioEnable: 0 | 1 | 2,\n /**\n * 入会时开启摄像头权限 0全员 1嘉宾 2主持人\n */\n joinVideoEnable: 0 | 1 | 2,\n /**\n * 参会者列表权限 0全员 1嘉宾 2主持人\n */\n userListEnable: 0 | 1 | 2,\n /**\n * 会议中是否允许开启麦克风 0全员 1嘉宾 2主持人\n */\n audioEnable: 0 | 1 | 2,\n /**\n * 会议中是否允许开启摄像头 0全员 1嘉宾 2主持人\n */\n videoEnable: 0 | 1 | 2,\n /**\n * 是否允许自行改名 0全员 1嘉宾\n */\n modifyNameEnable: 0 | 1\n /**\n * 是否允许开启虚拟背景 0全员 1嘉宾 2主持人\n */\n backgroundAIEnable: 0 | 1 | 2,\n /**\n * 是否允许举手 0禁止全员 1允许嘉宾 2全员可举手\n */\n raiseHandEnable: 0 | 1 | 2,\n /**\n * 入会提示音设置\n */\n joinCueVoice: 0 | 1\n}\n\nexport default class BMRoomInfo {\n\n private room: BMRoom | null = null;\n /**\n * 房间名\n */\n private _roomName = ''\n\n /**\n * 消息序列号\n */\n msgSeq = ''\n /**\n * 房间 号\n */\n public roomID = ''\n /**\n * 是否全员静音(业务端用)\n */\n public audioOff = false;\n /**\n * 是否可以自行开启(业务端用)\n */\n public selfopenaudio = false;\n\n /**\n * 是否锁定\n */\n public lock = false\n\n /**\n * 离开提示\n */\n private leaveNotice = false\n\n /**\n * 全员静音状态下是否允许打开麦克风\n * @private\n */\n private openSelf = false\n /**\n * 通知公告信息\n */\n public chatNotice = ''\n /**\n * 通知公告信息富文本\n */\n public chatNoticeRich = ''\n /**\n * 所有的音频举手人员\n */\n private raiseHandsList: Map<string, BMUser> = new Map()\n public raiseHandsWatcher = new BehaviorSubject(Array.from(this.raiseHandsList.values()))\n\n /**\n * 所有的视频举手的人员\n */\n private raiseVideoHandsList: Map<string, BMUser> = new Map()\n public raiseVideoHandsWatcher = new BehaviorSubject(Array.from(this.raiseVideoHandsList.values()))\n /**\n * 所有的举手的人员\n */\n private raiseSimpleHandsList: Map<string, BMUser> = new Map()\n public raiseSimpleHandsWatcher = new BehaviorSubject(Array.from(this.raiseSimpleHandsList.values()))\n\n public operationPermission: OperationCustomStats | undefined\n public operationPermissionWatcher = new Subject<OperationCustomStats>()\n\n public chatNoticeWatcher = new Subject()\n\n public totalUserWatcher = new BehaviorSubject(0)\n public totalWaitRoomUserWatcher = new BehaviorSubject(0)\n // 等候室状态更新之后,给端上的提示\n public isOpenWaitRoom = new Subject<boolean>()\n\n constructor() {\n BoomEmitter.emitter!.on(RAISE_HAND, (userInfo) => {\n if (userInfo.status === 'raiseHandsAudio') {\n if (userInfo.user.raiseAudioHands) {\n this.addRaiseHandUser(userInfo.user)\n } else {\n this.removeRaiseHandUser(userInfo.user.userId)\n }\n }\n else if (userInfo.status === 'raiseHandsVideo') {\n if (userInfo.user.raiseVideoHands) {\n this.addVideoRaiseHandUser(userInfo.user)\n } else {\n this.removeVideoRaiseHandUser(userInfo.user.userId)\n }\n } else if (userInfo.status === 'raiseHand') {\n if (userInfo.user.raiseHand) {\n this.addSimpleRaiseHandUser(userInfo.user)\n } else {\n this.removeSimpleRaiseHandUser(userInfo.user.userId)\n }\n }\n })\n }\n\n\n public get roomName() {\n if (this._roomName) {\n return this._roomName\n } else {\n this._roomName = this.room!.getName()\n return this._roomName\n }\n }\n\n /**\n * 判断是不是大房间使用\n */\n public get isBigRoom() {\n return this.room!.isBig\n }\n\n public setup(info: any) {\n this.roomID = info.room\n this.handleInitParams()\n }\n\n public bindRoom(room: BMRoom) {\n this.room = room\n }\n\n public initCustomStats(customStats: any) {\n this.operationPermission = customStats;\n if (customStats.chatNotice !== undefined) {\n this.chatNotice = customStats.chatNotice\n }\n if (customStats.chatNoticeRich !== undefined) {\n this.chatNoticeRich = customStats.chatNoticeRich\n }\n this.operationPermissionWatcher.next(this.operationPermission!)\n }\n\n public updateOperationPermission(stats: any) {\n this.operationPermission = {\n ...this.operationPermission,\n ...stats\n }\n //信令中stats是什么改变才会发什么,所以这里需要undefined判断\n if (stats.chatNotice !== undefined) {\n this.chatNotice = stats.chatNotice\n }\n if (stats.chatNoticeRich !== undefined) {\n this.chatNoticeRich = stats.chatNoticeRich\n }\n this.operationPermissionWatcher.next(this.operationPermission!)\n }\n\n private handleInitParams() {\n const audioOff = this.room!.boomCore.getAudioOff()\n const selfOpenAudio = this.room!.boomCore.getSelfOpenAudio()\n this.setAudioOff(audioOff, selfOpenAudio)\n // todo 初始化直播相关的信息,比如是否允许点赞,聊天是否可用,上传文档权限,共享屏幕权限等等\n }\n\n public audioOffWatcher = new Subject<audioOffWatcherValue>();//初始化时为值为null,用于区分初始化还是用户关闭全员静音, 解决业务端一初始化就弹出主持人关闭全员静音的问题\n public lockWatcher = new BehaviorSubject(this.lock)\n public leaveNoticeWatcher = new BehaviorSubject(this.leaveNotice)\n public openSelfWatcher = new BehaviorSubject(this.openSelf)\n\n /**\n * 设置是否全员静音\n * @param audioOff\n * @param selfopenaudio 是否可以自行开启\n */\n public setAudioOff(audioOff: boolean, selfopenaudio: boolean) {\n this.audioOff = audioOff;\n this.selfopenaudio = selfopenaudio\n this.audioOffWatcher.next({ audioOff, selfopenaudio })\n }\n\n /**\n * 设置是否锁定\n * @param lock\n */\n public setlock(lock: boolean) {\n this.lock = lock\n this.lockWatcher.next(lock)\n }\n\n public setLeaveNotice(leaveNotice: boolean) {\n this.leaveNotice = leaveNotice\n this.leaveNoticeWatcher.next(leaveNotice)\n }\n\n public setRaiseHandsList(userList: BMUser[]) {\n userList.forEach(user => {\n\n if (user.raiseAudioHands) {\n this.raiseHandsList.set(user.getID(), user)\n }\n if (user.raiseVideoHands) {\n this.raiseVideoHandsList.set(user.getID(), user)\n }\n if (user.raiseHand) {\n this.raiseSimpleHandsList.set(user.getID(), user)\n }\n\n\n })\n this.setRaiseHandsWatcherValue()\n this.setVideoRaiseHandsWatcherValue()\n this.setSimpleRaiseHandsWatcherValue()\n }\n\n /**\n * 音频举手处理\n * @param user\n */\n public addRaiseHandUser(user: BMUser) {\n this.raiseHandsList.set(user.getID(), user)\n this.setRaiseHandsWatcherValue()\n }\n\n /**\n * 取消音频举手处理\n * @param userId\n */\n public removeRaiseHandUser(userId: string) {\n this.raiseHandsList.delete(userId)\n this.setRaiseHandsWatcherValue()\n }\n\n\n /**\n * 视频申请处理\n * @param user\n */\n public addVideoRaiseHandUser(user: BMUser) {\n this.raiseVideoHandsList.set(user.getID(), user)\n this.setVideoRaiseHandsWatcherValue()\n }\n\n /**\n * 取消视频申请处理\n * @param userId\n */\n public removeVideoRaiseHandUser(userId: string) {\n this.raiseVideoHandsList.delete(userId)\n this.setVideoRaiseHandsWatcherValue()\n }\n /**\n * 举手处理\n * @param user\n */\n public addSimpleRaiseHandUser(user: BMUser) {\n this.raiseSimpleHandsList.set(user.getID(), user)\n this.setSimpleRaiseHandsWatcherValue()\n }\n\n /**\n * 取消举手处理\n * @param userId\n */\n public removeSimpleRaiseHandUser(userId: string) {\n this.raiseSimpleHandsList.delete(userId)\n this.setSimpleRaiseHandsWatcherValue()\n }\n\n private setRaiseHandsWatcherValue = debounce(() => {\n this.raiseHandsWatcher.next(Array.from(this.raiseHandsList.values()))\n }, 1000)\n\n private setVideoRaiseHandsWatcherValue = debounce(() => {\n this.raiseVideoHandsWatcher.next(Array.from(this.raiseVideoHandsList.values()))\n }, 1000)\n private setSimpleRaiseHandsWatcherValue = debounce(() => {\n this.raiseSimpleHandsWatcher.next(Array.from(this.raiseSimpleHandsList.values()))\n }, 1000)\n}","{\n \"name\": \"@hysc/meeting\",\n \"version\": \"5.0.117\",\n \"description\": \"boom meeting\",\n \"private\": false,\n \"main\": \"./dist/index.js\",\n \"module\": \"./dist/esm/index.js\",\n \"types\": \"./dist/index.d.ts\",\n \"files\": [\n \"dist\"\n ],\n \"scripts\": {\n \"build\": \"tsup ./src/index.ts --format cjs,esm --dts-resolve --minify --clean --legacy-output --sourcemap --dts\"\n },\n \"author\": \"yangliye\",\n \"license\": \"MIT\",\n \"dependencies\": {\n \"@hysc/bloud\": \"workspace:*\",\n \"@hysc/core\": \"workspace:*\",\n \"lodash-es\": \"^4.17.21\",\n \"mitt\": \"^3.0.0\",\n \"@hysc/p-queue\": \"6.3.0\",\n \"rxjs\": \"^7.5.5\",\n \"typescript\": \"^4.6.3\",\n \"@hysc/utils\": \"workspace:*\"\n },\n \"peerDependencies\": {\n \"@hysc/core\": \"workspace:*\"\n },\n \"devDependencies\": {\n \"@types/lodash-es\": \"^4.17.6\",\n \"@hysc/brtc\": \"workspace:*\"\n }\n}","/**\n * @name: BMLiveVM.ts\n * @author: yangliye\n * @date: 2022-07-15 13:53\n * @description:处理直播相关的流处理\n * @update: 2022-07-15 13:53\n */\nimport BMRoom from \"./BMRoom\";\nimport BMStreamModel from \"../BMStream/BMStreamModel\";\nimport { SingleRemoteStream } from \"../type\";\nimport { streamPullQueue } from \"../util/Pqueue\";\n\nclass BMLiveVM {\n private room: BMRoom\n\n constructor(room: BMRoom) {\n this.room = room\n }\n\n private get localBMUser() {\n return this.room.getLocalParticipant()\n }\n\n private get localIsAudience() {\n return this.room.getLocalParticipant().isAudience\n }\n\n\n /**\n * 拉流处理\n * @param bmStreamModel\n */\n public async handlePull(bmStreamModel: BMStreamModel) {\n if (this.localIsAudience && !this.localBMUser.audienceEnableSpeaking) {\n if (bmStreamModel.isMixer) {\n await this.room.handlePull(bmStreamModel)\n }\n } else {\n await this.room.handlePull(bmStreamModel)\n }\n }\n\n /**\n * 切换大小流处理\n * @param bmStreamModel\n */\n public async handleChangeStreamType(bmStreamModel: BMStreamModel) {\n await this.room.handleChangeStreamType(bmStreamModel)\n }\n\n public async handlePlay(bmStreamModel: BMStreamModel, noPlayChanged: boolean) {\n if (this.localIsAudience && !this.localBMUser.audienceEnableSpeaking) {\n if (bmStreamModel.isMixer) {\n await this.room.handlePlay(bmStreamModel, noPlayChanged, false)\n }\n } else {\n await this.room.handlePlay(bmStreamModel, noPlayChanged, true)\n }\n }\n\n /**\n * 处理观众端举手发言完了,然后在禁止发言,这个时候,没有必要在拉所有人的流,把除了混流的人的流都取消订阅,然后播放混流的声音\n */\n public async handleAudienceDisable() {\n this.room.bmStreamVm.getStreamModels().forEach(streamModel => {\n // 当前不在展示,而且没有音频流,就要取消订阅这股流\n if ((streamModel?.stream as SingleRemoteStream)?.isSubscribed() && streamModel.hasPulled) {\n streamModel.hasPulled = false\n streamModel.pulledStreamType = 'small'\n this.room.unsubscribe(streamModel.stream as SingleRemoteStream).then(() => {\n console.log('观众取消订阅这股流', streamModel.userId, streamModel.nickname, streamModel.isDisplay, streamModel.isCurrentDisplay)\n })\n }\n })\n const mixStreamModel = this.room.bmStreamVm.mixStreamModelWatcher.getValue()\n if (mixStreamModel) {\n await this.handlePlay(mixStreamModel, false)\n }\n }\n\n /**\n * 观众允许发言,允许发言之后,要把所有的流都拉,然后混流静音\n */\n public async handleAudienceEnable() {\n const mixStreamModel = this.room.bmStreamVm.mixStreamModelWatcher.getValue()\n if (mixStreamModel) {\n await this.handlePlay(mixStreamModel, false)\n }\n this.room.bmStreamVm.getStreamModels().forEach(streamModel => {\n streamPullQueue.addQueue(\n this.room.handleQueueTask.bind(this, streamModel),\n streamModel.streamId,\n 0,\n streamModel.nickname,\n )\n })\n }\n}\n\nexport default BMLiveVM","/**\n * @name: brtcNetEvent\n * @author: yangliye\n * @date: 2023-04-26 10:39\n * @description:brtcNetEvent\n * @update: 2023-04-26 10:39\n */\nimport BoomCore from \"@hysc/core\"\nimport { BRTC_ROOM_RECONNECTED, BRTC_ROOM_ROCONNECTING } from '@hysc/utils/events/brtcEvents'\n\nexport function addBrtcNetEvent(bcClient: BoomCore) {\n let fireBRTCREConnecting = () => bcClient.fire(BRTC_ROOM_ROCONNECTING)\n let fireBRTCREConnected = () => bcClient.fire(BRTC_ROOM_RECONNECTED)\n\n // 添加网络问题监听\n // @ts-ignore\n bcClient.brtcClient.client?.signal.channel.on('reconnecting', fireBRTCREConnecting)\n\n // @ts-ignore\n bcClient.brtcClient.client?.signal.channel.on('reconnected', fireBRTCREConnected)\n}","/**\n * @name: SingletonQueue\n * @author: yangliye\n * @date: 2023-05-18 09:47\n * @description:SingletonQueue\n * @update: 2023-05-18 09:47\n */\n\nimport * as logger from '../logger/logger'\n\n\ntype CallBack = (arg: Map<string, PullItem>, ...args: any) => void\nexport type PullItem = { id: string, isScreen: boolean, isWeb?: boolean, force?: boolean }\n\nexport default class SingletonQueue {\n private static instance: SingletonQueue\n private _callback: CallBack | undefined\n private pullMap: Map<string, PullItem> = new Map()\n constructor() {\n if (SingletonQueue.instance) {\n return SingletonQueue.instance\n }\n\n SingletonQueue.instance = this\n return this\n }\n\n addUsers(userIds: PullItem[]) {\n userIds.forEach(u => {\n if (u.isScreen) {\n this.pullMap.set(`${u.id}_screen`, u)\n }else {\n this.pullMap.set(u.id, u)\n }\n })\n if (this._callback) {\n this._callback(this.pullMap)\n }\n }\n\n removeUsers(userId: PullItem[]) {\n userId.forEach(u => {\n if (u.isScreen) {\n this.pullMap.delete(`${u.id}_screen`)\n }else {\n this.pullMap.delete(u.id)\n }\n })\n }\n\n restart() {\n if (this._callback) {\n this._callback(this.pullMap)\n }else {\n logger.error('no callback exists in streamQueue please setQueueProcessor first!')\n throw new Error('no callback')\n }\n }\n setQueueProcessor(callback: CallBack) {\n this._callback = callback\n }\n\n removeQueueProcessor() {\n this._callback = undefined\n }\n}\n\n\n","/**\n * @name: AudioPlay.ts\n * @author: yangliye\n * @date: 2023-06-08 16:35\n * @description:AudioPlay.ts\n * @update: 2023-06-08 16:35\n */\nimport { SingleRemoteStream, SingleStream } from \"../type\";\nimport { AudioPlayer } from '@hysc/core'\nimport * as logger from '../logger/logger'\nimport BMRoom from \"../BMRoom/BMRoom\";\nimport { Subject } from \"rxjs\";\nimport { isShareStream } from \"../util/roomUtils\";\nimport { transShareScreen2User } from \"../BMStream/BMStreamModelVM\";\nimport { sleep } from \"../util/Thread\";\n\nexport default class AudioPlay {\n playMap = new WeakSet<SingleStream>()\n playerMap = new Map<string, AudioPlayer>()\n container: HTMLDivElement | undefined\n muted = false\n room: BMRoom\n playStateChangeWatcher = new Subject<AudioPlayer>()\n deviceId?: string;\n\n constructor(containerId: string, room: BMRoom) {\n const container = document.getElementById(containerId) as HTMLDivElement\n if (container) {\n this.container = container\n }else {\n throw new Error('no container found, play failed')\n }\n this.room = room\n }\n\n addStream(stream: SingleRemoteStream, force = false) {\n if (this.room.shouldPlayAudio && this.room.autoPlayAudio && stream.isSubscribed()) {\n if (!this.playMap.has(stream) || force) {\n logger.info('add stream to player', '', stream.getUserId(), ['streamId ', stream.getStreamId()])\n this.playMap.add(stream)\n this.play(stream)\n }else {\n // logger.warn('stream is playing, replay', stream.getUserId())\n // const player = this.playerMap.get(stream.getStreamId())\n // if (player) {\n // player.replay(stream)\n // }\n }\n }\n }\n\n removeStream(stream: SingleStream) {\n const streamId = stream.getStreamId()\n let player = this.playerMap.get(streamId)\n if (player) {\n player.off()\n player.destroy()\n }\n logger.info('remove audio player', '', '', ['streamId =>', streamId])\n this.playerMap.delete(streamId)\n this.playMap.delete(stream)\n }\n\n removeStreamByUid(uid: string) {\n let players:Map<string, AudioPlayer> = new Map()\n this.playerMap.forEach(p => {\n if (!isShareStream(p.stream as SingleRemoteStream)) {\n if (p.stream.getUserId() === uid) {\n players.set(p.stream.getStreamId(), p)\n }\n }\n })\n\n players.forEach((p, sid) => {\n p.off()\n p.destroy()\n this.playerMap.delete(sid)\n this.playMap.delete(p.stream as SingleStream)\n })\n\n players.clear()\n }\n\n async play(stream: SingleRemoteStream) {\n if (stream.hasAudio() && this.container) {\n const player = new AudioPlayer(this.container, {})\n this.addPlayerEvent(player)\n await player.play(stream)\n\n if (this.deviceId) {\n await player.setSinkId(this.deviceId)\n }\n\n if (this.muted) {\n player.setVolume(0)\n }\n else {\n let sm\n const userId =transShareScreen2User(stream.getUserId().toString())\n if(isShareStream(stream)) {\n sm = this.room.bmStreamVm.shareStreamModels.get(userId)\n } else {\n sm = this.room.bmStreamVm.streamModels.get(userId)\n }\n\n if (sm) {\n const customInfo = sm.bloudStream?.customInfo\n if (customInfo && customInfo.volume) {\n player.audioLevel = customInfo.volume\n player.setVolume(customInfo.volume)\n }\n }\n }\n\n this.playerMap.set(stream.getStreamId(), player)\n }\n }\n\n mute(mute: boolean) {\n this.muted = mute\n if (mute) {\n this.playerMap.forEach(p => p.setVolume(0))\n }else {\n this.playerMap.forEach(p => {\n if (p.audioLevel > 0) {\n p.setVolume(p.audioLevel)\n }else {\n p.setVolume(1)\n }\n })\n }\n }\n\n setVolume(streamId: string, volume: number) {\n const player = this.playerMap.get(streamId)\n if (player) {\n player.audioLevel = volume\n if (this.muted) {\n return\n }\n player.setVolume(volume)\n }else {\n logger.error('设置了流的音量,但是没有找到对应的播放器', streamId)\n }\n }\n\n async setDevice(deviceId: string, force = false) {\n this.deviceId = deviceId\n if (force) {\n await sleep(2000)\n }\n\n this.playerMap.forEach(async p => {\n await p.setSinkId(deviceId)\n })\n }\n\n addPlayerEvent(player: AudioPlayer) {\n player.on('player-state-changed', (data: any) => {\n if (player.stream) {\n logger.info('audio player state change', '', '', [JSON.stringify(data)])\n if (data.type === 'error' && data.reason && data.reason.name === 'NotAllowedError') {\n this.playStateChangeWatcher.next(player)\n }\n if (data.state === 'PAUSED') {\n player.resume()\n }\n }\n })\n }\n\n clear() {\n logger.info('audio play clear')\n this.playerMap.forEach(player => player.destroy())\n this.playerMap.clear()\n this.playMap = new WeakSet()\n }\n\n destroy() {\n logger.info('audio play destroy')\n this.playerMap.forEach(player => player.destroy())\n this.playerMap.clear()\n this.playMap = new WeakSet()\n }\n}\n"],"mappings":"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","names":["src_exports","__export","src_default","__toCommonJS","import_core","BoomError","code","message","error","name","DEBUG","INFO","WARN","ERROR","EMPTY_FUNCTION","level","DEBUG","WARN","formatLog","msg","tag","userId","info","debug","msg","tag","userId","args","formatLog","info","warn","error","LogMap","DEBUG","debug","INFO","info","WARN","warn","ERROR","error","import_rxjs","RAW_UNDEFINED","WINDOW","RAW_UNDEFINED","GLOBAL","RAW_UNDEFINED","WINDOW","EMPTY_OBJECT","EMPTY_ARRAY","LOGGER_TAG_CLIENT","import_rxjs","STREAM_SUFFIX_SCREEN","MOBILE_STREAM_SUFFIX_SCREEN","SIGNAL_SUFFIX","RECEIVE_SUBSCRIBE_MESSAGE","USER_SORT_NUM_CHANGE","BIND_ELEMENT","HANDLE_STREAM_CONNECT_ERROR","RAISE_HAND","MANUAL_SUBSCRIPTION","UNSUBSCRIBE_STREAM","CHANG_IS_GUEST","BIND_BIG_ELEMENT","NO_CONTAINER","MODEL_SORT_NUM_CHANGE","ADD_PULL_USER","SET_VOLUME","ADD_AUDIO_PLAY","import_mitt","_BoomEmitter","mitt","_a","_b","_c","_d","_e","_f","_g","_h","_i","_j","_k","_l","_m","_n","RECEIVE_SUBSCRIBE_MESSAGE","USER_SORT_NUM_CHANGE","HANDLE_STREAM_CONNECT_ERROR","RAISE_HAND","UNSUBSCRIBE_STREAM","MANUAL_SUBSCRIPTION","CHANG_IS_GUEST","BIND_ELEMENT","BIND_BIG_ELEMENT","NO_CONTAINER","MODEL_SORT_NUM_CHANGE","ADD_PULL_USER","SET_VOLUME","ADD_AUDIO_PLAY","BoomEmitter","getSortNum","user","_selfSortType","sortZY","sortStand","sortNum","BMUser","user","isLocal","_a","defaultValue","userId","userinfo","nickname","STREAM_SUFFIX_SCREEN","model","isShare","stream","SIGNAL_SUFFIX","streamId","info","bcUser","participant","bmRoom","_b","_c","_d","_e","_f","customInfo","updateKeys","isRaiseHand","status","pos","BoomEmitter","RAISE_HAND","preIsGuest","CHANG_IS_GUEST","nickNameSuffix","force","shouldDelay","sortNum","getSortNum","USER_SORT_NUM_CHANGE","import_rxjs","RAW_UNDEFINED","RAW_FUNCTION","WINDOW","RAW_UNDEFINED","GLOBAL","RAW_UNDEFINED","WINDOW","EMPTY_OBJECT","EMPTY_ARRAY","EMPTY_STRING","func","value","RAW_FUNCTION","indexOf","str","part","start","has","str","part","indexOf","toString_default","target","defaultValue","EMPTY_STRING","isNative_default","target","func","has","toString_default","nextTick","RAW_FUNCTION","isNative_default","fn","channel","notGetTalkInterval","handleTime","timeStamp","listDate","currentDate","month","date","hours","minute","sortUsers","list","a","b","sortStreamModels","getIsCommonUser","permission","getPermission","getIsManager","getIsMaster","p","sleep","ms","resolve","import_lodash_es","ignoreUserId","BLOUD_PAGE_SIZE","PERMISSION_NOT_COMMON","BMUserVM","_BMUserVM","boomCore","localUser","room","bcUser","forceGetStream","_a","user","bmUser","error","sm","s","__async","_b","_c","video_enable","audio_enable","customInfo","item","map","userType","users","commonUsers","audiencesUsers","signalUsers","page","permission","useNew","failedNum","allUsers","raiseHandsUsers","BoomEmitter","CHANG_IS_GUEST","USER_SORT_NUM_CHANGE","info","isGuest","preIsGuest","isBigRoom","localIsCommonUser","streamModel","LOGGER_TAG_CLIENT","userId","foundUser","warn","BoomError","masterId","SIGNAL_SUFFIX","pageIndex","usersInRoom","total","u","bmuser","oldMasterId","isKeep","master","oldMaster","status","hasS","_d","_e","nextIsMaster","nextIsManager","getIsManager","getIsMaster","operation","currentIsMaster","currentRaiseHand","nextRaiseHand","currentVideoRaiseHand","nextVideoRaiseHand","currentAudioRaiseHand","nextAudioRaiseHand","currentNickname","nextNickname","getIsCommonUser","userMsg","BMUser","sortUsers","ignore","pullCount","pullPage","pullQueue","loop","pullBloudUsers","f","sleep","newBMStreamModels","pageSize","userList","waitRoom","getUsers","init","resolve","r","e","reject","searchTxt","commonUserList","cUser","err","searUsers","BMMessageInfo","props","isMeetingNotice","handleTime","import_lodash_es","isShareStream","remoteStream","streamId","STREAM_SUFFIX_SCREEN","MOBILE_STREAM_SUFFIX_SCREEN","import_lodash_es","import_utils","BRTCEvents","checkStreamIsNormal","streamModel","_a","_b","_c","_d","warn","handleBloudReconnectStreamEvent","bmStreamVm","_a","_b","localModel","info","audioEnable","videoEnable","shareStream","e","error","handleReconnectedStream","bmRoom","handleStreamPublished","event","observes","stream","localStreamModel","streamModel","handleBloudStreamPublished","data","handleBloudStreamPubAUpdate","isPublish","userId","isScreen","sm","item","handleBloudStreamUnPublished","handleBloudStreamUnpublish","handleBloudStreamUpdated","streamId","customInfo","_c","shareStreamModel","bsm","handleShareStreamFailed","__async","warn","import_utils","setupRoomInfo","data","bmRoom","userVM","localPermission","total","waitroom","audiooff","selfopenaudio","handleRoomConnected","observes","shouldNotification","__async","_a","info","handleInitRoomInfo","handleInitJoinRoomUsers","handleRoomUpdated","exitUserUpdateStream","userVm","u","bcu","bmStreamVm","streams","streamModel","error","shareModel","e","bsm","addUsers","users","user","handleRoomSync","localUserId","local","localIsCommonUser","PERMISSION_NOT_COMMON","pullCount","BLOUD_PAGE_SIZE","allUsers","i","usersInRoom","handleBrtcRoomReconnecting","BRTCEvents","handleBrtcRoomReconnected","handleReconnectedStream","handleBloudRoomReconnecting","handleBloudRoomReconnected","handleBloudRoomSync","handleBloudReconnectStreamEvent","import_bloudEvents","handleParticipantJoin","data","userVM","bmStreamVm","boomCore","chatVM","observes","_a","_b","_c","_d","_e","_f","_g","_h","_i","_j","_k","_l","_m","sync","mode","info","shouldDelay","hasRoleChanged","user","getIsCommonUser","bmUser","shouldIgnore","ignoreUserId","suffix","message","BMMessageInfo","handleLeaveUsers","bmRoom","userIds","u","leaveUser","sendLeveNotification","handleParticipantLeft","isPermissionChanged","uid","removedUser","warn","LOGGER_TAG_CLIENT","shouldNitify","handleChangeMaster","masterId","oldMasterId","isKeep","users","oldStream","newStream","handleEvict","evictedUser","handleUpdateUser","streamModel","handleUserRejoined","observes","data","handleMoveUserRoom","bmRoom","userVM","__async","info","toWait","localModel","v","audiooff","selfopenaudio","lock","handleRoomConnected","handleInitJoinRoomUsers","import_utils","handleSendMessage","msg","userVM","chatVM","observes","_a","_b","_c","_d","_e","_f","_g","_h","_i","_msg","__spreadValues","info","isLocal","msgStr","avatar","seq","message","BMMessageInfo","handleCustomMessage","bmRoom","_j","_k","_l","_m","status","total","warn","import_utils","reconnectFailed","shareReconnectFailed","NETWORK_ERROR_QUEUE","handleBRTCRoomError","data","bmRoom","boomCore","bmStreamVm","observes","__async","error","warn","e","reconnectBrtcWS","info","BRTCEvents","resolve","reject","handleReconnectedStream","reconnectFailed","code","reconnectBRTCShareWS","boomCore","__async","resolve","reject","info","shareReconnectFailed","e","code","error","handleBloudError","bmRoom","bmStreamVm","data","observes","handleBloudRoomReconnected","import_utils","handleCustomStats","data","bmRoom","observes","updateKeys","info","import_p_queue","Pqueue","maxTask","isStart","PQueue","status","fn","taskId","priority","nickName","temp","index","item","res","streamPullQueue","eventQueue","import_utils","attachEvents","boomCore","userVM","bmStreamVm","chatVM","bmRoom","info","observes","error","__async","data","reconnectBRTCShareWS","sleep","audioEnable","videoEnable","e","err","allEvents","BRTCEvents","CustomEvent","event","eventKey","eventQueue","handleStreamPublished","handleShareStreamFailed","handleBrtcRoomReconnecting","handleBrtcRoomReconnected","handleUserRejoined","handleBRTCRoomError","NETWORK_ERROR_QUEUE","handleRoomConnected","handleInitJoinRoomUsers","handleParticipantJoin","handleParticipantLeft","handleLeaveUsers","handleChangeMaster","msg","handleSendMessage","handleCustomMessage","handleEvict","handleUpdateUser","handleRoomUpdated","handleCustomStats","handleBloudError","handleBloudRoomReconnecting","handleBloudRoomReconnected","handleBloudRoomSync","handleBloudStreamPublished","handleBloudStreamUnPublished","handleBloudStreamUpdated","handleBloudStreamPubAUpdate","handleMoveUserRoom","import_utils","import_rxjs","BMRoomVM","boomCore","userVM","roomInfo","room","userId","withoutBlack","__async","error","info","e","isKeep","_a","LOGGER_TAG_CLIENT","status","hasS","nickName","nickInfo","message","uid","err","isNotCancelRootReport","_status","msg","richMsg","time","type","raise","localUserId","raiseInfo","raiseHandsType","raiseHands","_b","_c","audioRaiseHands","videoRaiseHands","simpleHands","user","BoomError","stats","replace","notice","richNotice","showTipNotice","enable","sendTime","localUser","permission","userid","layoutData","deviceList","__spreadProps","__spreadValues","videoInfo","profile","profileInfo","import_rxjs","import_lodash_es","BMChatVM","boomCore","userVM","bmRoom","talkMsg","userId","lostNet","__async","_talkMsg","sendTime","message","localUser","isDanger","seq","failed","r","e","warn","messageInfo","BMMessageInfo","err","error","LOGGER_TAG_CLIENT","BoomError","info","isParticipantNotice","notGetTalkInterval","messageList","respMsgs","userInfoArr","msgData","msgObj","content","userInfo","import_rxjs","import_core","BMSpeaker","user","stream","import_lodash_es","getMasterSort","a","v","getLocalSort","getManagerSort","getGuestSort","namespace","BMStreamModel","user","stream","display","_a","state","_b","info","BoomEmitter","HANDLE_STREAM_CONNECT_ERROR","eleId","RECEIVE_SUBSCRIBE_MESSAGE","BIND_ELEMENT","BIND_BIG_ELEMENT","containerId","container","canGetPlayer","playerNum","failedPlayerNum","players","player","__async","playerState","warn","NO_CONTAINER","e","error","playState","level","bigElement","canGetBigElement","value","type","mute","subscribeOptions","enable","needReProcess","bmStreamVm","hasVideo","hasAudio","BMSpeaker","streamState","bmStreamVM","forceSearch","_c","_d","videoChanged","audioChanged","ADD_PULL_USER","ADD_AUDIO_PLAY","customInfo","STREAM_SUFFIX_SCREEN","volume","SET_VOLUME","videoId","data","pos","force","sortNum","MODEL_SORT_NUM_CHANGE","getMasterSort","getLocalSort","getManagerSort","getGuestSort","smallElement","videoContainer","MANUAL_SUBSCRIPTION","UNSUBSCRIBE_STREAM","import_rxjs","import_utils","import_lodash_es","import_utils","getHTMLMediaStreamOptions","opts","localStream","videoElement","width","height","videoTrack","audioTrack","getMediaStreamInfo","mediaStream","videoInfo","e","transShareScreen2User","userId","namespace","BMStreamModelVM","_BMStreamModelVM","streamModels","info","type","container","id","sm","getHTMLMediaStreamOptions","getMediaStreamInfo","BoomEmitter","MODEL_SORT_NUM_CHANGE","NO_CONTAINER","item","ignoreUserId","ignore","room","enable","_a","user","stream","newStreamModel","BMStreamModel","STREAM_SUFFIX_SCREEN","streamModel","uid","_b","_c","_d","e","streamId","realUserId","isShareStream","ssm","streamModelShare","videoEnable","audioEnable","shareState","error","isShare","realUid","MOBILE_STREAM_SUFFIX_SCREEN","ssid","sortStreamModels","status","videoTrack","__async","localModel","res","_e","audio","video","localStreamModel","device","force","selectSpeakerDevice","_f","_g","_h","canvasStream","audioTrack","localModelId","handleUnpublish","_i","_j","_k","_l","_m","_n","_o","_p","_q","muted","label","enabled","readyState","ended","mute","getOn","opts","customShare","voiceMode","shareStream","contentHint","canvas","ctx","success","mod","recorder","filename","speaker","hasChanged","speakerId","sIds","k","i","shareOptions","streamInfo","import_rxjs","import_lodash_es","BMRoomInfo","BoomEmitter","RAISE_HAND","userInfo","info","room","customStats","stats","__spreadValues","audioOff","selfOpenAudio","selfopenaudio","lock","leaveNotice","userList","user","userId","import_rxjs","package_default","import_utils","BMLiveVM","room","bmStreamModel","__async","noPlayChanged","streamModel","_a","mixStreamModel","streamPullQueue","BMLiveVM_default","import_lodash_es","import_brtcEvents","addBrtcNetEvent","bcClient","_a","_b","fireBRTCREConnecting","fireBRTCREConnected","SingletonQueue","_SingletonQueue","userIds","u","userId","error","callback","import_core","import_rxjs","AudioPlay","containerId","room","container","stream","force","info","streamId","player","uid","players","p","isShareStream","sid","__async","_a","sm","userId","transShareScreen2User","customInfo","mute","volume","error","deviceId","sleep","data","_selfSortType","subscribeOptions","autoPlayAudio","BMRoom","initDevices","SingletonQueue","info","sn","__async","audioDevice","device","streamModel","noPlayChanged","warn","stream","audioEnable","videoEnable","uIds","realNeedQuery","u","shareStreamModel","user","streams","streamInfo","s","e","error","package_default","emitter","BoomEmitter","BMUser","BMRoomInfo","BMLiveVM_default","BMStreamModelVM","BoomCore","RECEIVE_SUBSCRIBE_MESSAGE","event","HANDLE_STREAM_CONNECT_ERROR","ADD_PULL_USER","MANUAL_SUBSCRIPTION","UNSUBSCRIBE_STREAM","BIND_ELEMENT","BIND_BIG_ELEMENT","SET_VOLUME","_a","ADD_AUDIO_PLAY","sm","NETWORK_ERROR_QUEUE","fn","v","mode","value","permission","__spreadValues","playerContainerId","AudioPlay","options","streamPullQueue","profile","column","col","type","sortType","audioProfile","sig","devices","videoDevices","item","videoDevice","audioDevices","speakerDevices","speakerDevice","observeName","subscribeParam","props","brtc_host","BMUserVM","BMRoomVM","BMChatVM","bcError","key","addBrtcNetEvent","_b","result","opts","filename","status","uid","err","isNotCancelRootReport","videoTrack","attachEvents","sid","initOptions","remoteStream","resolve","reject","userId","isKeep","hasS","withoutBlack","target","message","to","startSeq","endSeq","localUser","audiooff","selfopenaudio","videooff","msgoff","switch_","lock","msg","lostNet","BoomError","customStats","__spreadProps","nickName","_c","_d","_e","checkStreamIsNormal","isScreen","shouldPlayBig","sId","isLocal","handleShareStreamFailed","bmUser","toWait","autoJoin","url","localStream","m","STREAM_SUFFIX_SCREEN","handleReconnectedStream","pullItem","uids","isShareStream","transShareScreen2User","forceId","users","import_utils","src_default","BMRoom","BMRoom"]}