@webex/plugin-meetings 2.60.1-next.9 → 2.60.2

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 (539) hide show
  1. package/README.md +8 -58
  2. package/dist/common/browser-detection.js +3 -2
  3. package/dist/common/browser-detection.js.map +1 -1
  4. package/dist/common/collection.js +4 -3
  5. package/dist/common/collection.js.map +1 -1
  6. package/dist/common/config.js +2 -1
  7. package/dist/common/config.js.map +1 -1
  8. package/dist/common/errors/captcha-error.js +2 -1
  9. package/dist/common/errors/captcha-error.js.map +1 -1
  10. package/dist/common/errors/intent-to-join.js +2 -1
  11. package/dist/common/errors/intent-to-join.js.map +1 -1
  12. package/dist/common/errors/join-meeting.js +2 -1
  13. package/dist/common/errors/join-meeting.js.map +1 -1
  14. package/dist/common/errors/media.js +2 -1
  15. package/dist/common/errors/media.js.map +1 -1
  16. package/dist/common/errors/parameter.js +4 -3
  17. package/dist/common/errors/parameter.js.map +1 -1
  18. package/dist/common/errors/password-error.js +2 -1
  19. package/dist/common/errors/password-error.js.map +1 -1
  20. package/dist/common/errors/permission.js +2 -1
  21. package/dist/common/errors/permission.js.map +1 -1
  22. package/dist/common/errors/{reclaim-host-role-errors.js → reclaim-host-role-error.js} +11 -7
  23. package/dist/common/errors/reclaim-host-role-error.js.map +1 -0
  24. package/dist/common/errors/reconnection-in-progress.js +2 -1
  25. package/dist/common/errors/reconnection-in-progress.js.map +1 -1
  26. package/dist/common/errors/reconnection.js +2 -1
  27. package/dist/common/errors/reconnection.js.map +1 -1
  28. package/dist/common/errors/stats.js +2 -1
  29. package/dist/common/errors/stats.js.map +1 -1
  30. package/dist/common/errors/webex-errors.d.ts +8 -20
  31. package/dist/common/errors/webex-errors.js +28 -48
  32. package/dist/common/errors/webex-errors.js.map +1 -1
  33. package/dist/common/errors/webex-meetings-error.js +2 -1
  34. package/dist/common/errors/webex-meetings-error.js.map +1 -1
  35. package/dist/common/events/events-scope.js +2 -1
  36. package/dist/common/events/events-scope.js.map +1 -1
  37. package/dist/common/events/events.js +2 -1
  38. package/dist/common/events/events.js.map +1 -1
  39. package/dist/common/events/trigger-proxy.js +2 -1
  40. package/dist/common/events/trigger-proxy.js.map +1 -1
  41. package/dist/common/events/util.js +2 -1
  42. package/dist/common/events/util.js.map +1 -1
  43. package/dist/common/logs/logger-config.js +2 -1
  44. package/dist/common/logs/logger-config.js.map +1 -1
  45. package/dist/common/logs/logger-proxy.js +3 -2
  46. package/dist/common/logs/logger-proxy.js.map +1 -1
  47. package/dist/common/logs/request.d.ts +1 -3
  48. package/dist/common/logs/request.js +5 -8
  49. package/dist/common/logs/request.js.map +1 -1
  50. package/dist/common/queue.d.ts +7 -9
  51. package/dist/common/queue.js +9 -22
  52. package/dist/common/queue.js.map +1 -1
  53. package/dist/config.d.ts +7 -6
  54. package/dist/config.js +10 -8
  55. package/dist/config.js.map +1 -1
  56. package/dist/constants.d.ts +100 -234
  57. package/dist/constants.js +444 -433
  58. package/dist/constants.js.map +1 -1
  59. package/dist/controls-options-manager/constants.js +6 -3
  60. package/dist/controls-options-manager/constants.js.map +1 -1
  61. package/dist/controls-options-manager/enums.d.ts +1 -11
  62. package/dist/controls-options-manager/enums.js +6 -15
  63. package/dist/controls-options-manager/enums.js.map +1 -1
  64. package/dist/controls-options-manager/index.d.ts +1 -17
  65. package/dist/controls-options-manager/index.js +38 -127
  66. package/dist/controls-options-manager/index.js.map +1 -1
  67. package/dist/controls-options-manager/util.d.ts +7 -1
  68. package/dist/controls-options-manager/util.js +19 -309
  69. package/dist/controls-options-manager/util.js.map +1 -1
  70. package/dist/index.d.ts +3 -6
  71. package/dist/index.js +5 -121
  72. package/dist/index.js.map +1 -1
  73. package/dist/locus-info/controlsUtils.js +11 -100
  74. package/dist/locus-info/controlsUtils.js.map +1 -1
  75. package/dist/locus-info/embeddedAppsUtils.js +4 -3
  76. package/dist/locus-info/embeddedAppsUtils.js.map +1 -1
  77. package/dist/locus-info/fullState.js +2 -1
  78. package/dist/locus-info/fullState.js.map +1 -1
  79. package/dist/locus-info/hostUtils.js +2 -1
  80. package/dist/locus-info/hostUtils.js.map +1 -1
  81. package/dist/locus-info/index.d.ts +4 -57
  82. package/dist/locus-info/index.js +84 -425
  83. package/dist/locus-info/index.js.map +1 -1
  84. package/dist/locus-info/infoUtils.js +5 -13
  85. package/dist/locus-info/infoUtils.js.map +1 -1
  86. package/dist/locus-info/mediaSharesUtils.js +3 -58
  87. package/dist/locus-info/mediaSharesUtils.js.map +1 -1
  88. package/dist/locus-info/parser.d.ts +6 -66
  89. package/dist/locus-info/parser.js +80 -253
  90. package/dist/locus-info/parser.js.map +1 -1
  91. package/dist/locus-info/selfUtils.js +13 -97
  92. package/dist/locus-info/selfUtils.js.map +1 -1
  93. package/dist/media/index.d.ts +0 -2
  94. package/dist/media/index.js +319 -107
  95. package/dist/media/index.js.map +1 -1
  96. package/dist/media/properties.d.ts +53 -38
  97. package/dist/media/properties.js +153 -96
  98. package/dist/media/properties.js.map +1 -1
  99. package/dist/media/util.js +22 -1
  100. package/dist/media/util.js.map +1 -1
  101. package/dist/mediaQualityMetrics/config.d.ts +230 -234
  102. package/dist/mediaQualityMetrics/config.js +498 -302
  103. package/dist/mediaQualityMetrics/config.js.map +1 -1
  104. package/dist/meeting/effectsState.d.ts +42 -0
  105. package/dist/meeting/effectsState.js +260 -0
  106. package/dist/meeting/effectsState.js.map +1 -0
  107. package/dist/meeting/in-meeting-actions.d.ts +0 -88
  108. package/dist/meeting/in-meeting-actions.js +3 -94
  109. package/dist/meeting/in-meeting-actions.js.map +1 -1
  110. package/dist/meeting/index.d.ts +520 -705
  111. package/dist/meeting/index.js +3083 -5041
  112. package/dist/meeting/index.js.map +1 -1
  113. package/dist/meeting/muteState.d.ts +25 -93
  114. package/dist/meeting/muteState.js +133 -224
  115. package/dist/meeting/muteState.js.map +1 -1
  116. package/dist/meeting/request.d.ts +47 -82
  117. package/dist/meeting/request.js +199 -304
  118. package/dist/meeting/request.js.map +1 -1
  119. package/dist/meeting/state.js +2 -1
  120. package/dist/meeting/state.js.map +1 -1
  121. package/dist/meeting/util.d.ts +1 -118
  122. package/dist/meeting/util.js +435 -676
  123. package/dist/meeting/util.js.map +1 -1
  124. package/dist/meeting-info/collection.js +4 -3
  125. package/dist/meeting-info/collection.js.map +1 -1
  126. package/dist/meeting-info/index.d.ts +1 -13
  127. package/dist/meeting-info/index.js +7 -74
  128. package/dist/meeting-info/index.js.map +1 -1
  129. package/dist/meeting-info/meeting-info-v2.d.ts +1 -31
  130. package/dist/meeting-info/meeting-info-v2.js +63 -200
  131. package/dist/meeting-info/meeting-info-v2.js.map +1 -1
  132. package/dist/meeting-info/request.js +2 -1
  133. package/dist/meeting-info/request.js.map +1 -1
  134. package/dist/meeting-info/util.js +3 -2
  135. package/dist/meeting-info/util.js.map +1 -1
  136. package/dist/meeting-info/utilv2.js +41 -39
  137. package/dist/meeting-info/utilv2.js.map +1 -1
  138. package/dist/meetings/collection.d.ts +0 -17
  139. package/dist/meetings/collection.js +4 -42
  140. package/dist/meetings/collection.js.map +1 -1
  141. package/dist/meetings/index.d.ts +20 -114
  142. package/dist/meetings/index.js +133 -540
  143. package/dist/meetings/index.js.map +1 -1
  144. package/dist/meetings/request.js +3 -4
  145. package/dist/meetings/request.js.map +1 -1
  146. package/dist/meetings/util.js +6 -107
  147. package/dist/meetings/util.js.map +1 -1
  148. package/dist/member/index.d.ts +1 -13
  149. package/dist/member/index.js +2 -45
  150. package/dist/member/index.js.map +1 -1
  151. package/dist/member/member.types.js +4 -3
  152. package/dist/member/member.types.js.map +1 -1
  153. package/dist/member/util.js +29 -120
  154. package/dist/member/util.js.map +1 -1
  155. package/dist/members/collection.d.ts +0 -5
  156. package/dist/members/collection.js +2 -11
  157. package/dist/members/collection.js.map +1 -1
  158. package/dist/members/index.d.ts +11 -56
  159. package/dist/members/index.js +47 -174
  160. package/dist/members/index.js.map +1 -1
  161. package/dist/members/request.d.ts +11 -67
  162. package/dist/members/request.js +54 -102
  163. package/dist/members/request.js.map +1 -1
  164. package/dist/members/types.js +4 -3
  165. package/dist/members/types.js.map +1 -1
  166. package/dist/members/util.d.ts +1 -214
  167. package/dist/members/util.js +284 -327
  168. package/dist/members/util.js.map +1 -1
  169. package/dist/metrics/config.d.ts +169 -0
  170. package/dist/metrics/config.js +289 -0
  171. package/dist/metrics/config.js.map +1 -0
  172. package/dist/metrics/constants.d.ts +6 -15
  173. package/dist/metrics/constants.js +9 -17
  174. package/dist/metrics/constants.js.map +1 -1
  175. package/dist/metrics/index.d.ts +111 -4
  176. package/dist/metrics/index.js +452 -4
  177. package/dist/metrics/index.js.map +1 -1
  178. package/dist/networkQualityMonitor/index.js +4 -5
  179. package/dist/networkQualityMonitor/index.js.map +1 -1
  180. package/dist/peer-connection-manager/index.d.ts +6 -0
  181. package/dist/peer-connection-manager/index.js +671 -0
  182. package/dist/peer-connection-manager/index.js.map +1 -0
  183. package/dist/peer-connection-manager/util.d.ts +6 -0
  184. package/dist/peer-connection-manager/util.js +110 -0
  185. package/dist/peer-connection-manager/util.js.map +1 -0
  186. package/dist/personal-meeting-room/index.js +3 -2
  187. package/dist/personal-meeting-room/index.js.map +1 -1
  188. package/dist/personal-meeting-room/request.js +3 -2
  189. package/dist/personal-meeting-room/request.js.map +1 -1
  190. package/dist/personal-meeting-room/util.js +2 -1
  191. package/dist/personal-meeting-room/util.js.map +1 -1
  192. package/dist/reachability/index.d.ts +95 -61
  193. package/dist/reachability/index.js +392 -304
  194. package/dist/reachability/index.js.map +1 -1
  195. package/dist/reachability/request.d.ts +3 -7
  196. package/dist/reachability/request.js +10 -18
  197. package/dist/reachability/request.js.map +1 -1
  198. package/dist/reactions/reactions.d.ts +2 -2
  199. package/dist/reactions/reactions.js +6 -4
  200. package/dist/reactions/reactions.js.map +1 -1
  201. package/dist/reactions/reactions.type.d.ts +3 -23
  202. package/dist/reactions/reactions.type.js +23 -21
  203. package/dist/reactions/reactions.type.js.map +1 -1
  204. package/dist/reconnection-manager/index.d.ts +8 -32
  205. package/dist/reconnection-manager/index.js +232 -285
  206. package/dist/reconnection-manager/index.js.map +1 -1
  207. package/dist/recording-controller/enums.js +5 -4
  208. package/dist/recording-controller/enums.js.map +1 -1
  209. package/dist/recording-controller/index.d.ts +1 -15
  210. package/dist/recording-controller/index.js +46 -57
  211. package/dist/recording-controller/index.js.map +1 -1
  212. package/dist/recording-controller/util.d.ts +4 -5
  213. package/dist/recording-controller/util.js +10 -10
  214. package/dist/recording-controller/util.js.map +1 -1
  215. package/dist/roap/collection.d.ts +10 -0
  216. package/dist/roap/collection.js +63 -0
  217. package/dist/roap/collection.js.map +1 -0
  218. package/dist/roap/handler.d.ts +47 -0
  219. package/dist/roap/handler.js +279 -0
  220. package/dist/roap/handler.js.map +1 -0
  221. package/dist/roap/index.d.ts +47 -9
  222. package/dist/roap/index.js +238 -100
  223. package/dist/roap/index.js.map +1 -1
  224. package/dist/roap/request.d.ts +12 -18
  225. package/dist/roap/request.js +180 -126
  226. package/dist/roap/request.js.map +1 -1
  227. package/dist/roap/state.d.ts +9 -0
  228. package/dist/roap/state.js +127 -0
  229. package/dist/roap/state.js.map +1 -0
  230. package/dist/roap/turnDiscovery.d.ts +16 -27
  231. package/dist/roap/turnDiscovery.js +105 -115
  232. package/dist/roap/turnDiscovery.js.map +1 -1
  233. package/dist/roap/util.d.ts +2 -0
  234. package/dist/roap/util.js +76 -0
  235. package/dist/roap/util.js.map +1 -0
  236. package/dist/statsAnalyzer/global.d.ts +83 -1
  237. package/dist/statsAnalyzer/global.js +85 -2
  238. package/dist/statsAnalyzer/global.js.map +1 -1
  239. package/dist/statsAnalyzer/index.d.ts +30 -50
  240. package/dist/statsAnalyzer/index.js +511 -436
  241. package/dist/statsAnalyzer/index.js.map +1 -1
  242. package/dist/statsAnalyzer/mqaUtil.d.ts +6 -8
  243. package/dist/statsAnalyzer/mqaUtil.js +90 -130
  244. package/dist/statsAnalyzer/mqaUtil.js.map +1 -1
  245. package/dist/transcription/index.js +2 -1
  246. package/dist/transcription/index.js.map +1 -1
  247. package/package.json +26 -39
  248. package/src/common/errors/webex-errors.ts +12 -36
  249. package/src/common/logs/logger-proxy.ts +1 -1
  250. package/src/common/logs/request.ts +1 -5
  251. package/src/common/queue.ts +8 -22
  252. package/src/config.ts +7 -6
  253. package/src/constants.ts +100 -265
  254. package/src/controls-options-manager/enums.ts +0 -12
  255. package/src/controls-options-manager/index.ts +21 -116
  256. package/src/controls-options-manager/util.ts +14 -294
  257. package/src/index.js +15 -0
  258. package/src/locus-info/controlsUtils.ts +0 -110
  259. package/src/locus-info/index.ts +61 -450
  260. package/src/locus-info/infoUtils.ts +2 -14
  261. package/src/locus-info/mediaSharesUtils.ts +0 -64
  262. package/src/locus-info/parser.ts +47 -258
  263. package/src/locus-info/selfUtils.ts +2 -85
  264. package/src/media/index.ts +370 -153
  265. package/src/media/properties.ts +136 -106
  266. package/src/media/util.ts +21 -0
  267. package/src/mediaQualityMetrics/config.ts +377 -244
  268. package/src/meeting/effectsState.ts +209 -0
  269. package/src/meeting/in-meeting-actions.ts +0 -176
  270. package/src/meeting/index.ts +2581 -4306
  271. package/src/meeting/muteState.ts +138 -224
  272. package/src/meeting/request.ts +127 -214
  273. package/src/meeting/util.ts +423 -687
  274. package/src/meeting-info/index.ts +8 -81
  275. package/src/meeting-info/meeting-info-v2.ts +13 -163
  276. package/src/meeting-info/util.ts +1 -1
  277. package/src/meeting-info/utilv2.ts +28 -28
  278. package/src/meetings/collection.ts +0 -33
  279. package/src/meetings/index.ts +136 -531
  280. package/src/meetings/request.ts +0 -2
  281. package/src/meetings/util.ts +5 -116
  282. package/src/member/index.ts +1 -43
  283. package/src/member/util.ts +28 -125
  284. package/src/members/collection.ts +0 -8
  285. package/src/members/index.ts +52 -187
  286. package/src/members/request.ts +27 -87
  287. package/src/members/util.ts +291 -332
  288. package/src/metrics/config.ts +485 -0
  289. package/src/metrics/constants.ts +6 -15
  290. package/src/metrics/index.ts +471 -1
  291. package/src/networkQualityMonitor/index.ts +6 -6
  292. package/src/peer-connection-manager/index.ts +847 -0
  293. package/src/peer-connection-manager/util.ts +119 -0
  294. package/src/reachability/index.ts +347 -246
  295. package/src/reachability/request.ts +8 -17
  296. package/src/reactions/reactions.ts +4 -4
  297. package/src/reactions/reactions.type.ts +4 -30
  298. package/src/reconnection-manager/index.ts +156 -168
  299. package/src/recording-controller/index.ts +3 -20
  300. package/src/recording-controller/util.ts +9 -26
  301. package/src/roap/collection.ts +62 -0
  302. package/src/roap/handler.ts +294 -0
  303. package/src/roap/index.ts +241 -96
  304. package/src/roap/request.ts +148 -74
  305. package/src/roap/state.ts +156 -0
  306. package/src/roap/turnDiscovery.ts +56 -62
  307. package/src/roap/util.ts +100 -0
  308. package/src/statsAnalyzer/global.ts +84 -1
  309. package/src/statsAnalyzer/index.ts +645 -479
  310. package/src/statsAnalyzer/mqaUtil.ts +126 -128
  311. package/test/integration/spec/journey.js +264 -320
  312. package/test/integration/spec/space-meeting.js +4 -77
  313. package/test/unit/spec/common/queue.js +2 -31
  314. package/test/unit/spec/controls-options-manager/index.js +0 -163
  315. package/test/unit/spec/controls-options-manager/util.js +60 -576
  316. package/test/unit/spec/fixture/locus.js +0 -1
  317. package/test/unit/spec/locus-info/controlsUtils.js +30 -323
  318. package/test/unit/spec/locus-info/index.js +15 -1437
  319. package/test/unit/spec/locus-info/infoUtils.js +16 -54
  320. package/test/unit/spec/locus-info/lib/SeqCmp.json +0 -16
  321. package/test/unit/spec/locus-info/lib/selfConstant.js +0 -48
  322. package/test/unit/spec/locus-info/parser.js +35 -116
  323. package/test/unit/spec/locus-info/selfUtils.js +0 -275
  324. package/test/unit/spec/media/properties.ts +84 -75
  325. package/test/unit/spec/meeting/effectsState.js +281 -0
  326. package/test/unit/spec/meeting/in-meeting-actions.ts +0 -86
  327. package/test/unit/spec/meeting/index.js +2313 -8384
  328. package/test/unit/spec/meeting/muteState.js +213 -409
  329. package/test/unit/spec/meeting/request.js +43 -523
  330. package/test/unit/spec/meeting/utils.js +24 -834
  331. package/test/unit/spec/meeting-info/meetinginfov2.js +5 -527
  332. package/test/unit/spec/meeting-info/utilv2.js +0 -21
  333. package/test/unit/spec/meetings/collection.js +0 -26
  334. package/test/unit/spec/meetings/index.js +232 -1445
  335. package/test/unit/spec/meetings/utils.js +2 -202
  336. package/test/unit/spec/member/index.js +9 -32
  337. package/test/unit/spec/member/util.js +61 -499
  338. package/test/unit/spec/members/index.js +5 -394
  339. package/test/unit/spec/members/request.js +27 -206
  340. package/test/unit/spec/members/utils.js +38 -173
  341. package/test/unit/spec/metrics/index.js +50 -1
  342. package/test/unit/spec/networkQualityMonitor/index.js +4 -4
  343. package/test/unit/spec/peerconnection-manager/index.js +218 -0
  344. package/test/unit/spec/peerconnection-manager/utils.js +49 -0
  345. package/test/unit/spec/peerconnection-manager/utils.test-fixtures.ts +388 -0
  346. package/test/unit/spec/reachability/index.ts +24 -532
  347. package/test/unit/spec/reconnection-manager/index.js +24 -163
  348. package/test/unit/spec/recording-controller/index.js +218 -293
  349. package/test/unit/spec/recording-controller/util.js +96 -223
  350. package/test/unit/spec/roap/index.ts +77 -187
  351. package/test/unit/spec/roap/turnDiscovery.ts +48 -86
  352. package/test/unit/spec/roap/util.js +30 -0
  353. package/test/unit/spec/stats-analyzer/index.js +165 -644
  354. package/test/utils/testUtils.js +45 -0
  355. package/test/utils/webex-config.js +0 -4
  356. package/test/utils/webex-test-users.js +3 -7
  357. package/dist/annotation/annotation.types.d.ts +0 -42
  358. package/dist/annotation/annotation.types.js +0 -7
  359. package/dist/annotation/annotation.types.js.map +0 -1
  360. package/dist/annotation/constants.d.ts +0 -31
  361. package/dist/annotation/constants.js +0 -41
  362. package/dist/annotation/constants.js.map +0 -1
  363. package/dist/annotation/index.d.ts +0 -117
  364. package/dist/annotation/index.js +0 -357
  365. package/dist/annotation/index.js.map +0 -1
  366. package/dist/breakouts/breakout.d.ts +0 -8
  367. package/dist/breakouts/breakout.js +0 -215
  368. package/dist/breakouts/breakout.js.map +0 -1
  369. package/dist/breakouts/collection.d.ts +0 -5
  370. package/dist/breakouts/collection.js +0 -22
  371. package/dist/breakouts/collection.js.map +0 -1
  372. package/dist/breakouts/edit-lock-error.d.ts +0 -15
  373. package/dist/breakouts/edit-lock-error.js +0 -51
  374. package/dist/breakouts/edit-lock-error.js.map +0 -1
  375. package/dist/breakouts/events.d.ts +0 -8
  376. package/dist/breakouts/events.js +0 -44
  377. package/dist/breakouts/events.js.map +0 -1
  378. package/dist/breakouts/index.d.ts +0 -5
  379. package/dist/breakouts/index.js +0 -1047
  380. package/dist/breakouts/index.js.map +0 -1
  381. package/dist/breakouts/request.d.ts +0 -22
  382. package/dist/breakouts/request.js +0 -77
  383. package/dist/breakouts/request.js.map +0 -1
  384. package/dist/breakouts/utils.d.ts +0 -15
  385. package/dist/breakouts/utils.js +0 -64
  386. package/dist/breakouts/utils.js.map +0 -1
  387. package/dist/common/errors/no-meeting-info.d.ts +0 -14
  388. package/dist/common/errors/no-meeting-info.js +0 -50
  389. package/dist/common/errors/no-meeting-info.js.map +0 -1
  390. package/dist/common/errors/reclaim-host-role-errors.js.map +0 -1
  391. package/dist/controls-options-manager/types.d.ts +0 -43
  392. package/dist/controls-options-manager/types.js +0 -7
  393. package/dist/controls-options-manager/types.js.map +0 -1
  394. package/dist/interceptors/index.d.ts +0 -2
  395. package/dist/interceptors/index.js +0 -15
  396. package/dist/interceptors/index.js.map +0 -1
  397. package/dist/interceptors/locusRetry.d.ts +0 -27
  398. package/dist/interceptors/locusRetry.js +0 -94
  399. package/dist/interceptors/locusRetry.js.map +0 -1
  400. package/dist/interpretation/collection.d.ts +0 -5
  401. package/dist/interpretation/collection.js +0 -22
  402. package/dist/interpretation/collection.js.map +0 -1
  403. package/dist/interpretation/index.d.ts +0 -5
  404. package/dist/interpretation/index.js +0 -365
  405. package/dist/interpretation/index.js.map +0 -1
  406. package/dist/interpretation/siLanguage.d.ts +0 -5
  407. package/dist/interpretation/siLanguage.js +0 -24
  408. package/dist/interpretation/siLanguage.js.map +0 -1
  409. package/dist/meeting/locusMediaRequest.d.ts +0 -74
  410. package/dist/meeting/locusMediaRequest.js +0 -291
  411. package/dist/meeting/locusMediaRequest.js.map +0 -1
  412. package/dist/meeting/request.type.d.ts +0 -11
  413. package/dist/meeting/request.type.js +0 -7
  414. package/dist/meeting/request.type.js.map +0 -1
  415. package/dist/meeting/voicea-meeting.d.ts +0 -20
  416. package/dist/meeting/voicea-meeting.js +0 -201
  417. package/dist/meeting/voicea-meeting.js.map +0 -1
  418. package/dist/meetings/meetings.types.d.ts +0 -4
  419. package/dist/meetings/meetings.types.js +0 -7
  420. package/dist/meetings/meetings.types.js.map +0 -1
  421. package/dist/member/types.d.ts +0 -32
  422. package/dist/member/types.js +0 -23
  423. package/dist/member/types.js.map +0 -1
  424. package/dist/multistream/mediaRequestManager.d.ts +0 -118
  425. package/dist/multistream/mediaRequestManager.js +0 -344
  426. package/dist/multistream/mediaRequestManager.js.map +0 -1
  427. package/dist/multistream/receiveSlot.d.ts +0 -68
  428. package/dist/multistream/receiveSlot.js +0 -200
  429. package/dist/multistream/receiveSlot.js.map +0 -1
  430. package/dist/multistream/receiveSlotManager.d.ts +0 -56
  431. package/dist/multistream/receiveSlotManager.js +0 -174
  432. package/dist/multistream/receiveSlotManager.js.map +0 -1
  433. package/dist/multistream/remoteMedia.d.ts +0 -72
  434. package/dist/multistream/remoteMedia.js +0 -268
  435. package/dist/multistream/remoteMedia.js.map +0 -1
  436. package/dist/multistream/remoteMediaGroup.d.ts +0 -47
  437. package/dist/multistream/remoteMediaGroup.js +0 -267
  438. package/dist/multistream/remoteMediaGroup.js.map +0 -1
  439. package/dist/multistream/remoteMediaManager.d.ts +0 -285
  440. package/dist/multistream/remoteMediaManager.js +0 -1211
  441. package/dist/multistream/remoteMediaManager.js.map +0 -1
  442. package/dist/multistream/sendSlotManager.d.ts +0 -61
  443. package/dist/multistream/sendSlotManager.js +0 -236
  444. package/dist/multistream/sendSlotManager.js.map +0 -1
  445. package/dist/reachability/clusterReachability.d.ts +0 -109
  446. package/dist/reachability/clusterReachability.js +0 -357
  447. package/dist/reachability/clusterReachability.js.map +0 -1
  448. package/dist/reachability/util.d.ts +0 -8
  449. package/dist/reachability/util.js +0 -29
  450. package/dist/reachability/util.js.map +0 -1
  451. package/dist/reactions/constants.d.ts +0 -3
  452. package/dist/reactions/constants.js +0 -12
  453. package/dist/reactions/constants.js.map +0 -1
  454. package/dist/rtcMetrics/constants.d.ts +0 -4
  455. package/dist/rtcMetrics/constants.js +0 -11
  456. package/dist/rtcMetrics/constants.js.map +0 -1
  457. package/dist/rtcMetrics/index.d.ts +0 -54
  458. package/dist/rtcMetrics/index.js +0 -140
  459. package/dist/rtcMetrics/index.js.map +0 -1
  460. package/dist/webinar/collection.d.ts +0 -16
  461. package/dist/webinar/collection.js +0 -43
  462. package/dist/webinar/collection.js.map +0 -1
  463. package/dist/webinar/index.d.ts +0 -5
  464. package/dist/webinar/index.js +0 -68
  465. package/dist/webinar/index.js.map +0 -1
  466. package/src/annotation/annotation.types.ts +0 -50
  467. package/src/annotation/constants.ts +0 -36
  468. package/src/annotation/index.ts +0 -328
  469. package/src/breakouts/README.md +0 -220
  470. package/src/breakouts/breakout.ts +0 -188
  471. package/src/breakouts/collection.ts +0 -19
  472. package/src/breakouts/edit-lock-error.ts +0 -25
  473. package/src/breakouts/events.ts +0 -56
  474. package/src/breakouts/index.ts +0 -925
  475. package/src/breakouts/request.ts +0 -55
  476. package/src/breakouts/utils.ts +0 -57
  477. package/src/common/errors/no-meeting-info.ts +0 -24
  478. package/src/controls-options-manager/types.ts +0 -59
  479. package/src/index.ts +0 -44
  480. package/src/interceptors/index.ts +0 -3
  481. package/src/interceptors/locusRetry.ts +0 -67
  482. package/src/interpretation/README.md +0 -60
  483. package/src/interpretation/collection.ts +0 -19
  484. package/src/interpretation/index.ts +0 -332
  485. package/src/interpretation/siLanguage.ts +0 -18
  486. package/src/meeting/locusMediaRequest.ts +0 -313
  487. package/src/meeting/request.type.ts +0 -13
  488. package/src/meeting/voicea-meeting.ts +0 -161
  489. package/src/meetings/meetings.types.ts +0 -12
  490. package/src/member/types.ts +0 -38
  491. package/src/multistream/mediaRequestManager.ts +0 -440
  492. package/src/multistream/receiveSlot.ts +0 -184
  493. package/src/multistream/receiveSlotManager.ts +0 -166
  494. package/src/multistream/remoteMedia.ts +0 -254
  495. package/src/multistream/remoteMediaGroup.ts +0 -284
  496. package/src/multistream/remoteMediaManager.ts +0 -1145
  497. package/src/multistream/sendSlotManager.ts +0 -170
  498. package/src/reachability/clusterReachability.ts +0 -320
  499. package/src/reachability/util.ts +0 -24
  500. package/src/reactions/constants.ts +0 -4
  501. package/src/rtcMetrics/constants.ts +0 -3
  502. package/src/rtcMetrics/index.ts +0 -124
  503. package/src/webinar/collection.ts +0 -31
  504. package/src/webinar/index.ts +0 -62
  505. package/test/integration/spec/converged-space-meetings.js +0 -233
  506. package/test/unit/spec/annotation/index.ts +0 -418
  507. package/test/unit/spec/breakouts/breakout.ts +0 -237
  508. package/test/unit/spec/breakouts/collection.ts +0 -15
  509. package/test/unit/spec/breakouts/edit-lock-error.ts +0 -30
  510. package/test/unit/spec/breakouts/events.ts +0 -89
  511. package/test/unit/spec/breakouts/index.ts +0 -1790
  512. package/test/unit/spec/breakouts/request.ts +0 -104
  513. package/test/unit/spec/breakouts/utils.js +0 -72
  514. package/test/unit/spec/interceptors/locusRetry.ts +0 -131
  515. package/test/unit/spec/interpretation/collection.ts +0 -15
  516. package/test/unit/spec/interpretation/index.ts +0 -589
  517. package/test/unit/spec/interpretation/siLanguage.ts +0 -28
  518. package/test/unit/spec/locus-info/mediaSharesUtils.ts +0 -32
  519. package/test/unit/spec/media/index.ts +0 -290
  520. package/test/unit/spec/meeting/locusMediaRequest.ts +0 -442
  521. package/test/unit/spec/meeting-info/index.js +0 -300
  522. package/test/unit/spec/multistream/mediaRequestManager.ts +0 -1418
  523. package/test/unit/spec/multistream/receiveSlot.ts +0 -163
  524. package/test/unit/spec/multistream/receiveSlotManager.ts +0 -203
  525. package/test/unit/spec/multistream/remoteMedia.ts +0 -255
  526. package/test/unit/spec/multistream/remoteMediaGroup.ts +0 -662
  527. package/test/unit/spec/multistream/remoteMediaManager.ts +0 -1924
  528. package/test/unit/spec/multistream/sendSlotManager.ts +0 -242
  529. package/test/unit/spec/reachability/clusterReachability.ts +0 -279
  530. package/test/unit/spec/reachability/request.js +0 -68
  531. package/test/unit/spec/reachability/util.ts +0 -40
  532. package/test/unit/spec/roap/request.ts +0 -255
  533. package/test/unit/spec/rtcMetrics/index.ts +0 -93
  534. package/test/unit/spec/webinar/collection.ts +0 -13
  535. package/test/unit/spec/webinar/index.ts +0 -60
  536. package/test/utils/constants.js +0 -9
  537. package/test/utils/integrationTestUtils.js +0 -46
  538. /package/dist/common/errors/{reclaim-host-role-errors.d.ts → reclaim-host-role-error.d.ts} +0 -0
  539. /package/src/common/errors/{reclaim-host-role-errors.ts → reclaim-host-role-error.ts} +0 -0
