@webex/plugin-meetings 3.0.0-beta.34 → 3.0.0-beta.340

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 (392) hide show
  1. package/README.md +46 -8
  2. package/dist/annotation/annotation.types.js +7 -0
  3. package/dist/annotation/annotation.types.js.map +1 -0
  4. package/dist/annotation/constants.js +49 -0
  5. package/dist/annotation/constants.js.map +1 -0
  6. package/dist/annotation/index.js +342 -0
  7. package/dist/annotation/index.js.map +1 -0
  8. package/dist/breakouts/breakout.js +94 -15
  9. package/dist/breakouts/breakout.js.map +1 -1
  10. package/dist/breakouts/edit-lock-error.js +52 -0
  11. package/dist/breakouts/edit-lock-error.js.map +1 -0
  12. package/dist/breakouts/events.js +45 -0
  13. package/dist/breakouts/events.js.map +1 -0
  14. package/dist/breakouts/index.js +709 -35
  15. package/dist/breakouts/index.js.map +1 -1
  16. package/dist/breakouts/utils.js +45 -1
  17. package/dist/breakouts/utils.js.map +1 -1
  18. package/dist/common/errors/no-meeting-info.js +51 -0
  19. package/dist/common/errors/no-meeting-info.js.map +1 -0
  20. package/dist/common/errors/reclaim-host-role-errors.js +158 -0
  21. package/dist/common/errors/reclaim-host-role-errors.js.map +1 -0
  22. package/dist/common/errors/webex-errors.js +48 -7
  23. package/dist/common/errors/webex-errors.js.map +1 -1
  24. package/dist/common/logs/logger-proxy.js +1 -1
  25. package/dist/common/logs/logger-proxy.js.map +1 -1
  26. package/dist/common/logs/request.js +5 -1
  27. package/dist/common/logs/request.js.map +1 -1
  28. package/dist/common/queue.js +24 -9
  29. package/dist/common/queue.js.map +1 -1
  30. package/dist/config.js +5 -10
  31. package/dist/config.js.map +1 -1
  32. package/dist/constants.js +233 -29
  33. package/dist/constants.js.map +1 -1
  34. package/dist/controls-options-manager/enums.js +14 -2
  35. package/dist/controls-options-manager/enums.js.map +1 -1
  36. package/dist/controls-options-manager/index.js +109 -15
  37. package/dist/controls-options-manager/index.js.map +1 -1
  38. package/dist/controls-options-manager/types.js +7 -0
  39. package/dist/controls-options-manager/types.js.map +1 -0
  40. package/dist/controls-options-manager/util.js +309 -18
  41. package/dist/controls-options-manager/util.js.map +1 -1
  42. package/dist/index.js +112 -1
  43. package/dist/index.js.map +1 -1
  44. package/dist/interpretation/collection.js +23 -0
  45. package/dist/interpretation/collection.js.map +1 -0
  46. package/dist/interpretation/index.js +366 -0
  47. package/dist/interpretation/index.js.map +1 -0
  48. package/dist/interpretation/siLanguage.js +25 -0
  49. package/dist/interpretation/siLanguage.js.map +1 -0
  50. package/dist/locus-info/controlsUtils.js +91 -2
  51. package/dist/locus-info/controlsUtils.js.map +1 -1
  52. package/dist/locus-info/index.js +383 -62
  53. package/dist/locus-info/index.js.map +1 -1
  54. package/dist/locus-info/infoUtils.js +7 -1
  55. package/dist/locus-info/infoUtils.js.map +1 -1
  56. package/dist/locus-info/mediaSharesUtils.js +57 -1
  57. package/dist/locus-info/mediaSharesUtils.js.map +1 -1
  58. package/dist/locus-info/parser.js +249 -72
  59. package/dist/locus-info/parser.js.map +1 -1
  60. package/dist/locus-info/selfUtils.js +89 -14
  61. package/dist/locus-info/selfUtils.js.map +1 -1
  62. package/dist/media/index.js +62 -116
  63. package/dist/media/index.js.map +1 -1
  64. package/dist/media/properties.js +73 -124
  65. package/dist/media/properties.js.map +1 -1
  66. package/dist/mediaQualityMetrics/config.js +1 -204
  67. package/dist/mediaQualityMetrics/config.js.map +1 -1
  68. package/dist/meeting/in-meeting-actions.js +86 -2
  69. package/dist/meeting/in-meeting-actions.js.map +1 -1
  70. package/dist/meeting/index.js +3927 -2960
  71. package/dist/meeting/index.js.map +1 -1
  72. package/dist/meeting/locusMediaRequest.js +292 -0
  73. package/dist/meeting/locusMediaRequest.js.map +1 -0
  74. package/dist/meeting/muteState.js +224 -131
  75. package/dist/meeting/muteState.js.map +1 -1
  76. package/dist/meeting/request.js +260 -196
  77. package/dist/meeting/request.js.map +1 -1
  78. package/dist/meeting/util.js +601 -417
  79. package/dist/meeting/util.js.map +1 -1
  80. package/dist/meeting-info/index.js +73 -7
  81. package/dist/meeting-info/index.js.map +1 -1
  82. package/dist/meeting-info/meeting-info-v2.js +192 -51
  83. package/dist/meeting-info/meeting-info-v2.js.map +1 -1
  84. package/dist/meeting-info/util.js +1 -1
  85. package/dist/meeting-info/util.js.map +1 -1
  86. package/dist/meeting-info/utilv2.js +36 -36
  87. package/dist/meeting-info/utilv2.js.map +1 -1
  88. package/dist/meetings/collection.js +39 -0
  89. package/dist/meetings/collection.js.map +1 -1
  90. package/dist/meetings/index.js +424 -116
  91. package/dist/meetings/index.js.map +1 -1
  92. package/dist/meetings/meetings.types.js +7 -0
  93. package/dist/meetings/meetings.types.js.map +1 -0
  94. package/dist/meetings/request.js +2 -0
  95. package/dist/meetings/request.js.map +1 -1
  96. package/dist/meetings/util.js +72 -6
  97. package/dist/meetings/util.js.map +1 -1
  98. package/dist/member/index.js +58 -0
  99. package/dist/member/index.js.map +1 -1
  100. package/dist/member/types.js +25 -0
  101. package/dist/member/types.js.map +1 -0
  102. package/dist/member/util.js +132 -25
  103. package/dist/member/util.js.map +1 -1
  104. package/dist/members/collection.js +10 -0
  105. package/dist/members/collection.js.map +1 -1
  106. package/dist/members/index.js +102 -6
  107. package/dist/members/index.js.map +1 -1
  108. package/dist/members/request.js +106 -38
  109. package/dist/members/request.js.map +1 -1
  110. package/dist/members/types.js +15 -0
  111. package/dist/members/types.js.map +1 -0
  112. package/dist/members/util.js +326 -232
  113. package/dist/members/util.js.map +1 -1
  114. package/dist/metrics/constants.js +16 -5
  115. package/dist/metrics/constants.js.map +1 -1
  116. package/dist/metrics/index.js +1 -446
  117. package/dist/metrics/index.js.map +1 -1
  118. package/dist/multistream/mediaRequestManager.js +228 -58
  119. package/dist/multistream/mediaRequestManager.js.map +1 -1
  120. package/dist/multistream/receiveSlot.js +29 -16
  121. package/dist/multistream/receiveSlot.js.map +1 -1
  122. package/dist/multistream/receiveSlotManager.js +39 -36
  123. package/dist/multistream/receiveSlotManager.js.map +1 -1
  124. package/dist/multistream/remoteMedia.js +44 -18
  125. package/dist/multistream/remoteMedia.js.map +1 -1
  126. package/dist/multistream/remoteMediaGroup.js +60 -3
  127. package/dist/multistream/remoteMediaGroup.js.map +1 -1
  128. package/dist/multistream/remoteMediaManager.js +209 -59
  129. package/dist/multistream/remoteMediaManager.js.map +1 -1
  130. package/dist/multistream/sendSlotManager.js +233 -0
  131. package/dist/multistream/sendSlotManager.js.map +1 -0
  132. package/dist/reachability/clusterReachability.js +356 -0
  133. package/dist/reachability/clusterReachability.js.map +1 -0
  134. package/dist/reachability/index.js +273 -391
  135. package/dist/reachability/index.js.map +1 -1
  136. package/dist/reachability/request.js +17 -8
  137. package/dist/reachability/request.js.map +1 -1
  138. package/dist/reachability/util.js +29 -0
  139. package/dist/reachability/util.js.map +1 -0
  140. package/dist/reconnection-manager/index.js +214 -170
  141. package/dist/reconnection-manager/index.js.map +1 -1
  142. package/dist/recording-controller/index.js +21 -2
  143. package/dist/recording-controller/index.js.map +1 -1
  144. package/dist/recording-controller/util.js +9 -8
  145. package/dist/recording-controller/util.js.map +1 -1
  146. package/dist/roap/index.js +62 -35
  147. package/dist/roap/index.js.map +1 -1
  148. package/dist/roap/request.js +112 -97
  149. package/dist/roap/request.js.map +1 -1
  150. package/dist/roap/turnDiscovery.js +95 -38
  151. package/dist/roap/turnDiscovery.js.map +1 -1
  152. package/dist/rtcMetrics/constants.js +12 -0
  153. package/dist/rtcMetrics/constants.js.map +1 -0
  154. package/dist/rtcMetrics/index.js +142 -0
  155. package/dist/rtcMetrics/index.js.map +1 -0
  156. package/dist/statsAnalyzer/index.js +181 -214
  157. package/dist/statsAnalyzer/index.js.map +1 -1
  158. package/dist/statsAnalyzer/mqaUtil.js +22 -18
  159. package/dist/statsAnalyzer/mqaUtil.js.map +1 -1
  160. package/dist/types/annotation/annotation.types.d.ts +42 -0
  161. package/dist/types/annotation/constants.d.ts +31 -0
  162. package/dist/types/annotation/index.d.ts +117 -0
  163. package/dist/types/breakouts/edit-lock-error.d.ts +15 -0
  164. package/dist/types/breakouts/events.d.ts +8 -0
  165. package/dist/types/breakouts/utils.d.ts +14 -0
  166. package/dist/types/common/errors/no-meeting-info.d.ts +14 -0
  167. package/dist/types/common/errors/reclaim-host-role-errors.d.ts +60 -0
  168. package/dist/types/common/errors/webex-errors.d.ts +25 -1
  169. package/dist/types/common/logs/request.d.ts +2 -0
  170. package/dist/types/common/queue.d.ts +9 -7
  171. package/dist/types/config.d.ts +2 -7
  172. package/dist/types/constants.d.ts +201 -30
  173. package/dist/types/controls-options-manager/enums.d.ts +11 -1
  174. package/dist/types/controls-options-manager/index.d.ts +17 -1
  175. package/dist/types/controls-options-manager/types.d.ts +43 -0
  176. package/dist/types/controls-options-manager/util.d.ts +1 -7
  177. package/dist/types/index.d.ts +6 -4
  178. package/dist/types/interpretation/collection.d.ts +5 -0
  179. package/dist/types/interpretation/index.d.ts +5 -0
  180. package/dist/types/interpretation/siLanguage.d.ts +5 -0
  181. package/dist/types/locus-info/index.d.ts +57 -4
  182. package/dist/types/locus-info/parser.d.ts +66 -6
  183. package/dist/types/media/index.d.ts +2 -0
  184. package/dist/types/media/properties.d.ts +34 -48
  185. package/dist/types/mediaQualityMetrics/config.d.ts +0 -128
  186. package/dist/types/meeting/in-meeting-actions.d.ts +86 -2
  187. package/dist/types/meeting/index.d.ts +506 -512
  188. package/dist/types/meeting/locusMediaRequest.d.ts +74 -0
  189. package/dist/types/meeting/muteState.d.ts +93 -25
  190. package/dist/types/meeting/request.d.ts +72 -43
  191. package/dist/types/meeting/util.d.ts +101 -1
  192. package/dist/types/meeting-info/index.d.ts +13 -1
  193. package/dist/types/meeting-info/meeting-info-v2.d.ts +31 -1
  194. package/dist/types/meetings/collection.d.ts +17 -0
  195. package/dist/types/meetings/index.d.ts +91 -21
  196. package/dist/types/meetings/meetings.types.d.ts +4 -0
  197. package/dist/types/member/index.d.ts +14 -0
  198. package/dist/types/member/types.d.ts +32 -0
  199. package/dist/types/members/collection.d.ts +5 -0
  200. package/dist/types/members/index.d.ts +35 -2
  201. package/dist/types/members/request.d.ts +73 -9
  202. package/dist/types/members/types.d.ts +25 -0
  203. package/dist/types/members/util.d.ts +214 -1
  204. package/dist/types/metrics/constants.d.ts +15 -4
  205. package/dist/types/metrics/index.d.ts +4 -111
  206. package/dist/types/multistream/mediaRequestManager.d.ts +72 -5
  207. package/dist/types/multistream/receiveSlot.d.ts +13 -11
  208. package/dist/types/multistream/receiveSlotManager.d.ts +14 -4
  209. package/dist/types/multistream/remoteMedia.d.ts +8 -29
  210. package/dist/types/multistream/remoteMediaGroup.d.ts +0 -9
  211. package/dist/types/multistream/remoteMediaManager.d.ts +46 -2
  212. package/dist/types/multistream/sendSlotManager.d.ts +61 -0
  213. package/dist/types/reachability/clusterReachability.d.ts +109 -0
  214. package/dist/types/reachability/index.d.ts +60 -95
  215. package/dist/types/reachability/request.d.ts +7 -3
  216. package/dist/types/reachability/util.d.ts +8 -0
  217. package/dist/types/reconnection-manager/index.d.ts +19 -0
  218. package/dist/types/recording-controller/index.d.ts +15 -1
  219. package/dist/types/recording-controller/util.d.ts +5 -4
  220. package/dist/types/roap/index.d.ts +2 -1
  221. package/dist/types/roap/request.d.ts +15 -11
  222. package/dist/types/roap/turnDiscovery.d.ts +21 -3
  223. package/dist/types/rtcMetrics/constants.d.ts +4 -0
  224. package/dist/types/rtcMetrics/index.d.ts +54 -0
  225. package/dist/types/statsAnalyzer/index.d.ts +29 -11
  226. package/dist/types/webinar/collection.d.ts +16 -0
  227. package/dist/types/webinar/index.d.ts +5 -0
  228. package/dist/webinar/collection.js +44 -0
  229. package/dist/webinar/collection.js.map +1 -0
  230. package/dist/webinar/index.js +69 -0
  231. package/dist/webinar/index.js.map +1 -0
  232. package/package.json +22 -19
  233. package/src/annotation/annotation.types.ts +50 -0
  234. package/src/annotation/constants.ts +36 -0
  235. package/src/annotation/index.ts +328 -0
  236. package/src/breakouts/README.md +42 -12
  237. package/src/breakouts/breakout.ts +67 -9
  238. package/src/breakouts/edit-lock-error.ts +25 -0
  239. package/src/breakouts/events.ts +56 -0
  240. package/src/breakouts/index.ts +592 -20
  241. package/src/breakouts/utils.ts +42 -0
  242. package/src/common/errors/no-meeting-info.ts +24 -0
  243. package/src/common/errors/reclaim-host-role-errors.ts +134 -0
  244. package/src/common/errors/webex-errors.ts +44 -2
  245. package/src/common/logs/logger-proxy.ts +1 -1
  246. package/src/common/logs/request.ts +5 -1
  247. package/src/common/queue.ts +22 -8
  248. package/src/config.ts +4 -9
  249. package/src/constants.ts +224 -20
  250. package/src/controls-options-manager/enums.ts +12 -0
  251. package/src/controls-options-manager/index.ts +116 -21
  252. package/src/controls-options-manager/types.ts +59 -0
  253. package/src/controls-options-manager/util.ts +294 -14
  254. package/src/index.ts +40 -0
  255. package/src/interpretation/README.md +60 -0
  256. package/src/interpretation/collection.ts +19 -0
  257. package/src/interpretation/index.ts +332 -0
  258. package/src/interpretation/siLanguage.ts +18 -0
  259. package/src/locus-info/controlsUtils.ts +108 -0
  260. package/src/locus-info/index.ts +413 -59
  261. package/src/locus-info/infoUtils.ts +10 -2
  262. package/src/locus-info/mediaSharesUtils.ts +64 -0
  263. package/src/locus-info/parser.ts +258 -47
  264. package/src/locus-info/selfUtils.ts +81 -5
  265. package/src/media/index.ts +102 -122
  266. package/src/media/properties.ts +87 -110
  267. package/src/mediaQualityMetrics/config.ts +0 -135
  268. package/src/meeting/in-meeting-actions.ts +171 -3
  269. package/src/meeting/index.ts +3276 -2555
  270. package/src/meeting/locusMediaRequest.ts +313 -0
  271. package/src/meeting/muteState.ts +223 -136
  272. package/src/meeting/request.ts +177 -121
  273. package/src/meeting/util.ts +588 -394
  274. package/src/meeting-info/index.ts +81 -8
  275. package/src/meeting-info/meeting-info-v2.ts +170 -14
  276. package/src/meeting-info/util.ts +1 -1
  277. package/src/meeting-info/utilv2.ts +23 -23
  278. package/src/meetings/collection.ts +33 -0
  279. package/src/meetings/index.ts +454 -125
  280. package/src/meetings/meetings.types.ts +12 -0
  281. package/src/meetings/request.ts +2 -0
  282. package/src/meetings/util.ts +80 -11
  283. package/src/member/index.ts +58 -0
  284. package/src/member/types.ts +38 -0
  285. package/src/member/util.ts +141 -25
  286. package/src/members/collection.ts +8 -0
  287. package/src/members/index.ts +134 -8
  288. package/src/members/request.ts +97 -17
  289. package/src/members/types.ts +29 -0
  290. package/src/members/util.ts +333 -240
  291. package/src/metrics/constants.ts +15 -4
  292. package/src/metrics/index.ts +1 -469
  293. package/src/multistream/mediaRequestManager.ts +277 -82
  294. package/src/multistream/receiveSlot.ts +31 -17
  295. package/src/multistream/receiveSlotManager.ts +34 -24
  296. package/src/multistream/remoteMedia.ts +27 -2
  297. package/src/multistream/remoteMediaGroup.ts +59 -0
  298. package/src/multistream/remoteMediaManager.ts +148 -30
  299. package/src/multistream/sendSlotManager.ts +170 -0
  300. package/src/reachability/clusterReachability.ts +320 -0
  301. package/src/reachability/index.ts +236 -342
  302. package/src/reachability/request.ts +17 -8
  303. package/src/reachability/util.ts +24 -0
  304. package/src/reconnection-manager/index.ts +128 -106
  305. package/src/recording-controller/index.ts +20 -3
  306. package/src/recording-controller/util.ts +26 -9
  307. package/src/roap/index.ts +63 -32
  308. package/src/roap/request.ts +100 -104
  309. package/src/roap/turnDiscovery.ts +48 -26
  310. package/src/rtcMetrics/constants.ts +3 -0
  311. package/src/rtcMetrics/index.ts +124 -0
  312. package/src/statsAnalyzer/index.ts +218 -289
  313. package/src/statsAnalyzer/mqaUtil.ts +28 -30
  314. package/src/webinar/collection.ts +31 -0
  315. package/src/webinar/index.ts +62 -0
  316. package/test/integration/spec/converged-space-meetings.js +60 -3
  317. package/test/integration/spec/journey.js +320 -261
  318. package/test/integration/spec/space-meeting.js +76 -3
  319. package/test/unit/spec/annotation/index.ts +418 -0
  320. package/test/unit/spec/breakouts/breakout.ts +118 -28
  321. package/test/unit/spec/breakouts/edit-lock-error.ts +30 -0
  322. package/test/unit/spec/breakouts/events.ts +89 -0
  323. package/test/unit/spec/breakouts/index.ts +1395 -69
  324. package/test/unit/spec/breakouts/utils.js +52 -1
  325. package/test/unit/spec/common/queue.js +31 -2
  326. package/test/unit/spec/controls-options-manager/index.js +163 -0
  327. package/test/unit/spec/controls-options-manager/util.js +576 -60
  328. package/test/unit/spec/fixture/locus.js +1 -0
  329. package/test/unit/spec/interpretation/collection.ts +15 -0
  330. package/test/unit/spec/interpretation/index.ts +589 -0
  331. package/test/unit/spec/interpretation/siLanguage.ts +28 -0
  332. package/test/unit/spec/locus-info/controlsUtils.js +316 -43
  333. package/test/unit/spec/locus-info/index.js +1304 -33
  334. package/test/unit/spec/locus-info/infoUtils.js +37 -15
  335. package/test/unit/spec/locus-info/lib/SeqCmp.json +16 -0
  336. package/test/unit/spec/locus-info/mediaSharesUtils.ts +32 -0
  337. package/test/unit/spec/locus-info/parser.js +116 -35
  338. package/test/unit/spec/locus-info/selfConstant.js +27 -4
  339. package/test/unit/spec/locus-info/selfUtils.js +208 -17
  340. package/test/unit/spec/media/index.ts +120 -37
  341. package/test/unit/spec/media/properties.ts +2 -2
  342. package/test/unit/spec/meeting/in-meeting-actions.ts +85 -3
  343. package/test/unit/spec/meeting/index.js +5849 -2014
  344. package/test/unit/spec/meeting/locusMediaRequest.ts +442 -0
  345. package/test/unit/spec/meeting/muteState.js +402 -213
  346. package/test/unit/spec/meeting/request.js +483 -49
  347. package/test/unit/spec/meeting/utils.js +679 -64
  348. package/test/unit/spec/meeting-info/index.js +300 -0
  349. package/test/unit/spec/meeting-info/meetinginfov2.js +526 -5
  350. package/test/unit/spec/meeting-info/utilv2.js +21 -0
  351. package/test/unit/spec/meetings/collection.js +26 -0
  352. package/test/unit/spec/meetings/index.js +1231 -212
  353. package/test/unit/spec/meetings/utils.js +202 -2
  354. package/test/unit/spec/member/index.js +61 -6
  355. package/test/unit/spec/member/util.js +510 -34
  356. package/test/unit/spec/members/index.js +432 -1
  357. package/test/unit/spec/members/request.js +206 -27
  358. package/test/unit/spec/members/utils.js +210 -0
  359. package/test/unit/spec/metrics/index.js +1 -50
  360. package/test/unit/spec/multistream/mediaRequestManager.ts +776 -162
  361. package/test/unit/spec/multistream/receiveSlot.ts +28 -20
  362. package/test/unit/spec/multistream/receiveSlotManager.ts +32 -30
  363. package/test/unit/spec/multistream/remoteMedia.ts +30 -0
  364. package/test/unit/spec/multistream/remoteMediaGroup.ts +266 -0
  365. package/test/unit/spec/multistream/remoteMediaManager.ts +326 -0
  366. package/test/unit/spec/multistream/sendSlotManager.ts +242 -0
  367. package/test/unit/spec/reachability/clusterReachability.ts +279 -0
  368. package/test/unit/spec/reachability/index.ts +486 -13
  369. package/test/unit/spec/reachability/request.js +68 -0
  370. package/test/unit/spec/reachability/util.ts +40 -0
  371. package/test/unit/spec/reconnection-manager/index.js +117 -11
  372. package/test/unit/spec/recording-controller/index.js +294 -218
  373. package/test/unit/spec/recording-controller/util.js +223 -96
  374. package/test/unit/spec/roap/index.ts +174 -63
  375. package/test/unit/spec/roap/request.ts +226 -85
  376. package/test/unit/spec/roap/turnDiscovery.ts +76 -34
  377. package/test/unit/spec/rtcMetrics/index.ts +93 -0
  378. package/test/unit/spec/stats-analyzer/index.js +231 -7
  379. package/test/unit/spec/webinar/collection.ts +13 -0
  380. package/test/unit/spec/webinar/index.ts +60 -0
  381. package/test/utils/integrationTestUtils.js +46 -0
  382. package/test/utils/testUtils.js +0 -52
  383. package/dist/meeting/effectsState.js +0 -262
  384. package/dist/meeting/effectsState.js.map +0 -1
  385. package/dist/metrics/config.js +0 -289
  386. package/dist/metrics/config.js.map +0 -1
  387. package/dist/types/meeting/effectsState.d.ts +0 -42
  388. package/dist/types/metrics/config.d.ts +0 -169
  389. package/src/index.js +0 -16
  390. package/src/meeting/effectsState.ts +0 -211
  391. package/src/metrics/config.ts +0 -485
  392. package/test/unit/spec/meeting/effectsState.js +0 -285
