@webex/plugin-meetings 3.0.0-beta.17 → 3.0.0-beta.170

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 (427) hide show
  1. package/README.md +45 -1
  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 +359 -0
  7. package/dist/annotation/index.js.map +1 -0
  8. package/dist/breakouts/breakout.js +216 -0
  9. package/dist/breakouts/breakout.js.map +1 -0
  10. package/dist/breakouts/collection.js +23 -0
  11. package/dist/breakouts/collection.js.map +1 -0
  12. package/dist/breakouts/edit-lock-error.js +52 -0
  13. package/dist/breakouts/edit-lock-error.js.map +1 -0
  14. package/dist/breakouts/events.js +45 -0
  15. package/dist/breakouts/events.js.map +1 -0
  16. package/dist/breakouts/index.js +1048 -0
  17. package/dist/breakouts/index.js.map +1 -0
  18. package/dist/breakouts/request.js +78 -0
  19. package/dist/breakouts/request.js.map +1 -0
  20. package/dist/breakouts/utils.js +67 -0
  21. package/dist/breakouts/utils.js.map +1 -0
  22. package/dist/common/errors/webex-errors.js +3 -2
  23. package/dist/common/errors/webex-errors.js.map +1 -1
  24. package/dist/common/logs/logger-proxy.js +1 -1
  25. package/dist/common/logs/logger-proxy.js.map +1 -1
  26. package/dist/config.js +6 -8
  27. package/dist/config.js.map +1 -1
  28. package/dist/constants.js +194 -28
  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 +300 -0
  39. package/dist/controls-options-manager/util.js.map +1 -0
  40. package/dist/index.js +95 -0
  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 +214 -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 +92 -2
  49. package/dist/locus-info/controlsUtils.js.map +1 -1
  50. package/dist/locus-info/index.js +350 -41
  51. package/dist/locus-info/index.js.map +1 -1
  52. package/dist/locus-info/mediaSharesUtils.js +43 -1
  53. package/dist/locus-info/mediaSharesUtils.js.map +1 -1
  54. package/dist/locus-info/parser.js +2 -1
  55. package/dist/locus-info/parser.js.map +1 -1
  56. package/dist/locus-info/selfUtils.js +97 -14
  57. package/dist/locus-info/selfUtils.js.map +1 -1
  58. package/dist/media/index.js +39 -134
  59. package/dist/media/index.js.map +1 -1
  60. package/dist/media/properties.js +19 -97
  61. package/dist/media/properties.js.map +1 -1
  62. package/dist/mediaQualityMetrics/config.js +505 -493
  63. package/dist/mediaQualityMetrics/config.js.map +1 -1
  64. package/dist/meeting/in-meeting-actions.js +76 -2
  65. package/dist/meeting/in-meeting-actions.js.map +1 -1
  66. package/dist/meeting/index.js +2640 -2436
  67. package/dist/meeting/index.js.map +1 -1
  68. package/dist/meeting/locusMediaRequest.js +291 -0
  69. package/dist/meeting/locusMediaRequest.js.map +1 -0
  70. package/dist/meeting/muteState.js +229 -124
  71. package/dist/meeting/muteState.js.map +1 -1
  72. package/dist/meeting/request.js +191 -167
  73. package/dist/meeting/request.js.map +1 -1
  74. package/dist/meeting/request.type.js.map +1 -1
  75. package/dist/meeting/util.js +477 -466
  76. package/dist/meeting/util.js.map +1 -1
  77. package/dist/meeting-info/index.js +48 -7
  78. package/dist/meeting-info/index.js.map +1 -1
  79. package/dist/meeting-info/meeting-info-v2.js +172 -50
  80. package/dist/meeting-info/meeting-info-v2.js.map +1 -1
  81. package/dist/meeting-info/utilv2.js +20 -5
  82. package/dist/meeting-info/utilv2.js.map +1 -1
  83. package/dist/meetings/collection.js +22 -0
  84. package/dist/meetings/collection.js.map +1 -1
  85. package/dist/meetings/index.js +377 -82
  86. package/dist/meetings/index.js.map +1 -1
  87. package/dist/meetings/meetings.types.js +7 -0
  88. package/dist/meetings/meetings.types.js.map +1 -0
  89. package/dist/meetings/request.js +16 -12
  90. package/dist/meetings/request.js.map +1 -1
  91. package/dist/meetings/util.js +88 -1
  92. package/dist/meetings/util.js.map +1 -1
  93. package/dist/member/index.js +43 -0
  94. package/dist/member/index.js.map +1 -1
  95. package/dist/member/types.js +15 -0
  96. package/dist/member/types.js.map +1 -0
  97. package/dist/member/util.js +97 -3
  98. package/dist/member/util.js.map +1 -1
  99. package/dist/members/collection.js +10 -0
  100. package/dist/members/collection.js.map +1 -1
  101. package/dist/members/index.js +94 -11
  102. package/dist/members/index.js.map +1 -1
  103. package/dist/members/request.js +109 -39
  104. package/dist/members/request.js.map +1 -1
  105. package/dist/members/types.js +15 -0
  106. package/dist/members/types.js.map +1 -0
  107. package/dist/members/util.js +316 -233
  108. package/dist/members/util.js.map +1 -1
  109. package/dist/metrics/constants.js +3 -5
  110. package/dist/metrics/constants.js.map +1 -1
  111. package/dist/metrics/index.js +1 -468
  112. package/dist/metrics/index.js.map +1 -1
  113. package/dist/multistream/mediaRequestManager.js +265 -36
  114. package/dist/multistream/mediaRequestManager.js.map +1 -1
  115. package/dist/multistream/receiveSlot.js +52 -19
  116. package/dist/multistream/receiveSlot.js.map +1 -1
  117. package/dist/multistream/receiveSlotManager.js +53 -33
  118. package/dist/multistream/receiveSlotManager.js.map +1 -1
  119. package/dist/multistream/remoteMedia.js +44 -18
  120. package/dist/multistream/remoteMedia.js.map +1 -1
  121. package/dist/multistream/remoteMediaGroup.js +60 -3
  122. package/dist/multistream/remoteMediaGroup.js.map +1 -1
  123. package/dist/multistream/remoteMediaManager.js +322 -103
  124. package/dist/multistream/remoteMediaManager.js.map +1 -1
  125. package/dist/networkQualityMonitor/index.js +4 -2
  126. package/dist/networkQualityMonitor/index.js.map +1 -1
  127. package/dist/reachability/index.js +117 -60
  128. package/dist/reachability/index.js.map +1 -1
  129. package/dist/reachability/request.js +12 -5
  130. package/dist/reachability/request.js.map +1 -1
  131. package/dist/reactions/constants.js +13 -0
  132. package/dist/reactions/constants.js.map +1 -0
  133. package/dist/reactions/reactions.js +2 -2
  134. package/dist/reactions/reactions.js.map +1 -1
  135. package/dist/reactions/reactions.type.js +18 -18
  136. package/dist/reactions/reactions.type.js.map +1 -1
  137. package/dist/reconnection-manager/index.js +217 -162
  138. package/dist/reconnection-manager/index.js.map +1 -1
  139. package/dist/recording-controller/enums.js +17 -0
  140. package/dist/recording-controller/enums.js.map +1 -0
  141. package/dist/recording-controller/index.js +363 -0
  142. package/dist/recording-controller/index.js.map +1 -0
  143. package/dist/recording-controller/util.js +64 -0
  144. package/dist/recording-controller/util.js.map +1 -0
  145. package/dist/roap/index.js +21 -29
  146. package/dist/roap/index.js.map +1 -1
  147. package/dist/roap/request.js +135 -94
  148. package/dist/roap/request.js.map +1 -1
  149. package/dist/roap/turnDiscovery.js +135 -53
  150. package/dist/roap/turnDiscovery.js.map +1 -1
  151. package/dist/statsAnalyzer/global.js +1 -93
  152. package/dist/statsAnalyzer/global.js.map +1 -1
  153. package/dist/statsAnalyzer/index.js +329 -314
  154. package/dist/statsAnalyzer/index.js.map +1 -1
  155. package/dist/statsAnalyzer/mqaUtil.js +103 -54
  156. package/dist/statsAnalyzer/mqaUtil.js.map +1 -1
  157. package/dist/types/annotation/annotation.types.d.ts +43 -0
  158. package/dist/types/annotation/constants.d.ts +31 -0
  159. package/dist/types/annotation/index.d.ts +124 -0
  160. package/dist/types/breakouts/breakout.d.ts +8 -0
  161. package/dist/types/breakouts/collection.d.ts +5 -0
  162. package/dist/types/breakouts/edit-lock-error.d.ts +15 -0
  163. package/dist/types/breakouts/events.d.ts +8 -0
  164. package/dist/types/breakouts/index.d.ts +5 -0
  165. package/dist/types/breakouts/request.d.ts +22 -0
  166. package/dist/types/breakouts/utils.d.ts +15 -0
  167. package/dist/types/common/browser-detection.d.ts +9 -0
  168. package/dist/types/common/collection.d.ts +48 -0
  169. package/dist/types/common/config.d.ts +2 -0
  170. package/dist/types/common/errors/captcha-error.d.ts +15 -0
  171. package/dist/types/common/errors/intent-to-join.d.ts +16 -0
  172. package/dist/types/common/errors/join-meeting.d.ts +17 -0
  173. package/dist/types/common/errors/media.d.ts +15 -0
  174. package/dist/types/common/errors/parameter.d.ts +15 -0
  175. package/dist/types/common/errors/password-error.d.ts +15 -0
  176. package/dist/types/common/errors/permission.d.ts +14 -0
  177. package/dist/types/common/errors/reconnection-in-progress.d.ts +9 -0
  178. package/dist/types/common/errors/reconnection.d.ts +15 -0
  179. package/dist/types/common/errors/stats.d.ts +15 -0
  180. package/dist/types/common/errors/webex-errors.d.ts +69 -0
  181. package/dist/types/common/errors/webex-meetings-error.d.ts +20 -0
  182. package/dist/types/common/events/events-scope.d.ts +17 -0
  183. package/dist/types/common/events/events.d.ts +12 -0
  184. package/dist/types/common/events/trigger-proxy.d.ts +2 -0
  185. package/dist/types/common/events/util.d.ts +2 -0
  186. package/dist/types/common/logs/logger-config.d.ts +2 -0
  187. package/dist/types/common/logs/logger-proxy.d.ts +2 -0
  188. package/dist/types/common/logs/request.d.ts +34 -0
  189. package/dist/types/common/queue.d.ts +32 -0
  190. package/dist/types/config.d.ts +72 -0
  191. package/dist/types/constants.d.ts +1007 -0
  192. package/dist/types/controls-options-manager/constants.d.ts +4 -0
  193. package/dist/types/controls-options-manager/enums.d.ts +15 -0
  194. package/dist/types/controls-options-manager/index.d.ts +136 -0
  195. package/dist/types/controls-options-manager/types.d.ts +43 -0
  196. package/dist/types/controls-options-manager/util.d.ts +1 -0
  197. package/dist/types/index.d.ts +7 -0
  198. package/dist/types/interpretation/collection.d.ts +5 -0
  199. package/dist/types/interpretation/index.d.ts +5 -0
  200. package/dist/types/interpretation/siLanguage.d.ts +5 -0
  201. package/dist/types/locus-info/controlsUtils.d.ts +2 -0
  202. package/dist/types/locus-info/embeddedAppsUtils.d.ts +2 -0
  203. package/dist/types/locus-info/fullState.d.ts +2 -0
  204. package/dist/types/locus-info/hostUtils.d.ts +2 -0
  205. package/dist/types/locus-info/index.d.ts +315 -0
  206. package/dist/types/locus-info/infoUtils.d.ts +2 -0
  207. package/dist/types/locus-info/mediaSharesUtils.d.ts +2 -0
  208. package/dist/types/locus-info/parser.d.ts +212 -0
  209. package/dist/types/locus-info/selfUtils.d.ts +2 -0
  210. package/dist/types/media/index.d.ts +34 -0
  211. package/dist/types/media/properties.d.ts +86 -0
  212. package/dist/types/media/util.d.ts +2 -0
  213. package/dist/types/mediaQualityMetrics/config.d.ts +365 -0
  214. package/dist/types/meeting/in-meeting-actions.d.ts +149 -0
  215. package/dist/types/meeting/index.d.ts +1430 -0
  216. package/dist/types/meeting/locusMediaRequest.d.ts +70 -0
  217. package/dist/types/meeting/muteState.d.ts +184 -0
  218. package/dist/types/meeting/request.d.ts +270 -0
  219. package/dist/types/meeting/request.type.d.ts +11 -0
  220. package/dist/types/meeting/state.d.ts +9 -0
  221. package/dist/types/meeting/util.d.ts +77 -0
  222. package/dist/types/meeting-info/collection.d.ts +20 -0
  223. package/dist/types/meeting-info/index.d.ts +62 -0
  224. package/dist/types/meeting-info/meeting-info-v2.d.ts +122 -0
  225. package/dist/types/meeting-info/request.d.ts +22 -0
  226. package/dist/types/meeting-info/util.d.ts +2 -0
  227. package/dist/types/meeting-info/utilv2.d.ts +2 -0
  228. package/dist/types/meetings/collection.d.ts +31 -0
  229. package/dist/types/meetings/index.d.ts +365 -0
  230. package/dist/types/meetings/meetings.types.d.ts +4 -0
  231. package/dist/types/meetings/request.d.ts +27 -0
  232. package/dist/types/meetings/util.d.ts +18 -0
  233. package/dist/types/member/index.d.ts +158 -0
  234. package/dist/types/member/types.d.ts +21 -0
  235. package/dist/types/member/util.d.ts +2 -0
  236. package/dist/types/members/collection.d.ts +29 -0
  237. package/dist/types/members/index.d.ts +353 -0
  238. package/dist/types/members/request.d.ts +114 -0
  239. package/dist/types/members/types.d.ts +24 -0
  240. package/dist/types/members/util.d.ts +210 -0
  241. package/dist/types/metrics/constants.d.ts +55 -0
  242. package/dist/types/metrics/index.d.ts +45 -0
  243. package/dist/types/multistream/mediaRequestManager.d.ts +118 -0
  244. package/dist/types/multistream/receiveSlot.d.ts +68 -0
  245. package/dist/types/multistream/receiveSlotManager.d.ts +56 -0
  246. package/dist/types/multistream/remoteMedia.d.ts +72 -0
  247. package/dist/types/multistream/remoteMediaGroup.d.ts +47 -0
  248. package/dist/types/multistream/remoteMediaManager.d.ts +277 -0
  249. package/dist/types/networkQualityMonitor/index.d.ts +70 -0
  250. package/dist/types/personal-meeting-room/index.d.ts +47 -0
  251. package/dist/types/personal-meeting-room/request.d.ts +14 -0
  252. package/dist/types/personal-meeting-room/util.d.ts +2 -0
  253. package/dist/types/reachability/index.d.ts +152 -0
  254. package/dist/types/reachability/request.d.ts +37 -0
  255. package/dist/types/reactions/constants.d.ts +3 -0
  256. package/dist/types/reactions/reactions.d.ts +4 -0
  257. package/dist/types/reactions/reactions.type.d.ts +52 -0
  258. package/dist/types/reconnection-manager/index.d.ts +126 -0
  259. package/dist/types/recording-controller/enums.d.ts +7 -0
  260. package/dist/types/recording-controller/index.d.ts +208 -0
  261. package/dist/types/recording-controller/util.d.ts +14 -0
  262. package/dist/types/roap/index.d.ts +77 -0
  263. package/dist/types/roap/request.d.ts +36 -0
  264. package/dist/types/roap/turnDiscovery.d.ts +91 -0
  265. package/dist/types/statsAnalyzer/global.d.ts +36 -0
  266. package/dist/types/statsAnalyzer/index.d.ts +200 -0
  267. package/dist/types/statsAnalyzer/mqaUtil.d.ts +24 -0
  268. package/dist/types/transcription/index.d.ts +64 -0
  269. package/package.json +29 -21
  270. package/src/annotation/annotation.types.ts +52 -0
  271. package/src/annotation/constants.ts +36 -0
  272. package/src/annotation/index.ts +343 -0
  273. package/src/breakouts/README.md +220 -0
  274. package/src/breakouts/breakout.ts +188 -0
  275. package/src/breakouts/collection.ts +19 -0
  276. package/src/breakouts/edit-lock-error.ts +25 -0
  277. package/src/breakouts/events.ts +56 -0
  278. package/src/breakouts/index.ts +925 -0
  279. package/src/breakouts/request.ts +55 -0
  280. package/src/breakouts/utils.ts +57 -0
  281. package/src/common/errors/webex-errors.ts +6 -2
  282. package/src/common/logs/logger-proxy.ts +1 -1
  283. package/src/config.ts +5 -7
  284. package/src/constants.ts +183 -22
  285. package/src/controls-options-manager/constants.ts +5 -0
  286. package/src/controls-options-manager/enums.ts +18 -0
  287. package/src/controls-options-manager/index.ts +278 -0
  288. package/src/controls-options-manager/types.ts +59 -0
  289. package/src/controls-options-manager/util.ts +286 -0
  290. package/src/index.ts +37 -0
  291. package/src/interpretation/README.md +51 -0
  292. package/src/interpretation/collection.ts +19 -0
  293. package/src/interpretation/index.ts +182 -0
  294. package/src/interpretation/siLanguage.ts +18 -0
  295. package/src/locus-info/controlsUtils.ts +110 -0
  296. package/src/locus-info/index.ts +374 -38
  297. package/src/locus-info/mediaSharesUtils.ts +48 -0
  298. package/src/locus-info/parser.ts +2 -1
  299. package/src/locus-info/selfUtils.ts +86 -2
  300. package/src/media/index.ts +70 -142
  301. package/src/media/properties.ts +41 -104
  302. package/src/mediaQualityMetrics/config.ts +379 -377
  303. package/src/meeting/in-meeting-actions.ts +151 -3
  304. package/src/meeting/index.ts +2029 -2033
  305. package/src/meeting/locusMediaRequest.ts +309 -0
  306. package/src/meeting/muteState.ts +228 -132
  307. package/src/meeting/request.ts +100 -91
  308. package/src/meeting/request.type.ts +2 -0
  309. package/src/meeting/util.ts +450 -439
  310. package/src/meeting-info/index.ts +54 -8
  311. package/src/meeting-info/meeting-info-v2.ts +150 -14
  312. package/src/meeting-info/utilv2.ts +13 -3
  313. package/src/meetings/collection.ts +20 -0
  314. package/src/meetings/index.ts +396 -89
  315. package/src/meetings/meetings.types.ts +12 -0
  316. package/src/meetings/request.ts +3 -1
  317. package/src/meetings/util.ts +103 -4
  318. package/src/member/index.ts +42 -0
  319. package/src/member/types.ts +24 -0
  320. package/src/member/util.ts +95 -1
  321. package/src/members/collection.ts +8 -0
  322. package/src/members/index.ts +108 -6
  323. package/src/members/request.ts +98 -17
  324. package/src/members/types.ts +28 -0
  325. package/src/members/util.ts +319 -240
  326. package/src/metrics/constants.ts +2 -4
  327. package/src/metrics/index.ts +1 -490
  328. package/src/multistream/mediaRequestManager.ts +337 -63
  329. package/src/multistream/receiveSlot.ts +68 -26
  330. package/src/multistream/receiveSlotManager.ts +61 -38
  331. package/src/multistream/remoteMedia.ts +29 -3
  332. package/src/multistream/remoteMediaGroup.ts +61 -2
  333. package/src/multistream/remoteMediaManager.ts +260 -66
  334. package/src/networkQualityMonitor/index.ts +6 -6
  335. package/src/reachability/index.ts +75 -25
  336. package/src/reachability/request.ts +10 -5
  337. package/src/reactions/constants.ts +4 -0
  338. package/src/reactions/reactions.ts +4 -4
  339. package/src/reactions/reactions.type.ts +28 -3
  340. package/src/reconnection-manager/index.ts +80 -49
  341. package/src/recording-controller/enums.ts +8 -0
  342. package/src/recording-controller/index.ts +333 -0
  343. package/src/recording-controller/util.ts +75 -0
  344. package/src/roap/index.ts +21 -30
  345. package/src/roap/request.ts +72 -61
  346. package/src/roap/turnDiscovery.ts +51 -27
  347. package/src/statsAnalyzer/global.ts +1 -94
  348. package/src/statsAnalyzer/index.ts +380 -390
  349. package/src/statsAnalyzer/mqaUtil.ts +106 -99
  350. package/test/integration/spec/converged-space-meetings.js +233 -0
  351. package/test/integration/spec/journey.js +331 -254
  352. package/test/integration/spec/space-meeting.js +77 -4
  353. package/test/unit/spec/annotation/index.ts +436 -0
  354. package/test/unit/spec/breakouts/breakout.ts +237 -0
  355. package/test/unit/spec/breakouts/collection.ts +15 -0
  356. package/test/unit/spec/breakouts/edit-lock-error.ts +30 -0
  357. package/test/unit/spec/breakouts/events.ts +89 -0
  358. package/test/unit/spec/breakouts/index.ts +1790 -0
  359. package/test/unit/spec/breakouts/request.ts +104 -0
  360. package/test/unit/spec/breakouts/utils.js +72 -0
  361. package/test/unit/spec/controls-options-manager/index.js +287 -0
  362. package/test/unit/spec/controls-options-manager/util.js +518 -0
  363. package/test/unit/spec/fixture/locus.js +1 -0
  364. package/test/unit/spec/interpretation/collection.ts +15 -0
  365. package/test/unit/spec/interpretation/index.ts +329 -0
  366. package/test/unit/spec/interpretation/siLanguage.ts +26 -0
  367. package/test/unit/spec/locus-info/controlsUtils.js +323 -30
  368. package/test/unit/spec/locus-info/index.js +792 -4
  369. package/test/unit/spec/locus-info/mediaSharesUtils.ts +22 -0
  370. package/test/unit/spec/locus-info/selfConstant.js +48 -0
  371. package/test/unit/spec/locus-info/selfUtils.js +275 -0
  372. package/test/unit/spec/media/index.ts +118 -22
  373. package/test/unit/spec/media/properties.ts +9 -9
  374. package/test/unit/spec/meeting/in-meeting-actions.ts +75 -3
  375. package/test/unit/spec/meeting/index.js +2742 -1441
  376. package/test/unit/spec/meeting/locusMediaRequest.ts +436 -0
  377. package/test/unit/spec/meeting/muteState.js +370 -208
  378. package/test/unit/spec/meeting/request.js +354 -42
  379. package/test/unit/spec/meeting/utils.js +384 -170
  380. package/test/unit/spec/meeting-info/index.js +181 -0
  381. package/test/unit/spec/meeting-info/meetinginfov2.js +383 -5
  382. package/test/unit/spec/meeting-info/utilv2.js +21 -0
  383. package/test/unit/spec/meetings/collection.js +14 -0
  384. package/test/unit/spec/meetings/index.js +847 -121
  385. package/test/unit/spec/meetings/utils.js +206 -2
  386. package/test/unit/spec/member/index.js +31 -0
  387. package/test/unit/spec/member/util.js +408 -32
  388. package/test/unit/spec/members/index.js +320 -1
  389. package/test/unit/spec/members/request.js +206 -27
  390. package/test/unit/spec/members/utils.js +184 -0
  391. package/test/unit/spec/metrics/index.js +1 -50
  392. package/test/unit/spec/multistream/mediaRequestManager.ts +1012 -109
  393. package/test/unit/spec/multistream/receiveSlot.ts +77 -18
  394. package/test/unit/spec/multistream/receiveSlotManager.ts +69 -39
  395. package/test/unit/spec/multistream/remoteMedia.ts +32 -2
  396. package/test/unit/spec/multistream/remoteMediaGroup.ts +271 -5
  397. package/test/unit/spec/multistream/remoteMediaManager.ts +672 -65
  398. package/test/unit/spec/networkQualityMonitor/index.js +4 -4
  399. package/test/unit/spec/reachability/index.ts +176 -25
  400. package/test/unit/spec/reachability/request.js +66 -0
  401. package/test/unit/spec/reconnection-manager/index.js +95 -13
  402. package/test/unit/spec/recording-controller/index.js +307 -0
  403. package/test/unit/spec/recording-controller/util.js +229 -0
  404. package/test/unit/spec/roap/index.ts +28 -52
  405. package/test/unit/spec/roap/request.ts +225 -0
  406. package/test/unit/spec/roap/turnDiscovery.ts +73 -34
  407. package/test/unit/spec/stats-analyzer/index.js +94 -43
  408. package/test/utils/constants.js +9 -0
  409. package/test/utils/integrationTestUtils.js +46 -0
  410. package/test/utils/testUtils.js +0 -45
  411. package/test/utils/webex-config.js +4 -0
  412. package/test/utils/webex-test-users.js +7 -3
  413. package/tsconfig.json +6 -0
  414. package/dist/media/internal-media-core-wrapper.js +0 -18
  415. package/dist/media/internal-media-core-wrapper.js.map +0 -1
  416. package/dist/meeting/effectsState.js +0 -262
  417. package/dist/meeting/effectsState.js.map +0 -1
  418. package/dist/metrics/config.js +0 -299
  419. package/dist/metrics/config.js.map +0 -1
  420. package/dist/multistream/multistreamMedia.js +0 -106
  421. package/dist/multistream/multistreamMedia.js.map +0 -1
  422. package/src/index.js +0 -15
  423. package/src/media/internal-media-core-wrapper.ts +0 -9
  424. package/src/meeting/effectsState.ts +0 -211
  425. package/src/metrics/config.ts +0 -495
  426. package/src/multistream/multistreamMedia.ts +0 -93
  427. package/test/unit/spec/meeting/effectsState.js +0 -281
