@webex/plugin-meetings 3.0.0-beta.4 → 3.0.0-beta.400

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 (629) hide show
  1. package/README.md +58 -8
  2. package/UPGRADING.md +9 -9
  3. package/browsers.js +19 -24
  4. package/dist/annotation/annotation.types.js +7 -0
  5. package/dist/annotation/annotation.types.js.map +1 -0
  6. package/dist/annotation/constants.js +49 -0
  7. package/dist/annotation/constants.js.map +1 -0
  8. package/dist/annotation/index.js +342 -0
  9. package/dist/annotation/index.js.map +1 -0
  10. package/dist/breakouts/breakout.js +216 -0
  11. package/dist/breakouts/breakout.js.map +1 -0
  12. package/dist/breakouts/collection.js +23 -0
  13. package/dist/breakouts/collection.js.map +1 -0
  14. package/dist/breakouts/edit-lock-error.js +52 -0
  15. package/dist/breakouts/edit-lock-error.js.map +1 -0
  16. package/dist/breakouts/events.js +45 -0
  17. package/dist/breakouts/events.js.map +1 -0
  18. package/dist/breakouts/index.js +1048 -0
  19. package/dist/breakouts/index.js.map +1 -0
  20. package/dist/breakouts/request.js +78 -0
  21. package/dist/breakouts/request.js.map +1 -0
  22. package/dist/breakouts/utils.js +67 -0
  23. package/dist/breakouts/utils.js.map +1 -0
  24. package/dist/common/browser-detection.js +1 -20
  25. package/dist/common/browser-detection.js.map +1 -1
  26. package/dist/common/collection.js +5 -20
  27. package/dist/common/collection.js.map +1 -1
  28. package/dist/common/config.js +0 -7
  29. package/dist/common/config.js.map +1 -1
  30. package/dist/common/errors/captcha-error.js +10 -24
  31. package/dist/common/errors/captcha-error.js.map +1 -1
  32. package/dist/common/errors/intent-to-join.js +11 -24
  33. package/dist/common/errors/intent-to-join.js.map +1 -1
  34. package/dist/common/errors/join-meeting.js +12 -25
  35. package/dist/common/errors/join-meeting.js.map +1 -1
  36. package/dist/common/errors/media.js +10 -24
  37. package/dist/common/errors/media.js.map +1 -1
  38. package/dist/common/errors/no-meeting-info.js +51 -0
  39. package/dist/common/errors/no-meeting-info.js.map +1 -0
  40. package/dist/common/errors/parameter.js +5 -33
  41. package/dist/common/errors/parameter.js.map +1 -1
  42. package/dist/common/errors/password-error.js +10 -24
  43. package/dist/common/errors/password-error.js.map +1 -1
  44. package/dist/common/errors/permission.js +9 -23
  45. package/dist/common/errors/permission.js.map +1 -1
  46. package/dist/common/errors/reclaim-host-role-errors.js +158 -0
  47. package/dist/common/errors/reclaim-host-role-errors.js.map +1 -0
  48. package/dist/common/errors/reconnection-in-progress.js +0 -17
  49. package/dist/common/errors/reconnection-in-progress.js.map +1 -1
  50. package/dist/common/errors/reconnection.js +10 -24
  51. package/dist/common/errors/reconnection.js.map +1 -1
  52. package/dist/common/errors/stats.js +10 -24
  53. package/dist/common/errors/stats.js.map +1 -1
  54. package/dist/common/errors/webex-errors.js +54 -48
  55. package/dist/common/errors/webex-errors.js.map +1 -1
  56. package/dist/common/errors/webex-meetings-error.js +5 -25
  57. package/dist/common/errors/webex-meetings-error.js.map +1 -1
  58. package/dist/common/events/events-scope.js +0 -22
  59. package/dist/common/events/events-scope.js.map +1 -1
  60. package/dist/common/events/events.js +0 -23
  61. package/dist/common/events/events.js.map +1 -1
  62. package/dist/common/events/trigger-proxy.js +0 -12
  63. package/dist/common/events/trigger-proxy.js.map +1 -1
  64. package/dist/common/events/util.js +0 -15
  65. package/dist/common/events/util.js.map +1 -1
  66. package/dist/common/logs/logger-config.js +0 -4
  67. package/dist/common/logs/logger-config.js.map +1 -1
  68. package/dist/common/logs/logger-proxy.js +1 -8
  69. package/dist/common/logs/logger-proxy.js.map +1 -1
  70. package/dist/common/logs/request.js +41 -60
  71. package/dist/common/logs/request.js.map +1 -1
  72. package/dist/common/queue.js +28 -23
  73. package/dist/common/queue.js.map +1 -1
  74. package/dist/config.js +11 -15
  75. package/dist/config.js.map +1 -1
  76. package/dist/constants.js +347 -74
  77. package/dist/constants.js.map +1 -1
  78. package/dist/controls-options-manager/constants.js +14 -0
  79. package/dist/controls-options-manager/constants.js.map +1 -0
  80. package/dist/controls-options-manager/enums.js +27 -0
  81. package/dist/controls-options-manager/enums.js.map +1 -0
  82. package/dist/controls-options-manager/index.js +297 -0
  83. package/dist/controls-options-manager/index.js.map +1 -0
  84. package/dist/controls-options-manager/types.js +7 -0
  85. package/dist/controls-options-manager/types.js.map +1 -0
  86. package/dist/controls-options-manager/util.js +319 -0
  87. package/dist/controls-options-manager/util.js.map +1 -0
  88. package/dist/index.js +125 -18
  89. package/dist/index.js.map +1 -1
  90. package/dist/interceptors/index.js +15 -0
  91. package/dist/interceptors/index.js.map +1 -0
  92. package/dist/interceptors/locusRetry.js +93 -0
  93. package/dist/interceptors/locusRetry.js.map +1 -0
  94. package/dist/interpretation/collection.js +23 -0
  95. package/dist/interpretation/collection.js.map +1 -0
  96. package/dist/interpretation/index.js +380 -0
  97. package/dist/interpretation/index.js.map +1 -0
  98. package/dist/interpretation/siLanguage.js +25 -0
  99. package/dist/interpretation/siLanguage.js.map +1 -0
  100. package/dist/locus-info/controlsUtils.js +101 -29
  101. package/dist/locus-info/controlsUtils.js.map +1 -1
  102. package/dist/locus-info/embeddedAppsUtils.js +3 -26
  103. package/dist/locus-info/embeddedAppsUtils.js.map +1 -1
  104. package/dist/locus-info/fullState.js +0 -15
  105. package/dist/locus-info/fullState.js.map +1 -1
  106. package/dist/locus-info/hostUtils.js +4 -12
  107. package/dist/locus-info/hostUtils.js.map +1 -1
  108. package/dist/locus-info/index.js +564 -246
  109. package/dist/locus-info/index.js.map +1 -1
  110. package/dist/locus-info/infoUtils.js +10 -38
  111. package/dist/locus-info/infoUtils.js.map +1 -1
  112. package/dist/locus-info/mediaSharesUtils.js +82 -38
  113. package/dist/locus-info/mediaSharesUtils.js.map +1 -1
  114. package/dist/locus-info/parser.js +314 -163
  115. package/dist/locus-info/parser.js.map +1 -1
  116. package/dist/locus-info/selfUtils.js +110 -92
  117. package/dist/locus-info/selfUtils.js.map +1 -1
  118. package/dist/media/index.js +107 -231
  119. package/dist/media/index.js.map +1 -1
  120. package/dist/media/properties.js +137 -222
  121. package/dist/media/properties.js.map +1 -1
  122. package/dist/media/util.js +2 -9
  123. package/dist/media/util.js.map +1 -1
  124. package/dist/mediaQualityMetrics/config.js +316 -501
  125. package/dist/mediaQualityMetrics/config.js.map +1 -1
  126. package/dist/meeting/in-meeting-actions.js +97 -14
  127. package/dist/meeting/in-meeting-actions.js.map +1 -1
  128. package/dist/meeting/index.js +5311 -3871
  129. package/dist/meeting/index.js.map +1 -1
  130. package/dist/meeting/locusMediaRequest.js +292 -0
  131. package/dist/meeting/locusMediaRequest.js.map +1 -0
  132. package/dist/meeting/muteState.js +260 -183
  133. package/dist/meeting/muteState.js.map +1 -1
  134. package/dist/meeting/request.js +421 -347
  135. package/dist/meeting/request.js.map +1 -1
  136. package/dist/meeting/request.type.js +7 -0
  137. package/dist/meeting/request.type.js.map +1 -0
  138. package/dist/meeting/state.js +21 -31
  139. package/dist/meeting/state.js.map +1 -1
  140. package/dist/meeting/util.js +672 -585
  141. package/dist/meeting/util.js.map +1 -1
  142. package/dist/meeting/voicea-meeting.js +172 -0
  143. package/dist/meeting/voicea-meeting.js.map +1 -0
  144. package/dist/meeting-info/collection.js +6 -25
  145. package/dist/meeting-info/collection.js.map +1 -1
  146. package/dist/meeting-info/index.js +87 -39
  147. package/dist/meeting-info/index.js.map +1 -1
  148. package/dist/meeting-info/meeting-info-v2.js +352 -283
  149. package/dist/meeting-info/meeting-info-v2.js.map +1 -1
  150. package/dist/meeting-info/request.js +3 -15
  151. package/dist/meeting-info/request.js.map +1 -1
  152. package/dist/meeting-info/util.js +99 -183
  153. package/dist/meeting-info/util.js.map +1 -1
  154. package/dist/meeting-info/utilv2.js +147 -234
  155. package/dist/meeting-info/utilv2.js.map +1 -1
  156. package/dist/meetings/collection.js +43 -19
  157. package/dist/meetings/collection.js.map +1 -1
  158. package/dist/meetings/index.js +895 -600
  159. package/dist/meetings/index.js.map +1 -1
  160. package/dist/meetings/meetings.types.js +7 -0
  161. package/dist/meetings/meetings.types.js.map +1 -0
  162. package/dist/meetings/request.js +26 -41
  163. package/dist/meetings/request.js.map +1 -1
  164. package/dist/meetings/util.js +184 -157
  165. package/dist/meetings/util.js.map +1 -1
  166. package/dist/member/index.js +134 -85
  167. package/dist/member/index.js.map +1 -1
  168. package/dist/member/types.js +25 -0
  169. package/dist/member/types.js.map +1 -0
  170. package/dist/member/util.js +158 -88
  171. package/dist/member/util.js.map +1 -1
  172. package/dist/members/collection.js +13 -12
  173. package/dist/members/collection.js.map +1 -1
  174. package/dist/members/index.js +194 -204
  175. package/dist/members/index.js.map +1 -1
  176. package/dist/members/request.js +113 -68
  177. package/dist/members/request.js.map +1 -1
  178. package/dist/members/types.js +15 -0
  179. package/dist/members/types.js.map +1 -0
  180. package/dist/members/util.js +324 -259
  181. package/dist/members/util.js.map +1 -1
  182. package/dist/metrics/constants.js +19 -7
  183. package/dist/metrics/constants.js.map +1 -1
  184. package/dist/metrics/index.js +11 -558
  185. package/dist/metrics/index.js.map +1 -1
  186. package/dist/multistream/mediaRequestManager.js +263 -50
  187. package/dist/multistream/mediaRequestManager.js.map +1 -1
  188. package/dist/multistream/receiveSlot.js +58 -65
  189. package/dist/multistream/receiveSlot.js.map +1 -1
  190. package/dist/multistream/receiveSlotManager.js +76 -95
  191. package/dist/multistream/receiveSlotManager.js.map +1 -1
  192. package/dist/multistream/remoteMedia.js +62 -76
  193. package/dist/multistream/remoteMedia.js.map +1 -1
  194. package/dist/multistream/remoteMediaGroup.js +82 -45
  195. package/dist/multistream/remoteMediaGroup.js.map +1 -1
  196. package/dist/multistream/remoteMediaManager.js +657 -448
  197. package/dist/multistream/remoteMediaManager.js.map +1 -1
  198. package/dist/multistream/sendSlotManager.js +255 -0
  199. package/dist/multistream/sendSlotManager.js.map +1 -0
  200. package/dist/networkQualityMonitor/index.js +40 -59
  201. package/dist/networkQualityMonitor/index.js.map +1 -1
  202. package/dist/personal-meeting-room/index.js +21 -45
  203. package/dist/personal-meeting-room/index.js.map +1 -1
  204. package/dist/personal-meeting-room/request.js +1 -31
  205. package/dist/personal-meeting-room/request.js.map +1 -1
  206. package/dist/personal-meeting-room/util.js +0 -13
  207. package/dist/personal-meeting-room/util.js.map +1 -1
  208. package/dist/reachability/clusterReachability.js +356 -0
  209. package/dist/reachability/clusterReachability.js.map +1 -0
  210. package/dist/reachability/index.js +297 -460
  211. package/dist/reachability/index.js.map +1 -1
  212. package/dist/reachability/request.js +20 -26
  213. package/dist/reachability/request.js.map +1 -1
  214. package/dist/reachability/util.js +29 -0
  215. package/dist/reachability/util.js.map +1 -0
  216. package/dist/reactions/constants.js +13 -0
  217. package/dist/reactions/constants.js.map +1 -0
  218. package/dist/reactions/reactions.js +109 -0
  219. package/dist/reactions/reactions.js.map +1 -0
  220. package/dist/reactions/reactions.type.js +36 -0
  221. package/dist/reactions/reactions.type.js.map +1 -0
  222. package/dist/reconnection-manager/index.js +413 -483
  223. package/dist/reconnection-manager/index.js.map +1 -1
  224. package/dist/recording-controller/enums.js +17 -0
  225. package/dist/recording-controller/enums.js.map +1 -0
  226. package/dist/recording-controller/index.js +362 -0
  227. package/dist/recording-controller/index.js.map +1 -0
  228. package/dist/recording-controller/util.js +64 -0
  229. package/dist/recording-controller/util.js.map +1 -0
  230. package/dist/roap/index.js +102 -86
  231. package/dist/roap/index.js.map +1 -1
  232. package/dist/roap/request.js +131 -135
  233. package/dist/roap/request.js.map +1 -1
  234. package/dist/roap/turnDiscovery.js +437 -116
  235. package/dist/roap/turnDiscovery.js.map +1 -1
  236. package/dist/rtcMetrics/constants.js +12 -0
  237. package/dist/rtcMetrics/constants.js.map +1 -0
  238. package/dist/rtcMetrics/index.js +179 -0
  239. package/dist/rtcMetrics/index.js.map +1 -0
  240. package/dist/statsAnalyzer/global.js +1 -95
  241. package/dist/statsAnalyzer/global.js.map +1 -1
  242. package/dist/statsAnalyzer/index.js +557 -583
  243. package/dist/statsAnalyzer/index.js.map +1 -1
  244. package/dist/statsAnalyzer/mqaUtil.js +326 -130
  245. package/dist/statsAnalyzer/mqaUtil.js.map +1 -1
  246. package/dist/transcription/index.js +22 -47
  247. package/dist/transcription/index.js.map +1 -1
  248. package/dist/types/annotation/annotation.types.d.ts +42 -0
  249. package/dist/types/annotation/constants.d.ts +31 -0
  250. package/dist/types/annotation/index.d.ts +117 -0
  251. package/dist/types/breakouts/breakout.d.ts +8 -0
  252. package/dist/types/breakouts/collection.d.ts +5 -0
  253. package/dist/types/breakouts/edit-lock-error.d.ts +15 -0
  254. package/dist/types/breakouts/events.d.ts +8 -0
  255. package/dist/types/breakouts/index.d.ts +5 -0
  256. package/dist/types/breakouts/request.d.ts +22 -0
  257. package/dist/types/breakouts/utils.d.ts +15 -0
  258. package/dist/types/common/browser-detection.d.ts +9 -0
  259. package/dist/types/common/collection.d.ts +48 -0
  260. package/dist/types/common/config.d.ts +2 -0
  261. package/dist/types/common/errors/captcha-error.d.ts +15 -0
  262. package/dist/types/common/errors/intent-to-join.d.ts +16 -0
  263. package/dist/types/common/errors/join-meeting.d.ts +17 -0
  264. package/dist/types/common/errors/media.d.ts +15 -0
  265. package/dist/types/common/errors/no-meeting-info.d.ts +14 -0
  266. package/dist/types/common/errors/parameter.d.ts +15 -0
  267. package/dist/types/common/errors/password-error.d.ts +15 -0
  268. package/dist/types/common/errors/permission.d.ts +14 -0
  269. package/dist/types/common/errors/reclaim-host-role-errors.d.ts +60 -0
  270. package/dist/types/common/errors/reconnection-in-progress.d.ts +9 -0
  271. package/dist/types/common/errors/reconnection.d.ts +15 -0
  272. package/dist/types/common/errors/stats.d.ts +15 -0
  273. package/dist/types/common/errors/webex-errors.d.ts +93 -0
  274. package/dist/types/common/errors/webex-meetings-error.d.ts +20 -0
  275. package/dist/types/common/events/events-scope.d.ts +17 -0
  276. package/dist/types/common/events/events.d.ts +12 -0
  277. package/dist/types/common/events/trigger-proxy.d.ts +2 -0
  278. package/dist/types/common/events/util.d.ts +2 -0
  279. package/dist/types/common/logs/logger-config.d.ts +2 -0
  280. package/dist/types/common/logs/logger-proxy.d.ts +2 -0
  281. package/dist/types/common/logs/request.d.ts +36 -0
  282. package/dist/types/common/queue.d.ts +34 -0
  283. package/dist/types/config.d.ts +72 -0
  284. package/dist/types/constants.d.ts +1088 -0
  285. package/dist/types/controls-options-manager/constants.d.ts +4 -0
  286. package/dist/types/controls-options-manager/enums.d.ts +15 -0
  287. package/dist/types/controls-options-manager/index.d.ts +136 -0
  288. package/dist/types/controls-options-manager/types.d.ts +43 -0
  289. package/dist/types/controls-options-manager/util.d.ts +1 -0
  290. package/dist/types/index.d.ts +7 -0
  291. package/dist/types/interceptors/index.d.ts +2 -0
  292. package/dist/types/interceptors/locusRetry.d.ts +27 -0
  293. package/dist/types/interpretation/collection.d.ts +5 -0
  294. package/dist/types/interpretation/index.d.ts +5 -0
  295. package/dist/types/interpretation/siLanguage.d.ts +5 -0
  296. package/dist/types/locus-info/controlsUtils.d.ts +2 -0
  297. package/dist/types/locus-info/embeddedAppsUtils.d.ts +2 -0
  298. package/dist/types/locus-info/fullState.d.ts +2 -0
  299. package/dist/types/locus-info/hostUtils.d.ts +2 -0
  300. package/dist/types/locus-info/index.d.ts +322 -0
  301. package/dist/types/locus-info/infoUtils.d.ts +2 -0
  302. package/dist/types/locus-info/mediaSharesUtils.d.ts +2 -0
  303. package/dist/types/locus-info/parser.d.ts +272 -0
  304. package/dist/types/locus-info/selfUtils.d.ts +2 -0
  305. package/dist/types/media/index.d.ts +34 -0
  306. package/dist/types/media/properties.d.ts +93 -0
  307. package/dist/types/media/util.d.ts +2 -0
  308. package/dist/types/mediaQualityMetrics/config.d.ts +241 -0
  309. package/dist/types/meeting/in-meeting-actions.d.ts +167 -0
  310. package/dist/types/meeting/index.d.ts +1824 -0
  311. package/dist/types/meeting/locusMediaRequest.d.ts +74 -0
  312. package/dist/types/meeting/muteState.d.ts +178 -0
  313. package/dist/types/meeting/request.d.ts +293 -0
  314. package/dist/types/meeting/request.type.d.ts +11 -0
  315. package/dist/types/meeting/state.d.ts +9 -0
  316. package/dist/types/meeting/util.d.ts +118 -0
  317. package/dist/types/meeting/voicea-meeting.d.ts +16 -0
  318. package/dist/types/meeting-info/collection.d.ts +20 -0
  319. package/dist/types/meeting-info/index.d.ts +69 -0
  320. package/dist/types/meeting-info/meeting-info-v2.d.ts +123 -0
  321. package/dist/types/meeting-info/request.d.ts +22 -0
  322. package/dist/types/meeting-info/util.d.ts +2 -0
  323. package/dist/types/meeting-info/utilv2.d.ts +2 -0
  324. package/dist/types/meetings/collection.d.ts +40 -0
  325. package/dist/types/meetings/index.d.ts +389 -0
  326. package/dist/types/meetings/meetings.types.d.ts +4 -0
  327. package/dist/types/meetings/request.d.ts +27 -0
  328. package/dist/types/meetings/util.d.ts +18 -0
  329. package/dist/types/member/index.d.ts +160 -0
  330. package/dist/types/member/types.d.ts +32 -0
  331. package/dist/types/member/util.d.ts +2 -0
  332. package/dist/types/members/collection.d.ts +29 -0
  333. package/dist/types/members/index.d.ts +353 -0
  334. package/dist/types/members/request.d.ts +114 -0
  335. package/dist/types/members/types.d.ts +25 -0
  336. package/dist/types/members/util.d.ts +215 -0
  337. package/dist/types/metrics/constants.d.ts +70 -0
  338. package/dist/types/metrics/index.d.ts +45 -0
  339. package/dist/types/multistream/mediaRequestManager.d.ts +120 -0
  340. package/dist/types/multistream/receiveSlot.d.ts +68 -0
  341. package/dist/types/multistream/receiveSlotManager.d.ts +56 -0
  342. package/dist/types/multistream/remoteMedia.d.ts +72 -0
  343. package/dist/types/multistream/remoteMediaGroup.d.ts +49 -0
  344. package/dist/types/multistream/remoteMediaManager.d.ts +301 -0
  345. package/dist/types/multistream/sendSlotManager.d.ts +70 -0
  346. package/dist/types/networkQualityMonitor/index.d.ts +70 -0
  347. package/dist/types/personal-meeting-room/index.d.ts +47 -0
  348. package/dist/types/personal-meeting-room/request.d.ts +14 -0
  349. package/dist/types/personal-meeting-room/util.d.ts +2 -0
  350. package/dist/types/reachability/clusterReachability.d.ts +109 -0
  351. package/dist/types/reachability/index.d.ts +105 -0
  352. package/dist/types/reachability/request.d.ts +39 -0
  353. package/dist/types/reachability/util.d.ts +8 -0
  354. package/dist/types/reactions/constants.d.ts +3 -0
  355. package/dist/types/reactions/reactions.d.ts +4 -0
  356. package/dist/types/reactions/reactions.type.d.ts +52 -0
  357. package/dist/types/reconnection-manager/index.d.ts +136 -0
  358. package/dist/types/recording-controller/enums.d.ts +7 -0
  359. package/dist/types/recording-controller/index.d.ts +207 -0
  360. package/dist/types/recording-controller/util.d.ts +14 -0
  361. package/dist/types/roap/index.d.ts +86 -0
  362. package/dist/types/roap/request.d.ts +39 -0
  363. package/dist/types/roap/turnDiscovery.d.ts +155 -0
  364. package/dist/types/rtcMetrics/constants.d.ts +4 -0
  365. package/dist/types/rtcMetrics/index.d.ts +61 -0
  366. package/dist/types/statsAnalyzer/global.d.ts +36 -0
  367. package/dist/types/statsAnalyzer/index.d.ts +217 -0
  368. package/dist/types/statsAnalyzer/mqaUtil.d.ts +48 -0
  369. package/dist/types/transcription/index.d.ts +64 -0
  370. package/dist/types/webinar/collection.d.ts +16 -0
  371. package/dist/types/webinar/index.d.ts +5 -0
  372. package/dist/webinar/collection.js +44 -0
  373. package/dist/webinar/collection.js.map +1 -0
  374. package/dist/webinar/index.js +69 -0
  375. package/dist/webinar/index.js.map +1 -0
  376. package/internal-README.md +7 -6
  377. package/package.json +30 -21
  378. package/src/annotation/annotation.types.ts +50 -0
  379. package/src/annotation/constants.ts +36 -0
  380. package/src/annotation/index.ts +328 -0
  381. package/src/breakouts/README.md +220 -0
  382. package/src/breakouts/breakout.ts +188 -0
  383. package/src/breakouts/collection.ts +19 -0
  384. package/src/breakouts/edit-lock-error.ts +25 -0
  385. package/src/breakouts/events.ts +56 -0
  386. package/src/breakouts/index.ts +925 -0
  387. package/src/breakouts/request.ts +55 -0
  388. package/src/breakouts/utils.ts +57 -0
  389. package/src/common/{browser-detection.js → browser-detection.ts} +9 -6
  390. package/src/common/collection.ts +9 -7
  391. package/src/common/{config.js → config.ts} +1 -1
  392. package/src/common/errors/{captcha-error.js → captcha-error.ts} +11 -7
  393. package/src/common/errors/{intent-to-join.js → intent-to-join.ts} +12 -7
  394. package/src/common/errors/{join-meeting.js → join-meeting.ts} +17 -8
  395. package/src/common/errors/{media.js → media.ts} +11 -7
  396. package/src/common/errors/no-meeting-info.ts +24 -0
  397. package/src/common/errors/parameter.ts +11 -7
  398. package/src/common/errors/{password-error.js → password-error.ts} +11 -7
  399. package/src/common/errors/{permission.js → permission.ts} +10 -6
  400. package/src/common/errors/reclaim-host-role-errors.ts +134 -0
  401. package/src/common/errors/{reconnection.js → reconnection.ts} +11 -7
  402. package/src/common/errors/{stats.js → stats.ts} +11 -7
  403. package/src/common/errors/{webex-errors.js → webex-errors.ts} +51 -8
  404. package/src/common/errors/{webex-meetings-error.js → webex-meetings-error.ts} +4 -2
  405. package/src/common/events/{events-scope.js → events-scope.ts} +6 -2
  406. package/src/common/events/{events.js → events.ts} +5 -1
  407. package/src/common/events/{trigger-proxy.js → trigger-proxy.ts} +9 -5
  408. package/src/common/events/{util.js → util.ts} +2 -3
  409. package/src/common/logs/{logger-config.js → logger-config.ts} +1 -2
  410. package/src/common/logs/logger-proxy.ts +44 -0
  411. package/src/common/logs/{request.js → request.ts} +26 -9
  412. package/src/common/queue.ts +22 -9
  413. package/src/{config.js → config.ts} +19 -21
  414. package/src/constants.ts +296 -27
  415. package/src/controls-options-manager/constants.ts +5 -0
  416. package/src/controls-options-manager/enums.ts +18 -0
  417. package/src/controls-options-manager/index.ts +278 -0
  418. package/src/controls-options-manager/types.ts +59 -0
  419. package/src/controls-options-manager/util.ts +300 -0
  420. package/src/index.ts +45 -0
  421. package/src/interceptors/index.ts +3 -0
  422. package/src/interceptors/locusRetry.ts +67 -0
  423. package/src/interpretation/README.md +60 -0
  424. package/src/interpretation/collection.ts +19 -0
  425. package/src/interpretation/index.ts +349 -0
  426. package/src/interpretation/siLanguage.ts +18 -0
  427. package/src/locus-info/controlsUtils.ts +222 -0
  428. package/src/locus-info/{embeddedAppsUtils.js → embeddedAppsUtils.ts} +5 -6
  429. package/src/locus-info/{fullState.js → fullState.ts} +16 -12
  430. package/src/locus-info/{hostUtils.js → hostUtils.ts} +9 -8
  431. package/src/locus-info/{index.js → index.ts} +561 -119
  432. package/src/locus-info/{infoUtils.js → infoUtils.ts} +29 -10
  433. package/src/locus-info/{mediaSharesUtils.js → mediaSharesUtils.ts} +97 -17
  434. package/src/locus-info/{parser.js → parser.ts} +303 -104
  435. package/src/locus-info/{selfUtils.js → selfUtils.ts} +199 -68
  436. package/src/media/index.ts +460 -0
  437. package/src/media/properties.ts +283 -0
  438. package/src/media/{util.js → util.ts} +2 -2
  439. package/src/mediaQualityMetrics/config.ts +249 -0
  440. package/src/meeting/in-meeting-actions.ts +199 -3
  441. package/src/meeting/index.ts +8494 -0
  442. package/src/meeting/locusMediaRequest.ts +313 -0
  443. package/src/meeting/muteState.ts +465 -0
  444. package/src/meeting/request.ts +912 -0
  445. package/src/meeting/request.type.ts +13 -0
  446. package/src/meeting/{state.js → state.ts} +50 -35
  447. package/src/meeting/util.ts +799 -0
  448. package/src/meeting/voicea-meeting.ts +122 -0
  449. package/src/meeting-info/{collection.js → collection.ts} +6 -2
  450. package/src/meeting-info/index.ts +210 -0
  451. package/src/meeting-info/meeting-info-v2.ts +423 -0
  452. package/src/meeting-info/{request.js → request.ts} +14 -4
  453. package/src/meeting-info/{util.js → util.ts} +70 -58
  454. package/src/meeting-info/{utilv2.js → utilv2.ts} +99 -82
  455. package/src/meetings/collection.ts +76 -0
  456. package/src/meetings/index.ts +1539 -0
  457. package/src/meetings/meetings.types.ts +12 -0
  458. package/src/meetings/{request.js → request.ts} +34 -25
  459. package/src/meetings/{util.js → util.ts} +133 -38
  460. package/src/member/{index.js → index.ts} +159 -56
  461. package/src/member/types.ts +38 -0
  462. package/src/member/util.ts +397 -0
  463. package/src/members/{collection.js → collection.ts} +10 -2
  464. package/src/members/{index.js → index.ts} +351 -146
  465. package/src/members/request.ts +255 -0
  466. package/src/members/types.ts +29 -0
  467. package/src/members/util.ts +353 -0
  468. package/src/metrics/{constants.js → constants.ts} +17 -6
  469. package/src/metrics/index.ts +73 -0
  470. package/src/multistream/mediaRequestManager.ts +341 -64
  471. package/src/multistream/receiveSlot.ts +69 -26
  472. package/src/multistream/receiveSlotManager.ts +66 -42
  473. package/src/multistream/remoteMedia.ts +40 -5
  474. package/src/multistream/remoteMediaGroup.ts +82 -3
  475. package/src/multistream/remoteMediaManager.ts +401 -81
  476. package/src/multistream/sendSlotManager.ts +199 -0
  477. package/src/networkQualityMonitor/{index.js → index.ts} +41 -29
  478. package/src/personal-meeting-room/{index.js → index.ts} +28 -19
  479. package/src/personal-meeting-room/{request.js → request.ts} +13 -4
  480. package/src/personal-meeting-room/{util.js → util.ts} +4 -4
  481. package/src/reachability/clusterReachability.ts +320 -0
  482. package/src/reachability/index.ts +371 -0
  483. package/src/reachability/request.ts +50 -35
  484. package/src/reachability/util.ts +24 -0
  485. package/src/reactions/constants.ts +4 -0
  486. package/src/reactions/reactions.ts +104 -0
  487. package/src/reactions/reactions.type.ts +62 -0
  488. package/src/reconnection-manager/index.ts +643 -0
  489. package/src/recording-controller/enums.ts +8 -0
  490. package/src/recording-controller/index.ts +332 -0
  491. package/src/recording-controller/util.ts +75 -0
  492. package/src/roap/index.ts +288 -0
  493. package/src/roap/request.ts +153 -0
  494. package/src/roap/turnDiscovery.ts +374 -70
  495. package/src/rtcMetrics/constants.ts +3 -0
  496. package/src/rtcMetrics/index.ts +166 -0
  497. package/src/statsAnalyzer/global.ts +37 -0
  498. package/src/statsAnalyzer/index.ts +1275 -0
  499. package/src/statsAnalyzer/mqaUtil.ts +440 -0
  500. package/src/transcription/{index.js → index.ts} +46 -39
  501. package/src/webinar/collection.ts +31 -0
  502. package/src/webinar/index.ts +62 -0
  503. package/test/integration/spec/converged-space-meetings.js +233 -0
  504. package/test/integration/spec/journey.js +791 -531
  505. package/test/integration/spec/space-meeting.js +391 -204
  506. package/test/integration/spec/transcription.js +7 -8
  507. package/test/unit/spec/annotation/index.ts +418 -0
  508. package/test/unit/spec/breakouts/breakout.ts +238 -0
  509. package/test/unit/spec/breakouts/collection.ts +15 -0
  510. package/test/unit/spec/breakouts/edit-lock-error.ts +30 -0
  511. package/test/unit/spec/breakouts/events.ts +89 -0
  512. package/test/unit/spec/breakouts/index.ts +1793 -0
  513. package/test/unit/spec/breakouts/request.ts +104 -0
  514. package/test/unit/spec/breakouts/utils.js +72 -0
  515. package/test/unit/spec/common/browser-detection.js +9 -28
  516. package/test/unit/spec/common/queue.js +31 -2
  517. package/test/unit/spec/controls-options-manager/index.js +287 -0
  518. package/test/unit/spec/controls-options-manager/util.js +582 -0
  519. package/test/unit/spec/fixture/locus.js +93 -90
  520. package/test/unit/spec/interceptors/locusRetry.ts +131 -0
  521. package/test/unit/spec/interpretation/collection.ts +15 -0
  522. package/test/unit/spec/interpretation/index.ts +625 -0
  523. package/test/unit/spec/interpretation/siLanguage.ts +28 -0
  524. package/test/unit/spec/locus-info/controlsUtils.js +325 -32
  525. package/test/unit/spec/locus-info/embeddedAppsUtils.js +8 -6
  526. package/test/unit/spec/locus-info/index.js +1458 -21
  527. package/test/unit/spec/locus-info/infoUtils.js +71 -40
  528. package/test/unit/spec/locus-info/lib/BasicSeqCmp.json +88 -430
  529. package/test/unit/spec/locus-info/lib/SeqCmp.json +529 -685
  530. package/test/unit/spec/locus-info/mediaSharesUtils.ts +41 -0
  531. package/test/unit/spec/locus-info/parser.js +119 -44
  532. package/test/unit/spec/locus-info/selfConstant.js +120 -103
  533. package/test/unit/spec/locus-info/selfUtils.js +291 -12
  534. package/test/unit/spec/media/index.ts +194 -111
  535. package/test/unit/spec/media/properties.ts +11 -11
  536. package/test/unit/spec/meeting/in-meeting-actions.ts +96 -3
  537. package/test/unit/spec/meeting/index.js +8616 -1921
  538. package/test/unit/spec/meeting/locusMediaRequest.ts +442 -0
  539. package/test/unit/spec/meeting/muteState.js +568 -207
  540. package/test/unit/spec/meeting/request.js +602 -82
  541. package/test/unit/spec/meeting/utils.js +867 -179
  542. package/test/unit/spec/meeting/voicea-meeting.ts +266 -0
  543. package/test/unit/spec/meeting-info/index.js +300 -0
  544. package/test/unit/spec/meeting-info/meetinginfov2.js +631 -78
  545. package/test/unit/spec/meeting-info/request.js +7 -9
  546. package/test/unit/spec/meeting-info/util.js +11 -12
  547. package/test/unit/spec/meeting-info/utilv2.js +131 -74
  548. package/test/unit/spec/meetings/collection.js +27 -1
  549. package/test/unit/spec/meetings/index.js +1826 -374
  550. package/test/unit/spec/meetings/utils.js +243 -14
  551. package/test/unit/spec/member/index.js +61 -7
  552. package/test/unit/spec/member/util.js +526 -26
  553. package/test/unit/spec/members/index.js +536 -55
  554. package/test/unit/spec/members/request.js +228 -40
  555. package/test/unit/spec/members/utils.js +217 -4
  556. package/test/unit/spec/metrics/index.js +13 -68
  557. package/test/unit/spec/multistream/mediaRequestManager.ts +1032 -110
  558. package/test/unit/spec/multistream/receiveSlot.ts +77 -18
  559. package/test/unit/spec/multistream/receiveSlotManager.ts +69 -39
  560. package/test/unit/spec/multistream/remoteMedia.ts +40 -2
  561. package/test/unit/spec/multistream/remoteMediaGroup.ts +350 -5
  562. package/test/unit/spec/multistream/remoteMediaManager.ts +937 -65
  563. package/test/unit/spec/multistream/sendSlotManager.ts +274 -0
  564. package/test/unit/spec/networkQualityMonitor/index.js +24 -18
  565. package/test/unit/spec/personal-meeting-room/personal-meeting-room.js +2 -7
  566. package/test/unit/spec/reachability/clusterReachability.ts +279 -0
  567. package/test/unit/spec/reachability/index.ts +606 -26
  568. package/test/unit/spec/reachability/request.js +68 -0
  569. package/test/unit/spec/reachability/util.ts +40 -0
  570. package/test/unit/spec/reconnection-manager/index.js +222 -34
  571. package/test/unit/spec/recording-controller/index.js +306 -0
  572. package/test/unit/spec/recording-controller/util.js +229 -0
  573. package/test/unit/spec/roap/index.ts +238 -82
  574. package/test/unit/spec/roap/request.ts +255 -0
  575. package/test/unit/spec/roap/turnDiscovery.ts +707 -110
  576. package/test/unit/spec/rtcMetrics/index.ts +122 -0
  577. package/test/unit/spec/stats-analyzer/index.js +1331 -62
  578. package/test/unit/spec/webinar/collection.ts +13 -0
  579. package/test/unit/spec/webinar/index.ts +60 -0
  580. package/test/utils/cmr.js +44 -42
  581. package/test/utils/constants.js +9 -0
  582. package/test/utils/integrationTestUtils.js +46 -0
  583. package/test/utils/testUtils.js +63 -99
  584. package/test/utils/webex-config.js +22 -18
  585. package/test/utils/webex-test-users.js +65 -50
  586. package/tsconfig.json +6 -0
  587. package/dist/media/internal-media-core-wrapper.js +0 -22
  588. package/dist/media/internal-media-core-wrapper.js.map +0 -1
  589. package/dist/meeting/effectsState.js +0 -327
  590. package/dist/meeting/effectsState.js.map +0 -1
  591. package/dist/metrics/config.js +0 -301
  592. package/dist/metrics/config.js.map +0 -1
  593. package/dist/multistream/multistreamMedia.js +0 -116
  594. package/dist/multistream/multistreamMedia.js.map +0 -1
  595. package/dist/peer-connection-manager/util.js +0 -124
  596. package/dist/peer-connection-manager/util.js.map +0 -1
  597. package/src/common/logs/logger-proxy.js +0 -33
  598. package/src/index.js +0 -15
  599. package/src/locus-info/controlsUtils.js +0 -102
  600. package/src/media/index.js +0 -459
  601. package/src/media/internal-media-core-wrapper.ts +0 -9
  602. package/src/media/properties.js +0 -289
  603. package/src/mediaQualityMetrics/config.js +0 -382
  604. package/src/meeting/effectsState.js +0 -205
  605. package/src/meeting/index.js +0 -6284
  606. package/src/meeting/muteState.js +0 -318
  607. package/src/meeting/request.js +0 -684
  608. package/src/meeting/util.js +0 -506
  609. package/src/meeting-info/index.js +0 -131
  610. package/src/meeting-info/meeting-info-v2.js +0 -255
  611. package/src/meetings/collection.js +0 -40
  612. package/src/meetings/index.js +0 -1015
  613. package/src/member/util.js +0 -254
  614. package/src/members/request.js +0 -131
  615. package/src/members/util.js +0 -258
  616. package/src/metrics/config.js +0 -324
  617. package/src/metrics/index.js +0 -530
  618. package/src/multistream/multistreamMedia.ts +0 -92
  619. package/src/peer-connection-manager/util.ts +0 -117
  620. package/src/reachability/index.js +0 -464
  621. package/src/reconnection-manager/index.js +0 -519
  622. package/src/roap/index.js +0 -220
  623. package/src/roap/request.js +0 -127
  624. package/src/statsAnalyzer/global.js +0 -133
  625. package/src/statsAnalyzer/index.js +0 -1006
  626. package/src/statsAnalyzer/mqaUtil.js +0 -173
  627. package/test/unit/spec/meeting/effectsState.js +0 -291
  628. package/test/unit/spec/peerconnection-manager/utils.test-fixtures.ts +0 -389
  629. /package/src/common/errors/{reconnection-in-progress.js → reconnection-in-progress.ts} +0 -0
