@webex/plugin-meetings 3.0.0-beta.3 → 3.0.0-beta.300

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