@webex/plugin-meetings 3.0.0-beta.1 → 3.0.0-beta.11

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 (281) hide show
  1. package/dist/common/browser-detection.js.map +1 -1
  2. package/dist/common/collection.js.map +1 -1
  3. package/dist/common/config.js.map +1 -1
  4. package/dist/common/errors/captcha-error.js +7 -0
  5. package/dist/common/errors/captcha-error.js.map +1 -1
  6. package/dist/common/errors/intent-to-join.js +8 -0
  7. package/dist/common/errors/intent-to-join.js.map +1 -1
  8. package/dist/common/errors/join-meeting.js +8 -0
  9. package/dist/common/errors/join-meeting.js.map +1 -1
  10. package/dist/common/errors/media.js +7 -0
  11. package/dist/common/errors/media.js.map +1 -1
  12. package/dist/common/errors/parameter.js.map +1 -1
  13. package/dist/common/errors/password-error.js +7 -0
  14. package/dist/common/errors/password-error.js.map +1 -1
  15. package/dist/common/errors/permission.js +7 -0
  16. package/dist/common/errors/permission.js.map +1 -1
  17. package/dist/common/errors/reconnection-in-progress.js.map +1 -1
  18. package/dist/common/errors/reconnection.js +7 -0
  19. package/dist/common/errors/reconnection.js.map +1 -1
  20. package/dist/common/errors/stats.js +7 -0
  21. package/dist/common/errors/stats.js.map +1 -1
  22. package/dist/common/errors/webex-errors.js +5 -29
  23. package/dist/common/errors/webex-errors.js.map +1 -1
  24. package/dist/common/errors/webex-meetings-error.js +5 -2
  25. package/dist/common/errors/webex-meetings-error.js.map +1 -1
  26. package/dist/common/events/events-scope.js.map +1 -1
  27. package/dist/common/events/events.js.map +1 -1
  28. package/dist/common/events/trigger-proxy.js.map +1 -1
  29. package/dist/common/events/util.js.map +1 -1
  30. package/dist/common/logs/logger-config.js.map +1 -1
  31. package/dist/common/logs/logger-proxy.js.map +1 -1
  32. package/dist/common/logs/request.js +3 -0
  33. package/dist/common/logs/request.js.map +1 -1
  34. package/dist/common/queue.js.map +1 -1
  35. package/dist/config.js +1 -0
  36. package/dist/config.js.map +1 -1
  37. package/dist/constants.js +15 -74
  38. package/dist/constants.js.map +1 -1
  39. package/dist/locus-info/controlsUtils.js.map +1 -1
  40. package/dist/locus-info/embeddedAppsUtils.js.map +1 -1
  41. package/dist/locus-info/fullState.js.map +1 -1
  42. package/dist/locus-info/hostUtils.js.map +1 -1
  43. package/dist/locus-info/index.js +43 -5
  44. package/dist/locus-info/index.js.map +1 -1
  45. package/dist/locus-info/infoUtils.js +4 -0
  46. package/dist/locus-info/infoUtils.js.map +1 -1
  47. package/dist/locus-info/mediaSharesUtils.js.map +1 -1
  48. package/dist/locus-info/parser.js +12 -3
  49. package/dist/locus-info/parser.js.map +1 -1
  50. package/dist/locus-info/selfUtils.js.map +1 -1
  51. package/dist/media/index.js +71 -210
  52. package/dist/media/index.js.map +1 -1
  53. package/dist/media/internal-media-core-wrapper.js +22 -0
  54. package/dist/media/internal-media-core-wrapper.js.map +1 -0
  55. package/dist/media/properties.js +32 -25
  56. package/dist/media/properties.js.map +1 -1
  57. package/dist/media/util.js +0 -27
  58. package/dist/media/util.js.map +1 -1
  59. package/dist/mediaQualityMetrics/config.js.map +1 -1
  60. package/dist/meeting/effectsState.js +8 -1
  61. package/dist/meeting/effectsState.js.map +1 -1
  62. package/dist/meeting/index.js +1146 -602
  63. package/dist/meeting/index.js.map +1 -1
  64. package/dist/meeting/muteState.js +6 -0
  65. package/dist/meeting/muteState.js.map +1 -1
  66. package/dist/meeting/request.js +83 -24
  67. package/dist/meeting/request.js.map +1 -1
  68. package/dist/meeting/state.js.map +1 -1
  69. package/dist/meeting/util.js +5 -44
  70. package/dist/meeting/util.js.map +1 -1
  71. package/dist/meeting-info/collection.js +4 -1
  72. package/dist/meeting-info/collection.js.map +1 -1
  73. package/dist/meeting-info/index.js +5 -0
  74. package/dist/meeting-info/index.js.map +1 -1
  75. package/dist/meeting-info/meeting-info-v2.js +14 -2
  76. package/dist/meeting-info/meeting-info-v2.js.map +1 -1
  77. package/dist/meeting-info/request.js +3 -0
  78. package/dist/meeting-info/request.js.map +1 -1
  79. package/dist/meeting-info/util.js.map +1 -1
  80. package/dist/meeting-info/utilv2.js.map +1 -1
  81. package/dist/meetings/collection.js +4 -1
  82. package/dist/meetings/collection.js.map +1 -1
  83. package/dist/meetings/index.js +136 -25
  84. package/dist/meetings/index.js.map +1 -1
  85. package/dist/meetings/request.js +4 -0
  86. package/dist/meetings/request.js.map +1 -1
  87. package/dist/meetings/util.js +24 -1
  88. package/dist/meetings/util.js.map +1 -1
  89. package/dist/member/index.js +30 -7
  90. package/dist/member/index.js.map +1 -1
  91. package/dist/member/util.js +2 -1
  92. package/dist/member/util.js.map +1 -1
  93. package/dist/members/collection.js +1 -0
  94. package/dist/members/collection.js.map +1 -1
  95. package/dist/members/index.js +82 -1
  96. package/dist/members/index.js.map +1 -1
  97. package/dist/members/request.js +19 -9
  98. package/dist/members/request.js.map +1 -1
  99. package/dist/members/util.js.map +1 -1
  100. package/dist/metrics/config.js.map +1 -1
  101. package/dist/metrics/constants.js.map +1 -1
  102. package/dist/metrics/index.js +8 -0
  103. package/dist/metrics/index.js.map +1 -1
  104. package/dist/multistream/mediaRequestManager.js +133 -0
  105. package/dist/multistream/mediaRequestManager.js.map +1 -0
  106. package/dist/multistream/multistreamMedia.js +116 -0
  107. package/dist/multistream/multistreamMedia.js.map +1 -0
  108. package/dist/multistream/receiveSlot.js +209 -0
  109. package/dist/multistream/receiveSlot.js.map +1 -0
  110. package/dist/multistream/receiveSlotManager.js +195 -0
  111. package/dist/multistream/receiveSlotManager.js.map +1 -0
  112. package/dist/multistream/remoteMedia.js +289 -0
  113. package/dist/multistream/remoteMedia.js.map +1 -0
  114. package/dist/multistream/remoteMediaGroup.js +243 -0
  115. package/dist/multistream/remoteMediaGroup.js.map +1 -0
  116. package/dist/multistream/remoteMediaManager.js +1113 -0
  117. package/dist/multistream/remoteMediaManager.js.map +1 -0
  118. package/dist/networkQualityMonitor/index.js +10 -2
  119. package/dist/networkQualityMonitor/index.js.map +1 -1
  120. package/dist/personal-meeting-room/index.js +11 -0
  121. package/dist/personal-meeting-room/index.js.map +1 -1
  122. package/dist/personal-meeting-room/request.js +2 -1
  123. package/dist/personal-meeting-room/request.js.map +1 -1
  124. package/dist/personal-meeting-room/util.js.map +1 -1
  125. package/dist/reachability/index.js +17 -7
  126. package/dist/reachability/index.js.map +1 -1
  127. package/dist/reachability/request.js +1 -0
  128. package/dist/reachability/request.js.map +1 -1
  129. package/dist/reactions/reactions.js +111 -0
  130. package/dist/reactions/reactions.js.map +1 -0
  131. package/dist/reactions/reactions.type.js +40 -0
  132. package/dist/reactions/reactions.type.js.map +1 -0
  133. package/dist/reconnection-manager/index.js +130 -132
  134. package/dist/reconnection-manager/index.js.map +1 -1
  135. package/dist/roap/index.js +58 -231
  136. package/dist/roap/index.js.map +1 -1
  137. package/dist/roap/request.js +7 -116
  138. package/dist/roap/request.js.map +1 -1
  139. package/dist/roap/turnDiscovery.js +20 -6
  140. package/dist/roap/turnDiscovery.js.map +1 -1
  141. package/dist/statsAnalyzer/global.js +2 -0
  142. package/dist/statsAnalyzer/global.js.map +1 -1
  143. package/dist/statsAnalyzer/index.js +58 -37
  144. package/dist/statsAnalyzer/index.js.map +1 -1
  145. package/dist/statsAnalyzer/mqaUtil.js +9 -3
  146. package/dist/statsAnalyzer/mqaUtil.js.map +1 -1
  147. package/dist/transcription/index.js +10 -3
  148. package/dist/transcription/index.js.map +1 -1
  149. package/package.json +21 -20
  150. package/src/common/{browser-detection.js → browser-detection.ts} +1 -1
  151. package/src/common/collection.ts +6 -6
  152. package/src/common/{config.js → config.ts} +1 -1
  153. package/src/common/errors/{captcha-error.js → captcha-error.ts} +5 -1
  154. package/src/common/errors/{intent-to-join.js → intent-to-join.ts} +6 -1
  155. package/src/common/errors/{join-meeting.js → join-meeting.ts} +6 -1
  156. package/src/common/errors/{media.js → media.ts} +5 -1
  157. package/src/common/errors/parameter.ts +3 -2
  158. package/src/common/errors/{password-error.js → password-error.ts} +5 -1
  159. package/src/common/errors/{permission.js → permission.ts} +5 -1
  160. package/src/common/errors/{reconnection-in-progress.js → reconnection-in-progress.ts} +0 -0
  161. package/src/common/errors/{reconnection.js → reconnection.ts} +5 -1
  162. package/src/common/errors/{stats.js → stats.ts} +5 -1
  163. package/src/common/errors/{webex-errors.js → webex-errors.ts} +1 -20
  164. package/src/common/errors/{webex-meetings-error.js → webex-meetings-error.ts} +3 -1
  165. package/src/common/events/{events-scope.js → events-scope.ts} +1 -1
  166. package/src/common/events/{events.js → events.ts} +0 -0
  167. package/src/common/events/{trigger-proxy.js → trigger-proxy.ts} +1 -2
  168. package/src/common/events/{util.js → util.ts} +1 -1
  169. package/src/common/logs/{logger-config.js → logger-config.ts} +1 -2
  170. package/src/common/logs/{logger-proxy.js → logger-proxy.ts} +1 -1
  171. package/src/common/logs/{request.js → request.ts} +12 -2
  172. package/src/common/queue.ts +1 -2
  173. package/src/{config.js → config.ts} +2 -0
  174. package/src/constants.ts +139 -179
  175. package/src/locus-info/{controlsUtils.js → controlsUtils.ts} +4 -4
  176. package/src/locus-info/{embeddedAppsUtils.js → embeddedAppsUtils.ts} +5 -6
  177. package/src/locus-info/{fullState.js → fullState.ts} +1 -1
  178. package/src/locus-info/{hostUtils.js → hostUtils.ts} +5 -5
  179. package/src/locus-info/{index.js → index.ts} +67 -32
  180. package/src/locus-info/{infoUtils.js → infoUtils.ts} +7 -4
  181. package/src/locus-info/{mediaSharesUtils.js → mediaSharesUtils.ts} +13 -13
  182. package/src/locus-info/{parser.js → parser.ts} +22 -12
  183. package/src/locus-info/{selfUtils.js → selfUtils.ts} +17 -19
  184. package/src/media/{index.js → index.ts} +130 -205
  185. package/src/media/internal-media-core-wrapper.ts +9 -0
  186. package/src/media/{properties.js → properties.ts} +35 -29
  187. package/src/media/util.ts +16 -0
  188. package/src/mediaQualityMetrics/{config.js → config.ts} +1 -1
  189. package/src/meeting/{effectsState.js → effectsState.ts} +12 -6
  190. package/src/meeting/{index.js → index.ts} +993 -474
  191. package/src/meeting/{muteState.js → muteState.ts} +16 -11
  192. package/src/meeting/{request.js → request.ts} +148 -36
  193. package/src/meeting/{state.js → state.ts} +6 -6
  194. package/src/meeting/{util.js → util.ts} +9 -51
  195. package/src/meeting-info/{collection.js → collection.ts} +4 -1
  196. package/src/meeting-info/{index.js → index.ts} +10 -6
  197. package/src/meeting-info/{meeting-info-v2.js → meeting-info-v2.ts} +28 -10
  198. package/src/meeting-info/{request.js → request.ts} +6 -2
  199. package/src/meeting-info/{util.js → util.ts} +6 -5
  200. package/src/meeting-info/{utilv2.js → utilv2.ts} +8 -7
  201. package/src/meetings/{collection.js → collection.ts} +5 -2
  202. package/src/meetings/{index.js → index.ts} +118 -22
  203. package/src/meetings/{request.js → request.ts} +6 -1
  204. package/src/meetings/{util.js → util.ts} +28 -5
  205. package/src/member/{index.js → index.ts} +46 -15
  206. package/src/member/{util.js → util.ts} +17 -16
  207. package/src/members/{collection.js → collection.ts} +2 -1
  208. package/src/members/{index.js → index.ts} +94 -26
  209. package/src/members/{request.js → request.ts} +16 -5
  210. package/src/members/{util.js → util.ts} +7 -7
  211. package/src/metrics/{config.js → config.ts} +0 -2
  212. package/src/metrics/{constants.js → constants.ts} +0 -0
  213. package/src/metrics/{index.js → index.ts} +27 -8
  214. package/src/multistream/mediaRequestManager.ts +166 -0
  215. package/src/multistream/multistreamMedia.ts +92 -0
  216. package/src/multistream/receiveSlot.ts +141 -0
  217. package/src/multistream/receiveSlotManager.ts +142 -0
  218. package/src/multistream/remoteMedia.ts +228 -0
  219. package/src/multistream/remoteMediaGroup.ts +224 -0
  220. package/src/multistream/remoteMediaManager.ts +911 -0
  221. package/src/networkQualityMonitor/{index.js → index.ts} +18 -3
  222. package/src/personal-meeting-room/{index.js → index.ts} +17 -4
  223. package/src/personal-meeting-room/{request.js → request.ts} +3 -1
  224. package/src/personal-meeting-room/{util.js → util.ts} +1 -1
  225. package/src/reachability/{index.js → index.ts} +28 -17
  226. package/src/reachability/request.ts +4 -2
  227. package/src/reactions/reactions.ts +104 -0
  228. package/src/reactions/reactions.type.ts +36 -0
  229. package/src/reconnection-manager/{index.js → index.ts} +81 -65
  230. package/src/roap/index.ts +229 -0
  231. package/src/roap/{request.js → request.ts} +15 -74
  232. package/src/roap/turnDiscovery.ts +26 -11
  233. package/src/statsAnalyzer/{global.js → global.ts} +2 -0
  234. package/src/statsAnalyzer/{index.js → index.ts} +66 -61
  235. package/src/statsAnalyzer/{mqaUtil.js → mqaUtil.ts} +6 -1
  236. package/src/transcription/{index.js → index.ts} +16 -11
  237. package/test/integration/spec/journey.js +1 -1
  238. package/test/integration/spec/space-meeting.js +1 -2
  239. package/test/unit/spec/locus-info/infoUtils.js +17 -1
  240. package/test/unit/spec/media/index.ts +207 -0
  241. package/test/unit/spec/media/properties.ts +73 -82
  242. package/test/unit/spec/meeting/effectsState.js +1 -3
  243. package/test/unit/spec/meeting/index.js +672 -245
  244. package/test/unit/spec/meeting/muteState.js +7 -0
  245. package/test/unit/spec/meeting/request.js +25 -1
  246. package/test/unit/spec/meeting/utils.js +63 -2
  247. package/test/unit/spec/meetings/index.js +0 -4
  248. package/test/unit/spec/members/index.js +164 -2
  249. package/test/unit/spec/multistream/mediaRequestManager.ts +515 -0
  250. package/test/unit/spec/multistream/receiveSlot.ts +104 -0
  251. package/test/unit/spec/multistream/receiveSlotManager.ts +173 -0
  252. package/test/unit/spec/multistream/remoteMedia.ts +225 -0
  253. package/test/unit/spec/multistream/remoteMediaGroup.ts +396 -0
  254. package/test/unit/spec/multistream/remoteMediaManager.ts +1309 -0
  255. package/test/unit/spec/reconnection-manager/index.js +68 -2
  256. package/test/unit/spec/roap/index.ts +63 -35
  257. package/test/unit/spec/stats-analyzer/index.js +19 -22
  258. package/dist/peer-connection-manager/index.js +0 -794
  259. package/dist/peer-connection-manager/index.js.map +0 -1
  260. package/dist/peer-connection-manager/util.js +0 -124
  261. package/dist/peer-connection-manager/util.js.map +0 -1
  262. package/dist/roap/collection.js +0 -73
  263. package/dist/roap/collection.js.map +0 -1
  264. package/dist/roap/handler.js +0 -337
  265. package/dist/roap/handler.js.map +0 -1
  266. package/dist/roap/state.js +0 -164
  267. package/dist/roap/state.js.map +0 -1
  268. package/dist/roap/util.js +0 -102
  269. package/dist/roap/util.js.map +0 -1
  270. package/src/media/util.js +0 -38
  271. package/src/peer-connection-manager/index.js +0 -723
  272. package/src/peer-connection-manager/util.ts +0 -117
  273. package/src/roap/collection.js +0 -63
  274. package/src/roap/handler.js +0 -252
  275. package/src/roap/index.js +0 -380
  276. package/src/roap/state.js +0 -149
  277. package/src/roap/util.js +0 -93
  278. package/test/unit/spec/peerconnection-manager/index.js +0 -188
  279. package/test/unit/spec/peerconnection-manager/utils.js +0 -48
  280. package/test/unit/spec/peerconnection-manager/utils.test-fixtures.ts +0 -389
  281. package/test/unit/spec/roap/util.js +0 -30