@@ -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
44
  muteMember: sinon.stub().resolves(),
33
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,250 +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(
132
- new Promise((resolve) => {
133
- serverResponseResolve = resolve;
134
- })
135
- );
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);
136
144
 
137
- audio
138
- .handleClientRequest(meeting, true)
139
- .then(() => {
140
- clientPromiseResolved = true;
141
- })
142
- .catch(() => {
143
- clientPromiseRejected = true;
144
- });
145
+ assert.isTrue(video.isMuted());
145
146
 
146
147
  MeetingUtil.remoteUpdateAudioVideo.resetHistory();
147
148
 
148
149
  // now simulate server requiring us to locally unmute
149
- audio.handleServerLocalUnmuteRequired(meeting);
150
+ video.handleServerLocalUnmuteRequired(meeting);
150
151
  await testUtils.flushPromises();
151
152
 
152
- // the original client request should have been rejected by now
153
- assert.isTrue(clientPromiseRejected);
154
- assert.isFalse(clientPromiseResolved);
155
-
156
- // now make the server respond to the original mute request
157
- serverResponseResolve();
158
- await testUtils.flushPromises();
153
+ // check that local stream was unmuted
154
+ assert.calledWith(
155
+ meeting.mediaProperties.videoStream.setServerMuted,
156
+ false,
157
+ 'localUnmuteRequired'
158
+ );
159
159
 
