@webex/plugin-meetings 3.0.0-beta.4 → 3.0.0-beta.400

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 (629) hide show
  1. package/README.md +58 -8
  2. package/UPGRADING.md +9 -9
  3. package/browsers.js +19 -24
  4. package/dist/annotation/annotation.types.js +7 -0
  5. package/dist/annotation/annotation.types.js.map +1 -0
  6. package/dist/annotation/constants.js +49 -0
  7. package/dist/annotation/constants.js.map +1 -0
  8. package/dist/annotation/index.js +342 -0
  9. package/dist/annotation/index.js.map +1 -0
  10. package/dist/breakouts/breakout.js +216 -0
  11. package/dist/breakouts/breakout.js.map +1 -0
  12. package/dist/breakouts/collection.js +23 -0
  13. package/dist/breakouts/collection.js.map +1 -0
  14. package/dist/breakouts/edit-lock-error.js +52 -0
  15. package/dist/breakouts/edit-lock-error.js.map +1 -0
  16. package/dist/breakouts/events.js +45 -0
  17. package/dist/breakouts/events.js.map +1 -0
  18. package/dist/breakouts/index.js +1048 -0
  19. package/dist/breakouts/index.js.map +1 -0
  20. package/dist/breakouts/request.js +78 -0
  21. package/dist/breakouts/request.js.map +1 -0
  22. package/dist/breakouts/utils.js +67 -0
  23. package/dist/breakouts/utils.js.map +1 -0
  24. package/dist/common/browser-detection.js +1 -20
  25. package/dist/common/browser-detection.js.map +1 -1
  26. package/dist/common/collection.js +5 -20
  27. package/dist/common/collection.js.map +1 -1
  28. package/dist/common/config.js +0 -7
  29. package/dist/common/config.js.map +1 -1
  30. package/dist/common/errors/captcha-error.js +10 -24
  31. package/dist/common/errors/captcha-error.js.map +1 -1
  32. package/dist/common/errors/intent-to-join.js +11 -24
  33. package/dist/common/errors/intent-to-join.js.map +1 -1
  34. package/dist/common/errors/join-meeting.js +12 -25
  35. package/dist/common/errors/join-meeting.js.map +1 -1
  36. package/dist/common/errors/media.js +10 -24
  37. package/dist/common/errors/media.js.map +1 -1
  38. package/dist/common/errors/no-meeting-info.js +51 -0
  39. package/dist/common/errors/no-meeting-info.js.map +1 -0
  40. package/dist/common/errors/parameter.js +5 -33
  41. package/dist/common/errors/parameter.js.map +1 -1
  42. package/dist/common/errors/password-error.js +10 -24
  43. package/dist/common/errors/password-error.js.map +1 -1
  44. package/dist/common/errors/permission.js +9 -23
  45. package/dist/common/errors/permission.js.map +1 -1
  46. package/dist/common/errors/reclaim-host-role-errors.js +158 -0
  47. package/dist/common/errors/reclaim-host-role-errors.js.map +1 -0
  48. package/dist/common/errors/reconnection-in-progress.js +0 -17
  49. package/dist/common/errors/reconnection-in-progress.js.map +1 -1
  50. package/dist/common/errors/reconnection.js +10 -24
  51. package/dist/common/errors/reconnection.js.map +1 -1
  52. package/dist/common/errors/stats.js +10 -24
  53. package/dist/common/errors/stats.js.map +1 -1
  54. package/dist/common/errors/webex-errors.js +54 -48
  55. package/dist/common/errors/webex-errors.js.map +1 -1
  56. package/dist/common/errors/webex-meetings-error.js +5 -25
  57. package/dist/common/errors/webex-meetings-error.js.map +1 -1
  58. package/dist/common/events/events-scope.js +0 -22
  59. package/dist/common/events/events-scope.js.map +1 -1
  60. package/dist/common/events/events.js +0 -23
  61. package/dist/common/events/events.js.map +1 -1
  62. package/dist/common/events/trigger-proxy.js +0 -12
  63. package/dist/common/events/trigger-proxy.js.map +1 -1
  64. package/dist/common/events/util.js +0 -15
  65. package/dist/common/events/util.js.map +1 -1
  66. package/dist/common/logs/logger-config.js +0 -4
  67. package/dist/common/logs/logger-config.js.map +1 -1
  68. package/dist/common/logs/logger-proxy.js +1 -8
  69. package/dist/common/logs/logger-proxy.js.map +1 -1
  70. package/dist/common/logs/request.js +41 -60
  71. package/dist/common/logs/request.js.map +1 -1
  72. package/dist/common/queue.js +28 -23
  73. package/dist/common/queue.js.map +1 -1
  74. package/dist/config.js +11 -15
  75. package/dist/config.js.map +1 -1
  76. package/dist/constants.js +347 -74
  77. package/dist/constants.js.map +1 -1
  78. package/dist/controls-options-manager/constants.js +14 -0
  79. package/dist/controls-options-manager/constants.js.map +1 -0
  80. package/dist/controls-options-manager/enums.js +27 -0
  81. package/dist/controls-options-manager/enums.js.map +1 -0
  82. package/dist/controls-options-manager/index.js +297 -0
  83. package/dist/controls-options-manager/index.js.map +1 -0
  84. package/dist/controls-options-manager/types.js +7 -0
  85. package/dist/controls-options-manager/types.js.map +1 -0
  86. package/dist/controls-options-manager/util.js +319 -0
  87. package/dist/controls-options-manager/util.js.map +1 -0
  88. package/dist/index.js +125 -18
  89. package/dist/index.js.map +1 -1
  90. package/dist/interceptors/index.js +15 -0
  91. package/dist/interceptors/index.js.map +1 -0
  92. package/dist/interceptors/locusRetry.js +93 -0
  93. package/dist/interceptors/locusRetry.js.map +1 -0
  94. package/dist/interpretation/collection.js +23 -0
  95. package/dist/interpretation/collection.js.map +1 -0
  96. package/dist/interpretation/index.js +380 -0
  97. package/dist/interpretation/index.js.map +1 -0
  98. package/dist/interpretation/siLanguage.js +25 -0
  99. package/dist/interpretation/siLanguage.js.map +1 -0
  100. package/dist/locus-info/controlsUtils.js +101 -29
  101. package/dist/locus-info/controlsUtils.js.map +1 -1
  102. package/dist/locus-info/embeddedAppsUtils.js +3 -26
  103. package/dist/locus-info/embeddedAppsUtils.js.map +1 -1
  104. package/dist/locus-info/fullState.js +0 -15
  105. package/dist/locus-info/fullState.js.map +1 -1
  106. package/dist/locus-info/hostUtils.js +4 -12
  107. package/dist/locus-info/hostUtils.js.map +1 -1
  108. package/dist/locus-info/index.js +564 -246
  109. package/dist/locus-info/index.js.map +1 -1
  110. package/dist/locus-info/infoUtils.js +10 -38
  111. package/dist/locus-info/infoUtils.js.map +1 -1
  112. package/dist/locus-info/mediaSharesUtils.js +82 -38
  113. package/dist/locus-info/mediaSharesUtils.js.map +1 -1
  114. package/dist/locus-info/parser.js +314 -163
  115. package/dist/locus-info/parser.js.map +1 -1
  116. package/dist/locus-info/selfUtils.js +110 -92
  117. package/dist/locus-info/selfUtils.js.map +1 -1
  118. package/dist/media/index.js +107 -231
  119. package/dist/media/index.js.map +1 -1
  120. package/dist/media/properties.js +137 -222
  121. package/dist/media/properties.js.map +1 -1
  122. package/dist/media/util.js +2 -9
  123. package/dist/media/util.js.map +1 -1
  124. package/dist/mediaQualityMetrics/config.js +316 -501
  125. package/dist/mediaQualityMetrics/config.js.map +1 -1
  126. package/dist/meeting/in-meeting-actions.js +97 -14
  127. package/dist/meeting/in-meeting-actions.js.map +1 -1
  128. package/dist/meeting/index.js +5311 -3871
  129. package/dist/meeting/index.js.map +1 -1
  130. package/dist/meeting/locusMediaRequest.js +292 -0
  131. package/dist/meeting/locusMediaRequest.js.map +1 -0
  132. package/dist/meeting/muteState.js +260 -183
  133. package/dist/meeting/muteState.js.map +1 -1
  134. package/dist/meeting/request.js +421 -347
  135. package/dist/meeting/request.js.map +1 -1
  136. package/dist/meeting/request.type.js +7 -0
  137. package/dist/meeting/request.type.js.map +1 -0
  138. package/dist/meeting/state.js +21 -31
  139. package/dist/meeting/state.js.map +1 -1
  140. package/dist/meeting/util.js +672 -585
  141. package/dist/meeting/util.js.map +1 -1
  142. package/dist/meeting/voicea-meeting.js +172 -0
  143. package/dist/meeting/voicea-meeting.js.map +1 -0
  144. package/dist/meeting-info/collection.js +6 -25
  145. package/dist/meeting-info/collection.js.map +1 -1
  146. package/dist/meeting-info/index.js +87 -39
  147. package/dist/meeting-info/index.js.map +1 -1
  148. package/dist/meeting-info/meeting-info-v2.js +352 -283
  149. package/dist/meeting-info/meeting-info-v2.js.map +1 -1
  150. package/dist/meeting-info/request.js +3 -15
  151. package/dist/meeting-info/request.js.map +1 -1
  152. package/dist/meeting-info/util.js +99 -183
  153. package/dist/meeting-info/util.js.map +1 -1
  154. package/dist/meeting-info/utilv2.js +147 -234
  155. package/dist/meeting-info/utilv2.js.map +1 -1
  156. package/dist/meetings/collection.js +43 -19
  157. package/dist/meetings/collection.js.map +1 -1
  158. package/dist/meetings/index.js +895 -600
  159. package/dist/meetings/index.js.map +1 -1
  160. package/dist/meetings/meetings.types.js +7 -0
  161. package/dist/meetings/meetings.types.js.map +1 -0
  162. package/dist/meetings/request.js +26 -41
  163. package/dist/meetings/request.js.map +1 -1
  164. package/dist/meetings/util.js +184 -157
  165. package/dist/meetings/util.js.map +1 -1
  166. package/dist/member/index.js +134 -85
  167. package/dist/member/index.js.map +1 -1
  168. package/dist/member/types.js +25 -0
  169. package/dist/member/types.js.map +1 -0
  170. package/dist/member/util.js +158 -88
  171. package/dist/member/util.js.map +1 -1
  172. package/dist/members/collection.js +13 -12
  173. package/dist/members/collection.js.map +1 -1
  174. package/dist/members/index.js +194 -204
  175. package/dist/members/index.js.map +1 -1
  176. package/dist/members/request.js +113 -68
  177. package/dist/members/request.js.map +1 -1
  178. package/dist/members/types.js +15 -0
  179. package/dist/members/types.js.map +1 -0
  180. package/dist/members/util.js +324 -259
  181. package/dist/members/util.js.map +1 -1
  182. package/dist/metrics/constants.js +19 -7
  183. package/dist/metrics/constants.js.map +1 -1
  184. package/dist/metrics/index.js +11 -558
  185. package/dist/metrics/index.js.map +1 -1
  186. package/dist/multistream/mediaRequestManager.js +263 -50
  187. package/dist/multistream/mediaRequestManager.js.map +1 -1
  188. package/dist/multistream/receiveSlot.js +58 -65
  189. package/dist/multistream/receiveSlot.js.map +1 -1
  190. package/dist/multistream/receiveSlotManager.js +76 -95
  191. package/dist/multistream/receiveSlotManager.js.map +1 -1
  192. package/dist/multistream/remoteMedia.js +62 -76
  193. package/dist/multistream/remoteMedia.js.map +1 -1
  194. package/dist/multistream/remoteMediaGroup.js +82 -45
  195. package/dist/multistream/remoteMediaGroup.js.map +1 -1
  196. package/dist/multistream/remoteMediaManager.js +657 -448
  197. package/dist/multistream/remoteMediaManager.js.map +1 -1
  198. package/dist/multistream/sendSlotManager.js +255 -0
  199. package/dist/multistream/sendSlotManager.js.map +1 -0
  200. package/dist/networkQualityMonitor/index.js +40 -59
  201. package/dist/networkQualityMonitor/index.js.map +1 -1
  202. package/dist/personal-meeting-room/index.js +21 -45
  203. package/dist/personal-meeting-room/index.js.map +1 -1
  204. package/dist/personal-meeting-room/request.js +1 -31
  205. package/dist/personal-meeting-room/request.js.map +1 -1
  206. package/dist/personal-meeting-room/util.js +0 -13
  207. package/dist/personal-meeting-room/util.js.map +1 -1
  208. package/dist/reachability/clusterReachability.js +356 -0
  209. package/dist/reachability/clusterReachability.js.map +1 -0
  210. package/dist/reachability/index.js +297 -460
  211. package/dist/reachability/index.js.map +1 -1
  212. package/dist/reachability/request.js +20 -26
  213. package/dist/reachability/request.js.map +1 -1
  214. package/dist/reachability/util.js +29 -0
  215. package/dist/reachability/util.js.map +1 -0
  216. package/dist/reactions/constants.js +13 -0
  217. package/dist/reactions/constants.js.map +1 -0
  218. package/dist/reactions/reactions.js +109 -0
  219. package/dist/reactions/reactions.js.map +1 -0
  220. package/dist/reactions/reactions.type.js +36 -0
  221. package/dist/reactions/reactions.type.js.map +1 -0
  222. package/dist/reconnection-manager/index.js +413 -483
  223. package/dist/reconnection-manager/index.js.map +1 -1
  224. package/dist/recording-controller/enums.js +17 -0
  225. package/dist/recording-controller/enums.js.map +1 -0
  226. package/dist/recording-controller/index.js +362 -0
  227. package/dist/recording-controller/index.js.map +1 -0
  228. package/dist/recording-controller/util.js +64 -0
  229. package/dist/recording-controller/util.js.map +1 -0
  230. package/dist/roap/index.js +102 -86
  231. package/dist/roap/index.js.map +1 -1
  232. package/dist/roap/request.js +131 -135
  233. package/dist/roap/request.js.map +1 -1
  234. package/dist/roap/turnDiscovery.js +437 -116
  235. package/dist/roap/turnDiscovery.js.map +1 -1
  236. package/dist/rtcMetrics/constants.js +12 -0
  237. package/dist/rtcMetrics/constants.js.map +1 -0
  238. package/dist/rtcMetrics/index.js +179 -0
  239. package/dist/rtcMetrics/index.js.map +1 -0
  240. package/dist/statsAnalyzer/global.js +1 -95
  241. package/dist/statsAnalyzer/global.js.map +1 -1
  242. package/dist/statsAnalyzer/index.js +557 -583
  243. package/dist/statsAnalyzer/index.js.map +1 -1
  244. package/dist/statsAnalyzer/mqaUtil.js +326 -130
  245. package/dist/statsAnalyzer/mqaUtil.js.map +1 -1
  246. package/dist/transcription/index.js +22 -47
  247. package/dist/transcription/index.js.map +1 -1
  248. package/dist/types/annotation/annotation.types.d.ts +42 -0
  249. package/dist/types/annotation/constants.d.ts +31 -0
  250. package/dist/types/annotation/index.d.ts +117 -0
  251. package/dist/types/breakouts/breakout.d.ts +8 -0
  252. package/dist/types/breakouts/collection.d.ts +5 -0
  253. package/dist/types/breakouts/edit-lock-error.d.ts +15 -0
  254. package/dist/types/breakouts/events.d.ts +8 -0
  255. package/dist/types/breakouts/index.d.ts +5 -0
  256. package/dist/types/breakouts/request.d.ts +22 -0
  257. package/dist/types/breakouts/utils.d.ts +15 -0
  258. package/dist/types/common/browser-detection.d.ts +9 -0
  259. package/dist/types/common/collection.d.ts +48 -0
  260. package/dist/types/common/config.d.ts +2 -0
  261. package/dist/types/common/errors/captcha-error.d.ts +15 -0
  262. package/dist/types/common/errors/intent-to-join.d.ts +16 -0
  263. package/dist/types/common/errors/join-meeting.d.ts +17 -0
  264. package/dist/types/common/errors/media.d.ts +15 -0
  265. package/dist/types/common/errors/no-meeting-info.d.ts +14 -0
  266. package/dist/types/common/errors/parameter.d.ts +15 -0
  267. package/dist/types/common/errors/password-error.d.ts +15 -0
  268. package/dist/types/common/errors/permission.d.ts +14 -0
  269. package/dist/types/common/errors/reclaim-host-role-errors.d.ts +60 -0
  270. package/dist/types/common/errors/reconnection-in-progress.d.ts +9 -0
  271. package/dist/types/common/errors/reconnection.d.ts +15 -0
  272. package/dist/types/common/errors/stats.d.ts +15 -0
  273. package/dist/types/common/errors/webex-errors.d.ts +93 -0
  274. package/dist/types/common/errors/webex-meetings-error.d.ts +20 -0
  275. package/dist/types/common/events/events-scope.d.ts +17 -0
  276. package/dist/types/common/events/events.d.ts +12 -0
  277. package/dist/types/common/events/trigger-proxy.d.ts +2 -0
  278. package/dist/types/common/events/util.d.ts +2 -0
  279. package/dist/types/common/logs/logger-config.d.ts +2 -0
  280. package/dist/types/common/logs/logger-proxy.d.ts +2 -0
  281. package/dist/types/common/logs/request.d.ts +36 -0
  282. package/dist/types/common/queue.d.ts +34 -0
  283. package/dist/types/config.d.ts +72 -0
  284. package/dist/types/constants.d.ts +1088 -0
  285. package/dist/types/controls-options-manager/constants.d.ts +4 -0
  286. package/dist/types/controls-options-manager/enums.d.ts +15 -0
  287. package/dist/types/controls-options-manager/index.d.ts +136 -0
  288. package/dist/types/controls-options-manager/types.d.ts +43 -0
  289. package/dist/types/controls-options-manager/util.d.ts +1 -0
  290. package/dist/types/index.d.ts +7 -0
  291. package/dist/types/interceptors/index.d.ts +2 -0
  292. package/dist/types/interceptors/locusRetry.d.ts +27 -0
  293. package/dist/types/interpretation/collection.d.ts +5 -0
  294. package/dist/types/interpretation/index.d.ts +5 -0
  295. package/dist/types/interpretation/siLanguage.d.ts +5 -0
  296. package/dist/types/locus-info/controlsUtils.d.ts +2 -0
  297. package/dist/types/locus-info/embeddedAppsUtils.d.ts +2 -0
  298. package/dist/types/locus-info/fullState.d.ts +2 -0
  299. package/dist/types/locus-info/hostUtils.d.ts +2 -0
  300. package/dist/types/locus-info/index.d.ts +322 -0
  301. package/dist/types/locus-info/infoUtils.d.ts +2 -0
  302. package/dist/types/locus-info/mediaSharesUtils.d.ts +2 -0
  303. package/dist/types/locus-info/parser.d.ts +272 -0
  304. package/dist/types/locus-info/selfUtils.d.ts +2 -0
  305. package/dist/types/media/index.d.ts +34 -0
  306. package/dist/types/media/properties.d.ts +93 -0
  307. package/dist/types/media/util.d.ts +2 -0
  308. package/dist/types/mediaQualityMetrics/config.d.ts +241 -0
  309. package/dist/types/meeting/in-meeting-actions.d.ts +167 -0
  310. package/dist/types/meeting/index.d.ts +1824 -0
  311. package/dist/types/meeting/locusMediaRequest.d.ts +74 -0
  312. package/dist/types/meeting/muteState.d.ts +178 -0
  313. package/dist/types/meeting/request.d.ts +293 -0
  314. package/dist/types/meeting/request.type.d.ts +11 -0
  315. package/dist/types/meeting/state.d.ts +9 -0
  316. package/dist/types/meeting/util.d.ts +118 -0
  317. package/dist/types/meeting/voicea-meeting.d.ts +16 -0
  318. package/dist/types/meeting-info/collection.d.ts +20 -0
  319. package/dist/types/meeting-info/index.d.ts +69 -0
  320. package/dist/types/meeting-info/meeting-info-v2.d.ts +123 -0
  321. package/dist/types/meeting-info/request.d.ts +22 -0
  322. package/dist/types/meeting-info/util.d.ts +2 -0
  323. package/dist/types/meeting-info/utilv2.d.ts +2 -0
  324. package/dist/types/meetings/collection.d.ts +40 -0
  325. package/dist/types/meetings/index.d.ts +389 -0
  326. package/dist/types/meetings/meetings.types.d.ts +4 -0
  327. package/dist/types/meetings/request.d.ts +27 -0
  328. package/dist/types/meetings/util.d.ts +18 -0
  329. package/dist/types/member/index.d.ts +160 -0
  330. package/dist/types/member/types.d.ts +32 -0
  331. package/dist/types/member/util.d.ts +2 -0
  332. package/dist/types/members/collection.d.ts +29 -0
  333. package/dist/types/members/index.d.ts +353 -0
  334. package/dist/types/members/request.d.ts +114 -0
  335. package/dist/types/members/types.d.ts +25 -0
  336. package/dist/types/members/util.d.ts +215 -0
  337. package/dist/types/metrics/constants.d.ts +70 -0
  338. package/dist/types/metrics/index.d.ts +45 -0
  339. package/dist/types/multistream/mediaRequestManager.d.ts +120 -0
  340. package/dist/types/multistream/receiveSlot.d.ts +68 -0
  341. package/dist/types/multistream/receiveSlotManager.d.ts +56 -0
  342. package/dist/types/multistream/remoteMedia.d.ts +72 -0
  343. package/dist/types/multistream/remoteMediaGroup.d.ts +49 -0
  344. package/dist/types/multistream/remoteMediaManager.d.ts +301 -0
  345. package/dist/types/multistream/sendSlotManager.d.ts +70 -0
  346. package/dist/types/networkQualityMonitor/index.d.ts +70 -0
  347. package/dist/types/personal-meeting-room/index.d.ts +47 -0
  348. package/dist/types/personal-meeting-room/request.d.ts +14 -0
  349. package/dist/types/personal-meeting-room/util.d.ts +2 -0
  350. package/dist/types/reachability/clusterReachability.d.ts +109 -0
  351. package/dist/types/reachability/index.d.ts +105 -0
  352. package/dist/types/reachability/request.d.ts +39 -0
  353. package/dist/types/reachability/util.d.ts +8 -0
  354. package/dist/types/reactions/constants.d.ts +3 -0
  355. package/dist/types/reactions/reactions.d.ts +4 -0
  356. package/dist/types/reactions/reactions.type.d.ts +52 -0
  357. package/dist/types/reconnection-manager/index.d.ts +136 -0
  358. package/dist/types/recording-controller/enums.d.ts +7 -0
  359. package/dist/types/recording-controller/index.d.ts +207 -0
  360. package/dist/types/recording-controller/util.d.ts +14 -0
  361. package/dist/types/roap/index.d.ts +86 -0
  362. package/dist/types/roap/request.d.ts +39 -0
  363. package/dist/types/roap/turnDiscovery.d.ts +155 -0
  364. package/dist/types/rtcMetrics/constants.d.ts +4 -0
  365. package/dist/types/rtcMetrics/index.d.ts +61 -0
  366. package/dist/types/statsAnalyzer/global.d.ts +36 -0
  367. package/dist/types/statsAnalyzer/index.d.ts +217 -0
  368. package/dist/types/statsAnalyzer/mqaUtil.d.ts +48 -0
  369. package/dist/types/transcription/index.d.ts +64 -0
  370. package/dist/types/webinar/collection.d.ts +16 -0
  371. package/dist/types/webinar/index.d.ts +5 -0
  372. package/dist/webinar/collection.js +44 -0
  373. package/dist/webinar/collection.js.map +1 -0
  374. package/dist/webinar/index.js +69 -0
  375. package/dist/webinar/index.js.map +1 -0
  376. package/internal-README.md +7 -6
  377. package/package.json +30 -21
  378. package/src/annotation/annotation.types.ts +50 -0
  379. package/src/annotation/constants.ts +36 -0
  380. package/src/annotation/index.ts +328 -0
  381. package/src/breakouts/README.md +220 -0
  382. package/src/breakouts/breakout.ts +188 -0
  383. package/src/breakouts/collection.ts +19 -0
  384. package/src/breakouts/edit-lock-error.ts +25 -0
  385. package/src/breakouts/events.ts +56 -0
  386. package/src/breakouts/index.ts +925 -0
  387. package/src/breakouts/request.ts +55 -0
  388. package/src/breakouts/utils.ts +57 -0
  389. package/src/common/{browser-detection.js → browser-detection.ts} +9 -6
  390. package/src/common/collection.ts +9 -7
  391. package/src/common/{config.js → config.ts} +1 -1
  392. package/src/common/errors/{captcha-error.js → captcha-error.ts} +11 -7
  393. package/src/common/errors/{intent-to-join.js → intent-to-join.ts} +12 -7
  394. package/src/common/errors/{join-meeting.js → join-meeting.ts} +17 -8
  395. package/src/common/errors/{media.js → media.ts} +11 -7
  396. package/src/common/errors/no-meeting-info.ts +24 -0
  397. package/src/common/errors/parameter.ts +11 -7
  398. package/src/common/errors/{password-error.js → password-error.ts} +11 -7
  399. package/src/common/errors/{permission.js → permission.ts} +10 -6
  400. package/src/common/errors/reclaim-host-role-errors.ts +134 -0
  401. package/src/common/errors/{reconnection.js → reconnection.ts} +11 -7
  402. package/src/common/errors/{stats.js → stats.ts} +11 -7
  403. package/src/common/errors/{webex-errors.js → webex-errors.ts} +51 -8
  404. package/src/common/errors/{webex-meetings-error.js → webex-meetings-error.ts} +4 -2
  405. package/src/common/events/{events-scope.js → events-scope.ts} +6 -2
  406. package/src/common/events/{events.js → events.ts} +5 -1
  407. package/src/common/events/{trigger-proxy.js → trigger-proxy.ts} +9 -5
  408. package/src/common/events/{util.js → util.ts} +2 -3
  409. package/src/common/logs/{logger-config.js → logger-config.ts} +1 -2
  410. package/src/common/logs/logger-proxy.ts +44 -0
  411. package/src/common/logs/{request.js → request.ts} +26 -9
  412. package/src/common/queue.ts +22 -9
  413. package/src/{config.js → config.ts} +19 -21
  414. package/src/constants.ts +296 -27
  415. package/src/controls-options-manager/constants.ts +5 -0
  416. package/src/controls-options-manager/enums.ts +18 -0
  417. package/src/controls-options-manager/index.ts +278 -0
  418. package/src/controls-options-manager/types.ts +59 -0
  419. package/src/controls-options-manager/util.ts +300 -0
  420. package/src/index.ts +45 -0
  421. package/src/interceptors/index.ts +3 -0
  422. package/src/interceptors/locusRetry.ts +67 -0
  423. package/src/interpretation/README.md +60 -0
  424. package/src/interpretation/collection.ts +19 -0
  425. package/src/interpretation/index.ts +349 -0
  426. package/src/interpretation/siLanguage.ts +18 -0
  427. package/src/locus-info/controlsUtils.ts +222 -0
  428. package/src/locus-info/{embeddedAppsUtils.js → embeddedAppsUtils.ts} +5 -6
  429. package/src/locus-info/{fullState.js → fullState.ts} +16 -12
  430. package/src/locus-info/{hostUtils.js → hostUtils.ts} +9 -8
  431. package/src/locus-info/{index.js → index.ts} +561 -119
  432. package/src/locus-info/{infoUtils.js → infoUtils.ts} +29 -10
  433. package/src/locus-info/{mediaSharesUtils.js → mediaSharesUtils.ts} +97 -17
  434. package/src/locus-info/{parser.js → parser.ts} +303 -104
  435. package/src/locus-info/{selfUtils.js → selfUtils.ts} +199 -68
  436. package/src/media/index.ts +460 -0
  437. package/src/media/properties.ts +283 -0
  438. package/src/media/{util.js → util.ts} +2 -2
  439. package/src/mediaQualityMetrics/config.ts +249 -0
  440. package/src/meeting/in-meeting-actions.ts +199 -3
  441. package/src/meeting/index.ts +8494 -0
  442. package/src/meeting/locusMediaRequest.ts +313 -0
  443. package/src/meeting/muteState.ts +465 -0
  444. package/src/meeting/request.ts +912 -0
  445. package/src/meeting/request.type.ts +13 -0
  446. package/src/meeting/{state.js → state.ts} +50 -35
  447. package/src/meeting/util.ts +799 -0
  448. package/src/meeting/voicea-meeting.ts +122 -0
  449. package/src/meeting-info/{collection.js → collection.ts} +6 -2
  450. package/src/meeting-info/index.ts +210 -0
  451. package/src/meeting-info/meeting-info-v2.ts +423 -0
  452. package/src/meeting-info/{request.js → request.ts} +14 -4
  453. package/src/meeting-info/{util.js → util.ts} +70 -58
  454. package/src/meeting-info/{utilv2.js → utilv2.ts} +99 -82
  455. package/src/meetings/collection.ts +76 -0
  456. package/src/meetings/index.ts +1539 -0
  457. package/src/meetings/meetings.types.ts +12 -0
  458. package/src/meetings/{request.js → request.ts} +34 -25
  459. package/src/meetings/{util.js → util.ts} +133 -38
  460. package/src/member/{index.js → index.ts} +159 -56
  461. package/src/member/types.ts +38 -0
  462. package/src/member/util.ts +397 -0
  463. package/src/members/{collection.js → collection.ts} +10 -2
  464. package/src/members/{index.js → index.ts} +351 -146
  465. package/src/members/request.ts +255 -0
  466. package/src/members/types.ts +29 -0
  467. package/src/members/util.ts +353 -0
  468. package/src/metrics/{constants.js → constants.ts} +17 -6
  469. package/src/metrics/index.ts +73 -0
  470. package/src/multistream/mediaRequestManager.ts +341 -64
  471. package/src/multistream/receiveSlot.ts +69 -26
  472. package/src/multistream/receiveSlotManager.ts +66 -42
  473. package/src/multistream/remoteMedia.ts +40 -5
  474. package/src/multistream/remoteMediaGroup.ts +82 -3
  475. package/src/multistream/remoteMediaManager.ts +401 -81
  476. package/src/multistream/sendSlotManager.ts +199 -0
  477. package/src/networkQualityMonitor/{index.js → index.ts} +41 -29
  478. package/src/personal-meeting-room/{index.js → index.ts} +28 -19
  479. package/src/personal-meeting-room/{request.js → request.ts} +13 -4
  480. package/src/personal-meeting-room/{util.js → util.ts} +4 -4
  481. package/src/reachability/clusterReachability.ts +320 -0
  482. package/src/reachability/index.ts +371 -0
  483. package/src/reachability/request.ts +50 -35
  484. package/src/reachability/util.ts +24 -0
  485. package/src/reactions/constants.ts +4 -0
  486. package/src/reactions/reactions.ts +104 -0
  487. package/src/reactions/reactions.type.ts +62 -0
  488. package/src/reconnection-manager/index.ts +643 -0
  489. package/src/recording-controller/enums.ts +8 -0
  490. package/src/recording-controller/index.ts +332 -0
  491. package/src/recording-controller/util.ts +75 -0
  492. package/src/roap/index.ts +288 -0
  493. package/src/roap/request.ts +153 -0
  494. package/src/roap/turnDiscovery.ts +374 -70
  495. package/src/rtcMetrics/constants.ts +3 -0
  496. package/src/rtcMetrics/index.ts +166 -0
  497. package/src/statsAnalyzer/global.ts +37 -0
  498. package/src/statsAnalyzer/index.ts +1275 -0
  499. package/src/statsAnalyzer/mqaUtil.ts +440 -0
  500. package/src/transcription/{index.js → index.ts} +46 -39
  501. package/src/webinar/collection.ts +31 -0
  502. package/src/webinar/index.ts +62 -0
  503. package/test/integration/spec/converged-space-meetings.js +233 -0
  504. package/test/integration/spec/journey.js +791 -531
  505. package/test/integration/spec/space-meeting.js +391 -204
  506. package/test/integration/spec/transcription.js +7 -8
  507. package/test/unit/spec/annotation/index.ts +418 -0
  508. package/test/unit/spec/breakouts/breakout.ts +238 -0
  509. package/test/unit/spec/breakouts/collection.ts +15 -0
  510. package/test/unit/spec/breakouts/edit-lock-error.ts +30 -0
  511. package/test/unit/spec/breakouts/events.ts +89 -0
  512. package/test/unit/spec/breakouts/index.ts +1793 -0
  513. package/test/unit/spec/breakouts/request.ts +104 -0
  514. package/test/unit/spec/breakouts/utils.js +72 -0
  515. package/test/unit/spec/common/browser-detection.js +9 -28
  516. package/test/unit/spec/common/queue.js +31 -2
  517. package/test/unit/spec/controls-options-manager/index.js +287 -0
  518. package/test/unit/spec/controls-options-manager/util.js +582 -0
  519. package/test/unit/spec/fixture/locus.js +93 -90
  520. package/test/unit/spec/interceptors/locusRetry.ts +131 -0
  521. package/test/unit/spec/interpretation/collection.ts +15 -0
  522. package/test/unit/spec/interpretation/index.ts +625 -0
  523. package/test/unit/spec/interpretation/siLanguage.ts +28 -0
  524. package/test/unit/spec/locus-info/controlsUtils.js +325 -32
  525. package/test/unit/spec/locus-info/embeddedAppsUtils.js +8 -6
  526. package/test/unit/spec/locus-info/index.js +1458 -21
  527. package/test/unit/spec/locus-info/infoUtils.js +71 -40
  528. package/test/unit/spec/locus-info/lib/BasicSeqCmp.json +88 -430
  529. package/test/unit/spec/locus-info/lib/SeqCmp.json +529 -685
  530. package/test/unit/spec/locus-info/mediaSharesUtils.ts +41 -0
  531. package/test/unit/spec/locus-info/parser.js +119 -44
  532. package/test/unit/spec/locus-info/selfConstant.js +120 -103
  533. package/test/unit/spec/locus-info/selfUtils.js +291 -12
  534. package/test/unit/spec/media/index.ts +194 -111
  535. package/test/unit/spec/media/properties.ts +11 -11
  536. package/test/unit/spec/meeting/in-meeting-actions.ts +96 -3
  537. package/test/unit/spec/meeting/index.js +8616 -1921
  538. package/test/unit/spec/meeting/locusMediaRequest.ts +442 -0
  539. package/test/unit/spec/meeting/muteState.js +568 -207
  540. package/test/unit/spec/meeting/request.js +602 -82
  541. package/test/unit/spec/meeting/utils.js +867 -179
  542. package/test/unit/spec/meeting/voicea-meeting.ts +266 -0
  543. package/test/unit/spec/meeting-info/index.js +300 -0
  544. package/test/unit/spec/meeting-info/meetinginfov2.js +631 -78
  545. package/test/unit/spec/meeting-info/request.js +7 -9
  546. package/test/unit/spec/meeting-info/util.js +11 -12
  547. package/test/unit/spec/meeting-info/utilv2.js +131 -74
  548. package/test/unit/spec/meetings/collection.js +27 -1
  549. package/test/unit/spec/meetings/index.js +1826 -374
  550. package/test/unit/spec/meetings/utils.js +243 -14
  551. package/test/unit/spec/member/index.js +61 -7
  552. package/test/unit/spec/member/util.js +526 -26
  553. package/test/unit/spec/members/index.js +536 -55
  554. package/test/unit/spec/members/request.js +228 -40
  555. package/test/unit/spec/members/utils.js +217 -4
  556. package/test/unit/spec/metrics/index.js +13 -68
  557. package/test/unit/spec/multistream/mediaRequestManager.ts +1032 -110
  558. package/test/unit/spec/multistream/receiveSlot.ts +77 -18
  559. package/test/unit/spec/multistream/receiveSlotManager.ts +69 -39
  560. package/test/unit/spec/multistream/remoteMedia.ts +40 -2
  561. package/test/unit/spec/multistream/remoteMediaGroup.ts +350 -5
  562. package/test/unit/spec/multistream/remoteMediaManager.ts +937 -65
  563. package/test/unit/spec/multistream/sendSlotManager.ts +274 -0
  564. package/test/unit/spec/networkQualityMonitor/index.js +24 -18
  565. package/test/unit/spec/personal-meeting-room/personal-meeting-room.js +2 -7
  566. package/test/unit/spec/reachability/clusterReachability.ts +279 -0
  567. package/test/unit/spec/reachability/index.ts +606 -26
  568. package/test/unit/spec/reachability/request.js +68 -0
  569. package/test/unit/spec/reachability/util.ts +40 -0
  570. package/test/unit/spec/reconnection-manager/index.js +222 -34
  571. package/test/unit/spec/recording-controller/index.js +306 -0
  572. package/test/unit/spec/recording-controller/util.js +229 -0
  573. package/test/unit/spec/roap/index.ts +238 -82
  574. package/test/unit/spec/roap/request.ts +255 -0
  575. package/test/unit/spec/roap/turnDiscovery.ts +707 -110
  576. package/test/unit/spec/rtcMetrics/index.ts +122 -0
  577. package/test/unit/spec/stats-analyzer/index.js +1331 -62
  578. package/test/unit/spec/webinar/collection.ts +13 -0
  579. package/test/unit/spec/webinar/index.ts +60 -0
  580. package/test/utils/cmr.js +44 -42
  581. package/test/utils/constants.js +9 -0
  582. package/test/utils/integrationTestUtils.js +46 -0
  583. package/test/utils/testUtils.js +63 -99
  584. package/test/utils/webex-config.js +22 -18
  585. package/test/utils/webex-test-users.js +65 -50
  586. package/tsconfig.json +6 -0
  587. package/dist/media/internal-media-core-wrapper.js +0 -22
  588. package/dist/media/internal-media-core-wrapper.js.map +0 -1
  589. package/dist/meeting/effectsState.js +0 -327
  590. package/dist/meeting/effectsState.js.map +0 -1
  591. package/dist/metrics/config.js +0 -301
  592. package/dist/metrics/config.js.map +0 -1
  593. package/dist/multistream/multistreamMedia.js +0 -116
  594. package/dist/multistream/multistreamMedia.js.map +0 -1
  595. package/dist/peer-connection-manager/util.js +0 -124
  596. package/dist/peer-connection-manager/util.js.map +0 -1
  597. package/src/common/logs/logger-proxy.js +0 -33
  598. package/src/index.js +0 -15
  599. package/src/locus-info/controlsUtils.js +0 -102
  600. package/src/media/index.js +0 -459
  601. package/src/media/internal-media-core-wrapper.ts +0 -9
  602. package/src/media/properties.js +0 -289
  603. package/src/mediaQualityMetrics/config.js +0 -382
  604. package/src/meeting/effectsState.js +0 -205
  605. package/src/meeting/index.js +0 -6284
  606. package/src/meeting/muteState.js +0 -318
  607. package/src/meeting/request.js +0 -684
  608. package/src/meeting/util.js +0 -506
  609. package/src/meeting-info/index.js +0 -131
  610. package/src/meeting-info/meeting-info-v2.js +0 -255
  611. package/src/meetings/collection.js +0 -40
  612. package/src/meetings/index.js +0 -1015
  613. package/src/member/util.js +0 -254
  614. package/src/members/request.js +0 -131
  615. package/src/members/util.js +0 -258
  616. package/src/metrics/config.js +0 -324
  617. package/src/metrics/index.js +0 -530
  618. package/src/multistream/multistreamMedia.ts +0 -92
  619. package/src/peer-connection-manager/util.ts +0 -117
  620. package/src/reachability/index.js +0 -464
  621. package/src/reconnection-manager/index.js +0 -519
  622. package/src/roap/index.js +0 -220
  623. package/src/roap/request.js +0 -127
  624. package/src/statsAnalyzer/global.js +0 -133
  625. package/src/statsAnalyzer/index.js +0 -1006
  626. package/src/statsAnalyzer/mqaUtil.js +0 -173
  627. package/test/unit/spec/meeting/effectsState.js +0 -291
  628. package/test/unit/spec/peerconnection-manager/utils.test-fixtures.ts +0 -389
  629. /package/src/common/errors/{reconnection-in-progress.js → reconnection-in-progress.ts} +0 -0
