@webex/plugin-meetings 3.0.0-beta.21 → 3.0.0-beta.211

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