160
- // local unmute should be sent to server
160
+ // and local unmute was sent to server
161
161
  assert.calledOnce(MeetingUtil.remoteUpdateAudioVideo);
162
- assert.calledWith(MeetingUtil.remoteUpdateAudioVideo, false, undefined, meeting);
163
-
164
- // and local track should be enabled
165
- assert.calledWith(Media.setLocalTrack, true, meeting.mediaProperties.audioTrack);
162
+ assert.calledWith(MeetingUtil.remoteUpdateAudioVideo, meeting, undefined, false);
166
163
 
167
- assert.isFalse(audio.isMuted());
168
- assert.isFalse(audio.isSelf());
164
+ assert.isFalse(video.isMuted());
169
165
  });
170
166
 
171
167
  describe('#isLocallyMuted()', () => {
172
168
  it('does not consider remote mute status for audio', async () => {
173
- // simulate being already remote muted
169
+ // simulate being already remote muted and locally unmuted
174
170
  meeting.remoteMuted = true;
175
- // create a new MuteState intance
176
- audio = createMuteState(AUDIO, meeting, {sendAudio: true});
171
+ meeting.mediaProperties.audioStream.muted = false;
172
+
173
+ // create a new MuteState instance
174
+ audio = createMuteState(AUDIO, meeting, true);
175
+ audio.handleLocalStreamChange(meeting);
176
+
177
+ await testUtils.flushPromises();
177
178
 
178
179
  assert.isFalse(audio.isLocallyMuted());
179
180
  });
180
- });
181
181
 