@@ -1,1924 +0,0 @@
1
- /* eslint-disable require-jsdoc */
2
- import EventEmitter from 'events';
3
-
4
- import {MediaType} from '@webex/internal-media-core';
5
- import {
6
- Configuration,
7
- Event,
8
- RemoteMediaManager,
9
- VideoLayoutChangedEventData,
10
- } from '@webex/plugin-meetings/src/multistream/remoteMediaManager';
11
- import {RemoteMediaGroup} from '@webex/plugin-meetings/src/multistream/remoteMediaGroup';
12
- import sinon from 'sinon';
13
- import {assert} from '@webex/test-helper-chai';
14
- import {cloneDeep} from 'lodash';
15
- import {MediaRequest} from '@webex/plugin-meetings/src/multistream/mediaRequestManager';
16
- import {CSI, ReceiveSlotId} from '@webex/plugin-meetings/src/multistream/receiveSlot';
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
-
22
- class FakeSlot extends EventEmitter {
23
- public mediaType: MediaType;
24
-
25
- public id: string;
26
-
27
- public csi?: number;
28
-
29
- constructor(mediaType: MediaType, id: string) {
30
- super();
31
- this.mediaType = mediaType;
32
- this.id = id;
33
- // Many of the tests use the same FakeSlot instance for all remote media, so it gets
34
- // a lot of listeners registered causing a warning about a potential listener leak.
35
- // Calling setMaxListeners() fixes the warning.
36
- this.setMaxListeners(50);
37
- }
38
-
39
- public get logString() {
40
- return this.id;
41
- }
42
- }
43
-
44
- const DefaultTestConfiguration: Configuration = {
45
- audio: {
46
- numOfActiveSpeakerStreams: 3,
47
- numOfScreenShareStreams: 1,
48
- },
49
- video: {
50
- preferLiveVideo: true,
51
- initialLayoutId: 'AllEqual',
52
-
53
- layouts: {
54
- AllEqual: {
55
- activeSpeakerVideoPaneGroups: [
56
- {
57
- id: 'main',
58
- numPanes: 9,
59
- size: 'best',
60
- priority: 255,
61
- },
62
- ],
63
- },
64
- OnePlusFive: {
65
- activeSpeakerVideoPaneGroups: [
66
- {
67
- id: 'mainBigOne',
68
- numPanes: 1,
69
- size: 'large',
70
- priority: 255,
71
- },
72
- {
73
- id: 'secondarySetOfSmallPanes',
74
- numPanes: 5,
75
- size: 'very small',
76
- priority: 254,
77
- },
78
- ],
79
- },
80
- Single: {
81
- activeSpeakerVideoPaneGroups: [
82
- {
83
- id: 'main',
84
- numPanes: 1,
85
- size: 'best',
86
- priority: 255,
87
- },
88
- ],
89
- },
90
- Stage: {
91
- activeSpeakerVideoPaneGroups: [
92
- {
93
- id: 'thumbnails',
94
- numPanes: 6,
95
- size: 'thumbnail',
96
- priority: 255,
97
- },
98
- ],
99
- memberVideoPanes: [
100
- {id: 'stage-1', size: 'medium', csi: undefined},
101
- {id: 'stage-2', size: 'medium', csi: undefined},
102
- {id: 'stage-3', size: 'medium', csi: undefined},
103
- {id: 'stage-4', size: 'medium', csi: undefined},
104
- ],
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
- },
117
- },
118
- },
119
- };
120
-
121
- describe('RemoteMediaManager', () => {
122
- let remoteMediaManager;
123
- let fakeReceiveSlotManager;
124
- let fakeMediaRequestManagers;
125
- let fakeAudioSlot;
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
- });
142
-
143
- beforeEach(() => {
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
- );
157
-
158
- fakeReceiveSlotManager = {
159
- allocateSlot: sinon.stub().callsFake((mediaType) => {
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);
169
- }
170
- throw new Error(`invalid mediaType: ${mediaType}`);
171
- }),
172
- releaseSlot: sinon.stub(),
173
- };
174
-
175
- fakeMediaRequestManagers = {
176
- audio: {
177
- addRequest: sinon.stub(),
178
- cancelRequest: sinon.stub(),
179
- commit: sinon.stub(),
180
- },
181
- video: {
182
- addRequest: sinon.stub(),
183
- cancelRequest: sinon.stub(),
184
- commit: sinon.stub(),
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
- },
196
- };
197
-
198
- // create remote media manager with default configuration
199
- remoteMediaManager = new RemoteMediaManager(
200
- fakeReceiveSlotManager,
201
- fakeMediaRequestManagers,
202
- DefaultTestConfiguration
203
- );
204
- });
205
-
206
- const resetHistory = () => {
207
- fakeReceiveSlotManager.allocateSlot.resetHistory();
208
- fakeReceiveSlotManager.releaseSlot.resetHistory();
209
- fakeMediaRequestManagers.audio.addRequest.resetHistory();
210
- fakeMediaRequestManagers.audio.cancelRequest.resetHistory();
211
- fakeMediaRequestManagers.audio.commit.resetHistory();
212
- fakeMediaRequestManagers.video.addRequest.resetHistory();
213
- fakeMediaRequestManagers.video.cancelRequest.resetHistory();
214
- fakeMediaRequestManagers.video.commit.resetHistory();
215
- fakeMediaRequestManagers.screenShareVideo.commit.resetHistory();
216
- fakeMediaRequestManagers.screenShareAudio.commit.resetHistory();
217
- logger.log.resetHistory();
218
- };
219
-
220
- describe('start', () => {
221
- it('rejects if called twice', async () => {
222
- await remoteMediaManager.start();
223
- await assert.isRejected(remoteMediaManager.start());
224
- });
225
-
226
- it('can be called again after stop()', async () => {
227
- await remoteMediaManager.start();
228
- remoteMediaManager.stop();
229
-
230
- fakeReceiveSlotManager.allocateSlot.resetHistory();
231
-
232
- await remoteMediaManager.start();
233
-
234
- // check that the 2nd start() creates slots and media requests and is not a no-op
235
- assert.calledWith(fakeReceiveSlotManager.allocateSlot, MediaType.AudioMain);
236
- assert.calledWith(fakeReceiveSlotManager.allocateSlot, MediaType.VideoMain);
237
-
238
- assert.called(fakeMediaRequestManagers.audio.addRequest);
239
- assert.called(fakeMediaRequestManagers.video.addRequest);
240
- });
241
-
242
- it('creates a RemoteMediaGroup for audio correctly', async () => {
243
- let createdAudioGroup: RemoteMediaGroup | null = null;
244
-
245
- // create a config with just audio, no video at all and no screen share
246
- const config: Configuration = {
247
- audio: {
248
- numOfActiveSpeakerStreams: 5,
249
- numOfScreenShareStreams: 0,
250
- },
251
- video: {
252
- preferLiveVideo: false,
253
- initialLayoutId: 'empty',
254
- layouts: {
255
- empty: {},
256
- },
257
- },
258
- };
259
-
260
- remoteMediaManager = new RemoteMediaManager(
261
- fakeReceiveSlotManager,
262
- fakeMediaRequestManagers,
263
- config
264
- );
265
-
266
- remoteMediaManager.on(Event.AudioCreated, (audio: RemoteMediaGroup) => {
267
- createdAudioGroup = audio;
268
- });
269
-
270
- remoteMediaManager.start();
271
-
272
- await testUtils.flushPromises();
273
-
274
- assert.callCount(fakeReceiveSlotManager.allocateSlot, 5);
275
- assert.alwaysCalledWith(fakeReceiveSlotManager.allocateSlot, MediaType.AudioMain);
276
-
277
- assert.isNotNull(createdAudioGroup);
278
- if (createdAudioGroup) {
279
- assert.strictEqual(createdAudioGroup.getRemoteMedia().length, 5);
280
- assert.isTrue(
281
- createdAudioGroup
282
- .getRemoteMedia()
283
- .every((remoteMedia) => remoteMedia.mediaType === MediaType.AudioMain)
284
- );
285
- assert.strictEqual(createdAudioGroup.getRemoteMedia('pinned').length, 0);
286
- }
287
-
288
- assert.calledOnce(fakeMediaRequestManagers.audio.addRequest);
289
- assert.calledWith(
290
- fakeMediaRequestManagers.audio.addRequest,
291
- sinon.match({
292
- policyInfo: sinon.match({
293
- policy: 'active-speaker',
294
- priority: 255,
295
- }),
296
- receiveSlots: Array(5).fill(fakeAudioSlot),
297
- codecInfo: undefined,
298
- })
299
- );
300
- });
301
-
302
- it('pre-allocates receive slots based on the biggest layout', async () => {
303
- const config = cloneDeep(DefaultTestConfiguration);
304
-
305
- config.audio.numOfActiveSpeakerStreams = 0;
306
- config.video.layouts.huge = {
307
- activeSpeakerVideoPaneGroups: [
308
- {
309
- id: 'big one',
310
- numPanes: 99,
311
- size: 'small',
312
- priority: 255,
313
- },
314
- ],
315
- };
316
- config.audio.numOfScreenShareStreams = 0;
317
- delete config.video.layouts.ScreenShareView;
318
-
319
- remoteMediaManager = new RemoteMediaManager(
320
- fakeReceiveSlotManager,
321
- fakeMediaRequestManagers,
322
- config
323
- );
324
-
325
- await remoteMediaManager.start();
326
-
327
- // even though our "big one" layout is not the default one, the remote media manager should still
328
- // preallocate enough video receive slots for it up front
329
- assert.callCount(fakeReceiveSlotManager.allocateSlot, 99);
330
- assert.alwaysCalledWith(fakeReceiveSlotManager.allocateSlot, MediaType.VideoMain);
331
- });
332
-
333
- it('starts with the initial layout', async () => {
334
- let receivedLayoutInfo: VideoLayoutChangedEventData | null = null;
335
-
336
- remoteMediaManager.on(Event.VideoLayoutChanged, (layoutInfo: VideoLayoutChangedEventData) => {
337
- receivedLayoutInfo = layoutInfo;
338
- });
339
-
340
- // the initial layout is "AllEqual", so we check that it gets selected by default
341
- await remoteMediaManager.start();
342
-
343
- assert.strictEqual(remoteMediaManager.getLayoutId(), 'AllEqual');
344
- assert.isNotNull(receivedLayoutInfo);
345
- if (receivedLayoutInfo) {
346
- assert.strictEqual(receivedLayoutInfo.layoutId, 'AllEqual');
347
- assert.strictEqual(Object.keys(receivedLayoutInfo.memberVideoPanes).length, 0);
348
- assert.strictEqual(Object.keys(receivedLayoutInfo.activeSpeakerVideoPanes).length, 1); // this layout has only 1 active speaker group
349
- assert.strictEqual(
350
- receivedLayoutInfo.activeSpeakerVideoPanes.main.getRemoteMedia().length,
351
- 9
352
- );
353
- assert.isUndefined(receivedLayoutInfo.screenShareVideo); // the initial layout has no screen share
354
- }
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
-
475
- });
476
-
477
- describe('constructor', () => {
478
- it('throws if the initial layout in the config is invalid', () => {
479
- const config = cloneDeep(DefaultTestConfiguration);
480
-
481
- config.video.initialLayoutId = 'invalid';
482
-
483
- assert.throws(() => {
484
- remoteMediaManager = new RemoteMediaManager(
485
- fakeReceiveSlotManager,
486
- fakeMediaRequestManagers,
487
- config
488
- );
489
- }, 'invalid config: initialLayoutId "invalid" doesn\'t match any of the layouts');
490
- });
491
-
492
- it('throws if there are duplicate active speaker video pane groups', () => {
493
- const config = cloneDeep(DefaultTestConfiguration);
494
-
495
- config.video.layouts.test = {
496
- activeSpeakerVideoPaneGroups: [
497
- {
498
- id: 'someDuplicate',
499
- numPanes: 10,
500
- priority: 255,
501
- size: 'best',
502
- },
503
- {
504
- id: 'other',
505
- numPanes: 10,
506
- priority: 254,
507
- size: 'best',
508
- },
509
- {
510
- id: 'someDuplicate',
511
- numPanes: 10,
512
- priority: 255,
513
- size: 'best',
514
- },
515
- ],
516
- };
517
-
518
- assert.throws(() => {
519
- remoteMediaManager = new RemoteMediaManager(
520
- fakeReceiveSlotManager,
521
- fakeMediaRequestManagers,
522
- config
523
- );
524
- }, 'invalid config: duplicate active speaker video pane group id: someDuplicate');
525
- });
526
-
527
- it('throws if there are active speaker video pane groups with duplicate priority', () => {
528
- const config = cloneDeep(DefaultTestConfiguration);
529
-
530
- config.video.layouts.test = {
531
- activeSpeakerVideoPaneGroups: [
532
- {
533
- id: 'group1',
534
- numPanes: 10,
535
- priority: 200,
536
- size: 'best',
537
- },
538
- {
539
- id: 'group2',
540
- numPanes: 2,
541
- priority: 200,
542
- size: 'medium',
543
- },
544
- {
545
- id: 'group3',
546
- numPanes: 5,
547
- priority: 100,
548
- size: 'large',
549
- },
550
- ],
551
- };
552
-
553
- assert.throws(() => {
554
- remoteMediaManager = new RemoteMediaManager(
555
- fakeReceiveSlotManager,
556
- fakeMediaRequestManagers,
557
- config
558
- );
559
- }, 'invalid config: multiple active speaker video pane groups have same priority: 200');
560
- });
561
-
562
- it('throws if there are duplicate member video panes', () => {
563
- const config = cloneDeep(DefaultTestConfiguration);
564
-
565
- config.video.layouts.test = {
566
- memberVideoPanes: [
567
- {id: 'paneA', size: 'best', csi: 123},
568
- {id: 'paneB', size: 'large', csi: 222},
569
- {id: 'paneC', size: 'medium', csi: 333},
570
- {id: 'paneB', size: 'small', csi: 444},
571
- ],
572
- };
573
-
574
- assert.throws(() => {
575
- remoteMediaManager = new RemoteMediaManager(
576
- fakeReceiveSlotManager,
577
- fakeMediaRequestManagers,
578
- config
579
- );
580
- }, 'invalid config: duplicate member video pane id: paneB');
581
- });
582
-
583
- });
584
-
585
- describe('stop', () => {
586
- it('releases all the slots and invalidates all remote media', async () => {
587
- let audioStopStub;
588
- let videoActiveSpeakerGroupStopStub;
589
- const memberVideoPaneStopStubs: any[] = [];
590
- let screenShareAudioStopStub;
591
- let screenShareVideoStopStub;
592
-
593
- // change the initial layout to one that has both active speakers and receiver selected videos
594
- const config = cloneDeep(DefaultTestConfiguration);
595
-
596
- config.video.initialLayoutId = 'Stage';
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
-
601
- remoteMediaManager = new RemoteMediaManager(
602
- fakeReceiveSlotManager,
603
- fakeMediaRequestManagers,
604
- config
605
- );
606
-
607
- remoteMediaManager.on(Event.AudioCreated, (audio: RemoteMediaGroup) => {
608
- audioStopStub = sinon.stub(audio, 'stop');
609
- });
610
-
611
- remoteMediaManager.on(Event.ScreenShareAudioCreated, (audio: RemoteMediaGroup) => {
612
- screenShareAudioStopStub = sinon.stub(audio, 'stop');
613
- });
614
-
615
- remoteMediaManager.on(Event.VideoLayoutChanged, (layoutInfo: VideoLayoutChangedEventData) => {
616
- // The "Stage" layout that we're using has only 1 active speaker group called "thumbnails"
617
- videoActiveSpeakerGroupStopStub = sinon.stub(
618
- layoutInfo.activeSpeakerVideoPanes.thumbnails,
619
- 'stop'
620
- );
621
-
622
- Object.values(layoutInfo.memberVideoPanes).forEach((pane) => {
623
- memberVideoPaneStopStubs.push(sinon.stub(pane, 'stop'));
624
- });
625
-
626
- screenShareVideoStopStub = sinon.stub(layoutInfo.screenShareVideo, 'stop');
627
- });
628
-
629
- await remoteMediaManager.start();
630
-
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);
633
-
634
- // our layout has 4 member video panes, we should have a stub for each of these panes' stop methods
635
- assert.strictEqual(memberVideoPaneStopStubs.length, 4);
636
-
637
- resetHistory();
638
-
639
- remoteMediaManager.stop();
640
-
641
- // check that all slots have been released
642
- assert.callCount(fakeReceiveSlotManager.releaseSlot, 15);
643
-
644
- // and that all RemoteMedia and RemoteMediaGroups have been stopped
645
- assert.calledOnce(audioStopStub);
646
- assert.calledWith(audioStopStub, true);
647
- assert.calledOnce(screenShareAudioStopStub);
648
- assert.calledWith(screenShareAudioStopStub, true);
649
- assert.calledOnce(videoActiveSpeakerGroupStopStub);
650
- memberVideoPaneStopStubs.forEach((stub) => {
651
- assert.calledOnce(stub);
652
- });
653
- assert.calledOnce(fakeMediaRequestManagers.video.commit);
654
- assert.calledOnce(screenShareVideoStopStub);
655
- assert.calledOnce(fakeMediaRequestManagers.screenShareVideo.commit);
656
- });
657
-
658
- it('can be called multiple times', async () => {
659
- await remoteMediaManager.start();
660
-
661
- // just checking that nothing crashes etc.
662
- remoteMediaManager.stop();
663
- remoteMediaManager.stop();
664
- });
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
-
701
- describe('setLayout', () => {
702
- it('rejects if called with invalid layoutId', async () => {
703
- await assert.isRejected(remoteMediaManager.setLayout('invalid value'));
704
- });
705
-
706
- it('rejects if called before calling start()', async () => {
707
- await assert.isRejected(remoteMediaManager.setLayout('Stage'));
708
- });
709
-
710
- it('allocates more slots when switching to a layout that requires more slots', async () => {
711
- // start with "Single" layout that needs just 1 video slot
712
- const config = cloneDeep(DefaultTestConfiguration);
713
-
714
- config.video.initialLayoutId = 'Single';
715
-
716
- remoteMediaManager = new RemoteMediaManager(
717
- fakeReceiveSlotManager,
718
- fakeMediaRequestManagers,
719
- config
720
- );
721
-
722
- await remoteMediaManager.start();
723
-
724
- resetHistory();
725
-
726
- // switch to "Stage" layout that requires 9 more video slots (10)
727
- await remoteMediaManager.setLayout('Stage');
728
-
729
- assert.callCount(fakeReceiveSlotManager.allocateSlot, 9);
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#setLayout --> new layout selected: Stage'
751
- );
752
- assert.calledWith(
753
- logger.log,
754
- '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'
755
- );
756
- });
757
-
758
- it('logs layout changes - active speaker', async () => {
759
- const config = cloneDeep(DefaultTestConfiguration);
760
- config.video.initialLayoutId = 'OnePlusFive'
761
-
762
- remoteMediaManager = new RemoteMediaManager(
763
- fakeReceiveSlotManager,
764
- fakeMediaRequestManagers,
765
- config
766
- );
767
-
768
- await remoteMediaManager.start();
769
-
770
- resetHistory();
771
-
772
- await remoteMediaManager.setLayout('AllEqual');
773
-
774
- assert.calledWith(
775
- logger.log,
776
- 'RemoteMediaManager#setLayout --> new layout selected: AllEqual'
777
- );
778
- assert.calledWith(
779
- logger.log,
780
- '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'
781
- );
782
- });
783
-
784
-
785
- it('releases slots when switching to layout that requires less active speaker slots', async () => {
786
- // start with "AllEqual" layout that needs just 9 video slots
787
- const config = cloneDeep(DefaultTestConfiguration);
788
-
789
- config.video.initialLayoutId = 'AllEqual';
790
-
791
- remoteMediaManager = new RemoteMediaManager(
792
- fakeReceiveSlotManager,
793
- fakeMediaRequestManagers,
794
- config
795
- );
796
-
797
- await remoteMediaManager.start();
798
-
799
- resetHistory();
800
-
801
- // switch to "OnePlusFive" layout that requires 3 less video slots (6)
802
- await remoteMediaManager.setLayout('OnePlusFive');
803
-
804
- // verify that 3 main video slots were released
805
- assert.callCount(fakeReceiveSlotManager.releaseSlot, 3);
806
- fakeReceiveSlotManager.releaseSlot.getCalls().forEach((call) => {
807
- const slot = call.args[0];
808
-
809
- assert.strictEqual(slot.mediaType, MediaType.VideoMain);
810
- });
811
- });
812
-
813
- it('releases slots and reallocates slots when switching to layouts in correct order', async () => {
814
-
815
- const config = cloneDeep(DefaultTestConfiguration);
816
- let count = 0;
817
-
818
- fakeReceiveSlotManager.allocateSlot = sinon.stub().callsFake((mediaType) => {
819
- switch (mediaType) {
820
- case MediaType.AudioMain:
821
- return Promise.resolve(fakeAudioSlot);
822
- case MediaType.VideoMain:
823
- return Promise.resolve(new FakeSlot(MediaType.VideoMain, `fake video ${count++}`));
824
- case MediaType.AudioSlides:
825
- return Promise.resolve(fakeScreenShareAudioSlot);
826
- case MediaType.VideoSlides:
827
- return Promise.resolve(fakeScreenShareVideoSlot);
828
- }
829
- throw new Error(`invalid mediaType: ${mediaType}`);
830
- })
831
-
832
- remoteMediaManager = new RemoteMediaManager(
833
- fakeReceiveSlotManager,
834
- fakeMediaRequestManagers,
835
- config
836
- );
837
-
838
- await remoteMediaManager.start();
839
-
840
- resetHistory();
841
-
842
- assert.deepEqual(remoteMediaManager.slots.video.activeSpeaker.map((slot: any) => slot.id), [
843
- "fake video 0",
844
- "fake video 1",
845
- "fake video 2",
846
- "fake video 3",
847
- "fake video 4",
848
- "fake video 5",
849
- "fake video 6",
850
- "fake video 7",
851
- "fake video 8",
852
- ]);
853
-
854
- assert.deepEqual(remoteMediaManager.receiveSlotAllocations.activeSpeaker["main"].slots.map((slot: any) => slot.id), [
855
- "fake video 0",
856
- "fake video 1",
857
- "fake video 2",
858
- "fake video 3",
859
- "fake video 4",
860
- "fake video 5",
861
- "fake video 6",
862
- "fake video 7",
863
- "fake video 8",
864
- ])
865
-
866
- // switch to "OnePlusFive" layout that requires 3 less video slots (6)
867
- await remoteMediaManager.setLayout('OnePlusFive');
868
-
869
- assert.deepEqual(remoteMediaManager.slots.video.unused, []);
870
-
871
- assert.deepEqual(remoteMediaManager.slots.video.activeSpeaker.map((slot: any) => slot.id), [
872
- "fake video 0",
873
- "fake video 1",
874
- "fake video 2",
875
- "fake video 3",
876
- "fake video 4",
877
- "fake video 5"
878
- ]);
879
-
880
- // we're checking that the slots are in the same order as in the previous layout
881
- // first one goes into main
882
- assert.deepEqual(remoteMediaManager.receiveSlotAllocations.activeSpeaker["mainBigOne"].slots.map((slot: any) => slot.id), [
883
- "fake video 0",
884
- ])
885
- // and rest go in the pips
886
- assert.deepEqual(remoteMediaManager.receiveSlotAllocations.activeSpeaker["secondarySetOfSmallPanes"].slots.map((slot: any) => slot.id), [
887
- "fake video 1",
888
- "fake video 2",
889
- "fake video 3",
890
- "fake video 4",
891
- "fake video 5"
892
- ])
893
-
894
- // verify that 3 main video slots were released
895
- assert.callCount(fakeReceiveSlotManager.releaseSlot, 3);
896
- fakeReceiveSlotManager.releaseSlot.getCalls().forEach((call) => {
897
- const slot = call.args[0];
898
-
899
- assert.strictEqual(slot.mediaType, MediaType.VideoMain);
900
- });
901
-
902
- await remoteMediaManager.setLayout('AllEqual');
903
-
904
- assert.deepEqual(remoteMediaManager.slots.video.unused, []);
905
-
906
- // checking that slots are in the same order as in previous layout + 3 new ones
907
- assert.deepEqual(remoteMediaManager.slots.video.activeSpeaker.map((slot: any) => slot.id), [
908
- "fake video 0",
909
- "fake video 1",
910
- "fake video 2",
911
- "fake video 3",
912
- "fake video 4",
913
- "fake video 5",
914
- "fake video 10",
915
- "fake video 11",
916
- "fake video 12",
917
- ]);
918
-
919
- assert.deepEqual(remoteMediaManager.receiveSlotAllocations.activeSpeaker["main"].slots.map((slot: any) => slot.id), [
920
- "fake video 0",
921
- "fake video 1",
922
- "fake video 2",
923
- "fake video 3",
924
- "fake video 4",
925
- "fake video 5",
926
- "fake video 10",
927
- "fake video 11",
928
- "fake video 12"
929
- ])
930
-
931
- // verify that 3 main video slots were allocated
932
- assert.callCount(fakeReceiveSlotManager.allocateSlot, 3);
933
- fakeReceiveSlotManager.allocateSlot.getCalls().forEach((call) => {
934
- const mediaType = call.args[0];
935
-
936
- assert.strictEqual(mediaType, MediaType.VideoMain);
937
- });
938
- });
939
-
940
- it('stops all current video remoteMedia instances when switching to new layout', async () => {
941
- const audioStopStubs = [];
942
- const videoStopStubs = [];
943
-
944
- const config = cloneDeep(DefaultTestConfiguration);
945
-
946
- // start with the stage layout because it has both active speaker and receiver selected panes
947
- config.video.initialLayoutId = 'Stage';
948
-
949
- remoteMediaManager = new RemoteMediaManager(
950
- fakeReceiveSlotManager,
951
- fakeMediaRequestManagers,
952
- config
953
- );
954
-
955
- // mock all stop() methods for all remote audio objects we get with AudioCreated event
956
- remoteMediaManager.on(Event.AudioCreated, (audio: RemoteMediaGroup) => {
957
- audio
958
- .getRemoteMedia()
959
- .forEach((remoteAudio) => audioStopStubs.push(sinon.stub(remoteAudio, 'stop')));
960
- });
961
-
962
- // mock all stop() methods for all remote video objects we get with VideoLayoutChanged event
963
- remoteMediaManager.on(Event.VideoLayoutChanged, (layoutInfo: VideoLayoutChangedEventData) => {
964
- Object.values(layoutInfo.activeSpeakerVideoPanes).forEach((group) =>
965
- group
966
- .getRemoteMedia()
967
- .forEach((remoteMedia) => videoStopStubs.push(sinon.stub(remoteMedia, 'stop')))
968
- );
969
-
970
- Object.values(layoutInfo.memberVideoPanes).forEach((pane) => {
971
- videoStopStubs.push(sinon.stub(pane, 'stop'));
972
- });
973
- });
974
-
975
- await remoteMediaManager.start();
976
-
977
- // sanity check that we've got all our stop() mocks setup correctly
978
- assert.strictEqual(audioStopStubs.length, 3);
979
- assert.strictEqual(videoStopStubs.length, 10); // 10 = 6 thumbnail panes + 4 stage panes
980
-
981
- // next, we'll change the layout, we don't care about the new video panes from the new layout, so unregister the event listeners
982
- remoteMediaManager.removeAllListeners();
983
-
984
- await remoteMediaManager.setLayout('AllEqual');
985
-
986
- // check that NONE of the audio RemoteMedia instances were stopped
987
- audioStopStubs.forEach((audioStopStub) => {
988
- assert.notCalled(audioStopStub);
989
- });
990
-
991
- // check that ALL of the video RemoteMedia instances were stopped
992
- videoStopStubs.forEach((videoStopStub) => {
993
- assert.calledOnce(videoStopStub);
994
- assert.calledWith(videoStopStub, false);
995
- });
996
- });
997
-
998
- it('emits Event.VideoLayoutChanged with correct data', async () => {
999
- // setup the initial layout to be empty and a testLayout that has screen share, active speaker groups and member video panes
1000
- const config: Configuration = {
1001
- audio: {
1002
- numOfActiveSpeakerStreams: 0,
1003
- numOfScreenShareStreams: 0,
1004
- },
1005
- video: {
1006
- preferLiveVideo: true,
1007
- initialLayoutId: 'empty',
1008
- layouts: {
1009
- empty: {},
1010
- testLayout: {
1011
- screenShareVideo: {size: 'very small'},
1012
- activeSpeakerVideoPaneGroups: [
1013
- {
1014
- id: 'big',
1015
- numPanes: 10,
1016
- priority: 255,
1017
- size: 'large',
1018
- },
1019
- {
1020
- id: 'small',
1021
- numPanes: 3,
1022
- priority: 254,
1023
- size: 'medium',
1024
- },
1025
- ],
1026
- memberVideoPanes: [
1027
- {id: 'pane 1', size: 'best', csi: 555},
1028
- {id: 'pane 2', size: 'best', csi: undefined},
1029
- ],
1030
- },
1031
- },
1032
- },
1033
- };
1034
-
1035
- remoteMediaManager = new RemoteMediaManager(
1036
- fakeReceiveSlotManager,
1037
- fakeMediaRequestManagers,
1038
- config
1039
- );
1040
-
1041
- await remoteMediaManager.start();
1042
-
1043
- resetHistory();
1044
-
1045
- let receivedLayoutInfo: VideoLayoutChangedEventData | null = null;
1046
-
1047
- remoteMediaManager.on(Event.VideoLayoutChanged, (layoutInfo) => {
1048
- receivedLayoutInfo = layoutInfo;
1049
- });
1050
-
1051
- // switch to the test layout
1052
- await remoteMediaManager.setLayout('testLayout');
1053
-
1054
- assert.isNotNull(receivedLayoutInfo);
1055
-
1056
- if (receivedLayoutInfo) {
1057
- assert.strictEqual(receivedLayoutInfo.layoutId, 'testLayout');
1058
-
1059
- // check screen share video
1060
- assert.isTrue(!!receivedLayoutInfo.screenShareVideo);
1061
- assert.strictEqual(receivedLayoutInfo.screenShareVideo.mediaType, MediaType.VideoSlides);
1062
-
1063
- // check member videos
1064
- assert.strictEqual(Object.keys(receivedLayoutInfo.memberVideoPanes).length, 2);
1065
- Object.values(receivedLayoutInfo.memberVideoPanes).forEach((remoteMedia) =>
1066
- assert.strictEqual(remoteMedia.mediaType, MediaType.VideoMain)
1067
- );
1068
-
1069
- // check the 2 active speaker groups
1070
- assert.strictEqual(Object.keys(receivedLayoutInfo.activeSpeakerVideoPanes).length, 2);
1071
-
1072
- // "big" group
1073
- assert.strictEqual(
1074
- receivedLayoutInfo.activeSpeakerVideoPanes.big.getRemoteMedia().length,
1075
- 10
1076
- );
1077
- receivedLayoutInfo.activeSpeakerVideoPanes.big
1078
- .getRemoteMedia()
1079
- .forEach((remoteMedia) =>
1080
- assert.strictEqual(remoteMedia.mediaType, MediaType.VideoMain)
1081
- );
1082
-
1083
- // "small" group
1084
- assert.strictEqual(
1085
- receivedLayoutInfo.activeSpeakerVideoPanes.small.getRemoteMedia().length,
1086
- 3
1087
- );
1088
- receivedLayoutInfo.activeSpeakerVideoPanes.small
1089
- .getRemoteMedia()
1090
- .forEach((remoteMedia) =>
1091
- assert.strictEqual(remoteMedia.mediaType, MediaType.VideoMain)
1092
- );
1093
- }
1094
- });
1095
-
1096
- describe('switching between different receiver selected layouts', () => {
1097
- let fakeSlots: {[key: ReceiveSlotId]: FakeSlot};
1098
- let slotCounter: number;
1099
-
1100
- type Csi2SlotsMapping = {[key: CSI]: Array<ReceiveSlotId>};
1101
- // in these mappings: key is the CSI and value is an array of slot ids
1102
- // of slots that were used in media requests for that CSI
1103
- let csi2slotMappingBeforeLayoutChange: Csi2SlotsMapping;
1104
- let csi2slotMappingAfterLayoutChange: Csi2SlotsMapping;
1105
- let csi2slotMapping: Csi2SlotsMapping;
1106
-
1107
- beforeEach(() => {
1108
- // setup the mocks so that we can keep track of all the slots and their CSIs
1109
- fakeSlots = {};
1110
- slotCounter = 0;
1111
-
1112
- fakeReceiveSlotManager.allocateSlot.callsFake(() => {
1113
- slotCounter += 1;
1114
- const newSlotId = `fake video slot ${slotCounter}`;
1115
-
1116
- fakeSlots[newSlotId] = new FakeSlot(MediaType.VideoMain, newSlotId);
1117
- return fakeSlots[newSlotId];
1118
- });
1119
-
1120
- csi2slotMappingBeforeLayoutChange = {};
1121
- csi2slotMappingAfterLayoutChange = {};
1122
-
1123
- csi2slotMapping = csi2slotMappingBeforeLayoutChange;
1124
-
1125
- fakeMediaRequestManagers.video.addRequest.callsFake((mediaRequest: MediaRequest) => {
1126
- if (mediaRequest.policyInfo.policy === 'receiver-selected') {
1127
- const slot = mediaRequest.receiveSlots[0] as unknown as FakeSlot;
1128
- const csi = mediaRequest.policyInfo.csi;
1129
-
1130
- slot.csi = csi;
1131
- if (csi2slotMapping[csi]) {
1132
- csi2slotMapping[csi].push(slot.id);
1133
- } else {
1134
- csi2slotMapping[csi] = [slot.id];
1135
- }
1136
-
1137
- return slot.id;
1138
- }
1139
- });
1140
- });
1141
-
1142
- it('releases slots when switching to layout that requires less receiver selected slots', async () => {
1143
- const config = cloneDeep(DefaultTestConfiguration);
1144
-
1145
- // This test starts with a layout that has 5 receiver selected video slots
1146
- // and switches to a different layout that has fewer slots, but 2 of them match CSIs
1147
- // from the initial layout. We want to verify that these 2 slots get re-used correctly.
1148
- // There are no screen share or audio slots being used in this test.
1149
- delete config.video.layouts.ScreenShareView;
1150
- config.audio.numOfActiveSpeakerStreams = 0;
1151
- config.audio.numOfScreenShareStreams = 0;
1152
- config.video.initialLayoutId = 'biggerLayout';
1153
- config.video.layouts['biggerLayout'] = {
1154
- memberVideoPanes: [
1155
- {id: '1', size: 'best', csi: 100},
1156
- {id: '2', size: 'best', csi: 200},
1157
- {id: '3', size: 'best', csi: 300},
1158
- {id: '4', size: 'best', csi: 400},
1159
- {id: '5', size: 'best', csi: 500},
1160
- ],
1161
- };
1162
- config.video.layouts['smallerLayout'] = {
1163
- memberVideoPanes: [
1164
- {id: '1', size: 'medium', csi: 200}, // this csi matches pane '2' from biggerLayout
1165
- {id: '2', size: 'medium', csi: 123},
1166
- {id: '3', size: 'medium', csi: 400}, // this csi matches pane '4' from biggerLayout
1167
- ],
1168
- };
1169
-
1170
- remoteMediaManager = new RemoteMediaManager(
1171
- fakeReceiveSlotManager,
1172
- fakeMediaRequestManagers,
1173
- config
1174
- );
1175
-
1176
- await remoteMediaManager.start();
1177
-
1178
- resetHistory();
1179
-
1180
- // switch the mock to now use csi2slotMappingAfterLayoutChange as we're about to change the layout
1181
- csi2slotMapping = csi2slotMappingAfterLayoutChange;
1182
-
1183
- // switch to "smallerLayout" layout that requires 2 less video slots and has 2 receive selected slots with same CSIs
1184
- await remoteMediaManager.setLayout('smallerLayout');
1185
-
1186
- // verify that 2 main video slots were released
1187
- assert.callCount(fakeReceiveSlotManager.releaseSlot, 2);
1188
-
1189
- // verify that each CSI has 1 slot assigned
1190
- assert.equal(Object.keys(csi2slotMappingAfterLayoutChange).length, 3);
1191
- assert.equal(csi2slotMappingAfterLayoutChange[200].length, 1);
1192
- assert.equal(csi2slotMappingAfterLayoutChange[123].length, 1);
1193
- assert.equal(csi2slotMappingAfterLayoutChange[400].length, 1);
1194
-
1195
- // verify that the slots have been re-used for csi 200 and 400
1196
- assert.equal(
1197
- csi2slotMappingBeforeLayoutChange[200][0],
1198
- csi2slotMappingAfterLayoutChange[200][0]
1199
- );
1200
- assert.equal(
1201
- csi2slotMappingBeforeLayoutChange[400][0],
1202
- csi2slotMappingAfterLayoutChange[400][0]
1203
- );
1204
- });
1205
-
1206
- it('correctly handles a change to a layout that has member video panes with duplicate CSIs', async () => {
1207
- const config = cloneDeep(DefaultTestConfiguration);
1208
-
1209
- // This test starts with a layout that has video slot with a specific CSI
1210
- // and switches to a different layout that 2 panes with that same CSI.
1211
- // We want to verify that the slot gets reused, but also that a 2nd slot is allocated.
1212
- // There are no screen share or audio slots being used in this test.
1213
- delete config.video.layouts.ScreenShareView;
1214
- config.audio.numOfActiveSpeakerStreams = 0;
1215
- config.audio.numOfScreenShareStreams = 0;
1216
- config.video.initialLayoutId = 'initialEmptyLayout';
1217
- config.video.layouts['initialEmptyLayout'] = {
1218
- memberVideoPanes: [{id: '2', size: 'medium', csi: 456}],
1219
- };
1220
- config.video.layouts['layoutWithDuplicateCSIs'] = {
1221
- memberVideoPanes: [
1222
- {id: '1', size: 'medium', csi: 123},
1223
- {id: '2', size: 'medium', csi: 456},
1224
- {id: '3', size: 'medium', csi: 456}, // duplicate CSI and also matching one of CSIs from previous layout
1225
- {id: '4', size: 'medium', csi: 789},
1226
- ],
1227
- };
1228
-
1229
- remoteMediaManager = new RemoteMediaManager(
1230
- fakeReceiveSlotManager,
1231
- fakeMediaRequestManagers,
1232
- config
1233
- );
1234
-
1235
- await remoteMediaManager.start();
1236
-
1237
- resetHistory();
1238
-
1239
- // switch the mock to now use csi2slotMappingAfterLayoutChange as we're about to change the layout
1240
- csi2slotMapping = csi2slotMappingAfterLayoutChange;
1241
-
1242
- // switch to "smallerLayout" layout that requires 2 less video slots and has 2 receive selected slots with same CSIs
1243
- await remoteMediaManager.setLayout('layoutWithDuplicateCSIs');
1244
-
1245
- // verify that the 2 member panes with duplicate CSI value of 456 have 2 separate receive slots allocated
1246
- assert.equal(csi2slotMappingAfterLayoutChange[456].length, 2);
1247
- assert.notEqual(
1248
- csi2slotMappingAfterLayoutChange[456][0],
1249
- csi2slotMappingAfterLayoutChange[456][1]
1250
- );
1251
-
1252
- // and that one of them is the same re-used slot from previous layout
1253
- assert.isTrue(
1254
- csi2slotMappingBeforeLayoutChange[456][0] === csi2slotMappingAfterLayoutChange[456][0] ||
1255
- csi2slotMappingBeforeLayoutChange[456][0] === csi2slotMappingAfterLayoutChange[456][1]
1256
- );
1257
-
1258
- // and the other panes have 1 slot each
1259
- assert.equal(csi2slotMappingAfterLayoutChange[123].length, 1);
1260
- assert.equal(csi2slotMappingAfterLayoutChange[789].length, 1);
1261
- });
1262
- });
1263
-
1264
- describe('media requests', () => {
1265
- it('sends correct media requests when switching to a layout with receiver selected slots', async () => {
1266
- const config = cloneDeep(DefaultTestConfiguration);
1267
-
1268
- config.video.layouts.Stage.memberVideoPanes = [
1269
- {id: 'stage-1', size: 'medium', csi: 11111},
1270
- {id: 'stage-2', size: 'medium', csi: 22222},
1271
- {id: 'stage-3', size: 'medium', csi: undefined},
1272
- {id: 'stage-4', size: 'medium', csi: undefined},
1273
- ];
1274
- remoteMediaManager = new RemoteMediaManager(
1275
- fakeReceiveSlotManager,
1276
- fakeMediaRequestManagers,
1277
- config
1278
- );
1279
-
1280
- await remoteMediaManager.start();
1281
-
1282
- resetHistory();
1283
-
1284
- // switch to "Stage" layout that has an active speaker group and 4 receiver selected slots
1285
- // and a CSI set on 2 of them
1286
- await remoteMediaManager.setLayout('Stage');
1287
-
1288
- assert.callCount(fakeMediaRequestManagers.video.addRequest, 3);
1289
- assert.calledWith(
1290
- fakeMediaRequestManagers.video.addRequest,
1291
- sinon.match({
1292
- policyInfo: sinon.match({
1293
- policy: 'active-speaker',
1294
- priority: 255,
1295
- }),
1296
- receiveSlots: Array(6).fill(fakeVideoSlot),
1297
- codecInfo: sinon.match({
1298
- codec: 'h264',
1299
- maxFs: 60,
1300
- }),
1301
- })
1302
- );
1303
- assert.calledWith(
1304
- fakeMediaRequestManagers.video.addRequest,
1305
- sinon.match({
1306
- policyInfo: sinon.match({
1307
- policy: 'receiver-selected',
1308
- csi: 11111,
1309
- }),
1310
- receiveSlots: Array(1).fill(fakeVideoSlot),
1311
- codecInfo: sinon.match({
1312
- codec: 'h264',
1313
- maxFs: 3600,
1314
- }),
1315
- })
1316
- );
1317
- assert.calledWith(
1318
- fakeMediaRequestManagers.video.addRequest,
1319
- sinon.match({
1320
- policyInfo: sinon.match({
1321
- policy: 'receiver-selected',
1322
- csi: 22222,
1323
- }),
1324
- receiveSlots: Array(1).fill(fakeVideoSlot),
1325
- codecInfo: sinon.match({
1326
- codec: 'h264',
1327
- maxFs: 3600,
1328
- }),
1329
- })
1330
- );
1331
- });
1332
-
1333
- it('sends correct media requests when switching to a layout with multiple active-speaker groups', async () => {
1334
- // start with "AllEqual" layout that needs just 9 video slots
1335
- const config = cloneDeep(DefaultTestConfiguration);
1336
-
1337
- config.video.initialLayoutId = 'AllEqual';
1338
-
1339
- remoteMediaManager = new RemoteMediaManager(
1340
- fakeReceiveSlotManager,
1341
- fakeMediaRequestManagers,
1342
- config
1343
- );
1344
-
1345
- const allEqualMediaRequestId = 'fake request id';
1346
-
1347
- fakeMediaRequestManagers.video.addRequest.returns(allEqualMediaRequestId);
1348
-
1349
- await remoteMediaManager.start();
1350
-
1351
- resetHistory();
1352
-
1353
- // switch to "OnePlusFive" layout that has 2 active speaker groups
1354
- await remoteMediaManager.setLayout('OnePlusFive');
1355
-
1356
- // check that the previous active speaker request for "AllEqual" group was cancelled
1357
- assert.calledOnce(fakeMediaRequestManagers.video.cancelRequest);
1358
- assert.calledWith(fakeMediaRequestManagers.video.cancelRequest, allEqualMediaRequestId);
1359
-
1360
- // check that 2 correct active speaker media requests were sent out
1361
- assert.callCount(fakeMediaRequestManagers.video.addRequest, 2);
1362
- assert.calledWith(
1363
- fakeMediaRequestManagers.video.addRequest,
1364
- sinon.match({
1365
- policyInfo: sinon.match({
1366
- policy: 'active-speaker',
1367
- priority: 255,
1368
- }),
1369
- receiveSlots: Array(1).fill(fakeVideoSlot),
1370
- codecInfo: sinon.match({
1371
- codec: 'h264',
1372
- maxFs: 8192,
1373
- }),
1374
- })
1375
- );
1376
- assert.calledWith(
1377
- fakeMediaRequestManagers.video.addRequest,
1378
- sinon.match({
1379
- policyInfo: sinon.match({
1380
- policy: 'active-speaker',
1381
- priority: 254,
1382
- }),
1383
- receiveSlots: Array(5).fill(fakeVideoSlot),
1384
- codecInfo: sinon.match({
1385
- codec: 'h264',
1386
- maxFs: 240,
1387
- }),
1388
- })
1389
- );
1390
- });
1391
-
1392
- it('cancels all media requests for the previous layout when switching to a new one', async () => {
1393
- // setup the initial layout to have screen share, active speaker groups and member video panes
1394
- const config: Configuration = {
1395
- audio: {
1396
- numOfActiveSpeakerStreams: 0,
1397
- numOfScreenShareStreams: 0,
1398
- },
1399
- video: {
1400
- preferLiveVideo: true,
1401
- initialLayoutId: 'initial',
1402
- layouts: {
1403
- initial: {
1404
- screenShareVideo: {size: 'best'},
1405
- activeSpeakerVideoPaneGroups: [
1406
- {
1407
- id: 'big',
1408
- numPanes: 10,
1409
- priority: 255,
1410
- size: 'large',
1411
- },
1412
- {
1413
- id: 'small',
1414
- numPanes: 3,
1415
- priority: 254,
1416
- size: 'medium',
1417
- },
1418
- ],
1419
- memberVideoPanes: [
1420
- {id: 'pane 1', size: 'best', csi: 123},
1421
- {id: 'pane 2', size: 'best', csi: 234},
1422
- ],
1423
- },
1424
- other: {},
1425
- },
1426
- },
1427
- };
1428
-
1429
- remoteMediaManager = new RemoteMediaManager(
1430
- fakeReceiveSlotManager,
1431
- fakeMediaRequestManagers,
1432
- config
1433
- );
1434
-
1435
- let activeSpeakerRequestCounter = 0;
1436
- let receiverSelectedRequestCounter = 0;
1437
-
1438
- // setup the mock for addRequest to return request ids that we want
1439
- fakeMediaRequestManagers.video.addRequest.callsFake((mediaRequest) => {
1440
- if (mediaRequest.policyInfo.policy === 'active-speaker') {
1441
- activeSpeakerRequestCounter += 1;
1442
-
1443
- return `active speaker request ${activeSpeakerRequestCounter}`;
1444
- }
1445
- receiverSelectedRequestCounter += 1;
1446
-
1447
- return `receiver selected request ${receiverSelectedRequestCounter}`;
1448
- });
1449
- // setup the mock for screen share addRequest - this one should be called just once
1450
- fakeMediaRequestManagers.screenShareVideo.addRequest.callsFake(() => {
1451
- return 'video screen share request id';
1452
- });
1453
-
1454
- await remoteMediaManager.start();
1455
-
1456
- assert.calledOnce(fakeMediaRequestManagers.screenShareVideo.addRequest);
1457
-
1458
- resetHistory();
1459
-
1460
- // switch to "other" layout
1461
- await remoteMediaManager.setLayout('other');
1462
-
1463
- // check that all the previous media requests for "initial" layout have been cancelled
1464
- assert.callCount(fakeMediaRequestManagers.video.cancelRequest, 4);
1465
- assert.calledWith(fakeMediaRequestManagers.video.cancelRequest, 'active speaker request 1');
1466
- assert.calledWith(fakeMediaRequestManagers.video.cancelRequest, 'active speaker request 2');
1467
- assert.calledWith(
1468
- fakeMediaRequestManagers.video.cancelRequest,
1469
- 'receiver selected request 1'
1470
- );
1471
- assert.calledWith(
1472
- fakeMediaRequestManagers.video.cancelRequest,
1473
- 'receiver selected request 2'
1474
- );
1475
- assert.calledOnce(fakeMediaRequestManagers.screenShareVideo.cancelRequest);
1476
- assert.calledWith(
1477
- fakeMediaRequestManagers.screenShareVideo.cancelRequest,
1478
- 'video screen share request id'
1479
- );
1480
-
1481
- // new layout has no videos, so no new requests should be sent out
1482
- assert.callCount(fakeMediaRequestManagers.video.addRequest, 0);
1483
- });
1484
-
1485
- it('sends media request for screen share if layout contains screen share', async () => {
1486
- const allEqualMediaRequestId = 'fake request id';
1487
-
1488
- fakeMediaRequestManagers.video.addRequest.returns(allEqualMediaRequestId);
1489
-
1490
- await remoteMediaManager.start();
1491
-
1492
- resetHistory();
1493
-
1494
- // switch to a layout that contains a screen share video pane
1495
- await remoteMediaManager.setLayout('ScreenShareView');
1496
-
1497
- // check that a correct active speaker media request for screen share has been sent out
1498
- assert.callCount(fakeMediaRequestManagers.screenShareVideo.addRequest, 1);
1499
- assert.calledWith(
1500
- fakeMediaRequestManagers.screenShareVideo.addRequest,
1501
- sinon.match({
1502
- policyInfo: sinon.match({
1503
- policy: 'active-speaker',
1504
- priority: 255,
1505
- }),
1506
- receiveSlots: [fakeScreenShareVideoSlot],
1507
- codecInfo: sinon.match({
1508
- codec: 'h264',
1509
- maxFs: 3600,
1510
- }),
1511
- })
1512
- );
1513
- });
1514
- });
1515
- });
1516
-
1517
- describe('setRemoteVideoCsi', () => {
1518
- it('sends correct media requests', async () => {
1519
- let currentLayoutInfo: VideoLayoutChangedEventData | null = null;
1520
-
1521
- await remoteMediaManager.start();
1522
-
1523
- remoteMediaManager.on(Event.VideoLayoutChanged, (layoutInfo: VideoLayoutChangedEventData) => {
1524
- currentLayoutInfo = layoutInfo;
1525
- });
1526
- // switch to "Stage" layout which has some receiver selected slots
1527
- await remoteMediaManager.setLayout('Stage');
1528
- resetHistory();
1529
-
1530
- assert.isNotNull(currentLayoutInfo);
1531
-
1532
- if (currentLayoutInfo) {
1533
- const fakeRequestId1 = 'fake request id 1';
1534
- const fakeRequestId2 = 'fake request id 2';
1535
-
1536
- fakeMediaRequestManagers.video.addRequest.returns(fakeRequestId1);
1537
-
1538
- remoteMediaManager.setRemoteVideoCsi(currentLayoutInfo.memberVideoPanes['stage-1'], 1001);
1539
-
1540
- // a new media request should have been sent out
1541
- assert.calledOnce(fakeMediaRequestManagers.video.addRequest);
1542
- assert.calledWith(
1543
- fakeMediaRequestManagers.video.addRequest,
1544
- sinon.match({
1545
- policyInfo: sinon.match({
1546
- policy: 'receiver-selected',
1547
- csi: 1001,
1548
- }),
1549
- receiveSlots: Array(1).fill(fakeVideoSlot),
1550
- codecInfo: sinon.match({
1551
- codec: 'h264',
1552
- maxFs: 3600,
1553
- }),
1554
- })
1555
- );
1556
- assert.notCalled(fakeMediaRequestManagers.video.cancelRequest);
1557
-
1558
- resetHistory();
1559
-
1560
- // change the same video pane again
1561
- remoteMediaManager.setRemoteVideoCsi(currentLayoutInfo.memberVideoPanes['stage-1'], 1002);
1562
-
1563
- // a new media request should have been sent out
1564
- assert.calledOnce(fakeMediaRequestManagers.video.addRequest);
1565
- assert.calledWith(
1566
- fakeMediaRequestManagers.video.addRequest,
1567
- sinon.match({
1568
- policyInfo: sinon.match({
1569
- policy: 'receiver-selected',
1570
- csi: 1002,
1571
- }),
1572
- receiveSlots: Array(1).fill(fakeVideoSlot),
1573
- codecInfo: sinon.match({
1574
- codec: 'h264',
1575
- maxFs: 3600,
1576
- }),
1577
- })
1578
- );
1579
- // and previous one should have been cancelled
1580
- assert.calledOnce(fakeMediaRequestManagers.video.cancelRequest);
1581
- assert.calledWith(fakeMediaRequestManagers.video.cancelRequest, fakeRequestId1);
1582
-
1583
- resetHistory();
1584
-
1585
- fakeMediaRequestManagers.video.addRequest.returns(fakeRequestId2);
1586
-
1587
- // now change some other video pane
1588
- remoteMediaManager.setRemoteVideoCsi(currentLayoutInfo.memberVideoPanes['stage-3'], 2001);
1589
-
1590
- // a new media request should have been sent out
1591
- assert.calledOnce(fakeMediaRequestManagers.video.addRequest);
1592
- assert.calledWith(
1593
- fakeMediaRequestManagers.video.addRequest,
1594
- sinon.match({
1595
- policyInfo: sinon.match({
1596
- policy: 'receiver-selected',
1597
- csi: 2001,
1598
- }),
1599
- receiveSlots: Array(1).fill(fakeVideoSlot),
1600
- codecInfo: sinon.match({
1601
- codec: 'h264',
1602
- maxFs: 3600,
1603
- }),
1604
- })
1605
- );
1606
- // nothing should have been cancelled
1607
- assert.notCalled(fakeMediaRequestManagers.video.cancelRequest);
1608
-
1609
- resetHistory();
1610
-
1611
- // now set CSI back to undefined
1612
- remoteMediaManager.setRemoteVideoCsi(
1613
- currentLayoutInfo.memberVideoPanes['stage-3'],
1614
- undefined
1615
- );
1616
-
1617
- // no new media request should have been sent out
1618
- assert.notCalled(fakeMediaRequestManagers.video.addRequest);
1619
- // and previous one should have been cancelled
1620
- assert.calledOnce(fakeMediaRequestManagers.video.cancelRequest);
1621
- assert.calledWith(fakeMediaRequestManagers.video.cancelRequest, fakeRequestId2);
1622
- }
1623
- });
1624
- });
1625
-
1626
- describe('addMemberVideoPane()', () => {
1627
- it('fails if there is no current layout', () => {
1628
- // we haven't called start() so there is no layout set, yet
1629
- assert.isRejected(
1630
- remoteMediaManager.addMemberVideoPane({id: 'newPane', size: 'best', csi: 54321})
1631
- );
1632
- });
1633
-
1634
- it('fails if called with a duplicate paneId', async () => {
1635
- await remoteMediaManager.start();
1636
- await remoteMediaManager.setLayout('Stage');
1637
-
1638
- assert.isRejected(
1639
- remoteMediaManager.addMemberVideoPane({id: 'stage-3', size: 'best', csi: 54321})
1640
- );
1641
- });
1642
-
1643
- it('works as expected when called with a CSI value', async () => {
1644
- await remoteMediaManager.start();
1645
- await remoteMediaManager.setLayout('Stage');
1646
-
1647
- resetHistory();
1648
-
1649
- await remoteMediaManager.addMemberVideoPane({id: 'newPane', size: 'best', csi: 54321});
1650
-
1651
- // new slot should be allocated
1652
- assert.calledOnce(fakeReceiveSlotManager.allocateSlot);
1653
- assert.calledWith(fakeReceiveSlotManager.allocateSlot, MediaType.VideoMain);
1654
-
1655
- // and a media request sent out
1656
- assert.calledOnce(fakeMediaRequestManagers.video.addRequest);
1657
- assert.calledWith(
1658
- fakeMediaRequestManagers.video.addRequest,
1659
- sinon.match({
1660
- policyInfo: sinon.match({
1661
- policy: 'receiver-selected',
1662
- csi: 54321,
1663
- }),
1664
- receiveSlots: Array(1).fill(fakeVideoSlot),
1665
- codecInfo: sinon.match({
1666
- codec: 'h264',
1667
- maxFs: 8192,
1668
- }),
1669
- })
1670
- );
1671
- });
1672
- it('works as expected when called without a CSI value', async () => {
1673
- await remoteMediaManager.start();
1674
- await remoteMediaManager.setLayout('Stage');
1675
-
1676
- resetHistory();
1677
-
1678
- await remoteMediaManager.addMemberVideoPane({id: 'newPane', size: 'best'});
1679
-
1680
- // new slot should be allocated
1681
- assert.calledOnce(fakeReceiveSlotManager.allocateSlot);
1682
- assert.calledWith(fakeReceiveSlotManager.allocateSlot, MediaType.VideoMain);
1683
-
1684
- // but no media requests sent out
1685
- assert.notCalled(fakeMediaRequestManagers.video.addRequest);
1686
- });
1687
- });
1688
-
1689
- describe('removeMemberVideoPane()', () => {
1690
- it('fails if there is no current layout', () => {
1691
- // we haven't called start() so there is no layout set, yet
1692
- assert.isRejected(remoteMediaManager.removeMemberVideoPane('newPane'));
1693
- });
1694
-
1695
- it('does nothing when called for a pane not in the current layout', async () => {
1696
- await remoteMediaManager.start();
1697
- await remoteMediaManager.setLayout('Stage');
1698
-
1699
- resetHistory();
1700
-
1701
- await remoteMediaManager.removeMemberVideoPane('some pane');
1702
-
1703
- assert.notCalled(fakeReceiveSlotManager.releaseSlot);
1704
- assert.notCalled(fakeMediaRequestManagers.video.cancelRequest);
1705
- });
1706
-
1707
- it('works as expected', async () => {
1708
- await remoteMediaManager.start();
1709
- await remoteMediaManager.setLayout('Stage');
1710
-
1711
- const fakeNewSlot = new FakeSlot(MediaType.VideoMain, 'fake video slot');
1712
- const fakeRequestId = 'fake request id';
1713
-
1714
- fakeReceiveSlotManager.allocateSlot.resolves(fakeNewSlot);
1715
- fakeMediaRequestManagers.video.addRequest.returns(fakeRequestId);
1716
-
1717
- // first, add some pane
1718
- await remoteMediaManager.addMemberVideoPane({id: 'newPane', size: 'best', csi: 54321});
1719
-
1720
- resetHistory();
1721
-
1722
- // now remove it
1723
- await remoteMediaManager.removeMemberVideoPane('newPane');
1724
-
1725
- // slot should be released
1726
- assert.calledOnce(fakeReceiveSlotManager.releaseSlot);
1727
- assert.calledWith(fakeReceiveSlotManager.releaseSlot, fakeNewSlot);
1728
-
1729
- // and a media request cancelled
1730
- assert.calledOnce(fakeMediaRequestManagers.video.cancelRequest);
1731
- assert.calledWith(fakeMediaRequestManagers.video.cancelRequest, fakeRequestId);
1732
- });
1733
- });
1734
-
1735
- describe('setActiveSpeakerCsis', () => {
1736
- it('calls setActiveSpeakerCsis on the correct remote media group', async () => {
1737
- let currentLayoutInfo: VideoLayoutChangedEventData | null = null;
1738
- let setCsisStub;
1739
-
1740
- remoteMediaManager.on(Event.VideoLayoutChanged, (layoutInfo: VideoLayoutChangedEventData) => {
1741
- currentLayoutInfo = layoutInfo;
1742
- setCsisStub = sinon.stub(layoutInfo.activeSpeakerVideoPanes.main, 'setActiveSpeakerCsis');
1743
- });
1744
-
1745
- await remoteMediaManager.start();
1746
- resetHistory();
1747
-
1748
- assert.isNotNull(currentLayoutInfo);
1749
-
1750
- if (currentLayoutInfo) {
1751
- const remoteVideo = currentLayoutInfo.activeSpeakerVideoPanes.main.getRemoteMedia()[0];
1752
-
1753
- remoteMediaManager.setActiveSpeakerCsis([{remoteMedia: remoteVideo}]);
1754
-
1755
- assert.calledOnce(setCsisStub);
1756
- assert.calledWith(setCsisStub, [{remoteMedia: remoteVideo}], false);
1757
- assert.calledOnce(fakeMediaRequestManagers.video.commit);
1758
- }
1759
- });
1760
-
1761
- it('does not call setActiveSpeakerCsis on the incorrect media group', async () => {
1762
- let currentLayoutInfo: VideoLayoutChangedEventData | null = null;
1763
- let setCsisStub;
1764
-
1765
- remoteMediaManager.on(Event.VideoLayoutChanged, (layoutInfo: VideoLayoutChangedEventData) => {
1766
- currentLayoutInfo = layoutInfo;
1767
- setCsisStub = sinon.stub(layoutInfo.activeSpeakerVideoPanes.main, 'setActiveSpeakerCsis');
1768
- });
1769
-
1770
- await remoteMediaManager.start();
1771
- resetHistory();
1772
-
1773
- assert.isNotNull(currentLayoutInfo);
1774
-
1775
- if (currentLayoutInfo) {
1776
- remoteMediaManager.setActiveSpeakerCsis([{remoteMedia: {}}]);
1777
-
1778
- assert.notCalled(setCsisStub);
1779
- assert.calledOnce(fakeMediaRequestManagers.video.commit);
1780
- }
1781
- });
1782
-
1783
- it('checking when there is more than one group', async () => {
1784
- let currentLayoutInfo: VideoLayoutChangedEventData | null = null;
1785
- const config = cloneDeep(DefaultTestConfiguration);
1786
- let stubs = [];
1787
-
1788
- config.video.initialLayoutId = 'OnePlusFive';
1789
-
1790
- remoteMediaManager = new RemoteMediaManager(
1791
- fakeReceiveSlotManager,
1792
- fakeMediaRequestManagers,
1793
- config
1794
- );
1795
-
1796
- remoteMediaManager.on(Event.VideoLayoutChanged, (layoutInfo: VideoLayoutChangedEventData) => {
1797
- currentLayoutInfo = layoutInfo;
1798
- Object.values(layoutInfo.activeSpeakerVideoPanes).forEach((group) => stubs.push(sinon.stub(group, 'setActiveSpeakerCsis')));
1799
- });
1800
-
1801
- await remoteMediaManager.start();
1802
- resetHistory();
1803
-
1804
- assert.isNotNull(currentLayoutInfo);
1805
-
1806
- if (currentLayoutInfo) {
1807
-
1808
- const remoteMedia1 = currentLayoutInfo.activeSpeakerVideoPanes.mainBigOne.getRemoteMedia()[0];
1809
- const remoteMedia2 = currentLayoutInfo.activeSpeakerVideoPanes.secondarySetOfSmallPanes.getRemoteMedia()[0];
1810
-
1811
- const remoteMediaCsis = [{remoteMedia: remoteMedia1}, {remoteMedia: remoteMedia2}];
1812
-
1813
- remoteMediaManager.setActiveSpeakerCsis([{remoteMedia: remoteMedia1}, {remoteMedia: remoteMedia2}]);
1814
-
1815
- stubs.forEach((stub, index) => {
1816
- assert.calledWith(stub, [remoteMediaCsis[index]], false)
1817
- });
1818
- assert.calledOnce(fakeMediaRequestManagers.video.commit);
1819
- }
1820
- });
1821
- });
1822
-
1823
- describe('pinActiveSpeakerVideoPane() and isPinned()', () => {
1824
- it('throws if called on a pane not belonging to an active speaker group', async () => {
1825
- let currentLayoutInfo: VideoLayoutChangedEventData | null = null;
1826
-
1827
- remoteMediaManager.on(Event.VideoLayoutChanged, (layoutInfo: VideoLayoutChangedEventData) => {
1828
- currentLayoutInfo = layoutInfo;
1829
- });
1830
-
1831
- await remoteMediaManager.start();
1832
- await remoteMediaManager.setLayout('Stage');
1833
-
1834
- assert.isNotNull(currentLayoutInfo);
1835
-
1836
- if (currentLayoutInfo) {
1837
- const remoteVideo = currentLayoutInfo.memberVideoPanes['stage-1'];
1838
-
1839
- assert.throws(() => remoteMediaManager.pinActiveSpeakerVideoPane(remoteVideo));
1840
- assert.throws(() => remoteMediaManager.isPinned(remoteVideo));
1841
- }
1842
- });
1843
-
1844
- it('calls pin()/isPinned() on the correct remote media group', async () => {
1845
- let currentLayoutInfo: VideoLayoutChangedEventData | null = null;
1846
- let pinStub;
1847
- let isPinnedStub;
1848
-
1849
- remoteMediaManager.on(Event.VideoLayoutChanged, (layoutInfo: VideoLayoutChangedEventData) => {
1850
- currentLayoutInfo = layoutInfo;
1851
- pinStub = sinon.stub(layoutInfo.activeSpeakerVideoPanes.main, 'pin');
1852
- isPinnedStub = sinon.stub(layoutInfo.activeSpeakerVideoPanes.main, 'isPinned');
1853
- });
1854
-
1855
- await remoteMediaManager.start();
1856
-
1857
- assert.isNotNull(currentLayoutInfo);
1858
-
1859
- if (currentLayoutInfo) {
1860
- const remoteVideo = currentLayoutInfo.activeSpeakerVideoPanes.main.getRemoteMedia()[0];
1861
-
1862
- // first test pinActiveSpeakerVideoPane()
1863
- remoteMediaManager.pinActiveSpeakerVideoPane(remoteVideo);
1864
-
1865
- assert.calledOnce(pinStub);
1866
- assert.calledWith(pinStub, remoteVideo, undefined);
1867
-
1868
- // now test isPinned()
1869
- remoteMediaManager.isPinned(remoteVideo);
1870
-
1871
- assert.calledOnce(isPinnedStub);
1872
- assert.calledWith(isPinnedStub, remoteVideo);
1873
- }
1874
- });
1875
- });
1876
-
1877
- describe('unpinActiveSpeakerVideoPane', () => {
1878
- it('throws if called on a remote media instance that was not pinned', async () => {
1879
- let currentLayoutInfo: VideoLayoutChangedEventData | null = null;
1880
-
1881
- remoteMediaManager.on(Event.VideoLayoutChanged, (layoutInfo: VideoLayoutChangedEventData) => {
1882
- currentLayoutInfo = layoutInfo;
1883
- });
1884
-
1885
- await remoteMediaManager.start();
1886
-
1887
- assert.isNotNull(currentLayoutInfo);
1888
-
1889
- if (currentLayoutInfo) {
1890
- const remoteVideoToUnPin =
1891
- currentLayoutInfo.activeSpeakerVideoPanes.main.getRemoteMedia('unpinned')[0];
1892
-
1893
- assert.throws(() => remoteMediaManager.unpinActiveSpeakerVideoPane(remoteVideoToUnPin));
1894
- }
1895
- });
1896
-
1897
- it('calls unpin() on the correct remote media group', async () => {
1898
- let currentLayoutInfo: VideoLayoutChangedEventData | null = null;
1899
- let unpinStub;
1900
-
1901
- remoteMediaManager.on(Event.VideoLayoutChanged, (layoutInfo: VideoLayoutChangedEventData) => {
1902
- currentLayoutInfo = layoutInfo;
1903
- unpinStub = sinon.stub(layoutInfo.activeSpeakerVideoPanes.main, 'unpin');
1904
- });
1905
-
1906
- await remoteMediaManager.start();
1907
-
1908
- assert.isNotNull(currentLayoutInfo);
1909
-
1910
- if (currentLayoutInfo) {
1911
- const remoteVideo = currentLayoutInfo.activeSpeakerVideoPanes.main.getRemoteMedia()[0];
1912
-
1913
- // first we need to pin it
1914
- remoteMediaManager.pinActiveSpeakerVideoPane(remoteVideo, 99999);
1915
-
1916
- // now we can unpin it
1917
- remoteMediaManager.unpinActiveSpeakerVideoPane(remoteVideo);
1918
-
1919
- assert.calledOnce(unpinStub);
1920
- assert.calledWith(unpinStub, remoteVideo);
1921
- }
1922
- });
1923
- });
1924
- });