@@ -1,8 +1,7 @@
1
1
  import sinon from 'sinon';
2
2
  import {assert} from '@webex/test-helper-chai';
3
3
  import MeetingUtil from '@webex/plugin-meetings/src/meeting/util';
4
- import createMuteState from '@webex/plugin-meetings/src/meeting/muteState';
5
- import Media from '@webex/plugin-meetings/src/media/index';
4
+ import {createMuteState, MuteState} from '@webex/plugin-meetings/src/meeting/muteState';
6
5
  import PermissionError from '@webex/plugin-meetings/src/common/errors/permission';
7
6
  import {AUDIO, VIDEO} from '@webex/plugin-meetings/src/constants';
8
7
 
@@ -16,29 +15,48 @@ describe('plugin-meetings', () => {
16
15
 
17
16
  const fakeLocus = {info: 'this is a fake locus'};
18
17
 
19
- beforeEach(() => {
18
+ const createFakeLocalStream = (id, userMuted, systemMuted) => {
19
+ return {
20
+ id,
21
+ setServerMuted: sinon.stub(),
22
+ setUnmuteAllowed: sinon.stub(),
23
+ setUserMuted: sinon.stub(),
24
+ userMuted,
25
+ systemMuted,
26
+ get muted() {
27
+ return this.userMuted || this.systemMuted;
28
+ },
29
+ };
30
+ };
31
+
32
+ beforeEach(async () => {
20
33
  meeting = {
21
34
  mediaProperties: {
22
- audioTrack: 'fake audio track',
23
- videoTrack: 'fake video track'
35
+ audioStream: createFakeLocalStream('fake audio stream', false, false),
36
+ videoStream: createFakeLocalStream('fake video stream', false, false),
24
37
  },
25
38
  remoteMuted: false,
26
39
  unmuteAllowed: true,
40
+ remoteVideoMuted: false,
41
+ unmuteVideoAllowed: true,
42
+
27
43
  locusInfo: {
28
- onFullLocus: sinon.stub()
44
+ handleLocusDelta: sinon.stub(),
29
45
  },
30
46
  members: {
31
47
  selfId: 'fake self id',
32
- muteMember: sinon.stub().resolves()
33
- }
48
+ muteMember: sinon.stub().resolves(),
49
+ },
34
50
  };
35
- audio = createMuteState(AUDIO, meeting, {sendAudio: true});
36
- video = createMuteState(VIDEO, meeting, {sendVideo: true});
37
51
 
38
52
  originalRemoteUpdateAudioVideo = MeetingUtil.remoteUpdateAudioVideo;
39
53
 
40
54
  MeetingUtil.remoteUpdateAudioVideo = sinon.stub().resolves(fakeLocus);
41
- Media.setLocalTrack = sinon.stub();
55
+
56
+ audio = createMuteState(AUDIO, meeting, true);
57
+ video = createMuteState(VIDEO, meeting, true);
58
+
59
+ await testUtils.flushPromises();
42
60
  });
43
61
 
44
62
  afterEach(() => {
@@ -46,233 +64,332 @@ describe('plugin-meetings', () => {
46
64
  });
47
65
 
48
66
  describe('mute state library', () => {
49
- it('does not create an audio instance if we are not sending audio', async () => {
50
- assert.isNull(createMuteState(AUDIO, meeting, {sendAudio: false}));
51
- assert.isNull(createMuteState(AUDIO, meeting, {}));
52
- });
53
-
54
- it('does not create a video instance if we are not sending video', async () => {
55
- assert.isNull(createMuteState(VIDEO, meeting, {sendVideo: false}));
56
- assert.isNull(createMuteState(VIDEO, meeting, {}));
57
- });
58
-
59
67
  it('takes into account current remote mute status when instantiated', async () => {
60
68
  // simulate being already remote muted
61
69
  meeting.remoteMuted = true;
62
- // create a new MuteState intance
63
- audio = createMuteState(AUDIO, meeting, {sendAudio: true});
70
+
71
+ // create a new MuteState instance
72
+ audio = createMuteState(AUDIO, meeting, true);
73
+
74
+ await testUtils.flushPromises();
64
75
 
65
76
  assert.isTrue(audio.isMuted());
66
- assert.isFalse(audio.isSelf());
77
+ assert.isTrue(audio.isRemotelyMuted());
67
78
 
68
79
  // now check the opposite case
69
80
  meeting.remoteMuted = false;
70
81
 
71
- // create a new MuteState intance
72
- audio = createMuteState(AUDIO, meeting, {sendAudio: true});
82
+ // create a new MuteState instance
83
+ audio = createMuteState(AUDIO, meeting, true);
73
84
 
74
- assert.isFalse(audio.isMuted());
75
- assert.isFalse(audio.isSelf());
85
+ await testUtils.flushPromises();
86
+
87
+ assert.isTrue(audio.isMuted()); // because we start with no stream
88
+ assert.isFalse(audio.isRemotelyMuted());
76
89
  });
77
90
 
78
91
  it('initialises correctly for video', async () => {
79
- // setup fields related to audio remote state
80
- meeting.remoteMuted = true;
81
- meeting.unmuteAllowed = false;
82
- // create a new video MuteState intance
83
- video = createMuteState(VIDEO, meeting, {sendVideo: true});
92
+ // setup fields related to video remote state
93
+ meeting.remoteVideoMuted = false;
94
+ meeting.unmuteVideoAllowed = false;
84
95
 
85
- assert.isFalse(video.isMuted());
96
+ // create a new video MuteState instance
97
+ video = createMuteState(VIDEO, meeting, true);
98
+
99
+ await testUtils.flushPromises();
100
+
101
+ assert.isTrue(video.isMuted()); // because we start with no stream
102
+ assert.isFalse(video.isRemotelyMuted());
86
103
  assert.isFalse(video.state.server.remoteMute);
87
- assert.isTrue(video.state.server.unmuteAllowed);
104
+ assert.isFalse(video.state.server.unmuteAllowed);
88
105
  });
89
106
 
90
107
  it('takes remote mute into account when reporting current state', async () => {
91
- assert.isFalse(audio.isMuted());
108
+ assert.isFalse(audio.isRemotelyMuted());
92
109
 
93
110
  // simulate remote mute
94
- audio.handleServerRemoteMuteUpdate(true, true);
111
+ audio.handleServerRemoteMuteUpdate(meeting, true, true);
95
112
 
96
- assert.isTrue(audio.isMuted());
97
- assert.isFalse(audio.isSelf());
113
+ assert.isTrue(audio.isRemotelyMuted());
98
114
  });
99
115
 
100
- it('does local unmute if localAudioUnmuteRequired is received', async () => {
101
- // first we need to mute
102
- await audio.handleClientRequest(meeting, true);
116
+ it('does local audio unmute if localAudioUnmuteRequired is received', async () => {
117
+ // first we need to have the local stream user muted
118
+ meeting.mediaProperties.audioStream.userMuted = true;
119
+ audio.handleLocalStreamChange(meeting);
103
120
 
104
121
  assert.isTrue(audio.isMuted());
105
- assert.isTrue(audio.isSelf());
106
122
 
107
123
  MeetingUtil.remoteUpdateAudioVideo.resetHistory();
108
124
 
109
125
  // now simulate server requiring us to locally unmute
126
+ // assuming setServerMuted succeeds at updating userMuted
127
+ meeting.mediaProperties.audioStream.setServerMuted = sinon.stub().callsFake((muted) => {
128
+ meeting.mediaProperties.audioStream.userMuted = muted;
129
+ });
110
130
  audio.handleServerLocalUnmuteRequired(meeting);
131
+
111
132
  await testUtils.flushPromises();
112
133
 
113
- // check that local track was enabled
114
- assert.calledWith(Media.setLocalTrack, true, meeting.mediaProperties.audioTrack);
134
+ // check that local stream was unmuted
135
+ assert.calledWith(
136
+ meeting.mediaProperties.audioStream.setServerMuted,
137
+ false,
138
+ 'localUnmuteRequired'
139
+ );
115
140
 
116
141
  // and local unmute was sent to server
117
142
  assert.calledOnce(MeetingUtil.remoteUpdateAudioVideo);
118
- assert.calledWith(MeetingUtil.remoteUpdateAudioVideo, false, undefined, meeting);
143
+ assert.calledWith(MeetingUtil.remoteUpdateAudioVideo, meeting, false, undefined);
119
144
 
120
145
  assert.isFalse(audio.isMuted());
121
- assert.isFalse(audio.isSelf());
122
146
  });
123
147
 
124
- it('rejects client request in progress if localAudioUnmuteRequired is received', async () => {
125
- let clientPromiseResolved = false;
126
- let clientPromiseRejected = false;
127
-
128
- // first we need to mute and make that request last forever
129
- let serverResponseResolve;
130
-
131
- MeetingUtil.remoteUpdateAudioVideo = sinon.stub().returns(new Promise((resolve) => {
132
- serverResponseResolve = resolve;
133
- }));
148
+ it('handles localAudioUnmuteRequired but does not send unmute to server if system is muted', async () => {
149
+ // first we need to have the local stream user muted and system muted
150
+ meeting.mediaProperties.audioStream.userMuted = true;
151
+ meeting.mediaProperties.audioStream.systemMuted = true;
152
+ audio.handleLocalStreamChange(meeting);
134
153
 
135
- audio.handleClientRequest(meeting, true)
136
- .then(() => {
137
- clientPromiseResolved = true;
138
- })
139
- .catch(() => {
140
- clientPromiseRejected = true;
141
- });
154
+ assert.isTrue(audio.isMuted());
142
155
 
143
156
  MeetingUtil.remoteUpdateAudioVideo.resetHistory();
144
157
 
145
158
  // now simulate server requiring us to locally unmute
159
+ // assuming setServerMuted succeeds at updating userMuted
160
+ meeting.mediaProperties.audioStream.setServerMuted = sinon.stub().callsFake((muted) => {
161
+ meeting.mediaProperties.audioStream.userMuted = muted;
162
+ });
146
163
  audio.handleServerLocalUnmuteRequired(meeting);
164
+
147
165
  await testUtils.flushPromises();
148
166
 
149
- // the original client request should have been rejected by now
150
- assert.isTrue(clientPromiseRejected);
151
- assert.isFalse(clientPromiseResolved);
167
+ // check that local stream was unmuted
168
+ assert.calledWith(
169
+ meeting.mediaProperties.audioStream.setServerMuted,
170
+ false,
171
+ 'localUnmuteRequired'
172
+ );
173
+
174
+ // system was muted so local unmute was not sent to server
175
+ assert.notCalled(MeetingUtil.remoteUpdateAudioVideo);
176
+
177
+ assert.isTrue(audio.isMuted());
178
+ });
179
+
180
+ it('does local video unmute if localVideoUnmuteRequired is received', async () => {
181
+ // first we need to have the local stream user muted
182
+ meeting.mediaProperties.videoStream.userMuted = true;
183
+ video.handleLocalStreamChange(meeting);
184
+
185
+ assert.isTrue(video.isMuted());
186
+
187
+ MeetingUtil.remoteUpdateAudioVideo.resetHistory();
188
+
189
+ // now simulate server requiring us to locally unmute
190
+ // assuming setServerMuted succeeds at updating userMuted
191
+ meeting.mediaProperties.videoStream.setServerMuted = sinon.stub().callsFake((muted) => {
192
+ meeting.mediaProperties.videoStream.userMuted = muted;
193
+ });
194
+ video.handleServerLocalUnmuteRequired(meeting);
152
195
 
153
- // now make the server respond to the original mute request
154
- serverResponseResolve();
155
196
  await testUtils.flushPromises();
156
197
 
157
- // local unmute should be sent to server
198
+ // check that local stream was unmuted
199
+ assert.calledWith(
200
+ meeting.mediaProperties.videoStream.setServerMuted,
201
+ false,
202
+ 'localUnmuteRequired'
203
+ );
204
+
205
+ // and local unmute was sent to server
158
206
  assert.calledOnce(MeetingUtil.remoteUpdateAudioVideo);
159
- assert.calledWith(MeetingUtil.remoteUpdateAudioVideo, false, undefined, meeting);
207
+ assert.calledWith(MeetingUtil.remoteUpdateAudioVideo, meeting, undefined, false);
160
208
 
161
- // and local track should be enabled
162
- assert.calledWith(Media.setLocalTrack, true, meeting.mediaProperties.audioTrack);
209
+ assert.isFalse(video.isMuted());
210
+ });
163
211
 
164
- assert.isFalse(audio.isMuted());
165
- assert.isFalse(audio.isSelf());
212
+ it('handles localVideoUnmuteRequired but does not send unmute to server if system is muted', async () => {
213
+ // first we need to have the local stream user muted and system muted
214
+ meeting.mediaProperties.videoStream.userMuted = true;
215
+ meeting.mediaProperties.videoStream.systemMuted = true;
216
+ audio.handleLocalStreamChange(meeting);
217
+
218
+ assert.isTrue(video.isMuted());
219
+
220
+ MeetingUtil.remoteUpdateAudioVideo.resetHistory();
221
+
222
+ // now simulate server requiring us to locally unmute
223
+ // assuming setServerMuted succeeds at updating userMuted
224
+ meeting.mediaProperties.videoStream.setServerMuted = sinon.stub().callsFake((muted) => {
225
+ meeting.mediaProperties.videoStream.userMuted = muted;
226
+ });
227
+ video.handleServerLocalUnmuteRequired(meeting);
228
+
229
+ await testUtils.flushPromises();
230
+
231
+ // check that local stream was unmuted
232
+ assert.calledWith(
233
+ meeting.mediaProperties.videoStream.setServerMuted,
234
+ false,
235
+ 'localUnmuteRequired'
236
+ );
237
+
238
+ // system was muted so local unmute was not sent to server
239
+ assert.notCalled(MeetingUtil.remoteUpdateAudioVideo);
240
+
241
+ assert.isTrue(video.isMuted());
166
242
  });
167
243
 
168
- describe('#handleClientRequest', () => {
169
- it('disables/enables the local audio track when audio is muted/unmuted', async () => {
170
- // mute
171
- audio.handleClientRequest(meeting, true);
172
- assert.calledWith(Media.setLocalTrack, false, meeting.mediaProperties.audioTrack);
244
+ describe('#isLocallyMuted()', () => {
245
+ it('does not consider remote mute status for audio', async () => {
246
+ // simulate being already remote muted and locally unmuted
247
+ meeting.remoteMuted = true;
248
+ meeting.mediaProperties.audioStream.userMuted = false;
173
249
 
174
- // even when calling mute when it's already muted should still call setLocalTrack
175
- audio.handleClientRequest(meeting, true);
176
- assert.calledWith(Media.setLocalTrack, false, meeting.mediaProperties.audioTrack);
250
+ // create a new MuteState instance
251
+ audio = createMuteState(AUDIO, meeting, true);
252
+ audio.handleLocalStreamChange(meeting);
177
253
 
178
- // unmute
179
- audio.handleClientRequest(meeting, false);
180
- assert.calledWith(Media.setLocalTrack, true, meeting.mediaProperties.audioTrack);
254
+ await testUtils.flushPromises();
181
255
 
182
- // even when calling unmute when it's already unmuted should still call setLocalTrack
183
- audio.handleClientRequest(meeting, false);
184
- assert.calledWith(Media.setLocalTrack, true, meeting.mediaProperties.audioTrack);
256
+ assert.isFalse(audio.isLocallyMuted());
185
257
  });
186
258
 
187
- it('disables/enables the local video track when video is muted/unmuted', async () => {
188
- // mute
189
- video.handleClientRequest(meeting, true);
190
- assert.calledWith(Media.setLocalTrack, false, meeting.mediaProperties.videoTrack);
259
+ it('does not consider remote mute status for video', async () => {
260
+ // simulate being already remote muted
261
+ meeting.remoteVideoMuted = true;
262
+ meeting.mediaProperties.videoStream.userMuted = false;
191
263
 
192
- // even when calling mute when it's already muted should still call setLocalTrack
193
- video.handleClientRequest(meeting, false);
194
- assert.calledWith(Media.setLocalTrack, false, meeting.mediaProperties.videoTrack);
264
+ // create a new MuteState instance
265
+ video = createMuteState(VIDEO, meeting, true);
266
+ video.handleLocalStreamChange(meeting);
195
267
 
196
- // unmute
197
- video.handleClientRequest(meeting, false);
198
- assert.calledWith(Media.setLocalTrack, true, meeting.mediaProperties.videoTrack);
268
+ await testUtils.flushPromises();
199
269
 
200
- // even when calling unmute when it's already unmuted should still call setLocalTrack
201
- video.handleClientRequest(meeting, false);
202
- assert.calledWith(Media.setLocalTrack, true, meeting.mediaProperties.videoTrack);
270
+ assert.isFalse(video.isLocallyMuted());
203
271
  });
272
+ });
204
273
 
205
- it('returns correct value in isMuted()/isSelf() methods after client mute/unmute requests', async () => {
206
- // mute
207
- audio.handleClientRequest(meeting, true);
274
+ describe('handling local stream mute events', () => {
275
+ beforeEach(async () => {
276
+ audio.handleLocalStreamChange(meeting);
277
+ video.handleLocalStreamChange(meeting);
278
+
279
+ await testUtils.flushPromises();
280
+ });
281
+
282
+ const simulateAudioUserMuteChange = async (muteValue) => {
283
+ meeting.mediaProperties.audioStream.userMuted = muteValue;
284
+ audio.handleLocalStreamMuteStateChange(meeting);
285
+
286
+ await testUtils.flushPromises();
287
+ };
288
+
289
+ const simulateAudioSystemMuteChange = async (muteValue) => {
290
+ meeting.mediaProperties.audioStream.systemMuted = muteValue;
291
+ audio.handleLocalStreamMuteStateChange(meeting);
292
+
293
+ await testUtils.flushPromises();
294
+ };
295
+
296
+ const simulateVideoUserMuteChange = async (muteValue) => {
297
+ meeting.mediaProperties.videoStream.userMuted = muteValue;
298
+ video.handleLocalStreamMuteStateChange(meeting);
208
299
 
300
+ await testUtils.flushPromises();
301
+ };
302
+
303
+ it('returns correct value in isMuted() methods after local stream is user muted/unmuted', async () => {
304
+ // mute
305
+ await simulateAudioUserMuteChange(true);
209
306
  assert.isTrue(audio.isMuted());
210
- assert.isTrue(audio.isSelf());
211
307
 
212
308
  // unmute
213
- audio.handleClientRequest(meeting, false);
309
+ await simulateAudioUserMuteChange(false);
310
+ assert.isFalse(audio.isMuted());
311
+ });
214
312
 
313
+ it('returns correct value in isMuted() methods after local stream is system muted/unmuted', async () => {
314
+ // mute
315
+ await simulateAudioSystemMuteChange(true);
316
+ assert.isTrue(audio.isMuted());
317
+
318
+ // unmute
319
+ await simulateAudioSystemMuteChange(false);
215
320
  assert.isFalse(audio.isMuted());
216
- assert.isFalse(audio.isSelf());
217
321
  });
218
322
 
219
323
  it('does remote unmute when unmuting and remote mute is on', async () => {
220
324
  // simulate remote mute
221
- audio.handleServerRemoteMuteUpdate(true, true);
325
+ audio.handleServerRemoteMuteUpdate(meeting, true, true);
222
326
 
223
327
  // unmute
224
- await audio.handleClientRequest(meeting, false);
328
+ await simulateAudioUserMuteChange(false);
225
329
 
226
330
  // check that remote unmute was sent to server
227
331
  assert.calledOnce(meeting.members.muteMember);
228
- assert.calledWith(meeting.members.muteMember, meeting.members.selfId, false);
332
+ assert.calledWith(meeting.members.muteMember, meeting.members.selfId, false, true);
229
333
 
230
334
  assert.isFalse(audio.isMuted());
231
- assert.isFalse(audio.isSelf());
232
335
  });
233
336
 
234
- it('resolves client request promise once the server is updated', async () => {
235
- let clientPromiseResolved = false;
337
+ it('does video remote unmute when unmuting and remote mute is on', async () => {
338
+ // simulate remote mute
339
+ video.handleServerRemoteMuteUpdate(meeting, true, true);
236
340
 
237
- let serverResponseResolve;
341
+ // unmute
342
+ await simulateVideoUserMuteChange(false);
238
343
 
239
- MeetingUtil.remoteUpdateAudioVideo = sinon.stub().returns(new Promise((resolve) => {
240
- serverResponseResolve = resolve;
241
- }));
344
+ // check that remote unmute was sent to server
345
+ assert.calledOnce(meeting.members.muteMember);
346
+ assert.calledWith(meeting.members.muteMember, meeting.members.selfId, false, false);
242
347
 
243
- audio.handleClientRequest(meeting, true)
244
- .then(() => {
245
- clientPromiseResolved = true;
246
- });
348
+ assert.isFalse(video.isMuted());
349
+ });
247
350
 
248
- // do a small delay to make sure that the client promise doesn't resolve in that time
249
- await testUtils.waitUntil(200);
250
- assert.isFalse(clientPromiseResolved);
351
+ it('does not video remote unmute when unmuting and remote mute is off', async () => {
352
+ // simulate remote mute
353
+ video.handleServerRemoteMuteUpdate(meeting, false, true);
251
354
 
252
- // now allow the server response to arrive, this should trigger the client promise to get resolved
253
- serverResponseResolve();
254
- await testUtils.flushPromises();
355
+ // unmute
356
+ await simulateVideoUserMuteChange(false);
255
357
 
256
- assert.isTrue(clientPromiseResolved);
358
+ // check that remote unmute was not sent to server
359
+ assert.notCalled(meeting.members.muteMember);
360
+
361
+ assert.isFalse(video.isMuted());
257
362
  });
258
363
 
259
- it('rejects client request promise if server request for local mute fails', async () => {
260
- MeetingUtil.remoteUpdateAudioVideo = sinon.stub().returns(new Promise((resolve, reject) => {
261
- reject();
262
- }));
364
+ it('calls setServerMuted with "clientRequestFailed" when server request for local mute fails', async () => {
365
+ MeetingUtil.remoteUpdateAudioVideo = sinon.stub().rejects(new Error('fake error'));
263
366
 
264
- assert.isRejected(audio.handleClientRequest(meeting, true));
367
+ await simulateAudioUserMuteChange(true);
368
+
369
+ assert.calledOnceWithExactly(
370
+ meeting.mediaProperties.audioStream.setServerMuted,
371
+ false,
372
+ 'clientRequestFailed'
373
+ );
265
374
  });
266
375
 
267
- it('rejects client request promise if server request for remote mute fails', async () => {
376
+ it('calls setServerMuted with "clientRequestFailed" if server request for remote mute fails', async () => {
268
377
  // we only send remote mute requests when we're unmuting, so first we need to do a remote mute
269
- audio.handleServerRemoteMuteUpdate(true, true);
378
+ audio.handleServerRemoteMuteUpdate(meeting, true, true);
379
+
380
+ await testUtils.flushPromises();
270
381
 
271
382
  // setup the stub to simulate server error response
272
383
  meeting.members.muteMember = sinon.stub().rejects();
384
+ meeting.mediaProperties.audioStream.setServerMuted.resetHistory();
273
385
 
274
- // try to unmute - it should fail
275
- await assert.isRejected(audio.handleClientRequest(meeting, false));
386
+ await simulateAudioUserMuteChange(false);
387
+
388
+ assert.calledOnceWithExactly(
389
+ meeting.mediaProperties.audioStream.setServerMuted,
390
+ true,
391
+ 'clientRequestFailed'
392
+ );
276
393
 
277
394
  // even though remote mute update in the server failed, isMuted() should still return true,
278
395
  // because of local mute
@@ -282,16 +399,19 @@ describe('plugin-meetings', () => {
282
399
  it('does not send a server request if client state matches the server', async () => {
283
400
  let serverResponseResolve;
284
401
 
285
- MeetingUtil.remoteUpdateAudioVideo = sinon.stub().returns(new Promise((resolve) => {
286
- serverResponseResolve = resolve;
287
- }));
402
+ MeetingUtil.remoteUpdateAudioVideo = sinon.stub().returns(
403
+ new Promise((resolve) => {
404
+ serverResponseResolve = resolve;
405
+ })
406
+ );
288
407
 
289
- // simulate many client requests, with the last one matching the initial one
290
- audio.handleClientRequest(meeting, true);
291
- audio.handleClientRequest(meeting, false);
292
- audio.handleClientRequest(meeting, true);
293
- audio.handleClientRequest(meeting, false);
294
- audio.handleClientRequest(meeting, true);
408
+ // the stream is initially unmuted
409
+ // simulate many mute changes with the last one matching the first one
410
+ await simulateAudioUserMuteChange(true);
411
+ await simulateAudioUserMuteChange(false);
412
+ await simulateAudioUserMuteChange(true);
413
+ await simulateAudioUserMuteChange(false);
414
+ await simulateAudioUserMuteChange(true);
295
415
 
296
416
  // so far there should have been only 1 request to server (because our stub hasn't resolved yet
297
417
  // and MuteState sends only 1 server request at a time)
@@ -306,112 +426,353 @@ describe('plugin-meetings', () => {
306
426
  assert.notCalled(MeetingUtil.remoteUpdateAudioVideo);
307
427
  });
308
428
 
309
- it('queues up server requests when multiple client requests are received', async () => {
429
+ it('queues up server requests when multiple mute changes happen to local stream', async () => {
310
430
  let serverResponseResolve;
311
431
 
312
- MeetingUtil.remoteUpdateAudioVideo = sinon.stub().returns(new Promise((resolve) => {
313
- serverResponseResolve = resolve;
314
- }));
315
-
316
- let firstClientPromiseResolved = false;
317
- let secondClientPromiseResolved = false;
432
+ MeetingUtil.remoteUpdateAudioVideo = sinon.stub().returns(
433
+ new Promise((resolve) => {
434
+ serverResponseResolve = resolve;
435
+ })
436
+ );
318
437
 
319
438
  // 2 client requests, one after another without waiting for first one to resolve
320
- audio.handleClientRequest(meeting, true)
321
- .then(() => {
322
- firstClientPromiseResolved = true;
323
- });
324
- audio.handleClientRequest(meeting, false)
325
- .then(() => {
326
- secondClientPromiseResolved = true;
327
- });
328
-
329
- await testUtils.flushPromises();
439
+ await simulateAudioUserMuteChange(true);
440
+ await simulateAudioUserMuteChange(false);
330
441
 
331
442
  assert.calledOnce(MeetingUtil.remoteUpdateAudioVideo);
332
- assert.calledWith(MeetingUtil.remoteUpdateAudioVideo, true, undefined, meeting);
443
+ assert.calledWith(MeetingUtil.remoteUpdateAudioVideo, meeting, true, undefined);
333
444
 
334
445
  // now allow the first request to complete
335
446
  serverResponseResolve();
336
447
  await testUtils.flushPromises();
337
- assert.isTrue(firstClientPromiseResolved);
338
448
 
339
449
  // that should trigger the second server request to be sent
340
450
  assert.calledTwice(MeetingUtil.remoteUpdateAudioVideo);
341
- assert.strictEqual(false, MeetingUtil.remoteUpdateAudioVideo.getCall(1).args[0]);
342
- assert.strictEqual(undefined, MeetingUtil.remoteUpdateAudioVideo.getCall(1).args[1]);
343
- assert.strictEqual(meeting, MeetingUtil.remoteUpdateAudioVideo.getCall(1).args[2]);
451
+ assert.deepEqual(
452
+ [meeting, false, undefined],
453
+ MeetingUtil.remoteUpdateAudioVideo.getCall(1).args
454
+ );
344
455
 
345
456
  serverResponseResolve();
346
- await testUtils.flushPromises();
347
-
348
- assert.isTrue(secondClientPromiseResolved);
349
- });
350
-
351
- it('rejects client request to unmute if hard mute is used', (done) => {
352
- audio.handleServerRemoteMuteUpdate(true, false);
353
-
354
- audio.handleClientRequest(meeting, false)
355
- .then(() => {
356
- done(new Error('expected handleClientRequest to fail, but it did not!'));
357
- })
358
- .catch((e) => {
359
- assert.isTrue(e instanceof PermissionError);
360
- done();
361
- });
362
457
  });
363
458
 
364
459
  it('does not send remote mute for video', async () => {
365
460
  // mute
366
- await video.handleClientRequest(meeting, true);
461
+ await simulateVideoUserMuteChange(true);
367
462
 
368
463
  assert.isTrue(video.isMuted());
369
- assert.isTrue(video.isSelf());
370
464
 
371
465
  // check local mute is done, but not remote one
372
- assert.calledWith(Media.setLocalTrack, false, meeting.mediaProperties.videoTrack);
373
- assert.calledWith(MeetingUtil.remoteUpdateAudioVideo, undefined, true, meeting);
466
+ assert.calledWith(MeetingUtil.remoteUpdateAudioVideo, meeting, undefined, true);
374
467
  assert.notCalled(meeting.members.muteMember);
375
468
 
376
- Media.setLocalTrack.resetHistory();
377
469
  MeetingUtil.remoteUpdateAudioVideo.resetHistory();
378
470
  meeting.members.muteMember.resetHistory();
379
471
 
380
472
  // unmute
381
- await video.handleClientRequest(meeting, false);
473
+ await simulateVideoUserMuteChange(false);
382
474
 
383
475
  assert.isFalse(video.isMuted());
384
- assert.isFalse(video.isSelf());
385
476
 
386
- assert.calledWith(Media.setLocalTrack, true, meeting.mediaProperties.videoTrack);
387
- assert.calledWith(MeetingUtil.remoteUpdateAudioVideo, undefined, false, meeting);
477
+ assert.calledWith(MeetingUtil.remoteUpdateAudioVideo, meeting, undefined, false);
388
478
  assert.notCalled(meeting.members.muteMember);
389
479
  });
390
480
 
391
- it('sends correct audio value when sending local mute for video', async () => {
481
+ it('sends undefined value for the other media type when sending local mute', async () => {
392
482
  // make sure the meeting object has mute state machines for both audio and video
393
483
  meeting.audio = audio;
394
484
  meeting.video = video;
395
485
 
396
- // mute audio -> request sent to server should have video unmuted
397
- await audio.handleClientRequest(meeting, true);
398
- assert.calledWith(MeetingUtil.remoteUpdateAudioVideo, true, false, meeting);
486
+ // mute audio -> the call to remoteUpdateAudioVideo should have video undefined
487
+ await simulateAudioUserMuteChange(true);
488
+ assert.calledWith(MeetingUtil.remoteUpdateAudioVideo, meeting, true, undefined);
399
489
  MeetingUtil.remoteUpdateAudioVideo.resetHistory();
400
490
 
401
- // now mute video -> request sent to server should have mute for both audio and video
402
- await video.handleClientRequest(meeting, true);
403
- assert.calledWith(MeetingUtil.remoteUpdateAudioVideo, true, true, meeting);
491
+ // now mute video -> the call to remoteUpdateAudioVideo should have unmute for video and undefined for audio
492
+ await simulateVideoUserMuteChange(true);
493
+ assert.calledWith(MeetingUtil.remoteUpdateAudioVideo, meeting, undefined, true);
404
494
  MeetingUtil.remoteUpdateAudioVideo.resetHistory();
405
495
 
406
- // now unmute the audio -> request sent to server should still have video muted
407
- await audio.handleClientRequest(meeting, false);
408
- assert.calledWith(MeetingUtil.remoteUpdateAudioVideo, false, true, meeting);
496
+ // now unmute the audio -> the call to remoteUpdateAudioVideo should have video undefined
497
+ await simulateAudioUserMuteChange(false);
498
+ assert.calledWith(MeetingUtil.remoteUpdateAudioVideo, meeting, false, undefined);
409
499
  MeetingUtil.remoteUpdateAudioVideo.resetHistory();
410
500
 
411
- // unmute video -> request sent to server should have both audio and video unmuted
412
- await video.handleClientRequest(meeting, false);
413
- assert.calledWith(MeetingUtil.remoteUpdateAudioVideo, false, false, meeting);
501
+ // unmute video -> the call to remoteUpdateAudioVideo should have audio undefined
502
+ await simulateVideoUserMuteChange(false);
503
+ assert.calledWith(MeetingUtil.remoteUpdateAudioVideo, meeting, undefined, false);
414
504
  });
415
505
  });
506
+
507
+ describe('#init, #handleLocalStreamChange', () => {
508
+ let meeting;
509
+ let muteState;
510
+ let setServerMutedSpy;
511
+ let setUserMutedSpy, setUnmuteAllowedSpy;
512
+
513
+ const setupMeeting = (
514
+ mediaType,
515
+ remoteMuted = false,
516
+ userMuted = false,
517
+ systemMuted = false,
518
+ defineStreams = true
519
+ ) => {
520
+ const remoteMuteField = mediaType === AUDIO ? 'remoteMuted' : 'remoteVideoMuted';
521
+
522
+ meeting = {
523
+ mediaProperties: {
524
+ audioStream: defineStreams
525
+ ? createFakeLocalStream('fake audio stream', userMuted, systemMuted)
526
+ : undefined,
527
+ videoStream: defineStreams
528
+ ? createFakeLocalStream('fake video stream', userMuted, systemMuted)
529
+ : undefined,
530
+ },
531
+ [remoteMuteField]: remoteMuted,
532
+ unmuteAllowed: true,
533
+ unmuteVideoAllowed: true,
534
+
535
+ locusInfo: {
536
+ onFullLocus: sinon.stub(),
537
+ },
538
+ members: {
539
+ selfId: 'fake self id',
540
+ muteMember: sinon.stub().resolves(),
541
+ },
542
+ };
543
+ };
544
+
545
+ const setup = async (
546
+ mediaType,
547
+ remoteMuted = false,
548
+ userMuted = false,
549
+ systemMuted = false,
550
+ defineStreams = true
551
+ ) => {
552
+ setupMeeting(mediaType, remoteMuted, userMuted, systemMuted, defineStreams);
553
+
554
+ muteState = createMuteState(mediaType, meeting, true);
555
+ muteState.handleLocalStreamChange(meeting);
556
+
557
+ await testUtils.flushPromises();
558
+
559
+ MeetingUtil.remoteUpdateAudioVideo.resetHistory();
560
+ };
561
+
562
+ const setupSpies = (mediaType) => {
563
+ setUnmuteAllowedSpy =
564
+ mediaType === AUDIO
565
+ ? meeting.mediaProperties.audioStream?.setUnmuteAllowed
566
+ : meeting.mediaProperties.videoStream?.setUnmuteAllowed;
567
+ setServerMutedSpy =
568
+ mediaType === AUDIO
569
+ ? meeting.mediaProperties.audioStream?.setServerMuted
570
+ : meeting.mediaProperties.videoStream?.setServerMuted;
571
+ setUserMutedSpy =
572
+ mediaType === AUDIO
573
+ ? meeting.mediaProperties.audioStream?.setUserMuted
574
+ : meeting.mediaProperties.videoStream?.setUserMuted;
575
+
576
+ clearSpies();
577
+ };
578
+
579
+ const clearSpies = () => {
580
+ setUnmuteAllowedSpy?.resetHistory();
581
+ setServerMutedSpy?.resetHistory();
582
+ setUserMutedSpy?.resetHistory();
583
+ };
584
+
585
+ const simulateUserMute = (mediaType, mute) => {
586
+ if (mediaType === AUDIO) {
587
+ meeting.mediaProperties.audioStream.userMuted = mute;
588
+ } else {
589
+ meeting.mediaProperties.videoStream.userMuted = mute;
590
+ }
591
+ };
592
+
593
+ const simulateSystemMute = (mediaType, mute) => {
594
+ if (mediaType === AUDIO) {
595
+ meeting.mediaProperties.audioStream.systemMuted = mute;
596
+ } else {
597
+ meeting.mediaProperties.videoStream.systemMuted = mute;
598
+ }
599
+ };
600
+
601
+ const tests = [
602
+ {mediaType: AUDIO, title: 'audio'},
603
+ {mediaType: VIDEO, title: 'video'},
604
+ ];
605
+
606
+ tests.forEach(({mediaType, title}) =>
607
+ describe(title, () => {
608
+ let originalRemoteUpdateAudioVideo;
609
+
610
+ beforeEach(() => {
611
+ originalRemoteUpdateAudioVideo = MeetingUtil.remoteUpdateAudioVideo;
612
+ MeetingUtil.remoteUpdateAudioVideo = sinon.stub().resolves({info: 'fake locus'});
613
+ });
614
+
615
+ afterEach(() => {
616
+ MeetingUtil.remoteUpdateAudioVideo = originalRemoteUpdateAudioVideo;
617
+ sinon.restore();
618
+ });
619
+
620
+ describe('#handleLocalStreamChange', () => {
621
+ it('calls init()', async () => {
622
+ await setup(mediaType);
623
+ const spy = sinon.spy(muteState, 'init');
624
+ muteState.handleLocalStreamChange(meeting);
625
+ assert.calledOnceWithExactly(spy, meeting);
626
+ });
627
+ });
628
+
629
+ describe('#init', () => {
630
+ // does the setup by calling new MuteState() so that MuteState.init() doesn't get called
631
+ const setupWithoutInit = async (
632
+ mediaType,
633
+ remoteMuted = false,
634
+ userMuted = false,
635
+ systemMuted = false,
636
+ defineStreams = true
637
+ ) => {
638
+ setupMeeting(mediaType, remoteMuted, userMuted, systemMuted, defineStreams);
639
+
640
+ muteState = new MuteState(mediaType, meeting, true);
641
+ };
642
+
643
+ it('nothing goes bad when stream is undefined', async () => {
644
+ await setupWithoutInit(mediaType, false, false, false, false);
645
+ setupSpies(mediaType);
646
+
647
+ muteState.init(meeting);
648
+
649
+ assert.isTrue(muteState.state.client.localMute);
650
+ });
651
+
652
+ it('tests when stream user muted is true and remoteMuted is false', async () => {
653
+ await setupWithoutInit(mediaType, false, true, false, true);
654
+ setupSpies(mediaType);
655
+
656
+ muteState.init(meeting);
657
+
658
+ assert.calledWith(setUnmuteAllowedSpy, muteState.state.server.unmuteAllowed);
659
+ assert.notCalled(setServerMutedSpy);
660
+ assert.notCalled(MeetingUtil.remoteUpdateAudioVideo);
661
+ assert.isTrue(muteState.state.client.localMute);
662
+ });
663
+
664
+ it('tests when stream system muted is true and remoteMuted is false', async () => {
665
+ await setupWithoutInit(mediaType, false, false, true, true);
666
+ setupSpies(mediaType);
667
+
668
+ muteState.init(meeting);
669
+
670
+ assert.calledWith(setUnmuteAllowedSpy, muteState.state.server.unmuteAllowed);
671
+ assert.notCalled(setServerMutedSpy);
672
+ assert.notCalled(MeetingUtil.remoteUpdateAudioVideo);
673
+ assert.isTrue(muteState.state.client.localMute);
674
+ });
675
+
676
+ it('tests when both stream user muted and system muted are false and remoteMuted is false', async () => {
677
+ await setupWithoutInit(mediaType, false, false, false, true);
678
+ setupSpies(mediaType);
679
+
680
+ muteState.init(meeting);
681
+
682
+ assert.calledWith(setUnmuteAllowedSpy, muteState.state.server.unmuteAllowed);
683
+ assert.notCalled(setServerMutedSpy);
684
+ assert.calledOnce(MeetingUtil.remoteUpdateAudioVideo);
685
+ assert.isFalse(muteState.state.client.localMute);
686
+ });
687
+
688
+ it('tests when remoteMuted is true', async () => {
689
+ // testing that muteLocalStream is called
690
+ await setupWithoutInit(mediaType, true, false, false, true);
691
+ setupSpies(mediaType);
692
+
693
+ muteState.init(meeting);
694
+
695
+ assert.calledWith(setUnmuteAllowedSpy, muteState.state.server.unmuteAllowed);
696
+ assert.calledOnceWithExactly(setServerMutedSpy, true, 'remotelyMuted');
697
+ });
698
+ });
699
+
700
+ describe('#handleLocalStreamMuteStateChange', () => {
701
+ it('checks when ignoreMuteStateChange is true nothing changes', async () => {
702
+ await setup(mediaType, false, false, false, true);
703
+ muteState.ignoreMuteStateChange = true;
704
+
705
+ simulateUserMute(mediaType, true);
706
+ muteState.handleLocalStreamMuteStateChange(meeting);
707
+ assert.notCalled(MeetingUtil.remoteUpdateAudioVideo);
708
+
709
+ assert.isFalse(muteState.state.client.localMute);
710
+ });
711
+
712
+ it('tests localMute - user mute from true to false', async () => {
713
+ await setup(mediaType, false, true, false, true);
714
+
715
+ simulateUserMute(mediaType, false);
716
+ muteState.handleLocalStreamMuteStateChange(meeting);
717
+ assert.equal(muteState.state.client.localMute, false);
718
+ assert.called(MeetingUtil.remoteUpdateAudioVideo);
719
+ });
720
+
721
+ it('tests localMute - user mute from false to true', async () => {
722
+ await setup(mediaType, false, false, false, true);
723
+
724
+ simulateUserMute(mediaType, true);
725
+ muteState.handleLocalStreamMuteStateChange(meeting);
726
+ assert.equal(muteState.state.client.localMute, true);
727
+ assert.called(MeetingUtil.remoteUpdateAudioVideo);
728
+ });
729
+
730
+ it('tests localMute - system mute from true to false', async () => {
731
+ await setup(mediaType, false, false, true, true);
732
+
733
+ simulateSystemMute(mediaType, false);
734
+ muteState.handleLocalStreamMuteStateChange(meeting);
735
+ assert.equal(muteState.state.client.localMute, false);
736
+ assert.called(MeetingUtil.remoteUpdateAudioVideo);
737
+ });
738
+
739
+ it('tests localMute - system mute from false to true', async () => {
740
+ await setup(mediaType, false, false, false, true);
741
+
742
+ simulateSystemMute(mediaType, true);
743
+ muteState.handleLocalStreamMuteStateChange(meeting);
744
+ assert.equal(muteState.state.client.localMute, true);
745
+ assert.called(MeetingUtil.remoteUpdateAudioVideo);
746
+ });
747
+ });
748
+
749
+ describe('#applyClientStateLocally', () => {
750
+ afterEach(() => {
751
+ sinon.restore();
752
+ });
753
+
754
+ it('calls setServerMuted on the stream', async () => {
755
+ await setup(mediaType);
756
+ setupSpies(mediaType);
757
+
758
+ muteState.applyClientStateLocally(meeting, 'somereason');
759
+ assert.calledOnceWithExactly(
760
+ setServerMutedSpy,
761
+ muteState.state.client.localMute,
762
+ 'somereason'
763
+ );
764
+ assert.notCalled(setUserMutedSpy);
765
+ });
766
+
767
+ it('nothing explodes when streams are undefined', async () => {
768
+ await setup(mediaType, false, false, false);
769
+ setupSpies(mediaType);
770
+
771
+ muteState.applyClientStateLocally(meeting, 'somereason');
772
+ });
773
+ });
774
+ })
775
+ );
776
+ });
416
777
  });
417
778
  });