182
- describe('#handleClientRequest', () => {
183
- it('disables/enables the local audio track when audio is muted/unmuted', async () => {
184
- // mute
185
- audio.handleClientRequest(meeting, true);
186
- assert.calledWith(Media.setLocalTrack, false, meeting.mediaProperties.audioTrack);
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;
187
186
 
188
- // even when calling mute when it's already muted should still call setLocalTrack
189
- audio.handleClientRequest(meeting, true);
190
- assert.calledWith(Media.setLocalTrack, false, meeting.mediaProperties.audioTrack);
187
+ // create a new MuteState instance
188
+ video = createMuteState(VIDEO, meeting, true);
189
+ video.handleLocalStreamChange(meeting);
191
190
 
192
- // unmute
193
- audio.handleClientRequest(meeting, false);
194
- assert.calledWith(Media.setLocalTrack, true, meeting.mediaProperties.audioTrack);
191
+ await testUtils.flushPromises();
195
192
 
196
- // even when calling unmute when it's already unmuted should still call setLocalTrack
197
- audio.handleClientRequest(meeting, false);
198
- assert.calledWith(Media.setLocalTrack, true, meeting.mediaProperties.audioTrack);
193
+ assert.isFalse(video.isLocallyMuted());
199
194
  });
195
+ });
200
196
 