@@ -1,7 +1,7 @@
1
1
  /* eslint-disable require-jsdoc */
2
2
  import EventEmitter from 'events';
3
3
 
4
- import {MediaConnection as MC} from '@webex/internal-media-core';
4
+ import {MediaType} from '@webex/internal-media-core';
5
5
  import {
6
6
  Configuration,
7
7
  Event,
@@ -15,15 +15,18 @@ import {cloneDeep} from 'lodash';
15
15
  import {MediaRequest} from '@webex/plugin-meetings/src/multistream/mediaRequestManager';
16
16
  import {CSI, ReceiveSlotId} from '@webex/plugin-meetings/src/multistream/receiveSlot';
17
17
  import testUtils from '../../../utils/testUtils';
18
+ import LoggerProxy from '@webex/plugin-meetings/src/common/logs/logger-proxy';
19
+ import LoggerConfig from '@webex/plugin-meetings/src/common/logs/logger-config';
20
+ import { expect } from 'chai';
18
21
 
19
22
  class FakeSlot extends EventEmitter {
20
- public mediaType: MC.MediaType;
23
+ public mediaType: MediaType;
21
24
 
22
25
  public id: string;
23
26
 
24
27
  public csi?: number;
25
28
 
26
- constructor(mediaType: MC.MediaType, id: string) {
29
+ constructor(mediaType: MediaType, id: string) {
27
30
  super();
28
31
  this.mediaType = mediaType;
29
32
  this.id = id;
@@ -32,11 +35,16 @@ class FakeSlot extends EventEmitter {
32
35
  // Calling setMaxListeners() fixes the warning.
33
36
  this.setMaxListeners(50);
34
37
  }
38
+
39
+ public get logString() {
40
+ return this.id;
41
+ }
35
42
  }
36
43
 
37
44
  const DefaultTestConfiguration: Configuration = {
38
45
  audio: {
39
46
  numOfActiveSpeakerStreams: 3,
47
+ numOfScreenShareStreams: 1,
40
48
  },
41
49
  video: {
42
50
  preferLiveVideo: true,
@@ -44,7 +52,6 @@ const DefaultTestConfiguration: Configuration = {
44
52
 
45
53
  layouts: {
46
54
  AllEqual: {
47
- screenShareVideo: {size: null},
48
55
  activeSpeakerVideoPaneGroups: [
49
56
  {
50
57
  id: 'main',
@@ -55,7 +62,6 @@ const DefaultTestConfiguration: Configuration = {
55
62
  ],
56
63
  },
57
64
  OnePlusFive: {
58
- screenShareVideo: {size: null},
59
65
  activeSpeakerVideoPaneGroups: [
60
66
  {
61
67
  id: 'mainBigOne',
@@ -72,7 +78,6 @@ const DefaultTestConfiguration: Configuration = {
72
78
  ],
73
79
  },
74
80
  Single: {
75
- screenShareVideo: {size: null},
76
81
  activeSpeakerVideoPaneGroups: [
77
82
  {
78
83
  id: 'main',
@@ -83,7 +88,6 @@ const DefaultTestConfiguration: Configuration = {
83
88
  ],
84
89
  },
85
90
  Stage: {
86
- screenShareVideo: {size: null},
87
91
  activeSpeakerVideoPaneGroups: [
88
92
  {
89
93
  id: 'thumbnails',
@@ -99,12 +103,19 @@ const DefaultTestConfiguration: Configuration = {
99
103
  {id: 'stage-4', size: 'medium', csi: undefined},
100
104
  ],
101
105
  },
106
+ ScreenShareView: {
107
+ screenShareVideo: {size: 'medium'},
108
+ activeSpeakerVideoPaneGroups: [
109
+ {
110
+ id: 'thumbnails',
111
+ numPanes: 6,
112
+ size: 'thumbnail',
113
+ priority: 255,
114
+ },
115
+ ],
116
+ },
102
117
  },
103
118
  },
104
- screenShare: {
105
- audio: true,
106
- video: true,
107
- },
108
119
  };
109
120
 
110
121
  describe('RemoteMediaManager', () => {
@@ -113,18 +124,50 @@ describe('RemoteMediaManager', () => {
113
124
  let fakeMediaRequestManagers;
114
125
  let fakeAudioSlot;
115
126
  let fakeVideoSlot;
127
+ let fakeScreenShareAudioSlot;
128
+ let fakeScreenShareVideoSlot;
129
+
130
+ const logger = {
131
+ log: sinon.fake(),
132
+ error: () => {},
133
+ warn: () => {},
134
+ trace: () => {},
135
+ debug: () => {},
136
+ };
137
+
138
+ afterEach(() => {
139
+ LoggerConfig.set({enable: false});
140
+ LoggerProxy.set();
141
+ });
116
142
 
117
143
  beforeEach(() => {
118
- fakeAudioSlot = new FakeSlot(MC.MediaType.AudioMain, 'fake audio slot');
119
- fakeVideoSlot = new FakeSlot(MC.MediaType.VideoMain, 'fake video slot');
144
+ LoggerConfig.set({enable: true});
145
+ LoggerProxy.set(logger);
146
+
147
+ fakeAudioSlot = new FakeSlot(MediaType.AudioMain, 'fake audio slot');
148
+ fakeVideoSlot = new FakeSlot(MediaType.VideoMain, 'fake video slot');
149
+ fakeScreenShareAudioSlot = new FakeSlot(
150
+ MediaType.AudioSlides,
151
+ 'fake screen share audio slot'
152
+ );
153
+ fakeScreenShareVideoSlot = new FakeSlot(
154
+ MediaType.VideoSlides,
155
+ 'fake screen share video slot'
156
+ );
120
157
 
121
158
  fakeReceiveSlotManager = {
122
159
  allocateSlot: sinon.stub().callsFake((mediaType) => {
123
- if (mediaType === MC.MediaType.AudioMain) {
124
- return Promise.resolve(fakeAudioSlot);
160
+ switch (mediaType) {
161
+ case MediaType.AudioMain:
162
+ return Promise.resolve(fakeAudioSlot);
163
+ case MediaType.VideoMain:
164
+ return Promise.resolve(fakeVideoSlot);
165
+ case MediaType.AudioSlides:
166
+ return Promise.resolve(fakeScreenShareAudioSlot);
167
+ case MediaType.VideoSlides:
168
+ return Promise.resolve(fakeScreenShareVideoSlot);
125
169
  }
126
-
127
- return Promise.resolve(fakeVideoSlot);
170
+ throw new Error(`invalid mediaType: ${mediaType}`);
128
171
  }),
129
172
  releaseSlot: sinon.stub(),
130
173
  };
@@ -140,6 +183,16 @@ describe('RemoteMediaManager', () => {
140
183
  cancelRequest: sinon.stub(),
141
184
  commit: sinon.stub(),
142
185
  },
186
+ screenShareAudio: {
187
+ addRequest: sinon.stub(),
188
+ cancelRequest: sinon.stub(),
189
+ commit: sinon.stub(),
190
+ },
191
+ screenShareVideo: {
192
+ addRequest: sinon.stub(),
193
+ cancelRequest: sinon.stub(),
194
+ commit: sinon.stub(),
195
+ },
143
196
  };
144
197
 
145
198
  // create remote media manager with default configuration
@@ -159,6 +212,9 @@ describe('RemoteMediaManager', () => {
159
212
  fakeMediaRequestManagers.video.addRequest.resetHistory();
160
213
  fakeMediaRequestManagers.video.cancelRequest.resetHistory();
161
214
  fakeMediaRequestManagers.video.commit.resetHistory();
215
+ fakeMediaRequestManagers.screenShareVideo.commit.resetHistory();
216
+ fakeMediaRequestManagers.screenShareAudio.commit.resetHistory();
217
+ logger.log.resetHistory();
162
218
  };
163
219
 
164
220
  describe('start', () => {
@@ -176,8 +232,8 @@ describe('RemoteMediaManager', () => {
176
232
  await remoteMediaManager.start();
177
233
 
178
234
  // check that the 2nd start() creates slots and media requests and is not a no-op
179
- assert.calledWith(fakeReceiveSlotManager.allocateSlot, MC.MediaType.AudioMain);
180
- assert.calledWith(fakeReceiveSlotManager.allocateSlot, MC.MediaType.VideoMain);
235
+ assert.calledWith(fakeReceiveSlotManager.allocateSlot, MediaType.AudioMain);
236
+ assert.calledWith(fakeReceiveSlotManager.allocateSlot, MediaType.VideoMain);
181
237
 
182
238
  assert.called(fakeMediaRequestManagers.audio.addRequest);
183
239
  assert.called(fakeMediaRequestManagers.video.addRequest);
@@ -187,25 +243,18 @@ describe('RemoteMediaManager', () => {
187
243
  let createdAudioGroup: RemoteMediaGroup | null = null;
188
244
 
189
245
  // create a config with just audio, no video at all and no screen share
190
- const config = {
246
+ const config: Configuration = {
191
247
  audio: {
192
248
  numOfActiveSpeakerStreams: 5,
249
+ numOfScreenShareStreams: 0,
193
250
  },
194
251
  video: {
195
252
  preferLiveVideo: false,
196
253
  initialLayoutId: 'empty',
197
254
  layouts: {
198
- empty: {
199
- screenShareVideo: {
200
- size: null,
201
- },
202
- },
255
+ empty: {},
203
256
  },
204
257
  },
205
- screenShare: {
206
- audio: false,
207
- video: false,
208
- },
209
258
  };
210
259
 
211
260
  remoteMediaManager = new RemoteMediaManager(
@@ -223,7 +272,7 @@ describe('RemoteMediaManager', () => {
223
272
  await testUtils.flushPromises();
224
273
 
225
274
  assert.callCount(fakeReceiveSlotManager.allocateSlot, 5);
226
- assert.alwaysCalledWith(fakeReceiveSlotManager.allocateSlot, MC.MediaType.AudioMain);
275
+ assert.alwaysCalledWith(fakeReceiveSlotManager.allocateSlot, MediaType.AudioMain);
227
276
 
228
277
  assert.isNotNull(createdAudioGroup);
229
278
  if (createdAudioGroup) {
@@ -231,7 +280,7 @@ describe('RemoteMediaManager', () => {
231
280
  assert.isTrue(
232
281
  createdAudioGroup
233
282
  .getRemoteMedia()
234
- .every((remoteMedia) => remoteMedia.mediaType === MC.MediaType.AudioMain)
283
+ .every((remoteMedia) => remoteMedia.mediaType === MediaType.AudioMain)
235
284
  );
236
285
  assert.strictEqual(createdAudioGroup.getRemoteMedia('pinned').length, 0);
237
286
  }
@@ -255,9 +304,6 @@ describe('RemoteMediaManager', () => {
255
304
 
256
305
  config.audio.numOfActiveSpeakerStreams = 0;
257
306
  config.video.layouts.huge = {
258
- screenShareVideo: {
259
- size: null,
260
- },
261
307
  activeSpeakerVideoPaneGroups: [
262
308
  {
263
309
  id: 'big one',
@@ -267,6 +313,8 @@ describe('RemoteMediaManager', () => {
267
313
  },
268
314
  ],
269
315
  };
316
+ config.audio.numOfScreenShareStreams = 0;
317
+ delete config.video.layouts.ScreenShareView;
270
318
 
271
319
  remoteMediaManager = new RemoteMediaManager(
272
320
  fakeReceiveSlotManager,
@@ -279,7 +327,7 @@ describe('RemoteMediaManager', () => {
279
327
  // even though our "big one" layout is not the default one, the remote media manager should still
280
328
  // preallocate enough video receive slots for it up front
281
329
  assert.callCount(fakeReceiveSlotManager.allocateSlot, 99);
282
- assert.alwaysCalledWith(fakeReceiveSlotManager.allocateSlot, MC.MediaType.VideoMain);
330
+ assert.alwaysCalledWith(fakeReceiveSlotManager.allocateSlot, MediaType.VideoMain);
283
331
  });
284
332
 
285
333
  it('starts with the initial layout', async () => {
@@ -302,8 +350,128 @@ describe('RemoteMediaManager', () => {
302
350
  receivedLayoutInfo.activeSpeakerVideoPanes.main.getRemoteMedia().length,
303
351
  9
304
352
  );
353
+ assert.isUndefined(receivedLayoutInfo.screenShareVideo); // the initial layout has no screen share
305
354
  }
306
355
  });
356
+
357
+ it('creates RemoteMedia for screen share audio correctly', async () => {
358
+ let createdAudioGroup: RemoteMediaGroup | null = null;
359
+
360
+ const NUM_STREAMS = 2;
361
+
362
+ // create a config with just screen share audio, nothing else
363
+ const config: Configuration = {
364
+ audio: {
365
+ numOfActiveSpeakerStreams: 0,
366
+ numOfScreenShareStreams: NUM_STREAMS,
367
+ },
368
+ video: {
369
+ preferLiveVideo: false,
370
+ initialLayoutId: 'empty',
371
+ layouts: {
372
+ empty: {},
373
+ },
374
+ },
375
+ };
376
+
377
+ remoteMediaManager = new RemoteMediaManager(
378
+ fakeReceiveSlotManager,
379
+ fakeMediaRequestManagers,
380
+ config
381
+ );
382
+
383
+ remoteMediaManager.on(Event.ScreenShareAudioCreated, (audio: RemoteMediaGroup) => {
384
+ createdAudioGroup = audio;
385
+ });
386
+
387
+ remoteMediaManager.start();
388
+
389
+ await testUtils.flushPromises();
390
+
391
+ assert.callCount(fakeReceiveSlotManager.allocateSlot, NUM_STREAMS);
392
+ assert.alwaysCalledWith(fakeReceiveSlotManager.allocateSlot, MediaType.AudioSlides);
393
+
394
+ assert.isNotNull(createdAudioGroup);
395
+ if (createdAudioGroup) {
396
+ assert.strictEqual(createdAudioGroup.getRemoteMedia().length, NUM_STREAMS);
397
+ assert.isTrue(
398
+ createdAudioGroup
399
+ .getRemoteMedia()
400
+ .every((remoteMedia) => remoteMedia.mediaType === MediaType.AudioSlides)
401
+ );
402
+ assert.strictEqual(createdAudioGroup.getRemoteMedia('pinned').length, 0);
403
+ }
404
+
405
+ assert.calledOnce(fakeMediaRequestManagers.screenShareAudio.addRequest);
406
+ assert.calledWith(
407
+ fakeMediaRequestManagers.screenShareAudio.addRequest,
408
+ sinon.match({
409
+ policyInfo: sinon.match({
410
+ policy: 'active-speaker',
411
+ priority: 255,
412
+ }),
413
+ receiveSlots: Array(NUM_STREAMS).fill(fakeScreenShareAudioSlot),
414
+ codecInfo: undefined,
415
+ })
416
+ );
417
+ });
418
+
419
+ it('creates a single receive slot for screen share video if any layout has screen share', async () => {
420
+ // create a config with 2 layouts that use screen share
421
+ const config: Configuration = {
422
+ audio: {
423
+ numOfActiveSpeakerStreams: 0,
424
+ numOfScreenShareStreams: 0,
425
+ },
426
+ video: {
427
+ preferLiveVideo: false,
428
+ initialLayoutId: 'first',
429
+ layouts: {
430
+ first: {
431
+ screenShareVideo: { size: 'small'}
432
+ },
433
+ second: {
434
+ screenShareVideo: { size: 'medium'}
435
+ }
436
+ },
437
+ },
438
+ };
439
+
440
+ remoteMediaManager = new RemoteMediaManager(
441
+ fakeReceiveSlotManager,
442
+ fakeMediaRequestManagers,
443
+ config
444
+ );
445
+
446
+ await remoteMediaManager.start();
447
+
448
+ // even though 2 layouts use screen share, only 1 video screen share slot should be created
449
+ assert.callCount(fakeReceiveSlotManager.allocateSlot, 1);
450
+ assert.alwaysCalledWith(fakeReceiveSlotManager.allocateSlot, MediaType.VideoSlides);
451
+ });
452
+
453
+ it('does not create any receive slot for screen share video if none of the layouts have screen share', async () => {
454
+ const config = cloneDeep(DefaultTestConfiguration);
455
+
456
+ config.audio.numOfActiveSpeakerStreams = 0;
457
+ config.audio.numOfScreenShareStreams = 0;
458
+
459
+ // delete the only layout that uses screen share
460
+ delete config.video.layouts.ScreenShareView;
461
+
462
+ remoteMediaManager = new RemoteMediaManager(
463
+ fakeReceiveSlotManager,
464
+ fakeMediaRequestManagers,
465
+ config
466
+ );
467
+
468
+ await remoteMediaManager.start();
469
+
470
+ // we don't expect any audio and for video there should be no VideoSlides, so all the calls should be just for VideoMain
471
+ assert.alwaysCalledWith(fakeReceiveSlotManager.allocateSlot, MediaType.VideoMain);
472
+ });
473
+
474
+
307
475
  });
308
476
 
309
477
  describe('constructor', () => {
@@ -325,7 +493,6 @@ describe('RemoteMediaManager', () => {
325
493
  const config = cloneDeep(DefaultTestConfiguration);
326
494
 
327
495
  config.video.layouts.test = {
328
- screenShareVideo: {size: null},
329
496
  activeSpeakerVideoPaneGroups: [
330
497
  {
331
498
  id: 'someDuplicate',
@@ -361,7 +528,6 @@ describe('RemoteMediaManager', () => {
361
528
  const config = cloneDeep(DefaultTestConfiguration);
362
529
 
363
530
  config.video.layouts.test = {
364
- screenShareVideo: {size: null},
365
531
  activeSpeakerVideoPaneGroups: [
366
532
  {
367
533
  id: 'group1',
@@ -397,7 +563,6 @@ describe('RemoteMediaManager', () => {
397
563
  const config = cloneDeep(DefaultTestConfiguration);
398
564
 
399
565
  config.video.layouts.test = {
400
- screenShareVideo: {size: null},
401
566
  memberVideoPanes: [
402
567
  {id: 'paneA', size: 'best', csi: 123},
403
568
  {id: 'paneB', size: 'large', csi: 222},
@@ -414,6 +579,7 @@ describe('RemoteMediaManager', () => {
414
579
  );
415
580
  }, 'invalid config: duplicate member video pane id: paneB');
416
581
  });
582
+
417
583
  });
418
584
 
419
585
  describe('stop', () => {
@@ -421,12 +587,17 @@ describe('RemoteMediaManager', () => {
421
587
  let audioStopStub;
422
588
  let videoActiveSpeakerGroupStopStub;
423
589
  const memberVideoPaneStopStubs: any[] = [];
590
+ let screenShareAudioStopStub;
591
+ let screenShareVideoStopStub;
424
592
 
425
- // change the initial layout to one that has both active speakers and receveiver selected videos
593
+ // change the initial layout to one that has both active speakers and receiver selected videos
426
594
  const config = cloneDeep(DefaultTestConfiguration);
427
595
 
428
596
  config.video.initialLayoutId = 'Stage';
429
597
 
598
+ // and also modify it to have screen share so we can test that too
599
+ config.video.layouts['Stage'].screenShareVideo = {size: 'medium'};
600
+
430
601
  remoteMediaManager = new RemoteMediaManager(
431
602
  fakeReceiveSlotManager,
432
603
  fakeMediaRequestManagers,
@@ -437,6 +608,10 @@ describe('RemoteMediaManager', () => {
437
608
  audioStopStub = sinon.stub(audio, 'stop');
438
609
  });
439
610
 
611
+ remoteMediaManager.on(Event.ScreenShareAudioCreated, (audio: RemoteMediaGroup) => {
612
+ screenShareAudioStopStub = sinon.stub(audio, 'stop');
613
+ });
614
+
440
615
  remoteMediaManager.on(Event.VideoLayoutChanged, (layoutInfo: VideoLayoutChangedEventData) => {
441
616
  // The "Stage" layout that we're using has only 1 active speaker group called "thumbnails"
442
617
  videoActiveSpeakerGroupStopStub = sinon.stub(
@@ -447,12 +622,14 @@ describe('RemoteMediaManager', () => {
447
622
  Object.values(layoutInfo.memberVideoPanes).forEach((pane) => {
448
623
  memberVideoPaneStopStubs.push(sinon.stub(pane, 'stop'));
449
624
  });
625
+
626
+ screenShareVideoStopStub = sinon.stub(layoutInfo.screenShareVideo, 'stop');
450
627
  });
451
628
 
452
629
  await remoteMediaManager.start();
453
630
 
454
- // we're using the default config that requires 3 main audio slots and 10 video slots (for Stage2x2With6ThumbnailsLayout)
455
- assert.callCount(fakeReceiveSlotManager.allocateSlot, 13);
631
+ // we're using the default config that requires 3 main audio slots, 10 video slots (for Stage2x2With6ThumbnailsLayout), 1 screenshare audio, 1 screenshare video
632
+ assert.callCount(fakeReceiveSlotManager.allocateSlot, 15);
456
633
 
457
634
  // our layout has 4 member video panes, we should have a stub for each of these panes' stop methods
458
635
  assert.strictEqual(memberVideoPaneStopStubs.length, 4);
@@ -462,16 +639,20 @@ describe('RemoteMediaManager', () => {
462
639
  remoteMediaManager.stop();
463
640
 
464
641
  // check that all slots have been released
465
- assert.callCount(fakeReceiveSlotManager.releaseSlot, 13);
642
+ assert.callCount(fakeReceiveSlotManager.releaseSlot, 15);
466
643
 
467
644
  // and that all RemoteMedia and RemoteMediaGroups have been stopped
468
645
  assert.calledOnce(audioStopStub);
469
646
  assert.calledWith(audioStopStub, true);
647
+ assert.calledOnce(screenShareAudioStopStub);
648
+ assert.calledWith(screenShareAudioStopStub, true);
470
649
  assert.calledOnce(videoActiveSpeakerGroupStopStub);
471
650
  memberVideoPaneStopStubs.forEach((stub) => {
472
651
  assert.calledOnce(stub);
473
652
  });
474
653
  assert.calledOnce(fakeMediaRequestManagers.video.commit);
654
+ assert.calledOnce(screenShareVideoStopStub);
655
+ assert.calledOnce(fakeMediaRequestManagers.screenShareVideo.commit);
475
656
  });
476
657
 
477
658
  it('can be called multiple times', async () => {
@@ -482,6 +663,41 @@ describe('RemoteMediaManager', () => {
482
663
  remoteMediaManager.stop();
483
664
  });
484
665
  });
666
+
667
+ describe('setPreferLiveVideo', () => {
668
+
669
+ it('sets preferLiveVideo', async () => {
670
+ const config = cloneDeep(DefaultTestConfiguration);
671
+ let stubs = [];
672
+
673
+ config.video.initialLayoutId = 'OnePlusFive';
674
+
675
+ remoteMediaManager = new RemoteMediaManager(
676
+ fakeReceiveSlotManager,
677
+ fakeMediaRequestManagers,
678
+ config
679
+ );
680
+
681
+ remoteMediaManager.on(Event.VideoLayoutChanged, (layoutInfo: VideoLayoutChangedEventData) => {
682
+ Object.values(layoutInfo.activeSpeakerVideoPanes).forEach((group) => stubs.push(sinon.stub(group, 'setPreferLiveVideo')));
683
+ });
684
+
685
+ await remoteMediaManager.start();
686
+ resetHistory();
687
+ assert(stubs.length > 0);
688
+ await remoteMediaManager.setPreferLiveVideo(true);
689
+
690
+
691
+ stubs.forEach((stub) => {
692
+ assert.calledWith(stub, true, false)
693
+ });
694
+
695
+ expect(config.video.preferLiveVideo).to.equal(true);
696
+
697
+ assert.calledOnce(fakeMediaRequestManagers.video.commit);
698
+ });
699
+ });
700
+
485
701
  describe('setLayout', () => {
486
702
  it('rejects if called with invalid layoutId', async () => {
487
703
  await assert.isRejected(remoteMediaManager.setLayout('invalid value'));
@@ -511,9 +727,53 @@ describe('RemoteMediaManager', () => {
511
727
  await remoteMediaManager.setLayout('Stage');
512
728
 
513
729
  assert.callCount(fakeReceiveSlotManager.allocateSlot, 9);
514
- assert.alwaysCalledWith(fakeReceiveSlotManager.allocateSlot, MC.MediaType.VideoMain);
730
+ assert.alwaysCalledWith(fakeReceiveSlotManager.allocateSlot, MediaType.VideoMain);
731
+ });
732
+
733
+ it('logs layout changes - receiver selected', async () => {
734
+ const config = cloneDeep(DefaultTestConfiguration);
735
+
736
+ remoteMediaManager = new RemoteMediaManager(
737
+ fakeReceiveSlotManager,
738
+ fakeMediaRequestManagers,
739
+ config
740
+ );
741
+
742
+ await remoteMediaManager.start();
743
+
744
+ resetHistory();
745
+
746
+ await remoteMediaManager.setLayout('Stage');
747
+
748
+ assert.calledWith(
749
+ logger.log,
750
+ 'RemoteMediaManager#updateVideoReceiveSlots --> receive slots updated: unused=0, activeSpeaker=6, receiverSelected=4\ngroup: thumbnails\nfake video slot fake video slot fake video slot fake video slot fake video slot fake video slot\nreceiverSelected:\n stage-1: fake video slot\n stage-2: fake video slot\n stage-3: fake video slot\n stage-4: fake video slot\n'
751
+ );
752
+ });
753
+
754
+ it('logs layout changes - active speaker', async () => {
755
+ const config = cloneDeep(DefaultTestConfiguration);
756
+ config.video.initialLayoutId = 'OnePlusFive'
757
+
758
+ remoteMediaManager = new RemoteMediaManager(
759
+ fakeReceiveSlotManager,
760
+ fakeMediaRequestManagers,
761
+ config
762
+ );
763
+
764
+ await remoteMediaManager.start();
765
+
766
+ resetHistory();
767
+
768
+ await remoteMediaManager.setLayout('AllEqual');
769
+
770
+ assert.calledWith(
771
+ logger.log,
772
+ 'RemoteMediaManager#updateVideoReceiveSlots --> receive slots updated: unused=0, activeSpeaker=9, receiverSelected=0\ngroup: main\nfake video slot fake video slot fake video slot fake video slot fake video slot fake video slot fake video slot fake video slot fake video slot\nreceiverSelected:\n'
773
+ );
515
774
  });
516
775
 
776
+
517
777
  it('releases slots when switching to layout that requires less active speaker slots', async () => {
518
778
  // start with "AllEqual" layout that needs just 9 video slots
519
779
  const config = cloneDeep(DefaultTestConfiguration);
@@ -538,8 +798,135 @@ describe('RemoteMediaManager', () => {
538
798
  fakeReceiveSlotManager.releaseSlot.getCalls().forEach((call) => {
539
799
  const slot = call.args[0];
540
800
 
541
- assert.strictEqual(slot.mediaType, MC.MediaType.VideoMain);
801
+ assert.strictEqual(slot.mediaType, MediaType.VideoMain);
802
+ });
803
+ });
804
+
805
+ it('releases slots and reallocates slots when switching to layouts in correct order', async () => {
806
+
807
+ const config = cloneDeep(DefaultTestConfiguration);
808
+ let count = 0;
809
+
810
+ fakeReceiveSlotManager.allocateSlot = sinon.stub().callsFake((mediaType) => {
811
+ switch (mediaType) {
812
+ case MediaType.AudioMain:
813
+ return Promise.resolve(fakeAudioSlot);
814
+ case MediaType.VideoMain:
815
+ return Promise.resolve(new FakeSlot(MediaType.VideoMain, `fake video ${count++}`));
816
+ case MediaType.AudioSlides:
817
+ return Promise.resolve(fakeScreenShareAudioSlot);
818
+ case MediaType.VideoSlides:
819
+ return Promise.resolve(fakeScreenShareVideoSlot);
820
+ }
821
+ throw new Error(`invalid mediaType: ${mediaType}`);
822
+ })
823
+
824
+ remoteMediaManager = new RemoteMediaManager(
825
+ fakeReceiveSlotManager,
826
+ fakeMediaRequestManagers,
827
+ config
828
+ );
829
+
830
+ await remoteMediaManager.start();
831
+
832
+ resetHistory();
833
+
834
+ assert.deepEqual(remoteMediaManager.slots.video.activeSpeaker.map((slot: any) => slot.id), [
835
+ "fake video 0",
836
+ "fake video 1",
837
+ "fake video 2",
838
+ "fake video 3",
839
+ "fake video 4",
840
+ "fake video 5",
841
+ "fake video 6",
842
+ "fake video 7",
843
+ "fake video 8",
844
+ ]);
845
+
846
+ assert.deepEqual(remoteMediaManager.receiveSlotAllocations.activeSpeaker["main"].slots.map((slot: any) => slot.id), [
847
+ "fake video 0",
848
+ "fake video 1",
849
+ "fake video 2",
850
+ "fake video 3",
851
+ "fake video 4",
852
+ "fake video 5",
853
+ "fake video 6",
854
+ "fake video 7",
855
+ "fake video 8",
856
+ ])
857
+
858
+ // switch to "OnePlusFive" layout that requires 3 less video slots (6)
859
+ await remoteMediaManager.setLayout('OnePlusFive');
860
+
861
+ assert.deepEqual(remoteMediaManager.slots.video.unused, []);
862
+
863
+ assert.deepEqual(remoteMediaManager.slots.video.activeSpeaker.map((slot: any) => slot.id), [
864
+ "fake video 0",
865
+ "fake video 1",
866
+ "fake video 2",
867
+ "fake video 3",
868
+ "fake video 4",
869
+ "fake video 5"
870
+ ]);
871
+
872
+ // we're checking that the slots are in the same order as in the previous layout
873
+ // first one goes into main
874
+ assert.deepEqual(remoteMediaManager.receiveSlotAllocations.activeSpeaker["mainBigOne"].slots.map((slot: any) => slot.id), [
875
+ "fake video 0",
876
+ ])
877
+ // and rest go in the pips
878
+ assert.deepEqual(remoteMediaManager.receiveSlotAllocations.activeSpeaker["secondarySetOfSmallPanes"].slots.map((slot: any) => slot.id), [
879
+ "fake video 1",
880
+ "fake video 2",
881
+ "fake video 3",
882
+ "fake video 4",
883
+ "fake video 5"
884
+ ])
885
+
886
+ // verify that 3 main video slots were released
887
+ assert.callCount(fakeReceiveSlotManager.releaseSlot, 3);
888
+ fakeReceiveSlotManager.releaseSlot.getCalls().forEach((call) => {
889
+ const slot = call.args[0];
890
+
891
+ assert.strictEqual(slot.mediaType, MediaType.VideoMain);
542
892
  });
893
+
894
+ await remoteMediaManager.setLayout('AllEqual');
895
+
896
+ assert.deepEqual(remoteMediaManager.slots.video.unused, []);
897
+
898
+ // checking that slots are in the same order as in previous layout + 3 new ones
899
+ assert.deepEqual(remoteMediaManager.slots.video.activeSpeaker.map((slot: any) => slot.id), [
900
+ "fake video 0",
901
+ "fake video 1",
902
+ "fake video 2",
903
+ "fake video 3",
904
+ "fake video 4",
905
+ "fake video 5",
906
+ "fake video 10",
907
+ "fake video 11",
908
+ "fake video 12",
909
+ ]);
910
+
911
+ assert.deepEqual(remoteMediaManager.receiveSlotAllocations.activeSpeaker["main"].slots.map((slot: any) => slot.id), [
912
+ "fake video 0",
913
+ "fake video 1",
914
+ "fake video 2",
915
+ "fake video 3",
916
+ "fake video 4",
917
+ "fake video 5",
918
+ "fake video 10",
919
+ "fake video 11",
920
+ "fake video 12"
921
+ ])
922
+
923
+ // verify that 3 main video slots were allocated
924
+ assert.callCount(fakeReceiveSlotManager.allocateSlot, 3);
925
+ fakeReceiveSlotManager.allocateSlot.getCalls().forEach((call) => {
926
+ const mediaType = call.args[0];
927
+
928
+ assert.strictEqual(mediaType, MediaType.VideoMain);
929
+ });
543
930
  });
544
931
 
545
932
  it('stops all current video remoteMedia instances when switching to new layout', async () => {
@@ -600,6 +987,104 @@ describe('RemoteMediaManager', () => {
600
987
  });
601
988
  });
602
989
 
990
+ it('emits Event.VideoLayoutChanged with correct data', async () => {
991
+ // setup the initial layout to be empty and a testLayout that has screen share, active speaker groups and member video panes
992
+ const config: Configuration = {
993
+ audio: {
994
+ numOfActiveSpeakerStreams: 0,
995
+ numOfScreenShareStreams: 0,
996
+ },
997
+ video: {
998
+ preferLiveVideo: true,
999
+ initialLayoutId: 'empty',
1000
+ layouts: {
1001
+ empty: {},
1002
+ testLayout: {
1003
+ screenShareVideo: {size: 'very small'},
1004
+ activeSpeakerVideoPaneGroups: [
1005
+ {
1006
+ id: 'big',
1007
+ numPanes: 10,
1008
+ priority: 255,
1009
+ size: 'large',
1010
+ },
1011
+ {
1012
+ id: 'small',
1013
+ numPanes: 3,
1014
+ priority: 254,
1015
+ size: 'medium',
1016
+ },
1017
+ ],
1018
+ memberVideoPanes: [
1019
+ {id: 'pane 1', size: 'best', csi: 555},
1020
+ {id: 'pane 2', size: 'best', csi: undefined},
1021
+ ],
1022
+ },
1023
+ },
1024
+ },
1025
+ };
1026
+
1027
+ remoteMediaManager = new RemoteMediaManager(
1028
+ fakeReceiveSlotManager,
1029
+ fakeMediaRequestManagers,
1030
+ config
1031
+ );
1032
+
1033
+ await remoteMediaManager.start();
1034
+
1035
+ resetHistory();
1036
+
1037
+ let receivedLayoutInfo: VideoLayoutChangedEventData | null = null;
1038
+
1039
+ remoteMediaManager.on(Event.VideoLayoutChanged, (layoutInfo) => {
1040
+ receivedLayoutInfo = layoutInfo;
1041
+ });
1042
+
1043
+ // switch to the test layout
1044
+ await remoteMediaManager.setLayout('testLayout');
1045
+
1046
+ assert.isNotNull(receivedLayoutInfo);
1047
+
1048
+ if (receivedLayoutInfo) {
1049
+ assert.strictEqual(receivedLayoutInfo.layoutId, 'testLayout');
1050
+
1051
+ // check screen share video
1052
+ assert.isTrue(!!receivedLayoutInfo.screenShareVideo);
1053
+ assert.strictEqual(receivedLayoutInfo.screenShareVideo.mediaType, MediaType.VideoSlides);
1054
+
1055
+ // check member videos
1056
+ assert.strictEqual(Object.keys(receivedLayoutInfo.memberVideoPanes).length, 2);
1057
+ Object.values(receivedLayoutInfo.memberVideoPanes).forEach((remoteMedia) =>
1058
+ assert.strictEqual(remoteMedia.mediaType, MediaType.VideoMain)
1059
+ );
1060
+
1061
+ // check the 2 active speaker groups
1062
+ assert.strictEqual(Object.keys(receivedLayoutInfo.activeSpeakerVideoPanes).length, 2);
1063
+
1064
+ // "big" group
1065
+ assert.strictEqual(
1066
+ receivedLayoutInfo.activeSpeakerVideoPanes.big.getRemoteMedia().length,
1067
+ 10
1068
+ );
1069
+ receivedLayoutInfo.activeSpeakerVideoPanes.big
1070
+ .getRemoteMedia()
1071
+ .forEach((remoteMedia) =>
1072
+ assert.strictEqual(remoteMedia.mediaType, MediaType.VideoMain)
1073
+ );
1074
+
1075
+ // "small" group
1076
+ assert.strictEqual(
1077
+ receivedLayoutInfo.activeSpeakerVideoPanes.small.getRemoteMedia().length,
1078
+ 3
1079
+ );
1080
+ receivedLayoutInfo.activeSpeakerVideoPanes.small
1081
+ .getRemoteMedia()
1082
+ .forEach((remoteMedia) =>
1083
+ assert.strictEqual(remoteMedia.mediaType, MediaType.VideoMain)
1084
+ );
1085
+ }
1086
+ });
1087
+
603
1088
  describe('switching between different receiver selected layouts', () => {
604
1089
  let fakeSlots: {[key: ReceiveSlotId]: FakeSlot};
605
1090
  let slotCounter: number;
@@ -620,7 +1105,7 @@ describe('RemoteMediaManager', () => {
620
1105
  slotCounter += 1;
621
1106
  const newSlotId = `fake video slot ${slotCounter}`;
622
1107
 
623
- fakeSlots[newSlotId] = new FakeSlot(MC.MediaType.VideoMain, newSlotId);
1108
+ fakeSlots[newSlotId] = new FakeSlot(MediaType.VideoMain, newSlotId);
624
1109
  return fakeSlots[newSlotId];
625
1110
  });
626
1111
 
@@ -652,12 +1137,12 @@ describe('RemoteMediaManager', () => {
652
1137
  // This test starts with a layout that has 5 receiver selected video slots
653
1138
  // and switches to a different layout that has fewer slots, but 2 of them match CSIs
654
1139
  // from the initial layout. We want to verify that these 2 slots get re-used correctly.
1140
+ // There are no screen share or audio slots being used in this test.
1141
+ delete config.video.layouts.ScreenShareView;
655
1142
  config.audio.numOfActiveSpeakerStreams = 0;
656
- config.screenShare.audio = false;
657
- config.screenShare.video = false;
1143
+ config.audio.numOfScreenShareStreams = 0;
658
1144
  config.video.initialLayoutId = 'biggerLayout';
659
1145
  config.video.layouts['biggerLayout'] = {
660
- screenShareVideo: {size: null},
661
1146
  memberVideoPanes: [
662
1147
  {id: '1', size: 'best', csi: 100},
663
1148
  {id: '2', size: 'best', csi: 200},
@@ -667,7 +1152,6 @@ describe('RemoteMediaManager', () => {
667
1152
  ],
668
1153
  };
669
1154
  config.video.layouts['smallerLayout'] = {
670
- screenShareVideo: {size: null},
671
1155
  memberVideoPanes: [
672
1156
  {id: '1', size: 'medium', csi: 200}, // this csi matches pane '2' from biggerLayout
673
1157
  {id: '2', size: 'medium', csi: 123},
@@ -717,16 +1201,15 @@ describe('RemoteMediaManager', () => {
717
1201
  // This test starts with a layout that has video slot with a specific CSI
718
1202
  // and switches to a different layout that 2 panes with that same CSI.
719
1203
  // We want to verify that the slot gets reused, but also that a 2nd slot is allocated.
1204
+ // There are no screen share or audio slots being used in this test.
1205
+ delete config.video.layouts.ScreenShareView;
720
1206
  config.audio.numOfActiveSpeakerStreams = 0;
721
- config.screenShare.audio = false;
722
- config.screenShare.video = false;
1207
+ config.audio.numOfScreenShareStreams = 0;
723
1208
  config.video.initialLayoutId = 'initialEmptyLayout';
724
1209
  config.video.layouts['initialEmptyLayout'] = {
725
- screenShareVideo: {size: null},
726
1210
  memberVideoPanes: [{id: '2', size: 'medium', csi: 456}],
727
1211
  };
728
1212
  config.video.layouts['layoutWithDuplicateCSIs'] = {
729
- screenShareVideo: {size: null},
730
1213
  memberVideoPanes: [
731
1214
  {id: '1', size: 'medium', csi: 123},
732
1215
  {id: '2', size: 'medium', csi: 456},
@@ -899,16 +1382,18 @@ describe('RemoteMediaManager', () => {
899
1382
  });
900
1383
 
901
1384
  it('cancels all media requests for the previous layout when switching to a new one', async () => {
1385
+ // setup the initial layout to have screen share, active speaker groups and member video panes
902
1386
  const config: Configuration = {
903
1387
  audio: {
904
1388
  numOfActiveSpeakerStreams: 0,
1389
+ numOfScreenShareStreams: 0,
905
1390
  },
906
1391
  video: {
907
1392
  preferLiveVideo: true,
908
1393
  initialLayoutId: 'initial',
909
1394
  layouts: {
910
1395
  initial: {
911
- screenShareVideo: {size: null},
1396
+ screenShareVideo: {size: 'best'},
912
1397
  activeSpeakerVideoPaneGroups: [
913
1398
  {
914
1399
  id: 'big',
@@ -928,15 +1413,9 @@ describe('RemoteMediaManager', () => {
928
1413
  {id: 'pane 2', size: 'best', csi: 234},
929
1414
  ],
930
1415
  },
931
- other: {
932
- screenShareVideo: {size: null},
933
- },
1416
+ other: {},
934
1417
  },
935
1418
  },
936
- screenShare: {
937
- audio: false,
938
- video: false,
939
- },
940
1419
  };
941
1420
 
942
1421
  remoteMediaManager = new RemoteMediaManager(
@@ -959,9 +1438,15 @@ describe('RemoteMediaManager', () => {
959
1438
 
960
1439
  return `receiver selected request ${receiverSelectedRequestCounter}`;
961
1440
  });
1441
+ // setup the mock for screen share addRequest - this one should be called just once
1442
+ fakeMediaRequestManagers.screenShareVideo.addRequest.callsFake(() => {
1443
+ return 'video screen share request id';
1444
+ });
962
1445
 
963
1446
  await remoteMediaManager.start();
964
1447
 
1448
+ assert.calledOnce(fakeMediaRequestManagers.screenShareVideo.addRequest);
1449
+
965
1450
  resetHistory();
966
1451
 
967
1452
  // switch to "other" layout
@@ -979,11 +1464,45 @@ describe('RemoteMediaManager', () => {
979
1464
  fakeMediaRequestManagers.video.cancelRequest,
980
1465
  'receiver selected request 2'
981
1466
  );
1467
+ assert.calledOnce(fakeMediaRequestManagers.screenShareVideo.cancelRequest);
1468
+ assert.calledWith(
1469
+ fakeMediaRequestManagers.screenShareVideo.cancelRequest,
1470
+ 'video screen share request id'
1471
+ );
982
1472
 
983
1473
  // new layout has no videos, so no new requests should be sent out
984
- // check that 2 correct active speaker media requests were sent out
985
1474
  assert.callCount(fakeMediaRequestManagers.video.addRequest, 0);
986
1475
  });
1476
+
1477
+ it('sends media request for screen share if layout contains screen share', async () => {
1478
+ const allEqualMediaRequestId = 'fake request id';
1479
+
1480
+ fakeMediaRequestManagers.video.addRequest.returns(allEqualMediaRequestId);
1481
+
1482
+ await remoteMediaManager.start();
1483
+
1484
+ resetHistory();
1485
+
1486
+ // switch to a layout that contains a screen share video pane
1487
+ await remoteMediaManager.setLayout('ScreenShareView');
1488
+
1489
+ // check that a correct active speaker media request for screen share has been sent out
1490
+ assert.callCount(fakeMediaRequestManagers.screenShareVideo.addRequest, 1);
1491
+ assert.calledWith(
1492
+ fakeMediaRequestManagers.screenShareVideo.addRequest,
1493
+ sinon.match({
1494
+ policyInfo: sinon.match({
1495
+ policy: 'active-speaker',
1496
+ priority: 255,
1497
+ }),
1498
+ receiveSlots: [fakeScreenShareVideoSlot],
1499
+ codecInfo: sinon.match({
1500
+ codec: 'h264',
1501
+ maxFs: 3600,
1502
+ }),
1503
+ })
1504
+ );
1505
+ });
987
1506
  });
988
1507
  });
989
1508
 
@@ -1123,7 +1642,7 @@ describe('RemoteMediaManager', () => {
1123
1642
 
1124
1643
  // new slot should be allocated
1125
1644
  assert.calledOnce(fakeReceiveSlotManager.allocateSlot);
1126
- assert.calledWith(fakeReceiveSlotManager.allocateSlot, MC.MediaType.VideoMain);
1645
+ assert.calledWith(fakeReceiveSlotManager.allocateSlot, MediaType.VideoMain);
1127
1646
 
1128
1647
  // and a media request sent out
1129
1648
  assert.calledOnce(fakeMediaRequestManagers.video.addRequest);
@@ -1152,7 +1671,7 @@ describe('RemoteMediaManager', () => {
1152
1671
 
1153
1672
  // new slot should be allocated
1154
1673
  assert.calledOnce(fakeReceiveSlotManager.allocateSlot);
1155
- assert.calledWith(fakeReceiveSlotManager.allocateSlot, MC.MediaType.VideoMain);
1674
+ assert.calledWith(fakeReceiveSlotManager.allocateSlot, MediaType.VideoMain);
1156
1675
 
1157
1676
  // but no media requests sent out
1158
1677
  assert.notCalled(fakeMediaRequestManagers.video.addRequest);
@@ -1181,7 +1700,7 @@ describe('RemoteMediaManager', () => {
1181
1700
  await remoteMediaManager.start();
1182
1701
  await remoteMediaManager.setLayout('Stage');
1183
1702
 
1184
- const fakeNewSlot = new FakeSlot(MC.MediaType.VideoMain, 'fake video slot');
1703
+ const fakeNewSlot = new FakeSlot(MediaType.VideoMain, 'fake video slot');
1185
1704
  const fakeRequestId = 'fake request id';
1186
1705
 
1187
1706
  fakeReceiveSlotManager.allocateSlot.resolves(fakeNewSlot);
@@ -1205,6 +1724,94 @@ describe('RemoteMediaManager', () => {
1205
1724
  });
1206
1725
  });
1207
1726
 
1727
+ describe('setActiveSpeakerCsis', () => {
1728
+ it('calls setActiveSpeakerCsis on the correct remote media group', async () => {
1729
+ let currentLayoutInfo: VideoLayoutChangedEventData | null = null;
1730
+ let setCsisStub;
1731
+
1732
+ remoteMediaManager.on(Event.VideoLayoutChanged, (layoutInfo: VideoLayoutChangedEventData) => {
1733
+ currentLayoutInfo = layoutInfo;
1734
+ setCsisStub = sinon.stub(layoutInfo.activeSpeakerVideoPanes.main, 'setActiveSpeakerCsis');
1735
+ });
1736
+
1737
+ await remoteMediaManager.start();
1738
+ resetHistory();
1739
+
1740
+ assert.isNotNull(currentLayoutInfo);
1741
+
1742
+ if (currentLayoutInfo) {
1743
+ const remoteVideo = currentLayoutInfo.activeSpeakerVideoPanes.main.getRemoteMedia()[0];
1744
+
1745
+ remoteMediaManager.setActiveSpeakerCsis([{remoteMedia: remoteVideo}]);
1746
+
1747
+ assert.calledOnce(setCsisStub);
1748
+ assert.calledWith(setCsisStub, [{remoteMedia: remoteVideo}], false);
1749
+ assert.calledOnce(fakeMediaRequestManagers.video.commit);
1750
+ }
1751
+ });
1752
+
1753
+ it('does not call setActiveSpeakerCsis on the incorrect media group', async () => {
1754
+ let currentLayoutInfo: VideoLayoutChangedEventData | null = null;
1755
+ let setCsisStub;
1756
+
1757
+ remoteMediaManager.on(Event.VideoLayoutChanged, (layoutInfo: VideoLayoutChangedEventData) => {
1758
+ currentLayoutInfo = layoutInfo;
1759
+ setCsisStub = sinon.stub(layoutInfo.activeSpeakerVideoPanes.main, 'setActiveSpeakerCsis');
1760
+ });
1761
+
1762
+ await remoteMediaManager.start();
1763
+ resetHistory();
1764
+
1765
+ assert.isNotNull(currentLayoutInfo);
1766
+
1767
+ if (currentLayoutInfo) {
1768
+ remoteMediaManager.setActiveSpeakerCsis([{remoteMedia: {}}]);
1769
+
1770
+ assert.notCalled(setCsisStub);
1771
+ assert.calledOnce(fakeMediaRequestManagers.video.commit);
1772
+ }
1773
+ });
1774
+
1775
+ it('checking when there is more than one group', async () => {
1776
+ let currentLayoutInfo: VideoLayoutChangedEventData | null = null;
1777
+ const config = cloneDeep(DefaultTestConfiguration);
1778
+ let stubs = [];
1779
+
1780
+ config.video.initialLayoutId = 'OnePlusFive';
1781
+
1782
+ remoteMediaManager = new RemoteMediaManager(
1783
+ fakeReceiveSlotManager,
1784
+ fakeMediaRequestManagers,
1785
+ config
1786
+ );
1787
+
1788
+ remoteMediaManager.on(Event.VideoLayoutChanged, (layoutInfo: VideoLayoutChangedEventData) => {
1789
+ currentLayoutInfo = layoutInfo;
1790
+ Object.values(layoutInfo.activeSpeakerVideoPanes).forEach((group) => stubs.push(sinon.stub(group, 'setActiveSpeakerCsis')));
1791
+ });
1792
+
1793
+ await remoteMediaManager.start();
1794
+ resetHistory();
1795
+
1796
+ assert.isNotNull(currentLayoutInfo);
1797
+
1798
+ if (currentLayoutInfo) {
1799
+
1800
+ const remoteMedia1 = currentLayoutInfo.activeSpeakerVideoPanes.mainBigOne.getRemoteMedia()[0];
1801
+ const remoteMedia2 = currentLayoutInfo.activeSpeakerVideoPanes.secondarySetOfSmallPanes.getRemoteMedia()[0];
1802
+
1803
+ const remoteMediaCsis = [{remoteMedia: remoteMedia1}, {remoteMedia: remoteMedia2}];
1804
+
1805
+ remoteMediaManager.setActiveSpeakerCsis([{remoteMedia: remoteMedia1}, {remoteMedia: remoteMedia2}]);
1806
+
1807
+ stubs.forEach((stub, index) => {
1808
+ assert.calledWith(stub, [remoteMediaCsis[index]], false)
1809
+ });
1810
+ assert.calledOnce(fakeMediaRequestManagers.video.commit);
1811
+ }
1812
+ });
1813
+ });
1814
+
1208
1815
  describe('pinActiveSpeakerVideoPane() and isPinned()', () => {
1209
1816
  it('throws if called on a pane not belonging to an active speaker group', async () => {
1210
1817
  let currentLayoutInfo: VideoLayoutChangedEventData | null = null;