@webex/plugin-meetings 3.0.0-beta.39 → 3.0.0-beta.391

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