201
- it('disables/enables the local video track when video is muted/unmuted', async () => {
202
- // mute
203
- video.handleClientRequest(meeting, true);
204
- assert.calledWith(Media.setLocalTrack, false, meeting.mediaProperties.videoTrack);
197
+ describe('handling local stream mute events', () => {
198
+ beforeEach(async () => {
199
+ audio.handleLocalStreamChange(meeting);
200
+ video.handleLocalStreamChange(meeting);
201
+
202
+ await testUtils.flushPromises();
203
+ });
205
204
 
206
- // even when calling mute when it's already muted should still call setLocalTrack
207
- video.handleClientRequest(meeting, false);
208
- assert.calledWith(Media.setLocalTrack, false, meeting.mediaProperties.videoTrack);
205
+ const simulateAudioMuteChange = async (muteValue) => {
206
+ meeting.mediaProperties.audioStream.muted = muteValue;
207
+ audio.handleLocalStreamMuteStateChange(meeting, muteValue);
209
208
 
210
- // unmute
211
- video.handleClientRequest(meeting, false);
212
- assert.calledWith(Media.setLocalTrack, true, meeting.mediaProperties.videoTrack);
209
+ await testUtils.flushPromises();
210
+ };
213
211
 
214
- // even when calling unmute when it's already unmuted should still call setLocalTrack
215
- video.handleClientRequest(meeting, false);
216
- assert.calledWith(Media.setLocalTrack, true, meeting.mediaProperties.videoTrack);
217
- });
212
+ const simulateVideoMuteChange = async (muteValue) => {
213
+ meeting.mediaProperties.videoStream.muted = muteValue;
214
+ video.handleLocalStreamMuteStateChange(meeting, muteValue);
218
215
 
219
- it('returns correct value in isMuted()/isSelf() methods after client mute/unmute requests', async () => {
220
- // mute
221
- audio.handleClientRequest(meeting, true);
216
+ await testUtils.flushPromises();
217
+ };
222
218
 
219
+ it('returns correct value in isMuted() methods after local stream is muted/unmuted', async () => {
220
+ // mute
221
+ await simulateAudioMuteChange(true);
223
222
  assert.isTrue(audio.isMuted());
224
- assert.isTrue(audio.isSelf());
225
223
 
226
224
  // unmute
227
- audio.handleClientRequest(meeting, false);
228
-
225
+ await simulateAudioMuteChange(false);
229
226
  assert.isFalse(audio.isMuted());
230
- assert.isFalse(audio.isSelf());
231
227
  });
232
228
 
233
229
  it('does remote unmute when unmuting and remote mute is on', async () => {
234
230
  // simulate remote mute
235
- audio.handleServerRemoteMuteUpdate(true, true);
231
+ audio.handleServerRemoteMuteUpdate(meeting, true, true);
236
232
 
237
233
  // unmute
238
- await audio.handleClientRequest(meeting, false);
234
+ await simulateAudioMuteChange(false);
239
235
 
240
236
  // check that remote unmute was sent to server
241
237
  assert.calledOnce(meeting.members.muteMember);
242
- assert.calledWith(meeting.members.muteMember, meeting.members.selfId, false);
238
+ assert.calledWith(meeting.members.muteMember, meeting.members.selfId, false, true);
243
239
 
244
240
  assert.isFalse(audio.isMuted());
245
- assert.isFalse(audio.isSelf());
246
241
  });
247
242
 
248
- it('resolves client request promise once the server is updated', async () => {
249
- 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);
250
246
 
251
- let serverResponseResolve;
247
+ // unmute
248
+ await simulateVideoMuteChange(false);
252
249
 
253
- MeetingUtil.remoteUpdateAudioVideo = sinon.stub().returns(
254
- new Promise((resolve) => {
255
- serverResponseResolve = resolve;
256
- })
257
- );
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);
258
253
 
259
- audio.handleClientRequest(meeting, true).then(() => {
260
- clientPromiseResolved = true;
261
- });
254
+ assert.isFalse(video.isMuted());
255
+ });
262
256
 
263
- // do a small delay to make sure that the client promise doesn't resolve in that time
264
- await testUtils.waitUntil(200);
265
- 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);
266
260
 
267
- // now allow the server response to arrive, this should trigger the client promise to get resolved
268
- serverResponseResolve();
269
- await testUtils.flushPromises();
261
+ // unmute
262
+ await simulateVideoMuteChange(false);
263
+
264
+ // check that remote unmute was not sent to server
265
+ assert.notCalled(meeting.members.muteMember);
270
266
 
271
- assert.isTrue(clientPromiseResolved);
267
+ assert.isFalse(video.isMuted());
272
268
  });