@@ -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,19 @@ 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';
21
+ import { NamedMediaGroup } from "@webex/json-multistream";
18
22
 
19
23
  class FakeSlot extends EventEmitter {
20
- public mediaType: MC.MediaType;
24
+ public mediaType: MediaType;
21
25
 
22
26
  public id: string;
23
27
 
24
28
  public csi?: number;
25
29
 
26
- constructor(mediaType: MC.MediaType, id: string) {
30
+ constructor(mediaType: MediaType, id: string) {
27
31
  super();
28
32
  this.mediaType = mediaType;
29
33
  this.id = id;
@@ -32,11 +36,16 @@ class FakeSlot extends EventEmitter {
32
36
  // Calling setMaxListeners() fixes the warning.
33
37
  this.setMaxListeners(50);
34
38
  }
39
+
40
+ public get logString() {
41
+ return this.id;
42
+ }
35
43
  }
36
44
 
37
45
  const DefaultTestConfiguration: Configuration = {
38
46
  audio: {
39
47
  numOfActiveSpeakerStreams: 3,
48
+ numOfScreenShareStreams: 1,
40
49
  },
41
50
  video: {
42
51
  preferLiveVideo: true,
@@ -44,7 +53,6 @@ const DefaultTestConfiguration: Configuration = {
44
53
 
45
54
  layouts: {
46
55
  AllEqual: {
47
- screenShareVideo: {size: null},
48
56
  activeSpeakerVideoPaneGroups: [
49
57
  {
50
58
  id: 'main',
@@ -55,7 +63,6 @@ const DefaultTestConfiguration: Configuration = {
55
63
  ],
56
64
  },
57
65
  OnePlusFive: {
58
- screenShareVideo: {size: null},
59
66
  activeSpeakerVideoPaneGroups: [
60
67
  {
61
68
  id: 'mainBigOne',
@@ -72,7 +79,6 @@ const DefaultTestConfiguration: Configuration = {
72
79
  ],
73
80
  },
74
81
  Single: {
75
- screenShareVideo: {size: null},
76
82
  activeSpeakerVideoPaneGroups: [
77
83
  {
78
84
  id: 'main',
@@ -83,7 +89,6 @@ const DefaultTestConfiguration: Configuration = {
83
89
  ],
84
90
  },
85
91
  Stage: {
86
- screenShareVideo: {size: null},
87
92
  activeSpeakerVideoPaneGroups: [
88
93
  {
89
94
  id: 'thumbnails',
@@ -99,12 +104,19 @@ const DefaultTestConfiguration: Configuration = {
99
104
  {id: 'stage-4', size: 'medium', csi: undefined},
100
105
  ],
101
106
  },
107
+ ScreenShareView: {
108
+ screenShareVideo: {size: 'medium'},
109
+ activeSpeakerVideoPaneGroups: [
110
+ {
111
+ id: 'thumbnails',
112
+ numPanes: 6,
113
+ size: 'thumbnail',
114
+ priority: 255,
115
+ },
116
+ ],
117
+ },
102
118
  },
103
119
  },
104
- screenShare: {
105
- audio: true,
106
- video: true,
107
- },
108
120
  };
109
121
 
110
122
  describe('RemoteMediaManager', () => {
@@ -113,18 +125,50 @@ describe('RemoteMediaManager', () => {
113
125
  let fakeMediaRequestManagers;
114
126
  let fakeAudioSlot;
115
127
  let fakeVideoSlot;
128
+ let fakeScreenShareAudioSlot;
129
+ let fakeScreenShareVideoSlot;
130
+
131
+ const logger = {
132
+ log: sinon.fake(),
133
+ error: () => {},
134
+ warn: () => {},
135
+ trace: () => {},
136
+ debug: () => {},
137
+ };
138
+
139
+ afterEach(() => {
140
+ LoggerConfig.set({enable: false});
141
+ LoggerProxy.set();
142
+ });
116
143
 
117
144
  beforeEach(() => {
118
- fakeAudioSlot = new FakeSlot(MC.MediaType.AudioMain, 'fake audio slot');
119
- fakeVideoSlot = new FakeSlot(MC.MediaType.VideoMain, 'fake video slot');
145
+ LoggerConfig.set({enable: true});
146
+ LoggerProxy.set(logger);
147
+
148
+ fakeAudioSlot = new FakeSlot(MediaType.AudioMain, 'fake audio slot');
149
+ fakeVideoSlot = new FakeSlot(MediaType.VideoMain, 'fake video slot');
150
+ fakeScreenShareAudioSlot = new FakeSlot(
151
+ MediaType.AudioSlides,
152
+ 'fake screen share audio slot'
153
+ );
154
+ fakeScreenShareVideoSlot = new FakeSlot(
155
+ MediaType.VideoSlides,
156
+ 'fake screen share video slot'
157
+ );
120
158
 
121
159
  fakeReceiveSlotManager = {
122
160
  allocateSlot: sinon.stub().callsFake((mediaType) => {
123
- if (mediaType === MC.MediaType.AudioMain) {
124
- return Promise.resolve(fakeAudioSlot);
161
+ switch (mediaType) {
162
+ case MediaType.AudioMain:
163
+ return Promise.resolve(fakeAudioSlot);
164
+ case MediaType.VideoMain:
165
+ return Promise.resolve(fakeVideoSlot);
166
+ case MediaType.AudioSlides:
167
+ return Promise.resolve(fakeScreenShareAudioSlot);
168
+ case MediaType.VideoSlides:
169
+ return Promise.resolve(fakeScreenShareVideoSlot);
125
170
  }
126
-
127
- return Promise.resolve(fakeVideoSlot);
171
+ throw new Error(`invalid mediaType: ${mediaType}`);
128
172
  }),
129
173
  releaseSlot: sinon.stub(),
130
174
  };
@@ -140,6 +184,16 @@ describe('RemoteMediaManager', () => {
140
184
  cancelRequest: sinon.stub(),
141
185
  commit: sinon.stub(),
142
186
  },
187
+ screenShareAudio: {
188
+ addRequest: sinon.stub(),
189
+ cancelRequest: sinon.stub(),
190
+ commit: sinon.stub(),
191
+ },
192
+ screenShareVideo: {
193
+ addRequest: sinon.stub(),
194
+ cancelRequest: sinon.stub(),
195
+ commit: sinon.stub(),
196
+ },
143
197
  };
144
198
 
145
199
  // create remote media manager with default configuration
@@ -159,6 +213,9 @@ describe('RemoteMediaManager', () => {
159
213
  fakeMediaRequestManagers.video.addRequest.resetHistory();
160
214
  fakeMediaRequestManagers.video.cancelRequest.resetHistory();
161
215
  fakeMediaRequestManagers.video.commit.resetHistory();
216
+ fakeMediaRequestManagers.screenShareVideo.commit.resetHistory();
217
+ fakeMediaRequestManagers.screenShareAudio.commit.resetHistory();
218
+ logger.log.resetHistory();
162
219
  };
163
220
 
164
221
  describe('start', () => {
@@ -176,8 +233,8 @@ describe('RemoteMediaManager', () => {
176
233
  await remoteMediaManager.start();
177
234
 
178
235
  // 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);
236
+ assert.calledWith(fakeReceiveSlotManager.allocateSlot, MediaType.AudioMain);
237
+ assert.calledWith(fakeReceiveSlotManager.allocateSlot, MediaType.VideoMain);
181
238
 
182
239
  assert.called(fakeMediaRequestManagers.audio.addRequest);
183
240
  assert.called(fakeMediaRequestManagers.video.addRequest);
@@ -187,25 +244,18 @@ describe('RemoteMediaManager', () => {
187
244
  let createdAudioGroup: RemoteMediaGroup | null = null;
188
245
 
189
246
  // create a config with just audio, no video at all and no screen share
190
- const config = {
247
+ const config: Configuration = {
191
248
  audio: {
192
249
  numOfActiveSpeakerStreams: 5,
250
+ numOfScreenShareStreams: 0,
193
251
  },
194
252
  video: {
195
253
  preferLiveVideo: false,
196
254
  initialLayoutId: 'empty',
197
255
  layouts: {
198
- empty: {
199
- screenShareVideo: {
200
- size: null,
201
- },
202
- },
256
+ empty: {},
203
257
  },
204
258
  },
205
- screenShare: {
206
- audio: false,
207
- video: false,
208
- },
209
259
  };
210
260
 
211
261
  remoteMediaManager = new RemoteMediaManager(
@@ -223,7 +273,7 @@ describe('RemoteMediaManager', () => {
223
273
  await testUtils.flushPromises();
224
274
 
225
275
  assert.callCount(fakeReceiveSlotManager.allocateSlot, 5);
226
- assert.alwaysCalledWith(fakeReceiveSlotManager.allocateSlot, MC.MediaType.AudioMain);
276
+ assert.alwaysCalledWith(fakeReceiveSlotManager.allocateSlot, MediaType.AudioMain);
227
277
 
228
278
  assert.isNotNull(createdAudioGroup);
229
279
  if (createdAudioGroup) {
@@ -231,7 +281,7 @@ describe('RemoteMediaManager', () => {
231
281
  assert.isTrue(
232
282
  createdAudioGroup
233
283
  .getRemoteMedia()
234
- .every((remoteMedia) => remoteMedia.mediaType === MC.MediaType.AudioMain)
284
+ .every((remoteMedia) => remoteMedia.mediaType === MediaType.AudioMain)
235
285
  );
236
286
  assert.strictEqual(createdAudioGroup.getRemoteMedia('pinned').length, 0);
237
287
  }
@@ -250,14 +300,209 @@ describe('RemoteMediaManager', () => {
250
300
  );
251
301
  });
252
302
 
303
+ it('creates a RemoteMediaGroup for named media group audio correctly', async () => {
304
+ let createdInterpretationAudioGroup: RemoteMediaGroup | null = null;
305
+ // create a config with just audio, no video at all and no screen share
306
+ const config: Configuration = {
307
+ audio: {
308
+ numOfActiveSpeakerStreams: 3,
309
+ numOfScreenShareStreams: 0,
310
+ },
311
+ video: {
312
+ preferLiveVideo: false,
313
+ initialLayoutId: 'empty',
314
+ layouts: {
315
+ empty: {},
316
+ },
317
+ },
318
+ namedMediaGroup: {type: 1, value: 20},
319
+ };
320
+
321
+ remoteMediaManager = new RemoteMediaManager(
322
+ fakeReceiveSlotManager,
323
+ fakeMediaRequestManagers,
324
+ config
325
+ );
326
+
327
+ remoteMediaManager.on(Event.InterpretationAudioCreated, (audio: RemoteMediaGroup) => {
328
+ createdInterpretationAudioGroup = audio;
329
+ });
330
+
331
+ remoteMediaManager.start();
332
+
333
+ await testUtils.flushPromises();
334
+
335
+ assert.callCount(fakeReceiveSlotManager.allocateSlot, 4);
336
+ assert.alwaysCalledWith(fakeReceiveSlotManager.allocateSlot, MediaType.AudioMain);
337
+
338
+ assert.isNotNull(createdInterpretationAudioGroup);
339
+ if (createdInterpretationAudioGroup) {
340
+ assert.strictEqual(createdInterpretationAudioGroup.getRemoteMedia().length, 1);
341
+ assert.isTrue(
342
+ createdInterpretationAudioGroup
343
+ .getRemoteMedia()
344
+ .every((remoteMedia) => remoteMedia.mediaType === MediaType.AudioMain)
345
+ );
346
+ assert.strictEqual(createdInterpretationAudioGroup.getRemoteMedia('pinned').length, 0);
347
+ assert.calledTwice(fakeMediaRequestManagers.audio.addRequest);
348
+ assert.calledWith(
349
+ fakeMediaRequestManagers.audio.addRequest,
350
+ sinon.match({
351
+ policyInfo: sinon.match({
352
+ policy: 'active-speaker',
353
+ priority: 255,
354
+ namedMediaGroups: sinon.match([{type: 1, value: 20}]),
355
+ }),
356
+ receiveSlots: Array(1).fill(fakeAudioSlot),
357
+ codecInfo: undefined,
358
+ }),
359
+ false,
360
+ );
361
+ }
362
+ });
363
+
364
+ it('creates new media request when call setReceiveNamedMediaGroup', async () => {
365
+ let createdInterpretationAudioGroup: RemoteMediaGroup | null = null;
366
+ // create a config with just audio, no video at all and no screen share
367
+ const config: Configuration = {
368
+ audio: {
369
+ numOfActiveSpeakerStreams: 3,
370
+ numOfScreenShareStreams: 0,
371
+ },
372
+ video: {
373
+ preferLiveVideo: false,
374
+ initialLayoutId: 'empty',
375
+ layouts: {
376
+ empty: {},
377
+ },
378
+ },
379
+ namedMediaGroup: {type: 1, value: 24},
380
+ };
381
+
382
+ remoteMediaManager = new RemoteMediaManager(
383
+ fakeReceiveSlotManager,
384
+ fakeMediaRequestManagers,
385
+ config
386
+ );
387
+
388
+ remoteMediaManager.on(Event.InterpretationAudioCreated, (audio: RemoteMediaGroup) => {
389
+ createdInterpretationAudioGroup = audio;
390
+ createdInterpretationAudioGroup.setNamedMediaGroup = sinon.stub();
391
+ });
392
+
393
+ await remoteMediaManager.start();
394
+
395
+ // requires 3 main audio slots and one interpretation audio slot
396
+ assert.callCount(fakeReceiveSlotManager.allocateSlot, 4);
397
+
398
+
399
+ resetHistory();
400
+
401
+
402
+ remoteMediaManager.setReceiveNamedMediaGroup(MediaType.AudioMain, 28);
403
+
404
+ // check that setNamedMediaGroup has been called
405
+ assert.calledOnce(createdInterpretationAudioGroup.setNamedMediaGroup);
406
+ assert.calledWith(
407
+ createdInterpretationAudioGroup.setNamedMediaGroup,
408
+ {type: 1, value: 28},
409
+ true,
410
+ );
411
+
412
+ });
413
+
414
+ it('ignore duplicated group when call setReceiveNamedMediaGroup', async () => {
415
+ let createdAudioGroup: RemoteMediaGroup | null = null;
416
+ let audioStopStub;
417
+ // create a config with just audio, no video at all and no screen share
418
+ const config: Configuration = {
419
+ audio: {
420
+ numOfActiveSpeakerStreams: 3,
421
+ numOfScreenShareStreams: 0,
422
+ },
423
+ video: {
424
+ preferLiveVideo: false,
425
+ initialLayoutId: 'empty',
426
+ layouts: {
427
+ empty: {},
428
+ },
429
+ },
430
+ namedMediaGroup: {type: 1, value: 24},
431
+ };
432
+
433
+ remoteMediaManager = new RemoteMediaManager(
434
+ fakeReceiveSlotManager,
435
+ fakeMediaRequestManagers,
436
+ config
437
+ );
438
+
439
+ remoteMediaManager.on(Event.AudioCreated, (audio: RemoteMediaGroup) => {
440
+ audioStopStub = sinon.stub(audio, 'stop');
441
+ });
442
+
443
+ await remoteMediaManager.start();
444
+
445
+ // we're using the default config that requires 3 main audio slots
446
+ assert.callCount(fakeReceiveSlotManager.allocateSlot, 4);
447
+
448
+
449
+ resetHistory();
450
+
451
+ remoteMediaManager.setReceiveNamedMediaGroup(MediaType.AudioMain, 24);
452
+
453
+ assert.notCalled(audioStopStub);
454
+ assert.callCount(fakeReceiveSlotManager.releaseSlot, 0);
455
+
456
+ await testUtils.flushPromises();
457
+ assert.callCount(fakeReceiveSlotManager.allocateSlot, 0);
458
+ assert.notCalled(fakeReceiveSlotManager.allocateSlot);
459
+
460
+ });
461
+
462
+
463
+ it('should throw error if set receive named media group which type is not audio', async () => {
464
+ let createdAudioGroup: RemoteMediaGroup | null = null;
465
+ let audioStopStub;
466
+ // create a config with just audio, no video at all and no screen share
467
+ const config: Configuration = {
468
+ audio: {
469
+ numOfActiveSpeakerStreams: 3,
470
+ numOfScreenShareStreams: 0,
471
+ },
472
+ video: {
473
+ preferLiveVideo: false,
474
+ initialLayoutId: 'empty',
475
+ layouts: {
476
+ empty: {},
477
+ },
478
+ },
479
+ namedMediaGroup: {type: 1, value: 24},
480
+ };
481
+
482
+ remoteMediaManager = new RemoteMediaManager(
483
+ fakeReceiveSlotManager,
484
+ fakeMediaRequestManagers,
485
+ config
486
+ );
487
+
488
+ // Assuming setReceiveNamedMediaGroup returns a promise
489
+ it('should throw error when media type is not audio-main', async () => {
490
+ try {
491
+ await remoteMediaManager.setReceiveNamedMediaGroup(MediaType.VideoMain, 0);
492
+ // If the promise resolves successfully, we should fail the test
493
+ throw new Error('Expected an error but none was thrown');
494
+ } catch (error) {
495
+ // Check if the error message matches the expected one
496
+ expect(error.message).to.equal('cannot set receive named media group which media type is not audio-main');
497
+ }
498
+ });
499
+ });
500
+
253
501
  it('pre-allocates receive slots based on the biggest layout', async () => {
254
502
  const config = cloneDeep(DefaultTestConfiguration);
255
503
 
256
504
  config.audio.numOfActiveSpeakerStreams = 0;
257
505
  config.video.layouts.huge = {
258
- screenShareVideo: {
259
- size: null,
260
- },
261
506
  activeSpeakerVideoPaneGroups: [
262
507
  {
263
508
  id: 'big one',
@@ -267,6 +512,8 @@ describe('RemoteMediaManager', () => {
267
512
  },
268
513
  ],
269
514
  };
515
+ config.audio.numOfScreenShareStreams = 0;
516
+ delete config.video.layouts.ScreenShareView;
270
517
 
271
518
  remoteMediaManager = new RemoteMediaManager(
272
519
  fakeReceiveSlotManager,
@@ -279,7 +526,7 @@ describe('RemoteMediaManager', () => {
279
526
  // even though our "big one" layout is not the default one, the remote media manager should still
280
527
  // preallocate enough video receive slots for it up front
281
528
  assert.callCount(fakeReceiveSlotManager.allocateSlot, 99);
282
- assert.alwaysCalledWith(fakeReceiveSlotManager.allocateSlot, MC.MediaType.VideoMain);
529
+ assert.alwaysCalledWith(fakeReceiveSlotManager.allocateSlot, MediaType.VideoMain);
283
530
  });
284
531
 
285
532
  it('starts with the initial layout', async () => {
@@ -302,8 +549,128 @@ describe('RemoteMediaManager', () => {
302
549
  receivedLayoutInfo.activeSpeakerVideoPanes.main.getRemoteMedia().length,
303
550
  9
304
551
  );
552
+ assert.isUndefined(receivedLayoutInfo.screenShareVideo); // the initial layout has no screen share
305
553
  }
306
554
  });
555
+
556
+ it('creates RemoteMedia for screen share audio correctly', async () => {
557
+ let createdAudioGroup: RemoteMediaGroup | null = null;
558
+
559
+ const NUM_STREAMS = 2;
560
+
561
+ // create a config with just screen share audio, nothing else
562
+ const config: Configuration = {
563
+ audio: {
564
+ numOfActiveSpeakerStreams: 0,
565
+ numOfScreenShareStreams: NUM_STREAMS,
566
+ },
567
+ video: {
568
+ preferLiveVideo: false,
569
+ initialLayoutId: 'empty',
570
+ layouts: {
571
+ empty: {},
572
+ },
573
+ },
574
+ };
575
+
576
+ remoteMediaManager = new RemoteMediaManager(
577
+ fakeReceiveSlotManager,
578
+ fakeMediaRequestManagers,
579
+ config
580
+ );
581
+
582
+ remoteMediaManager.on(Event.ScreenShareAudioCreated, (audio: RemoteMediaGroup) => {
583
+ createdAudioGroup = audio;
584
+ });
585
+
586
+ remoteMediaManager.start();
587
+
588
+ await testUtils.flushPromises();
589
+
590
+ assert.callCount(fakeReceiveSlotManager.allocateSlot, NUM_STREAMS);
591
+ assert.alwaysCalledWith(fakeReceiveSlotManager.allocateSlot, MediaType.AudioSlides);
592
+
593
+ assert.isNotNull(createdAudioGroup);
594
+ if (createdAudioGroup) {
595
+ assert.strictEqual(createdAudioGroup.getRemoteMedia().length, NUM_STREAMS);
596
+ assert.isTrue(
597
+ createdAudioGroup
598
+ .getRemoteMedia()
599
+ .every((remoteMedia) => remoteMedia.mediaType === MediaType.AudioSlides)
600
+ );
601
+ assert.strictEqual(createdAudioGroup.getRemoteMedia('pinned').length, 0);
602
+ }
603
+
604
+ assert.calledOnce(fakeMediaRequestManagers.screenShareAudio.addRequest);
605
+ assert.calledWith(
606
+ fakeMediaRequestManagers.screenShareAudio.addRequest,
607
+ sinon.match({
608
+ policyInfo: sinon.match({
609
+ policy: 'active-speaker',
610
+ priority: 255,
611
+ }),
612
+ receiveSlots: Array(NUM_STREAMS).fill(fakeScreenShareAudioSlot),
613
+ codecInfo: undefined,
614
+ })
615
+ );
616
+ });
617
+
618
+ it('creates a single receive slot for screen share video if any layout has screen share', async () => {
619
+ // create a config with 2 layouts that use screen share
620
+ const config: Configuration = {
621
+ audio: {
622
+ numOfActiveSpeakerStreams: 0,
623
+ numOfScreenShareStreams: 0,
624
+ },
625
+ video: {
626
+ preferLiveVideo: false,
627
+ initialLayoutId: 'first',
628
+ layouts: {
629
+ first: {
630
+ screenShareVideo: { size: 'small'}
631
+ },
632
+ second: {
633
+ screenShareVideo: { size: 'medium'}
634
+ }
635
+ },
636
+ },
637
+ };
638
+
639
+ remoteMediaManager = new RemoteMediaManager(
640
+ fakeReceiveSlotManager,
641
+ fakeMediaRequestManagers,
642
+ config
643
+ );
644
+
645
+ await remoteMediaManager.start();
646
+
647
+ // even though 2 layouts use screen share, only 1 video screen share slot should be created
648
+ assert.callCount(fakeReceiveSlotManager.allocateSlot, 1);
649
+ assert.alwaysCalledWith(fakeReceiveSlotManager.allocateSlot, MediaType.VideoSlides);
650
+ });
651
+
652
+ it('does not create any receive slot for screen share video if none of the layouts have screen share', async () => {
653
+ const config = cloneDeep(DefaultTestConfiguration);
654
+
655
+ config.audio.numOfActiveSpeakerStreams = 0;
656
+ config.audio.numOfScreenShareStreams = 0;
657
+
658
+ // delete the only layout that uses screen share
659
+ delete config.video.layouts.ScreenShareView;
660
+
661
+ remoteMediaManager = new RemoteMediaManager(
662
+ fakeReceiveSlotManager,
663
+ fakeMediaRequestManagers,
664
+ config
665
+ );
666
+
667
+ await remoteMediaManager.start();
668
+
669
+ // we don't expect any audio and for video there should be no VideoSlides, so all the calls should be just for VideoMain
670
+ assert.alwaysCalledWith(fakeReceiveSlotManager.allocateSlot, MediaType.VideoMain);
671
+ });
672
+
673
+
307
674
  });
308
675
 
309
676
  describe('constructor', () => {
@@ -325,7 +692,6 @@ describe('RemoteMediaManager', () => {
325
692
  const config = cloneDeep(DefaultTestConfiguration);
326
693
 
327
694
  config.video.layouts.test = {
328
- screenShareVideo: {size: null},
329
695
  activeSpeakerVideoPaneGroups: [
330
696
  {
331
697
  id: 'someDuplicate',
@@ -361,7 +727,6 @@ describe('RemoteMediaManager', () => {
361
727
  const config = cloneDeep(DefaultTestConfiguration);
362
728
 
363
729
  config.video.layouts.test = {
364
- screenShareVideo: {size: null},
365
730
  activeSpeakerVideoPaneGroups: [
366
731
  {
367
732
  id: 'group1',
@@ -397,7 +762,6 @@ describe('RemoteMediaManager', () => {
397
762
  const config = cloneDeep(DefaultTestConfiguration);
398
763
 
399
764
  config.video.layouts.test = {
400
- screenShareVideo: {size: null},
401
765
  memberVideoPanes: [
402
766
  {id: 'paneA', size: 'best', csi: 123},
403
767
  {id: 'paneB', size: 'large', csi: 222},
@@ -414,6 +778,7 @@ describe('RemoteMediaManager', () => {
414
778
  );
415
779
  }, 'invalid config: duplicate member video pane id: paneB');
416
780
  });
781
+
417
782
  });
418
783
 
419
784
  describe('stop', () => {
@@ -421,12 +786,17 @@ describe('RemoteMediaManager', () => {
421
786
  let audioStopStub;
422
787
  let videoActiveSpeakerGroupStopStub;
423
788
  const memberVideoPaneStopStubs: any[] = [];
789
+ let screenShareAudioStopStub;
790
+ let screenShareVideoStopStub;
424
791
 
425
- // change the initial layout to one that has both active speakers and receveiver selected videos
792
+ // change the initial layout to one that has both active speakers and receiver selected videos
426
793
  const config = cloneDeep(DefaultTestConfiguration);
427
794
 
428
795
  config.video.initialLayoutId = 'Stage';
429
796
 
797
+ // and also modify it to have screen share so we can test that too
798
+ config.video.layouts['Stage'].screenShareVideo = {size: 'medium'};
799
+
430
800
  remoteMediaManager = new RemoteMediaManager(
431
801
  fakeReceiveSlotManager,
432
802
  fakeMediaRequestManagers,
@@ -437,6 +807,10 @@ describe('RemoteMediaManager', () => {
437
807
  audioStopStub = sinon.stub(audio, 'stop');
438
808
  });
439
809
 
810
+ remoteMediaManager.on(Event.ScreenShareAudioCreated, (audio: RemoteMediaGroup) => {
811
+ screenShareAudioStopStub = sinon.stub(audio, 'stop');
812
+ });
813
+
440
814
  remoteMediaManager.on(Event.VideoLayoutChanged, (layoutInfo: VideoLayoutChangedEventData) => {
441
815
  // The "Stage" layout that we're using has only 1 active speaker group called "thumbnails"
442
816
  videoActiveSpeakerGroupStopStub = sinon.stub(
@@ -447,12 +821,14 @@ describe('RemoteMediaManager', () => {
447
821
  Object.values(layoutInfo.memberVideoPanes).forEach((pane) => {
448
822
  memberVideoPaneStopStubs.push(sinon.stub(pane, 'stop'));
449
823
  });
824
+
825
+ screenShareVideoStopStub = sinon.stub(layoutInfo.screenShareVideo, 'stop');
450
826
  });
451
827
 
452
828
  await remoteMediaManager.start();
453
829
 
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);
830
+ // we're using the default config that requires 3 main audio slots, 10 video slots (for Stage2x2With6ThumbnailsLayout), 1 screenshare audio, 1 screenshare video
831
+ assert.callCount(fakeReceiveSlotManager.allocateSlot, 15);
456
832
 
457
833
  // our layout has 4 member video panes, we should have a stub for each of these panes' stop methods
458
834
  assert.strictEqual(memberVideoPaneStopStubs.length, 4);
@@ -462,16 +838,20 @@ describe('RemoteMediaManager', () => {
462
838
  remoteMediaManager.stop();
463
839
 
464
840
  // check that all slots have been released
465
- assert.callCount(fakeReceiveSlotManager.releaseSlot, 13);
841
+ assert.callCount(fakeReceiveSlotManager.releaseSlot, 15);
466
842
 
467
843
  // and that all RemoteMedia and RemoteMediaGroups have been stopped
468
844
  assert.calledOnce(audioStopStub);
469
845
  assert.calledWith(audioStopStub, true);
846
+ assert.calledOnce(screenShareAudioStopStub);
847
+ assert.calledWith(screenShareAudioStopStub, true);
470
848
  assert.calledOnce(videoActiveSpeakerGroupStopStub);
471
849
  memberVideoPaneStopStubs.forEach((stub) => {
472
850
  assert.calledOnce(stub);
473
851
  });
474
852
  assert.calledOnce(fakeMediaRequestManagers.video.commit);
853
+ assert.calledOnce(screenShareVideoStopStub);
854
+ assert.calledOnce(fakeMediaRequestManagers.screenShareVideo.commit);
475
855
  });
476
856
 
477
857
  it('can be called multiple times', async () => {
@@ -482,6 +862,41 @@ describe('RemoteMediaManager', () => {
482
862
  remoteMediaManager.stop();
483
863
  });
484
864
  });
865
+
866
+ describe('setPreferLiveVideo', () => {
867
+
868
+ it('sets preferLiveVideo', async () => {
869
+ const config = cloneDeep(DefaultTestConfiguration);
870
+ let stubs = [];
871
+
872
+ config.video.initialLayoutId = 'OnePlusFive';
873
+
874
+ remoteMediaManager = new RemoteMediaManager(
875
+ fakeReceiveSlotManager,
876
+ fakeMediaRequestManagers,
877
+ config
878
+ );
879
+
880
+ remoteMediaManager.on(Event.VideoLayoutChanged, (layoutInfo: VideoLayoutChangedEventData) => {
881
+ Object.values(layoutInfo.activeSpeakerVideoPanes).forEach((group) => stubs.push(sinon.stub(group, 'setPreferLiveVideo')));
882
+ });
883
+
884
+ await remoteMediaManager.start();
885
+ resetHistory();
886
+ assert(stubs.length > 0);
887
+ await remoteMediaManager.setPreferLiveVideo(true);
888
+
889
+
890
+ stubs.forEach((stub) => {
891
+ assert.calledWith(stub, true, false)
892
+ });
893
+
894
+ expect(config.video.preferLiveVideo).to.equal(true);
895
+
896
+ assert.calledOnce(fakeMediaRequestManagers.video.commit);
897
+ });
898
+ });
899
+
485
900
  describe('setLayout', () => {
486
901
  it('rejects if called with invalid layoutId', async () => {
487
902
  await assert.isRejected(remoteMediaManager.setLayout('invalid value'));
@@ -511,9 +926,61 @@ describe('RemoteMediaManager', () => {
511
926
  await remoteMediaManager.setLayout('Stage');
512
927
 
513
928
  assert.callCount(fakeReceiveSlotManager.allocateSlot, 9);
514
- assert.alwaysCalledWith(fakeReceiveSlotManager.allocateSlot, MC.MediaType.VideoMain);
929
+ assert.alwaysCalledWith(fakeReceiveSlotManager.allocateSlot, MediaType.VideoMain);
930
+ });
931
+
932
+ it('logs layout changes - receiver selected', async () => {
933
+ const config = cloneDeep(DefaultTestConfiguration);
934
+
935
+ remoteMediaManager = new RemoteMediaManager(
936
+ fakeReceiveSlotManager,
937
+ fakeMediaRequestManagers,
938
+ config
939
+ );
940
+
941
+ await remoteMediaManager.start();
942
+
943
+ resetHistory();
944
+
945
+ await remoteMediaManager.setLayout('Stage');
946
+
947
+ assert.calledWith(
948
+ logger.log,
949
+ 'RemoteMediaManager#setLayout --> new layout selected: Stage'
950
+ );
951
+ assert.calledWith(
952
+ logger.log,
953
+ 'RemoteMediaManager#logMainVideoReceiveSlots --> MAIN VIDEO receive slots: 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'
954
+ );
955
+ });
956
+
957
+ it('logs layout changes - active speaker', async () => {
958
+ const config = cloneDeep(DefaultTestConfiguration);
959
+ config.video.initialLayoutId = 'OnePlusFive'
960
+
961
+ remoteMediaManager = new RemoteMediaManager(
962
+ fakeReceiveSlotManager,
963
+ fakeMediaRequestManagers,
964
+ config
965
+ );
966
+
967
+ await remoteMediaManager.start();
968
+
969
+ resetHistory();
970
+
971
+ await remoteMediaManager.setLayout('AllEqual');
972
+
973
+ assert.calledWith(
974
+ logger.log,
975
+ 'RemoteMediaManager#setLayout --> new layout selected: AllEqual'
976
+ );
977
+ assert.calledWith(
978
+ logger.log,
979
+ 'RemoteMediaManager#logMainVideoReceiveSlots --> MAIN VIDEO receive slots: 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'
980
+ );
515
981
  });
516
982
 
983
+
517
984
  it('releases slots when switching to layout that requires less active speaker slots', async () => {
518
985
  // start with "AllEqual" layout that needs just 9 video slots
519
986
  const config = cloneDeep(DefaultTestConfiguration);
@@ -538,8 +1005,291 @@ describe('RemoteMediaManager', () => {
538
1005
  fakeReceiveSlotManager.releaseSlot.getCalls().forEach((call) => {
539
1006
  const slot = call.args[0];
540
1007
 
541
- assert.strictEqual(slot.mediaType, MC.MediaType.VideoMain);
1008
+ assert.strictEqual(slot.mediaType, MediaType.VideoMain);
1009
+ });
1010
+ });
1011
+
1012
+ it('releases slots and reallocates slots when switching to layouts in correct order', async () => {
1013
+
1014
+ const config = cloneDeep(DefaultTestConfiguration);
1015
+ let count = 0;
1016
+
1017
+ fakeReceiveSlotManager.allocateSlot = sinon.stub().callsFake((mediaType) => {
1018
+ switch (mediaType) {
1019
+ case MediaType.AudioMain:
1020
+ return Promise.resolve(fakeAudioSlot);
1021
+ case MediaType.VideoMain:
1022
+ return Promise.resolve(new FakeSlot(MediaType.VideoMain, `fake video ${count++}`));
1023
+ case MediaType.AudioSlides:
1024
+ return Promise.resolve(fakeScreenShareAudioSlot);
1025
+ case MediaType.VideoSlides:
1026
+ return Promise.resolve(fakeScreenShareVideoSlot);
1027
+ }
1028
+ throw new Error(`invalid mediaType: ${mediaType}`);
1029
+ })
1030
+
1031
+ remoteMediaManager = new RemoteMediaManager(
1032
+ fakeReceiveSlotManager,
1033
+ fakeMediaRequestManagers,
1034
+ config
1035
+ );
1036
+
1037
+ await remoteMediaManager.start();
1038
+
1039
+ resetHistory();
1040
+
1041
+ assert.deepEqual(remoteMediaManager.slots.video.activeSpeaker.map((slot: any) => slot.id), [
1042
+ "fake video 0",
1043
+ "fake video 1",
1044
+ "fake video 2",
1045
+ "fake video 3",
1046
+ "fake video 4",
1047
+ "fake video 5",
1048
+ "fake video 6",
1049
+ "fake video 7",
1050
+ "fake video 8",
1051
+ ]);
1052
+
1053
+ assert.deepEqual(remoteMediaManager.receiveSlotAllocations.activeSpeaker["main"].slots.map((slot: any) => slot.id), [
1054
+ "fake video 0",
1055
+ "fake video 1",
1056
+ "fake video 2",
1057
+ "fake video 3",
1058
+ "fake video 4",
1059
+ "fake video 5",
1060
+ "fake video 6",
1061
+ "fake video 7",
1062
+ "fake video 8",
1063
+ ])
1064
+
1065
+ // switch to "OnePlusFive" layout that requires 3 less video slots (6)
1066
+ await remoteMediaManager.setLayout('OnePlusFive');
1067
+
1068
+ assert.deepEqual(remoteMediaManager.slots.video.unused, []);
1069
+
1070
+ assert.deepEqual(remoteMediaManager.slots.video.activeSpeaker.map((slot: any) => slot.id), [
1071
+ "fake video 0",
1072
+ "fake video 1",
1073
+ "fake video 2",
1074
+ "fake video 3",
1075
+ "fake video 4",
1076
+ "fake video 5"
1077
+ ]);
1078
+
1079
+ // we're checking that the slots are in the same order as in the previous layout
1080
+ // first one goes into main
1081
+ assert.deepEqual(remoteMediaManager.receiveSlotAllocations.activeSpeaker["mainBigOne"].slots.map((slot: any) => slot.id), [
1082
+ "fake video 0",
1083
+ ])
1084
+ // and rest go in the pips
1085
+ assert.deepEqual(remoteMediaManager.receiveSlotAllocations.activeSpeaker["secondarySetOfSmallPanes"].slots.map((slot: any) => slot.id), [
1086
+ "fake video 1",
1087
+ "fake video 2",
1088
+ "fake video 3",
1089
+ "fake video 4",
1090
+ "fake video 5"
1091
+ ])
1092
+
1093
+ // verify that 3 main video slots were released
1094
+ assert.callCount(fakeReceiveSlotManager.releaseSlot, 3);
1095
+ fakeReceiveSlotManager.releaseSlot.getCalls().forEach((call) => {
1096
+ const slot = call.args[0];
1097
+
1098
+ assert.strictEqual(slot.mediaType, MediaType.VideoMain);
1099
+ });
1100
+
1101
+ await remoteMediaManager.setLayout('AllEqual');
1102
+
1103
+ assert.deepEqual(remoteMediaManager.slots.video.unused, []);
1104
+
1105
+ // checking that slots are in the same order as in previous layout + 3 new ones
1106
+ assert.deepEqual(remoteMediaManager.slots.video.activeSpeaker.map((slot: any) => slot.id), [
1107
+ "fake video 0",
1108
+ "fake video 1",
1109
+ "fake video 2",
1110
+ "fake video 3",
1111
+ "fake video 4",
1112
+ "fake video 5",
1113
+ "fake video 10",
1114
+ "fake video 11",
1115
+ "fake video 12",
1116
+ ]);
1117
+
1118
+ assert.deepEqual(remoteMediaManager.receiveSlotAllocations.activeSpeaker["main"].slots.map((slot: any) => slot.id), [
1119
+ "fake video 0",
1120
+ "fake video 1",
1121
+ "fake video 2",
1122
+ "fake video 3",
1123
+ "fake video 4",
1124
+ "fake video 5",
1125
+ "fake video 10",
1126
+ "fake video 11",
1127
+ "fake video 12"
1128
+ ])
1129
+
1130
+ // verify that 3 main video slots were allocated
1131
+ assert.callCount(fakeReceiveSlotManager.allocateSlot, 3);
1132
+ fakeReceiveSlotManager.allocateSlot.getCalls().forEach((call) => {
1133
+ const mediaType = call.args[0];
1134
+
1135
+ assert.strictEqual(mediaType, MediaType.VideoMain);
1136
+ });
1137
+ });
1138
+
1139
+ it('stops all current video remoteMedia instances when switching to new layout', async () => {
1140
+ const audioStopStubs = [];
1141
+ const videoStopStubs = [];
1142
+
1143
+ const config = cloneDeep(DefaultTestConfiguration);
1144
+
1145
+ // start with the stage layout because it has both active speaker and receiver selected panes
1146
+ config.video.initialLayoutId = 'Stage';
1147
+
1148
+ remoteMediaManager = new RemoteMediaManager(
1149
+ fakeReceiveSlotManager,
1150
+ fakeMediaRequestManagers,
1151
+ config
1152
+ );
1153
+
1154
+ // mock all stop() methods for all remote audio objects we get with AudioCreated event
1155
+ remoteMediaManager.on(Event.AudioCreated, (audio: RemoteMediaGroup) => {
1156
+ audio
1157
+ .getRemoteMedia()
1158
+ .forEach((remoteAudio) => audioStopStubs.push(sinon.stub(remoteAudio, 'stop')));
1159
+ });
1160
+
1161
+ // mock all stop() methods for all remote video objects we get with VideoLayoutChanged event
1162
+ remoteMediaManager.on(Event.VideoLayoutChanged, (layoutInfo: VideoLayoutChangedEventData) => {
1163
+ Object.values(layoutInfo.activeSpeakerVideoPanes).forEach((group) =>
1164
+ group
1165
+ .getRemoteMedia()
1166
+ .forEach((remoteMedia) => videoStopStubs.push(sinon.stub(remoteMedia, 'stop')))
1167
+ );
1168
+
1169
+ Object.values(layoutInfo.memberVideoPanes).forEach((pane) => {
1170
+ videoStopStubs.push(sinon.stub(pane, 'stop'));
1171
+ });
1172
+ });
1173
+
1174
+ await remoteMediaManager.start();
1175
+
1176
+ // sanity check that we've got all our stop() mocks setup correctly
1177
+ assert.strictEqual(audioStopStubs.length, 3);
1178
+ assert.strictEqual(videoStopStubs.length, 10); // 10 = 6 thumbnail panes + 4 stage panes
1179
+
1180
+ // next, we'll change the layout, we don't care about the new video panes from the new layout, so unregister the event listeners
1181
+ remoteMediaManager.removeAllListeners();
1182
+
1183
+ await remoteMediaManager.setLayout('AllEqual');
1184
+
1185
+ // check that NONE of the audio RemoteMedia instances were stopped
1186
+ audioStopStubs.forEach((audioStopStub) => {
1187
+ assert.notCalled(audioStopStub);
1188
+ });
1189
+
1190
+ // check that ALL of the video RemoteMedia instances were stopped
1191
+ videoStopStubs.forEach((videoStopStub) => {
1192
+ assert.calledOnce(videoStopStub);
1193
+ assert.calledWith(videoStopStub, false);
1194
+ });
1195
+ });
1196
+
1197
+ it('emits Event.VideoLayoutChanged with correct data', async () => {
1198
+ // setup the initial layout to be empty and a testLayout that has screen share, active speaker groups and member video panes
1199
+ const config: Configuration = {
1200
+ audio: {
1201
+ numOfActiveSpeakerStreams: 0,
1202
+ numOfScreenShareStreams: 0,
1203
+ },
1204
+ video: {
1205
+ preferLiveVideo: true,
1206
+ initialLayoutId: 'empty',
1207
+ layouts: {
1208
+ empty: {},
1209
+ testLayout: {
1210
+ screenShareVideo: {size: 'very small'},
1211
+ activeSpeakerVideoPaneGroups: [
1212
+ {
1213
+ id: 'big',
1214
+ numPanes: 10,
1215
+ priority: 255,
1216
+ size: 'large',
1217
+ },
1218
+ {
1219
+ id: 'small',
1220
+ numPanes: 3,
1221
+ priority: 254,
1222
+ size: 'medium',
1223
+ },
1224
+ ],
1225
+ memberVideoPanes: [
1226
+ {id: 'pane 1', size: 'best', csi: 555},
1227
+ {id: 'pane 2', size: 'best', csi: undefined},
1228
+ ],
1229
+ },
1230
+ },
1231
+ },
1232
+ };
1233
+
1234
+ remoteMediaManager = new RemoteMediaManager(
1235
+ fakeReceiveSlotManager,
1236
+ fakeMediaRequestManagers,
1237
+ config
1238
+ );
1239
+
1240
+ await remoteMediaManager.start();
1241
+
1242
+ resetHistory();
1243
+
1244
+ let receivedLayoutInfo: VideoLayoutChangedEventData | null = null;
1245
+
1246
+ remoteMediaManager.on(Event.VideoLayoutChanged, (layoutInfo) => {
1247
+ receivedLayoutInfo = layoutInfo;
542
1248
  });
1249
+
1250
+ // switch to the test layout
1251
+ await remoteMediaManager.setLayout('testLayout');
1252
+
1253
+ assert.isNotNull(receivedLayoutInfo);
1254
+
1255
+ if (receivedLayoutInfo) {
1256
+ assert.strictEqual(receivedLayoutInfo.layoutId, 'testLayout');
1257
+
1258
+ // check screen share video
1259
+ assert.isTrue(!!receivedLayoutInfo.screenShareVideo);
1260
+ assert.strictEqual(receivedLayoutInfo.screenShareVideo.mediaType, MediaType.VideoSlides);
1261
+
1262
+ // check member videos
1263
+ assert.strictEqual(Object.keys(receivedLayoutInfo.memberVideoPanes).length, 2);
1264
+ Object.values(receivedLayoutInfo.memberVideoPanes).forEach((remoteMedia) =>
1265
+ assert.strictEqual(remoteMedia.mediaType, MediaType.VideoMain)
1266
+ );
1267
+
1268
+ // check the 2 active speaker groups
1269
+ assert.strictEqual(Object.keys(receivedLayoutInfo.activeSpeakerVideoPanes).length, 2);
1270
+
1271
+ // "big" group
1272
+ assert.strictEqual(
1273
+ receivedLayoutInfo.activeSpeakerVideoPanes.big.getRemoteMedia().length,
1274
+ 10
1275
+ );
1276
+ receivedLayoutInfo.activeSpeakerVideoPanes.big
1277
+ .getRemoteMedia()
1278
+ .forEach((remoteMedia) =>
1279
+ assert.strictEqual(remoteMedia.mediaType, MediaType.VideoMain)
1280
+ );
1281
+
1282
+ // "small" group
1283
+ assert.strictEqual(
1284
+ receivedLayoutInfo.activeSpeakerVideoPanes.small.getRemoteMedia().length,
1285
+ 3
1286
+ );
1287
+ receivedLayoutInfo.activeSpeakerVideoPanes.small
1288
+ .getRemoteMedia()
1289
+ .forEach((remoteMedia) =>
1290
+ assert.strictEqual(remoteMedia.mediaType, MediaType.VideoMain)
1291
+ );
1292
+ }
543
1293
  });
544
1294
 
545
1295
  describe('switching between different receiver selected layouts', () => {
@@ -562,7 +1312,7 @@ describe('RemoteMediaManager', () => {
562
1312
  slotCounter += 1;
563
1313
  const newSlotId = `fake video slot ${slotCounter}`;
564
1314
 
565
- fakeSlots[newSlotId] = new FakeSlot(MC.MediaType.VideoMain, newSlotId);
1315
+ fakeSlots[newSlotId] = new FakeSlot(MediaType.VideoMain, newSlotId);
566
1316
  return fakeSlots[newSlotId];
567
1317
  });
568
1318
 
@@ -594,12 +1344,12 @@ describe('RemoteMediaManager', () => {
594
1344
  // This test starts with a layout that has 5 receiver selected video slots
595
1345
  // and switches to a different layout that has fewer slots, but 2 of them match CSIs
596
1346
  // from the initial layout. We want to verify that these 2 slots get re-used correctly.
1347
+ // There are no screen share or audio slots being used in this test.
1348
+ delete config.video.layouts.ScreenShareView;
597
1349
  config.audio.numOfActiveSpeakerStreams = 0;
598
- config.screenShare.audio = false;
599
- config.screenShare.video = false;
1350
+ config.audio.numOfScreenShareStreams = 0;
600
1351
  config.video.initialLayoutId = 'biggerLayout';
601
1352
  config.video.layouts['biggerLayout'] = {
602
- screenShareVideo: {size: null},
603
1353
  memberVideoPanes: [
604
1354
  {id: '1', size: 'best', csi: 100},
605
1355
  {id: '2', size: 'best', csi: 200},
@@ -609,7 +1359,6 @@ describe('RemoteMediaManager', () => {
609
1359
  ],
610
1360
  };
611
1361
  config.video.layouts['smallerLayout'] = {
612
- screenShareVideo: {size: null},
613
1362
  memberVideoPanes: [
614
1363
  {id: '1', size: 'medium', csi: 200}, // this csi matches pane '2' from biggerLayout
615
1364
  {id: '2', size: 'medium', csi: 123},
@@ -659,16 +1408,15 @@ describe('RemoteMediaManager', () => {
659
1408
  // This test starts with a layout that has video slot with a specific CSI
660
1409
  // and switches to a different layout that 2 panes with that same CSI.
661
1410
  // We want to verify that the slot gets reused, but also that a 2nd slot is allocated.
1411
+ // There are no screen share or audio slots being used in this test.
1412
+ delete config.video.layouts.ScreenShareView;
662
1413
  config.audio.numOfActiveSpeakerStreams = 0;
663
- config.screenShare.audio = false;
664
- config.screenShare.video = false;
1414
+ config.audio.numOfScreenShareStreams = 0;
665
1415
  config.video.initialLayoutId = 'initialEmptyLayout';
666
1416
  config.video.layouts['initialEmptyLayout'] = {
667
- screenShareVideo: {size: null},
668
1417
  memberVideoPanes: [{id: '2', size: 'medium', csi: 456}],
669
1418
  };
670
1419
  config.video.layouts['layoutWithDuplicateCSIs'] = {
671
- screenShareVideo: {size: null},
672
1420
  memberVideoPanes: [
673
1421
  {id: '1', size: 'medium', csi: 123},
674
1422
  {id: '2', size: 'medium', csi: 456},
@@ -841,16 +1589,18 @@ describe('RemoteMediaManager', () => {
841
1589
  });
842
1590
 
843
1591
  it('cancels all media requests for the previous layout when switching to a new one', async () => {
1592
+ // setup the initial layout to have screen share, active speaker groups and member video panes
844
1593
  const config: Configuration = {
845
1594
  audio: {
846
1595
  numOfActiveSpeakerStreams: 0,
1596
+ numOfScreenShareStreams: 0,
847
1597
  },
848
1598
  video: {
849
1599
  preferLiveVideo: true,
850
1600
  initialLayoutId: 'initial',
851
1601
  layouts: {
852
1602
  initial: {
853
- screenShareVideo: {size: null},
1603
+ screenShareVideo: {size: 'best'},
854
1604
  activeSpeakerVideoPaneGroups: [
855
1605
  {
856
1606
  id: 'big',
@@ -870,15 +1620,9 @@ describe('RemoteMediaManager', () => {
870
1620
  {id: 'pane 2', size: 'best', csi: 234},
871
1621
  ],
872
1622
  },
873
- other: {
874
- screenShareVideo: {size: null},
875
- },
1623
+ other: {},
876
1624
  },
877
1625
  },
878
- screenShare: {
879
- audio: false,
880
- video: false,
881
- },
882
1626
  };
883
1627
 
884
1628
  remoteMediaManager = new RemoteMediaManager(
@@ -901,9 +1645,15 @@ describe('RemoteMediaManager', () => {
901
1645
 
902
1646
  return `receiver selected request ${receiverSelectedRequestCounter}`;
903
1647
  });
1648
+ // setup the mock for screen share addRequest - this one should be called just once
1649
+ fakeMediaRequestManagers.screenShareVideo.addRequest.callsFake(() => {
1650
+ return 'video screen share request id';
1651
+ });
904
1652
 
905
1653
  await remoteMediaManager.start();
906
1654
 
1655
+ assert.calledOnce(fakeMediaRequestManagers.screenShareVideo.addRequest);
1656
+
907
1657
  resetHistory();
908
1658
 
909
1659
  // switch to "other" layout
@@ -921,11 +1671,45 @@ describe('RemoteMediaManager', () => {
921
1671
  fakeMediaRequestManagers.video.cancelRequest,
922
1672
  'receiver selected request 2'
923
1673
  );
1674
+ assert.calledOnce(fakeMediaRequestManagers.screenShareVideo.cancelRequest);
1675
+ assert.calledWith(
1676
+ fakeMediaRequestManagers.screenShareVideo.cancelRequest,
1677
+ 'video screen share request id'
1678
+ );
924
1679
 
925
1680
  // new layout has no videos, so no new requests should be sent out
926
- // check that 2 correct active speaker media requests were sent out
927
1681
  assert.callCount(fakeMediaRequestManagers.video.addRequest, 0);
928
1682
  });
1683
+
1684
+ it('sends media request for screen share if layout contains screen share', async () => {
1685
+ const allEqualMediaRequestId = 'fake request id';
1686
+
1687
+ fakeMediaRequestManagers.video.addRequest.returns(allEqualMediaRequestId);
1688
+
1689
+ await remoteMediaManager.start();
1690
+
1691
+ resetHistory();
1692
+
1693
+ // switch to a layout that contains a screen share video pane
1694
+ await remoteMediaManager.setLayout('ScreenShareView');
1695
+
1696
+ // check that a correct active speaker media request for screen share has been sent out
1697
+ assert.callCount(fakeMediaRequestManagers.screenShareVideo.addRequest, 1);
1698
+ assert.calledWith(
1699
+ fakeMediaRequestManagers.screenShareVideo.addRequest,
1700
+ sinon.match({
1701
+ policyInfo: sinon.match({
1702
+ policy: 'active-speaker',
1703
+ priority: 255,
1704
+ }),
1705
+ receiveSlots: [fakeScreenShareVideoSlot],
1706
+ codecInfo: sinon.match({
1707
+ codec: 'h264',
1708
+ maxFs: 3600,
1709
+ }),
1710
+ })
1711
+ );
1712
+ });
929
1713
  });
930
1714
  });
931
1715
 
@@ -1065,7 +1849,7 @@ describe('RemoteMediaManager', () => {
1065
1849
 
1066
1850
  // new slot should be allocated
1067
1851
  assert.calledOnce(fakeReceiveSlotManager.allocateSlot);
1068
- assert.calledWith(fakeReceiveSlotManager.allocateSlot, MC.MediaType.VideoMain);
1852
+ assert.calledWith(fakeReceiveSlotManager.allocateSlot, MediaType.VideoMain);
1069
1853
 
1070
1854
  // and a media request sent out
1071
1855
  assert.calledOnce(fakeMediaRequestManagers.video.addRequest);
@@ -1094,7 +1878,7 @@ describe('RemoteMediaManager', () => {
1094
1878
 
1095
1879
  // new slot should be allocated
1096
1880
  assert.calledOnce(fakeReceiveSlotManager.allocateSlot);
1097
- assert.calledWith(fakeReceiveSlotManager.allocateSlot, MC.MediaType.VideoMain);
1881
+ assert.calledWith(fakeReceiveSlotManager.allocateSlot, MediaType.VideoMain);
1098
1882
 
1099
1883
  // but no media requests sent out
1100
1884
  assert.notCalled(fakeMediaRequestManagers.video.addRequest);
@@ -1123,7 +1907,7 @@ describe('RemoteMediaManager', () => {
1123
1907
  await remoteMediaManager.start();
1124
1908
  await remoteMediaManager.setLayout('Stage');
1125
1909
 
1126
- const fakeNewSlot = new FakeSlot(MC.MediaType.VideoMain, 'fake video slot');
1910
+ const fakeNewSlot = new FakeSlot(MediaType.VideoMain, 'fake video slot');
1127
1911
  const fakeRequestId = 'fake request id';
1128
1912
 
1129
1913
  fakeReceiveSlotManager.allocateSlot.resolves(fakeNewSlot);
@@ -1147,6 +1931,94 @@ describe('RemoteMediaManager', () => {
1147
1931
  });
1148
1932
  });
1149
1933
 
1934
+ describe('setActiveSpeakerCsis', () => {
1935
+ it('calls setActiveSpeakerCsis on the correct remote media group', async () => {
1936
+ let currentLayoutInfo: VideoLayoutChangedEventData | null = null;
1937
+ let setCsisStub;
1938
+
1939
+ remoteMediaManager.on(Event.VideoLayoutChanged, (layoutInfo: VideoLayoutChangedEventData) => {
1940
+ currentLayoutInfo = layoutInfo;
1941
+ setCsisStub = sinon.stub(layoutInfo.activeSpeakerVideoPanes.main, 'setActiveSpeakerCsis');
1942
+ });
1943
+
1944
+ await remoteMediaManager.start();
1945
+ resetHistory();
1946
+
1947
+ assert.isNotNull(currentLayoutInfo);
1948
+
1949
+ if (currentLayoutInfo) {
1950
+ const remoteVideo = currentLayoutInfo.activeSpeakerVideoPanes.main.getRemoteMedia()[0];
1951
+
1952
+ remoteMediaManager.setActiveSpeakerCsis([{remoteMedia: remoteVideo}]);
1953
+
1954
+ assert.calledOnce(setCsisStub);
1955
+ assert.calledWith(setCsisStub, [{remoteMedia: remoteVideo}], false);
1956
+ assert.calledOnce(fakeMediaRequestManagers.video.commit);
1957
+ }
1958
+ });
1959
+
1960
+ it('does not call setActiveSpeakerCsis on the incorrect media group', async () => {
1961
+ let currentLayoutInfo: VideoLayoutChangedEventData | null = null;
1962
+ let setCsisStub;
1963
+
1964
+ remoteMediaManager.on(Event.VideoLayoutChanged, (layoutInfo: VideoLayoutChangedEventData) => {
1965
+ currentLayoutInfo = layoutInfo;
1966
+ setCsisStub = sinon.stub(layoutInfo.activeSpeakerVideoPanes.main, 'setActiveSpeakerCsis');
1967
+ });
1968
+
1969
+ await remoteMediaManager.start();
1970
+ resetHistory();
1971
+
1972
+ assert.isNotNull(currentLayoutInfo);
1973
+
1974
+ if (currentLayoutInfo) {
1975
+ remoteMediaManager.setActiveSpeakerCsis([{remoteMedia: {}}]);
1976
+
1977
+ assert.notCalled(setCsisStub);
1978
+ assert.calledOnce(fakeMediaRequestManagers.video.commit);
1979
+ }
1980
+ });
1981
+
1982
+ it('checking when there is more than one group', async () => {
1983
+ let currentLayoutInfo: VideoLayoutChangedEventData | null = null;
1984
+ const config = cloneDeep(DefaultTestConfiguration);
1985
+ let stubs = [];
1986
+
1987
+ config.video.initialLayoutId = 'OnePlusFive';
1988
+
1989
+ remoteMediaManager = new RemoteMediaManager(
1990
+ fakeReceiveSlotManager,
1991
+ fakeMediaRequestManagers,
1992
+ config
1993
+ );
1994
+
1995
+ remoteMediaManager.on(Event.VideoLayoutChanged, (layoutInfo: VideoLayoutChangedEventData) => {
1996
+ currentLayoutInfo = layoutInfo;
1997
+ Object.values(layoutInfo.activeSpeakerVideoPanes).forEach((group) => stubs.push(sinon.stub(group, 'setActiveSpeakerCsis')));
1998
+ });
1999
+
2000
+ await remoteMediaManager.start();
2001
+ resetHistory();
2002
+
2003
+ assert.isNotNull(currentLayoutInfo);
2004
+
2005
+ if (currentLayoutInfo) {
2006
+
2007
+ const remoteMedia1 = currentLayoutInfo.activeSpeakerVideoPanes.mainBigOne.getRemoteMedia()[0];
2008
+ const remoteMedia2 = currentLayoutInfo.activeSpeakerVideoPanes.secondarySetOfSmallPanes.getRemoteMedia()[0];
2009
+
2010
+ const remoteMediaCsis = [{remoteMedia: remoteMedia1}, {remoteMedia: remoteMedia2}];
2011
+
2012
+ remoteMediaManager.setActiveSpeakerCsis([{remoteMedia: remoteMedia1}, {remoteMedia: remoteMedia2}]);
2013
+
2014
+ stubs.forEach((stub, index) => {
2015
+ assert.calledWith(stub, [remoteMediaCsis[index]], false)
2016
+ });
2017
+ assert.calledOnce(fakeMediaRequestManagers.video.commit);
2018
+ }
2019
+ });
2020
+ });
2021
+
1150
2022
  describe('pinActiveSpeakerVideoPane() and isPinned()', () => {
1151
2023
  it('throws if called on a pane not belonging to an active speaker group', async () => {
1152
2024
  let currentLayoutInfo: VideoLayoutChangedEventData | null = null;