@@ -0,0 +1,396 @@
1
+ import EventEmitter from 'events';
2
+
3
+ import {MediaConnection as MC} from '@webex/internal-media-core';
4
+ import {RemoteMediaGroup} from '@webex/plugin-meetings/src/multistream/remoteMediaGroup';
5
+ import {RemoteMedia} from '@webex/plugin-meetings/src/multistream/remoteMedia';
6
+ import {ReceiveSlot} from '@webex/plugin-meetings/src/multistream/receiveSlot';
7
+ import sinon from 'sinon';
8
+ import {assert} from '@webex/test-helper-chai';
9
+
10
+ class FakeSlot extends EventEmitter {
11
+ public mediaType: MC.MediaType;
12
+
13
+ public id: string;
14
+
15
+ constructor(mediaType: MC.MediaType, id: string) {
16
+ super();
17
+ this.mediaType = mediaType;
18
+ this.id = id;
19
+ }
20
+ }
21
+
22
+ describe('RemoteMediaGroup', () => {
23
+ const NUM_SLOTS = 10;
24
+
25
+ let fakeMediaRequestManager;
26
+ let fakeReceiveSlots;
27
+
28
+ let activeSpeakerRequestCounter;
29
+ let receiverSelectedRequestCounter;
30
+
31
+ beforeEach(() => {
32
+ activeSpeakerRequestCounter = 0;
33
+ receiverSelectedRequestCounter = 0;
34
+
35
+ fakeMediaRequestManager = {
36
+ addRequest: sinon.stub().callsFake((mediaRequest) => {
37
+ if (mediaRequest.policyInfo.policy === 'active-speaker') {
38
+ activeSpeakerRequestCounter += 1;
39
+
40
+ return `fake active speaker request ${activeSpeakerRequestCounter}`;
41
+ }
42
+ receiverSelectedRequestCounter += 1;
43
+
44
+ return `fake receiver selected request ${receiverSelectedRequestCounter}`;
45
+ }),
46
+ cancelRequest: sinon.stub(),
47
+ commit: sinon.stub(),
48
+ };
49
+
50
+ fakeReceiveSlots = Array(NUM_SLOTS)
51
+ .fill(null)
52
+ .map((_, index) => new FakeSlot(MC.MediaType.VideoMain, `fake receive slot ${index}`));
53
+ });
54
+
55
+ const getLastActiveSpeakerRequestId = () =>
56
+ `fake active speaker request ${activeSpeakerRequestCounter}`;
57
+
58
+ const resetHistory = () => {
59
+ fakeMediaRequestManager.addRequest.resetHistory();
60
+ fakeMediaRequestManager.cancelRequest.resetHistory();
61
+ fakeMediaRequestManager.commit.resetHistory();
62
+ };
63
+
64
+ describe('constructor', () => {
65
+ it('creates a list or RemoteMedia objects and sends the active speaker media request', () => {
66
+ const group = new RemoteMediaGroup(fakeMediaRequestManager, fakeReceiveSlots, 211, true, {
67
+ resolution: 'medium',
68
+ preferLiveVideo: true,
69
+ });
70
+
71
+ assert.strictEqual(group.getRemoteMedia().length, NUM_SLOTS);
72
+ assert.strictEqual(group.getRemoteMedia('all').length, NUM_SLOTS);
73
+ assert.strictEqual(group.getRemoteMedia('unpinned').length, NUM_SLOTS);
74
+ assert.strictEqual(group.getRemoteMedia('pinned').length, 0);
75
+
76
+ assert.strictEqual(
77
+ group.getRemoteMedia('all').every((item) => item instanceof RemoteMedia),
78
+ true
79
+ );
80
+
81
+ assert.calledOnce(fakeMediaRequestManager.addRequest);
82
+ assert.calledWith(
83
+ fakeMediaRequestManager.addRequest,
84
+ sinon.match({
85
+ policyInfo: sinon.match({
86
+ policy: 'active-speaker',
87
+ priority: 211,
88
+ }),
89
+ receiveSlots: fakeReceiveSlots,
90
+ codecInfo: sinon.match({
91
+ codec: 'h264',
92
+ maxFs: 3600,
93
+ }),
94
+ }),
95
+ true
96
+ );
97
+ });
98
+ });
99
+
100
+ describe('pinning', () => {
101
+ it('works as expected', () => {
102
+ const PINNED_INDEX = 2;
103
+ const PINNED_INDEX2 = 0;
104
+ const CSI = 11111;
105
+ const CSI2 = 12345;
106
+
107
+ const group = new RemoteMediaGroup(fakeMediaRequestManager, fakeReceiveSlots, 255, true, {
108
+ resolution: 'medium',
109
+ preferLiveVideo: true,
110
+ });
111
+
112
+ // initially nothing should be pinned
113
+ assert.strictEqual(group.getRemoteMedia().length, NUM_SLOTS); // by default should return 'all'
114
+ assert.strictEqual(group.getRemoteMedia('all').length, NUM_SLOTS);
115
+ assert.strictEqual(group.getRemoteMedia('unpinned').length, NUM_SLOTS);
116
+ assert.strictEqual(group.getRemoteMedia('pinned').length, 0);
117
+
118
+ // take one instance of remote media from the group
119
+ const remoteMedia = group.getRemoteMedia('all')[PINNED_INDEX];
120
+
121
+ resetHistory();
122
+
123
+ // pin it
124
+ group.pin(remoteMedia, CSI);
125
+
126
+ assert.strictEqual(group.getRemoteMedia().length, NUM_SLOTS); // by default should return 'all'
127
+ assert.strictEqual(group.getRemoteMedia('all').length, NUM_SLOTS);
128
+ assert.strictEqual(group.getRemoteMedia('unpinned').length, NUM_SLOTS - 1);
129
+ assert.strictEqual(group.getRemoteMedia('pinned').length, 1);
130
+
131
+ assert.strictEqual(group.isPinned(remoteMedia), true);
132
+
133
+ // now check that correct media requests were sent...
134
+
135
+ const expectedReceiverSelectedSlots = [fakeReceiveSlots[PINNED_INDEX]];
136
+ const expectedActiveSpeakerReceiveSlots = fakeReceiveSlots.filter(
137
+ (_, idx) => idx !== PINNED_INDEX
138
+ );
139
+
140
+ // the previous active speaker media request for the group should have been cancelled
141
+ assert.calledOnce(fakeMediaRequestManager.cancelRequest);
142
+ assert.calledWith(fakeMediaRequestManager.cancelRequest, 'fake active speaker request 1');
143
+ // a new one should be sent for active speaker and for receiver selected
144
+ assert.calledTwice(fakeMediaRequestManager.addRequest);
145
+ assert.calledWith(
146
+ fakeMediaRequestManager.addRequest,
147
+ sinon.match({
148
+ policyInfo: sinon.match({
149
+ policy: 'active-speaker',
150
+ priority: 255,
151
+ }),
152
+ receiveSlots: expectedActiveSpeakerReceiveSlots,
153
+ codecInfo: sinon.match({
154
+ codec: 'h264',
155
+ maxFs: 3600,
156
+ }),
157
+ })
158
+ );
159
+ assert.calledWith(
160
+ fakeMediaRequestManager.addRequest,
161
+ sinon.match({
162
+ policyInfo: sinon.match({
163
+ policy: 'receiver-selected',
164
+ csi: CSI,
165
+ }),
166
+ receiveSlots: expectedReceiverSelectedSlots,
167
+ codecInfo: sinon.match({
168
+ codec: 'h264',
169
+ maxFs: 3600,
170
+ }),
171
+ })
172
+ );
173
+
174
+ resetHistory();
175
+
176
+ // pin another video
177
+ const remoteMedia2 = group.getRemoteMedia('all')[PINNED_INDEX2];
178
+
179
+ group.pin(remoteMedia2, CSI2);
180
+
181
+ assert.strictEqual(group.getRemoteMedia().length, NUM_SLOTS);
182
+ assert.strictEqual(group.getRemoteMedia('all').length, NUM_SLOTS);
183
+ assert.strictEqual(group.getRemoteMedia('unpinned').length, NUM_SLOTS - 2);
184
+ assert.strictEqual(group.getRemoteMedia('pinned').length, 2);
185
+
186
+ assert.strictEqual(group.isPinned(remoteMedia2), true);
187
+
188
+ // now check that correct media requests were sent...
189
+ const expectedReceiverSelectedSlots2 = [fakeReceiveSlots[PINNED_INDEX2]];
190
+ const expectedActiveSpeakerReceiveSlots2 = fakeReceiveSlots.filter(
191
+ (_, idx) => idx !== PINNED_INDEX && idx !== PINNED_INDEX2
192
+ );
193
+
194
+ // the previous active speaker media request for the group should have been cancelled
195
+ assert.calledOnce(fakeMediaRequestManager.cancelRequest);
196
+ assert.calledWith(fakeMediaRequestManager.cancelRequest, 'fake active speaker request 2');
197
+ // a new one should be sent for active speaker and for receiver selected
198
+ assert.calledTwice(fakeMediaRequestManager.addRequest);
199
+ assert.calledWith(
200
+ fakeMediaRequestManager.addRequest,
201
+ sinon.match({
202
+ policyInfo: sinon.match({
203
+ policy: 'active-speaker',
204
+ priority: 255,
205
+ }),
206
+ receiveSlots: expectedActiveSpeakerReceiveSlots2,
207
+ codecInfo: sinon.match({
208
+ codec: 'h264',
209
+ maxFs: 3600,
210
+ }),
211
+ })
212
+ );
213
+ assert.calledWith(
214
+ fakeMediaRequestManager.addRequest,
215
+ sinon.match({
216
+ policyInfo: sinon.match({
217
+ policy: 'receiver-selected',
218
+ csi: CSI2,
219
+ }),
220
+ receiveSlots: expectedReceiverSelectedSlots2,
221
+ codecInfo: sinon.match({
222
+ codec: 'h264',
223
+ maxFs: 3600,
224
+ }),
225
+ })
226
+ );
227
+
228
+ resetHistory();
229
+
230
+ // now unpin the video pane that was first pinned
231
+ group.unpin(remoteMedia);
232
+
233
+ // one pane should still remain pinned
234
+ assert.strictEqual(group.getRemoteMedia().length, NUM_SLOTS);
235
+ assert.strictEqual(group.getRemoteMedia('all').length, NUM_SLOTS);
236
+ assert.strictEqual(group.getRemoteMedia('unpinned').length, NUM_SLOTS - 1);
237
+ assert.strictEqual(group.getRemoteMedia('pinned').length, 1);
238
+
239
+ assert.strictEqual(group.isPinned(remoteMedia), false);
240
+
241
+ // the previous requests for the group and the individual remote media should have been cancelled
242
+ assert.calledTwice(fakeMediaRequestManager.cancelRequest);
243
+ assert.calledWith(fakeMediaRequestManager.cancelRequest, 'fake active speaker request 3');
244
+ assert.calledWith(fakeMediaRequestManager.cancelRequest, 'fake receiver selected request 1');
245
+
246
+ // a new one should be sent for active speaker
247
+ assert.calledOnce(fakeMediaRequestManager.addRequest);
248
+ assert.calledWith(
249
+ fakeMediaRequestManager.addRequest,
250
+ sinon.match({
251
+ policyInfo: sinon.match({
252
+ policy: 'active-speaker',
253
+ priority: 255,
254
+ }),
255
+ codecInfo: sinon.match({
256
+ codec: 'h264',
257
+ maxFs: 3600,
258
+ }),
259
+ })
260
+ );
261
+ // checking that the receiveSlots array passed in to addRequest() has the right length without
262
+ // being strict on the order of elements in it:
263
+ const receiveSlotsArg = fakeMediaRequestManager.addRequest.getCall(0).args[0].receiveSlots;
264
+
265
+ assert.strictEqual(receiveSlotsArg.length, fakeReceiveSlots.length - 1);
266
+ });
267
+
268
+ it('works as expected when pin() is called on already pinned RemoteMedia', () => {
269
+ const PINNED_INDEX = 4;
270
+
271
+ const group = new RemoteMediaGroup(fakeMediaRequestManager, fakeReceiveSlots, 255, true, {
272
+ resolution: 'medium',
273
+ preferLiveVideo: true,
274
+ });
275
+
276
+ // take one instance of remote media from the group
277
+ const remoteMedia = group.getRemoteMedia('all')[PINNED_INDEX];
278
+
279
+ resetHistory();
280
+
281
+ // pin it
282
+ group.pin(remoteMedia, 1234);
283
+
284
+ resetHistory();
285
+ // normally this would result in the underlying receive slot csi to be updated, because we're using fake
286
+ // receive slots, we have to do that manually:
287
+ fakeReceiveSlots[PINNED_INDEX].csi = 1234;
288
+
289
+ // pin again to same CSI
290
+ group.pin(remoteMedia, 1234);
291
+
292
+ assert.notCalled(fakeMediaRequestManager.addRequest);
293
+ assert.notCalled(fakeMediaRequestManager.cancelRequest);
294
+ assert.notCalled(fakeMediaRequestManager.commit);
295
+
296
+ // again, this time without even specifying the csi
297
+ group.pin(remoteMedia);
298
+
299
+ assert.notCalled(fakeMediaRequestManager.addRequest);
300
+ assert.notCalled(fakeMediaRequestManager.cancelRequest);
301
+ assert.notCalled(fakeMediaRequestManager.commit);
302
+
303
+ // pin it again but to a different CSI
304
+ group.pin(remoteMedia, 2345);
305
+
306
+ // it should trigger a new receiver selected media request
307
+ assert.calledOnce(fakeMediaRequestManager.addRequest);
308
+ assert.calledWith(
309
+ fakeMediaRequestManager.addRequest,
310
+ sinon.match({
311
+ policyInfo: sinon.match({
312
+ policy: 'receiver-selected',
313
+ csi: 2345,
314
+ }),
315
+ receiveSlots: [fakeReceiveSlots[PINNED_INDEX]],
316
+ codecInfo: sinon.match({
317
+ codec: 'h264',
318
+ maxFs: 3600,
319
+ }),
320
+ })
321
+ );
322
+ });
323
+ });
324
+
325
+ describe('stop()', () => {
326
+ it('stops all RemoteMedia in the group', () => {
327
+ const group = new RemoteMediaGroup(fakeMediaRequestManager, fakeReceiveSlots, 255, true, {
328
+ resolution: 'medium',
329
+ preferLiveVideo: true,
330
+ });
331
+ const stopStubs: any[] = [];
332
+
333
+ group.getRemoteMedia('all').forEach((remoteMedia) => {
334
+ stopStubs.push(sinon.stub(remoteMedia, 'stop'));
335
+ });
336
+
337
+ // pin a few remote media instances
338
+ group.pin(group.getRemoteMedia('unpinned')[2], 12345);
339
+ group.pin(group.getRemoteMedia('unpinned')[1], 12345);
340
+ group.pin(group.getRemoteMedia('unpinned')[0], 12345);
341
+
342
+ assert.strictEqual(group.getRemoteMedia('unpinned').length, NUM_SLOTS - 3);
343
+ assert.strictEqual(group.getRemoteMedia('pinned').length, 3);
344
+
345
+ resetHistory();
346
+
347
+ group.stop(true);
348
+
349
+ // check that all remote media (including pinned ones) have been stopped
350
+ stopStubs.forEach((stub) => {
351
+ assert.calledOnce(stub);
352
+ assert.calledWith(stub, false);
353
+ });
354
+
355
+ // and that we've cancelled the media request for this group
356
+ assert.calledOnce(fakeMediaRequestManager.cancelRequest);
357
+ assert.calledWith(fakeMediaRequestManager.cancelRequest, getLastActiveSpeakerRequestId());
358
+ assert.calledOnce(fakeMediaRequestManager.commit);
359
+ });
360
+ });
361
+
362
+ describe('includes()', () => {
363
+ it('checks if a given RemoteMedia belongs to the group', () => {
364
+ const group = new RemoteMediaGroup(fakeMediaRequestManager, fakeReceiveSlots, 255, true, {
365
+ resolution: 'medium',
366
+ preferLiveVideo: true,
367
+ });
368
+
369
+ const unpinnedRemoteMediaFromGroup = group.getRemoteMedia('all')[0];
370
+ const otherRemoteMedia = new RemoteMedia(
371
+ new FakeSlot(MC.MediaType.VideoMain, 'other slot') as unknown as ReceiveSlot,
372
+ fakeMediaRequestManager
373
+ );
374
+
375
+ group.pin(group.getRemoteMedia('all')[1], 12345);
376
+ const pinnedRemoteMedia = group.getRemoteMedia('pinned')[0];
377
+
378
+ // by default includes() uses 'all' filter
379
+ assert.strictEqual(group.includes(unpinnedRemoteMediaFromGroup), true);
380
+ assert.strictEqual(group.includes(otherRemoteMedia), false);
381
+ assert.strictEqual(group.includes(pinnedRemoteMedia), true);
382
+
383
+ assert.strictEqual(group.includes(unpinnedRemoteMediaFromGroup, 'all'), true);
384
+ assert.strictEqual(group.includes(otherRemoteMedia, 'all'), false);
385
+ assert.strictEqual(group.includes(pinnedRemoteMedia, 'all'), true);
386
+
387
+ assert.strictEqual(group.includes(unpinnedRemoteMediaFromGroup, 'pinned'), false);
388
+ assert.strictEqual(group.includes(otherRemoteMedia, 'pinned'), false);
389
+ assert.strictEqual(group.includes(pinnedRemoteMedia, 'pinned'), true);
390
+
391
+ assert.strictEqual(group.includes(unpinnedRemoteMediaFromGroup, 'unpinned'), true);
392
+ assert.strictEqual(group.includes(pinnedRemoteMedia, 'unpinned'), false);
393
+ assert.strictEqual(group.includes(otherRemoteMedia, 'unpinned'), false);
394
+ });
395
+ });
396
+ });