273
269
 
274
- it('rejects client request promise if server request for local mute fails', async () => {
275
- MeetingUtil.remoteUpdateAudioVideo = sinon.stub().returns(
276
- new Promise((resolve, reject) => {
277
- reject();
278
- })
279
- );
270
+ it('calls setServerMuted with "clientRequestFailed" when server request for local mute fails', async () => {
271
+ MeetingUtil.remoteUpdateAudioVideo = sinon.stub().rejects(new Error('fake error'));
280
272
 
281
- assert.isRejected(audio.handleClientRequest(meeting, true));
273
+ await simulateAudioMuteChange(true);
274
+
275
+ assert.calledOnceWithExactly(
276
+ meeting.mediaProperties.audioStream.setServerMuted,
277
+ false,
278
+ 'clientRequestFailed'
279
+ );
282
280
  });
283
281
 
284
- 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 () => {
285
283
  // we only send remote mute requests when we're unmuting, so first we need to do a remote mute
286
- audio.handleServerRemoteMuteUpdate(true, true);
284
+ audio.handleServerRemoteMuteUpdate(meeting, true, true);
285
+
286
+ await testUtils.flushPromises();
287
287
 
288
288
  // setup the stub to simulate server error response
289
289
  meeting.members.muteMember = sinon.stub().rejects();
290
+ meeting.mediaProperties.audioStream.setServerMuted.resetHistory();
290
291
 
291
- // try to unmute - it should fail
292
- 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
+ );
293
299
 
294
300
  // even though remote mute update in the server failed, isMuted() should still return true,
295
301
  // because of local mute
@@ -305,12 +311,13 @@ describe('plugin-meetings', () => {
305
311
  })
306
312
  );
307
313
 
308
- // simulate many client requests, with the last one matching the initial one
309
- audio.handleClientRequest(meeting, true);
310
- audio.handleClientRequest(meeting, false);
311
- audio.handleClientRequest(meeting, true);
312
- audio.handleClientRequest(meeting, false);
313
- 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);
314
321
 
315
322
  // so far there should have been only 1 request to server (because our stub hasn't resolved yet
316
323
  // and MuteState sends only 1 server request at a time)
@@ -325,7 +332,7 @@ describe('plugin-meetings', () => {
325
332
  assert.notCalled(MeetingUtil.remoteUpdateAudioVideo);
326
333
  });
327
334
 
328
- 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 () => {
329
336
  let serverResponseResolve;
330
337
 
331
338
  MeetingUtil.remoteUpdateAudioVideo = sinon.stub().returns(
@@ -334,104 +341,286 @@ describe('plugin-meetings', () => {
334
341
  })
335
342
  );
336
343
 
337
- let firstClientPromiseResolved = false;
338
- let secondClientPromiseResolved = false;
339
-
340
344
  // 2 client requests, one after another without waiting for first one to resolve
341
- audio.handleClientRequest(meeting, true).then(() => {
342
- firstClientPromiseResolved = true;
343
- });
344
- audio.handleClientRequest(meeting, false).then(() => {
345
- secondClientPromiseResolved = true;
346
- });
347
-
348
- await testUtils.flushPromises();
345
+ await simulateAudioMuteChange(true);
346
+ await simulateAudioMuteChange(false);
349
347
 
350
348
  assert.calledOnce(MeetingUtil.remoteUpdateAudioVideo);
351
- assert.calledWith(MeetingUtil.remoteUpdateAudioVideo, true, undefined, meeting);
349
+ assert.calledWith(MeetingUtil.remoteUpdateAudioVideo, meeting, true, undefined);
352
350
 
353
351
  // now allow the first request to complete
354
352
  serverResponseResolve();
355
353
  await testUtils.flushPromises();
356
- assert.isTrue(firstClientPromiseResolved);
357
354
 
358
355
  // that should trigger the second server request to be sent
359
356
  assert.calledTwice(MeetingUtil.remoteUpdateAudioVideo);
360
- assert.strictEqual(false, MeetingUtil.remoteUpdateAudioVideo.getCall(1).args[0]);
361
- assert.strictEqual(undefined, MeetingUtil.remoteUpdateAudioVideo.getCall(1).args[1]);
362
- assert.strictEqual(meeting, MeetingUtil.remoteUpdateAudioVideo.getCall(1).args[2]);
357
+ assert.deepEqual(
358
+ [meeting, false, undefined],
359
+ MeetingUtil.remoteUpdateAudioVideo.getCall(1).args
360
+ );
363
361
 
364
362
  serverResponseResolve();
365
- await testUtils.flushPromises();
366
-
367
- assert.isTrue(secondClientPromiseResolved);
368
- });
369
-
370
- it('rejects client request to unmute if hard mute is used', (done) => {
371
- audio.handleServerRemoteMuteUpdate(true, false);
372
-
373
- audio
374
- .handleClientRequest(meeting, false)
375
- .then(() => {
376
- done(new Error('expected handleClientRequest to fail, but it did not!'));
377
- })
378
- .catch((e) => {
379
- assert.isTrue(e instanceof PermissionError);
380
- done();
381
- });
382
363
  });
383
364
 
384
365
  it('does not send remote mute for video', async () => {
385
366
  // mute
386
- await video.handleClientRequest(meeting, true);
367
+ await simulateVideoMuteChange(true);
387
368
 
388
369
  assert.isTrue(video.isMuted());
389
- assert.isTrue(video.isSelf());
390
370
 
391
371
  // check local mute is done, but not remote one
392
- assert.calledWith(Media.setLocalTrack, false, meeting.mediaProperties.videoTrack);
393
- assert.calledWith(MeetingUtil.remoteUpdateAudioVideo, undefined, true, meeting);
372
+ assert.calledWith(MeetingUtil.remoteUpdateAudioVideo, meeting, undefined, true);
394
373
  assert.notCalled(meeting.members.muteMember);
395
374
 
396
- Media.setLocalTrack.resetHistory();
397
375
  MeetingUtil.remoteUpdateAudioVideo.resetHistory();
398
376
  meeting.members.muteMember.resetHistory();
399
377
 
400
378
  // unmute
401
- await video.handleClientRequest(meeting, false);
379
+ await simulateVideoMuteChange(false);
402
380
 
403
381
  assert.isFalse(video.isMuted());
404
- assert.isFalse(video.isSelf());
405
382
 
406
- assert.calledWith(Media.setLocalTrack, true, meeting.mediaProperties.videoTrack);
407
- assert.calledWith(MeetingUtil.remoteUpdateAudioVideo, undefined, false, meeting);
383
+ assert.calledWith(MeetingUtil.remoteUpdateAudioVideo, meeting, undefined, false);
408
384
  assert.notCalled(meeting.members.muteMember);
409
385
  });
410
386
 
411
- 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 () => {
412
388
  // make sure the meeting object has mute state machines for both audio and video
413
389
  meeting.audio = audio;
414
390
  meeting.video = video;
415
391
 
416
- // mute audio -> request sent to server should have video unmuted
417
- await audio.handleClientRequest(meeting, true);
418
- 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);
419
395
  MeetingUtil.remoteUpdateAudioVideo.resetHistory();
420
396
 
421
- // now mute video -> request sent to server should have mute for both audio and video
422
- await video.handleClientRequest(meeting, true);
423
- 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);
424
400
  MeetingUtil.remoteUpdateAudioVideo.resetHistory();
425
401
 
426
- // now unmute the audio -> request sent to server should still have video muted
427
- await audio.handleClientRequest(meeting, false);
428
- 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);
429
405
  MeetingUtil.remoteUpdateAudioVideo.resetHistory();
430
406
 
431
- // unmute video -> request sent to server should have both audio and video unmuted
432
- await video.handleClientRequest(meeting, false);
433
- 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);
434
410
  });
435
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
+ });
436
625
  });
437
626
  });