@webex/plugin-meetings 3.0.0-beta.1 → 3.0.0-beta.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 (111) hide show
  1. package/dist/common/errors/webex-errors.js +5 -29
  2. package/dist/common/errors/webex-errors.js.map +1 -1
  3. package/dist/constants.js +15 -74
  4. package/dist/constants.js.map +1 -1
  5. package/dist/media/index.js +68 -213
  6. package/dist/media/index.js.map +1 -1
  7. package/dist/media/internal-media-core-wrapper.js +22 -0
  8. package/dist/media/internal-media-core-wrapper.js.map +1 -0
  9. package/dist/media/properties.js +20 -25
  10. package/dist/media/properties.js.map +1 -1
  11. package/dist/media/util.js +0 -27
  12. package/dist/media/util.js.map +1 -1
  13. package/dist/meeting/index.js +694 -432
  14. package/dist/meeting/index.js.map +1 -1
  15. package/dist/meeting/request.js +1 -0
  16. package/dist/meeting/request.js.map +1 -1
  17. package/dist/meeting/util.js +3 -44
  18. package/dist/meeting/util.js.map +1 -1
  19. package/dist/meetings/index.js +64 -5
  20. package/dist/meetings/index.js.map +1 -1
  21. package/dist/meetings/util.js +24 -1
  22. package/dist/meetings/util.js.map +1 -1
  23. package/dist/members/index.js +68 -0
  24. package/dist/members/index.js.map +1 -1
  25. package/dist/multistream/mediaRequestManager.js +132 -0
  26. package/dist/multistream/mediaRequestManager.js.map +1 -0
  27. package/dist/multistream/multistreamMedia.js +116 -0
  28. package/dist/multistream/multistreamMedia.js.map +1 -0
  29. package/dist/multistream/receiveSlot.js +209 -0
  30. package/dist/multistream/receiveSlot.js.map +1 -0
  31. package/dist/multistream/receiveSlotManager.js +195 -0
  32. package/dist/multistream/receiveSlotManager.js.map +1 -0
  33. package/dist/multistream/remoteMedia.js +284 -0
  34. package/dist/multistream/remoteMedia.js.map +1 -0
  35. package/dist/multistream/remoteMediaGroup.js +243 -0
  36. package/dist/multistream/remoteMediaGroup.js.map +1 -0
  37. package/dist/multistream/remoteMediaManager.js +1113 -0
  38. package/dist/multistream/remoteMediaManager.js.map +1 -0
  39. package/dist/reconnection-manager/index.js +109 -130
  40. package/dist/reconnection-manager/index.js.map +1 -1
  41. package/dist/roap/index.js +57 -240
  42. package/dist/roap/index.js.map +1 -1
  43. package/dist/roap/request.js +2 -114
  44. package/dist/roap/request.js.map +1 -1
  45. package/dist/roap/turnDiscovery.js +11 -5
  46. package/dist/roap/turnDiscovery.js.map +1 -1
  47. package/dist/statsAnalyzer/global.js +2 -0
  48. package/dist/statsAnalyzer/global.js.map +1 -1
  49. package/dist/statsAnalyzer/index.js +39 -36
  50. package/dist/statsAnalyzer/index.js.map +1 -1
  51. package/package.json +20 -19
  52. package/src/common/errors/webex-errors.js +0 -18
  53. package/src/constants.ts +139 -180
  54. package/src/media/index.js +60 -194
  55. package/src/media/internal-media-core-wrapper.ts +9 -0
  56. package/src/media/properties.js +19 -25
  57. package/src/media/util.js +0 -22
  58. package/src/meeting/index.js +565 -320
  59. package/src/meeting/request.js +1 -0
  60. package/src/meeting/util.js +3 -46
  61. package/src/meetings/index.js +30 -1
  62. package/src/meetings/util.js +23 -2
  63. package/src/members/index.js +48 -0
  64. package/src/multistream/mediaRequestManager.ts +164 -0
  65. package/src/multistream/multistreamMedia.ts +92 -0
  66. package/src/multistream/receiveSlot.ts +141 -0
  67. package/src/multistream/receiveSlotManager.ts +142 -0
  68. package/src/multistream/remoteMedia.ts +219 -0
  69. package/src/multistream/remoteMediaGroup.ts +224 -0
  70. package/src/multistream/remoteMediaManager.ts +911 -0
  71. package/src/reconnection-manager/index.js +40 -53
  72. package/src/roap/index.js +47 -207
  73. package/src/roap/request.js +1 -72
  74. package/src/roap/turnDiscovery.ts +12 -6
  75. package/src/statsAnalyzer/global.js +2 -0
  76. package/src/statsAnalyzer/index.js +32 -46
  77. package/test/integration/spec/journey.js +1 -1
  78. package/test/unit/spec/media/index.ts +223 -0
  79. package/test/unit/spec/media/properties.ts +73 -82
  80. package/test/unit/spec/meeting/effectsState.js +1 -3
  81. package/test/unit/spec/meeting/index.js +420 -228
  82. package/test/unit/spec/meeting/muteState.js +7 -0
  83. package/test/unit/spec/meeting/utils.js +61 -2
  84. package/test/unit/spec/meetings/index.js +0 -4
  85. package/test/unit/spec/members/index.js +164 -2
  86. package/test/unit/spec/multistream/mediaRequestManager.ts +511 -0
  87. package/test/unit/spec/multistream/receiveSlot.ts +104 -0
  88. package/test/unit/spec/multistream/receiveSlotManager.ts +173 -0
  89. package/test/unit/spec/multistream/remoteMedia.ts +217 -0
  90. package/test/unit/spec/multistream/remoteMediaGroup.ts +396 -0
  91. package/test/unit/spec/multistream/remoteMediaManager.ts +1251 -0
  92. package/test/unit/spec/roap/index.ts +63 -35
  93. package/test/unit/spec/stats-analyzer/index.js +19 -22
  94. package/dist/peer-connection-manager/index.js +0 -794
  95. package/dist/peer-connection-manager/index.js.map +0 -1
  96. package/dist/roap/collection.js +0 -73
  97. package/dist/roap/collection.js.map +0 -1
  98. package/dist/roap/handler.js +0 -337
  99. package/dist/roap/handler.js.map +0 -1
  100. package/dist/roap/state.js +0 -164
  101. package/dist/roap/state.js.map +0 -1
  102. package/dist/roap/util.js +0 -102
  103. package/dist/roap/util.js.map +0 -1
  104. package/src/peer-connection-manager/index.js +0 -723
  105. package/src/roap/collection.js +0 -63
  106. package/src/roap/handler.js +0 -252
  107. package/src/roap/state.js +0 -149
  108. package/src/roap/util.js +0 -93
  109. package/test/unit/spec/peerconnection-manager/index.js +0 -188
  110. package/test/unit/spec/peerconnection-manager/utils.js +0 -48
  111. package/test/unit/spec/roap/util.js +0 -30
@@ -0,0 +1,511 @@
1
+ import {MediaRequestManager} from '@webex/plugin-meetings/src/multistream/mediaRequestManager';
2
+ import {ReceiveSlot} from '@webex/plugin-meetings/src/multistream/receiveSlot';
3
+ import sinon from 'sinon';
4
+ import {assert} from '@webex/test-helper-chai';
5
+
6
+ type ExpectedActiveSpeaker = {
7
+ policy: 'active-speaker';
8
+ priority: number;
9
+ receiveSlots: Array<ReceiveSlot>;
10
+ };
11
+ type ExpectedReceiverSelected = {
12
+ policy: 'receiver-selected';
13
+ csi: number;
14
+ receiveSlot: ReceiveSlot;
15
+ };
16
+ type ExpectedRequest = ExpectedActiveSpeaker | ExpectedReceiverSelected;
17
+
18
+ describe('MediaRequestManager', () => {
19
+ const CROSS_PRIORITY_DUPLICATION = true;
20
+ const CROSS_POLICY_DUPLICATION = true;
21
+ const PREFER_LIVE_VIDEO = true;
22
+ const ACTIVE_SPEAKER_MAX_FS = 3600;
23
+ const RECEIVER_SELECTED_MAX_FS = 8190;
24
+
25
+ const NUM_SLOTS = 10;
26
+
27
+ let mediaRequestManager: MediaRequestManager;
28
+ let sendMediaRequestsCallback;
29
+ let fakeWcmeSlots;
30
+ let fakeReceiveSlots;
31
+
32
+ beforeEach(() => {
33
+ sendMediaRequestsCallback = sinon.stub();
34
+ mediaRequestManager = new MediaRequestManager(sendMediaRequestsCallback);
35
+
36
+ // create some fake receive slots used by the tests
37
+ fakeWcmeSlots = Array(NUM_SLOTS)
38
+ .fill(null)
39
+ .map((_, index) => ({
40
+ id: `fake WCME slot ${index}`,
41
+ }));
42
+
43
+ fakeReceiveSlots = Array(NUM_SLOTS)
44
+ .fill(null)
45
+ .map(
46
+ (_, index) =>
47
+ ({
48
+ id: `fake receive slot ${index}`,
49
+ wcmeReceiveSlot: fakeWcmeSlots[index],
50
+ resetSourceState: sinon.stub(),
51
+ } as unknown as ReceiveSlot)
52
+ );
53
+ });
54
+
55
+ // helper function for adding an active speaker request
56
+ const addActiveSpeakerRequest = (priority, receiveSlots, commit = false) =>
57
+ mediaRequestManager.addRequest(
58
+ {
59
+ policyInfo: {
60
+ policy: 'active-speaker',
61
+ priority,
62
+ crossPriorityDuplication: CROSS_PRIORITY_DUPLICATION,
63
+ crossPolicyDuplication: CROSS_POLICY_DUPLICATION,
64
+ preferLiveVideo: PREFER_LIVE_VIDEO,
65
+ },
66
+ receiveSlots,
67
+ codecInfo: {
68
+ codec: 'h264',
69
+ maxFs: ACTIVE_SPEAKER_MAX_FS,
70
+ },
71
+ },
72
+ commit
73
+ );
74
+
75
+ // helper function for adding a receiver selected request
76
+ const addReceiverSelectedRequest = (csi, receiveSlot, commit = false) =>
77
+ mediaRequestManager.addRequest(
78
+ {
79
+ policyInfo: {
80
+ policy: 'receiver-selected',
81
+ csi,
82
+ },
83
+ receiveSlots: [receiveSlot],
84
+ codecInfo: {
85
+ codec: 'h264',
86
+ maxFs: RECEIVER_SELECTED_MAX_FS,
87
+ },
88
+ },
89
+ commit
90
+ );
91
+
92
+ // helper function for verifying that the right active speaker and receiver selected
93
+ // requests have been sent out
94
+ // It should be used only for verifying requests created with
95
+ // addActiveSpeakerRequest() or addReceiverSelectedRequest(), because of some
96
+ // hardcoded values used in them
97
+ const checkMediaRequestsSent = (expectedRequests: ExpectedRequest[]) => {
98
+ assert.calledOnce(sendMediaRequestsCallback);
99
+ assert.calledWith(
100
+ sendMediaRequestsCallback,
101
+ expectedRequests.map((expectedRequest) => {
102
+ if (expectedRequest.policy === 'active-speaker') {
103
+ return sinon.match({
104
+ policy: 'active-speaker',
105
+ policySpecificInfo: sinon.match({
106
+ priority: expectedRequest.priority,
107
+ crossPriorityDuplication: CROSS_PRIORITY_DUPLICATION,
108
+ crossPolicyDuplication: CROSS_POLICY_DUPLICATION,
109
+ preferLiveVideo: PREFER_LIVE_VIDEO,
110
+ }),
111
+ receiveSlots: expectedRequest.receiveSlots,
112
+ codecInfos: [
113
+ sinon.match({
114
+ payloadType: 0x80,
115
+ h264: sinon.match({
116
+ maxFs: ACTIVE_SPEAKER_MAX_FS,
117
+ }),
118
+ }),
119
+ ],
120
+ });
121
+ }
122
+ if (expectedRequest.policy === 'receiver-selected') {
123
+ return sinon.match({
124
+ policy: 'receiver-selected',
125
+ policySpecificInfo: sinon.match({
126
+ csi: expectedRequest.csi,
127
+ }),
128
+ receiveSlots: [expectedRequest.receiveSlot],
129
+ codecInfos: [
130
+ sinon.match({
131
+ payloadType: 0x80,
132
+ h264: sinon.match({
133
+ maxFs: RECEIVER_SELECTED_MAX_FS,
134
+ }),
135
+ }),
136
+ ],
137
+ });
138
+ }
139
+
140
+ return undefined;
141
+ })
142
+ );
143
+ sendMediaRequestsCallback.resetHistory();
144
+ };
145
+
146
+ it('starts with no requests', () => {
147
+ mediaRequestManager.commit();
148
+
149
+ assert.calledOnce(sendMediaRequestsCallback);
150
+ assert.calledWith(sendMediaRequestsCallback, []);
151
+ });
152
+
153
+ it('sends correct wcme media requests when addRequest() is called with commit=true', () => {
154
+ // this is the only test that doesn't use the helper addActiveSpeakerRequest(), addReceiverSelectedRequest() methods
155
+ // because it tests other values for some of the parameters that are otherwise always fixed by those helpers
156
+
157
+ // first call addRequest a couple of times with commit=false
158
+ mediaRequestManager.addRequest(
159
+ {
160
+ policyInfo: {
161
+ policy: 'active-speaker',
162
+ priority: 255,
163
+ crossPriorityDuplication: true,
164
+ crossPolicyDuplication: false,
165
+ preferLiveVideo: false,
166
+ },
167
+ receiveSlots: [fakeReceiveSlots[0], fakeReceiveSlots[1], fakeReceiveSlots[2]],
168
+ codecInfo: {
169
+ codec: 'h264',
170
+ maxFs: 1620,
171
+ maxFps: 1500,
172
+ },
173
+ },
174
+ false
175
+ );
176
+ mediaRequestManager.addRequest(
177
+ {
178
+ policyInfo: {
179
+ policy: 'receiver-selected',
180
+ csi: 123,
181
+ },
182
+ receiveSlots: [fakeReceiveSlots[3]],
183
+ codecInfo: {
184
+ codec: 'h264',
185
+ maxFs: 3600,
186
+ maxFps: 2500,
187
+ maxMbps: 90000,
188
+ },
189
+ },
190
+ false
191
+ );
192
+
193
+ // finally call it with commit=true
194
+ mediaRequestManager.addRequest(
195
+ {
196
+ policyInfo: {
197
+ policy: 'receiver-selected',
198
+ csi: 123,
199
+ },
200
+ receiveSlots: [fakeReceiveSlots[4]],
201
+ codecInfo: {
202
+ codec: 'h264',
203
+ maxFs: 8192,
204
+ maxFps: 2500,
205
+ maxMbps: 204800,
206
+ },
207
+ },
208
+ true
209
+ );
210
+
211
+ // all 3 requests should be sent out together
212
+ assert.calledOnce(sendMediaRequestsCallback);
213
+ assert.calledWith(sendMediaRequestsCallback, [
214
+ sinon.match({
215
+ policy: 'active-speaker',
216
+ policySpecificInfo: sinon.match({
217
+ priority: 255,
218
+ crossPriorityDuplication: true,
219
+ crossPolicyDuplication: false,
220
+ preferLiveVideo: false,
221
+ }),
222
+ receiveSlots: [fakeWcmeSlots[0], fakeWcmeSlots[1], fakeWcmeSlots[2]],
223
+ codecInfos: [
224
+ sinon.match({
225
+ payloadType: 0x80,
226
+ h264: sinon.match({
227
+ maxFs: 1620,
228
+ maxFps: 1500,
229
+ maxMbps: 245760,
230
+ }),
231
+ }),
232
+ ],
233
+ }),
234
+ sinon.match({
235
+ policy: 'receiver-selected',
236
+ policySpecificInfo: sinon.match({
237
+ csi: 123,
238
+ }),
239
+ receiveSlots: [fakeWcmeSlots[3]],
240
+ codecInfos: [
241
+ sinon.match({
242
+ payloadType: 0x80,
243
+ h264: sinon.match({
244
+ maxFs: 3600,
245
+ maxFps: 2500,
246
+ maxMbps: 90000,
247
+ }),
248
+ }),
249
+ ],
250
+ }),
251
+ sinon.match({
252
+ policy: 'receiver-selected',
253
+ policySpecificInfo: sinon.match({
254
+ csi: 123,
255
+ }),
256
+ receiveSlots: [fakeWcmeSlots[4]],
257
+ codecInfos: [
258
+ sinon.match({
259
+ payloadType: 0x80,
260
+ h264: sinon.match({
261
+ maxFs: 8192,
262
+ maxFps: 2500,
263
+ maxMbps: 204800,
264
+ }),
265
+ }),
266
+ ],
267
+ }),
268
+ ]);
269
+ });
270
+
271
+ it('keeps adding requests with every call to addRequest()', () => {
272
+ // start with 1 request
273
+ addReceiverSelectedRequest(100, fakeReceiveSlots[0], true);
274
+
275
+ checkMediaRequestsSent([
276
+ {policy: 'receiver-selected', csi: 100, receiveSlot: fakeWcmeSlots[0]},
277
+ ]);
278
+
279
+ // now add another one
280
+ addReceiverSelectedRequest(101, fakeReceiveSlots[1], true);
281
+
282
+ checkMediaRequestsSent([
283
+ {policy: 'receiver-selected', csi: 100, receiveSlot: fakeWcmeSlots[0]},
284
+ {policy: 'receiver-selected', csi: 101, receiveSlot: fakeWcmeSlots[1]},
285
+ ]);
286
+
287
+ // and one more
288
+ addActiveSpeakerRequest(
289
+ 1,
290
+ [fakeReceiveSlots[2], fakeReceiveSlots[3], fakeReceiveSlots[4]],
291
+ true
292
+ );
293
+
294
+ checkMediaRequestsSent([
295
+ {policy: 'receiver-selected', csi: 100, receiveSlot: fakeWcmeSlots[0]},
296
+ {policy: 'receiver-selected', csi: 101, receiveSlot: fakeWcmeSlots[1]},
297
+ {
298
+ policy: 'active-speaker',
299
+ priority: 1,
300
+ receiveSlots: [fakeWcmeSlots[2], fakeWcmeSlots[3], fakeWcmeSlots[4]],
301
+ },
302
+ ]);
303
+ });
304
+
305
+ it('cancels the requests correctly when cancelRequest() is called with commit=true', () => {
306
+ const requestIds = [
307
+ addActiveSpeakerRequest(255, [fakeReceiveSlots[0], fakeReceiveSlots[1]]),
308
+ addActiveSpeakerRequest(255, [fakeReceiveSlots[2], fakeReceiveSlots[3]]),
309
+ addReceiverSelectedRequest(100, fakeReceiveSlots[4]),
310
+ addReceiverSelectedRequest(200, fakeReceiveSlots[5]),
311
+ ];
312
+
313
+ // cancel one of the active speaker requests
314
+ mediaRequestManager.cancelRequest(requestIds[1], true);
315
+
316
+ // expect only the 3 remaining requests to be sent out
317
+ checkMediaRequestsSent([
318
+ {policy: 'active-speaker', priority: 255, receiveSlots: [fakeWcmeSlots[0], fakeWcmeSlots[1]]},
319
+ {policy: 'receiver-selected', csi: 100, receiveSlot: fakeWcmeSlots[4]},
320
+ {policy: 'receiver-selected', csi: 200, receiveSlot: fakeWcmeSlots[5]},
321
+ ]);
322
+
323
+ // cancel one of the receiver selected requests
324
+ mediaRequestManager.cancelRequest(requestIds[3], true);
325
+
326
+ // expect only the 2 remaining requests to be sent out
327
+ checkMediaRequestsSent([
328
+ {policy: 'active-speaker', priority: 255, receiveSlots: [fakeWcmeSlots[0], fakeWcmeSlots[1]]},
329
+ {policy: 'receiver-selected', csi: 100, receiveSlot: fakeWcmeSlots[4]},
330
+ ]);
331
+ });
332
+
333
+ it('does not send out anything if addRequest() is called with commit=false', () => {
334
+ addActiveSpeakerRequest(
335
+ 10,
336
+ [fakeReceiveSlots[0], fakeReceiveSlots[1], fakeReceiveSlots[2]],
337
+ false
338
+ );
339
+ addReceiverSelectedRequest(123, fakeReceiveSlots[3], false);
340
+
341
+ // nothing should be sent out as we didn't commit the requests
342
+ assert.notCalled(sendMediaRequestsCallback);
343
+
344
+ // now do the commit
345
+ mediaRequestManager.commit();
346
+
347
+ // check that the 2 requests have been sent out
348
+ checkMediaRequestsSent([
349
+ {
350
+ policy: 'active-speaker',
351
+ priority: 10,
352
+ receiveSlots: [fakeWcmeSlots[0], fakeWcmeSlots[1], fakeWcmeSlots[2]],
353
+ },
354
+ {policy: 'receiver-selected', csi: 123, receiveSlot: fakeWcmeSlots[3]},
355
+ ]);
356
+ });
357
+
358
+ it('does not send out anything if cancelRequest() is called with commit=false', () => {
359
+ // send 4 requests
360
+ const requestIds = [
361
+ addActiveSpeakerRequest(
362
+ 250,
363
+ [fakeReceiveSlots[0], fakeReceiveSlots[1], fakeReceiveSlots[2]],
364
+ false
365
+ ),
366
+ addReceiverSelectedRequest(98765, fakeReceiveSlots[3], false),
367
+ addReceiverSelectedRequest(99999, fakeReceiveSlots[4], false),
368
+ addReceiverSelectedRequest(88888, fakeReceiveSlots[5], true),
369
+ ];
370
+
371
+ checkMediaRequestsSent([
372
+ {
373
+ policy: 'active-speaker',
374
+ priority: 250,
375
+ receiveSlots: [fakeWcmeSlots[0], fakeWcmeSlots[1], fakeWcmeSlots[2]],
376
+ },
377
+ {policy: 'receiver-selected', csi: 98765, receiveSlot: fakeWcmeSlots[3]},
378
+ {policy: 'receiver-selected', csi: 99999, receiveSlot: fakeWcmeSlots[4]},
379
+ {policy: 'receiver-selected', csi: 88888, receiveSlot: fakeWcmeSlots[5]},
380
+ ]);
381
+
382
+ // now cancel 3 of them, but with commit=false => nothing should happen
383
+ mediaRequestManager.cancelRequest(requestIds[0], false);
384
+ mediaRequestManager.cancelRequest(requestIds[2], false);
385
+ mediaRequestManager.cancelRequest(requestIds[3], false);
386
+
387
+ assert.notCalled(sendMediaRequestsCallback);
388
+
389
+ // now do the commit
390
+ mediaRequestManager.commit();
391
+
392
+ checkMediaRequestsSent([
393
+ {policy: 'receiver-selected', csi: 98765, receiveSlot: fakeWcmeSlots[3]},
394
+ ]);
395
+ });
396
+
397
+ it('sends the wcme media requests when commit() is called', () => {
398
+ // send some requests, all of them with commit=false
399
+ addReceiverSelectedRequest(123000, fakeReceiveSlots[0], false);
400
+ addReceiverSelectedRequest(456000, fakeReceiveSlots[1], false);
401
+ addActiveSpeakerRequest(
402
+ 255,
403
+ [fakeReceiveSlots[2], fakeReceiveSlots[3], fakeReceiveSlots[4]],
404
+ false
405
+ );
406
+ addActiveSpeakerRequest(
407
+ 254,
408
+ [fakeReceiveSlots[5], fakeReceiveSlots[6], fakeReceiveSlots[7]],
409
+ false
410
+ );
411
+
412
+ // nothing should be sent out as we didn't commit the requests
413
+ assert.notCalled(sendMediaRequestsCallback);
414
+
415
+ // now do the commit
416
+ mediaRequestManager.commit();
417
+
418
+ // check that all requests have been sent out
419
+ checkMediaRequestsSent([
420
+ {policy: 'receiver-selected', csi: 123000, receiveSlot: fakeWcmeSlots[0]},
421
+ {policy: 'receiver-selected', csi: 456000, receiveSlot: fakeWcmeSlots[1]},
422
+ {
423
+ policy: 'active-speaker',
424
+ priority: 255,
425
+ receiveSlots: [fakeWcmeSlots[2], fakeWcmeSlots[3], fakeWcmeSlots[4]],
426
+ },
427
+ {
428
+ policy: 'active-speaker',
429
+ priority: 254,
430
+ receiveSlots: [fakeWcmeSlots[5], fakeWcmeSlots[6], fakeWcmeSlots[7]],
431
+ },
432
+ ]);
433
+ });
434
+
435
+ it('clears all the requests on reset()', () => {
436
+ // send some requests and commit them one by one
437
+ addReceiverSelectedRequest(1500, fakeReceiveSlots[0], true);
438
+ addReceiverSelectedRequest(1501, fakeReceiveSlots[1], true);
439
+ addActiveSpeakerRequest(
440
+ 255,
441
+ [fakeReceiveSlots[2], fakeReceiveSlots[3], fakeReceiveSlots[4]],
442
+ true
443
+ );
444
+ addActiveSpeakerRequest(
445
+ 254,
446
+ [fakeReceiveSlots[5], fakeReceiveSlots[6], fakeReceiveSlots[7]],
447
+ true
448
+ );
449
+
450
+ sendMediaRequestsCallback.resetHistory();
451
+
452
+ // check that when calling commit() all requests are re-sent again
453
+ mediaRequestManager.commit();
454
+
455
+ checkMediaRequestsSent([
456
+ {policy: 'receiver-selected', csi: 1500, receiveSlot: fakeWcmeSlots[0]},
457
+ {policy: 'receiver-selected', csi: 1501, receiveSlot: fakeWcmeSlots[1]},
458
+ {
459
+ policy: 'active-speaker',
460
+ priority: 255,
461
+ receiveSlots: [fakeWcmeSlots[2], fakeWcmeSlots[3], fakeWcmeSlots[4]],
462
+ },
463
+ {
464
+ policy: 'active-speaker',
465
+ priority: 254,
466
+ receiveSlots: [fakeWcmeSlots[5], fakeWcmeSlots[6], fakeWcmeSlots[7]],
467
+ },
468
+ ]);
469
+
470
+ // now reset everything
471
+ mediaRequestManager.reset();
472
+
473
+ // calling commit now should not cause any requests to be sent out
474
+ mediaRequestManager.commit();
475
+ checkMediaRequestsSent([]);
476
+ });
477
+
478
+ it('calls resetSourceState() on slots that are stopped being used', () => {
479
+ const requestIds = [
480
+ addActiveSpeakerRequest(255, [fakeReceiveSlots[0], fakeReceiveSlots[1]]),
481
+ addActiveSpeakerRequest(255, [fakeReceiveSlots[2], fakeReceiveSlots[3]]),
482
+ addReceiverSelectedRequest(100, fakeReceiveSlots[4]),
483
+ addReceiverSelectedRequest(200, fakeReceiveSlots[5]),
484
+ ];
485
+
486
+ mediaRequestManager.commit();
487
+ checkMediaRequestsSent([
488
+ {policy: 'active-speaker', priority: 255, receiveSlots: [fakeWcmeSlots[0], fakeWcmeSlots[1]]},
489
+ {policy: 'active-speaker', priority: 255, receiveSlots: [fakeWcmeSlots[2], fakeWcmeSlots[3]]},
490
+ {policy: 'receiver-selected', csi: 100, receiveSlot: fakeWcmeSlots[4]},
491
+ {policy: 'receiver-selected', csi: 200, receiveSlot: fakeWcmeSlots[5]},
492
+ ]);
493
+
494
+ // cancel 2 of the requests
495
+ mediaRequestManager.cancelRequest(requestIds[1], false);
496
+ mediaRequestManager.cancelRequest(requestIds[3], false);
497
+
498
+ mediaRequestManager.commit();
499
+
500
+ // expect only the 2 remaining requests to be sent out
501
+ checkMediaRequestsSent([
502
+ {policy: 'active-speaker', priority: 255, receiveSlots: [fakeWcmeSlots[0], fakeWcmeSlots[1]]},
503
+ {policy: 'receiver-selected', csi: 100, receiveSlot: fakeWcmeSlots[4]},
504
+ ]);
505
+
506
+ // and that the receive slots of the 2 cancelled ones had resetSourceState() called
507
+ assert.calledOnce(fakeReceiveSlots[2].resetSourceState);
508
+ assert.calledOnce(fakeReceiveSlots[3].resetSourceState);
509
+ assert.calledOnce(fakeReceiveSlots[5].resetSourceState);
510
+ });
511
+ });
@@ -0,0 +1,104 @@
1
+ /* eslint-disable require-jsdoc */
2
+ import EventEmitter from 'events';
3
+
4
+ import {MediaConnection as MC} from '@webex/internal-media-core';
5
+ import {ReceiveSlot, ReceiveSlotEvents} from '@webex/plugin-meetings/src/multistream/receiveSlot';
6
+ import sinon from 'sinon';
7
+ import {assert} from '@webex/test-helper-chai';
8
+
9
+ class FakeWcmeSlot extends EventEmitter {
10
+ public stream;
11
+
12
+ constructor(stream) {
13
+ super();
14
+ this.stream = stream;
15
+ }
16
+ }
17
+
18
+ describe('ReceiveSlot', () => {
19
+ let receiveSlot;
20
+ let fakeWcmeSlot;
21
+ let findMemberIdCallbackStub;
22
+ let fakeStream;
23
+
24
+ beforeEach(() => {
25
+ fakeStream = {id: 'fake stream'};
26
+ fakeWcmeSlot = new FakeWcmeSlot(fakeStream);
27
+ findMemberIdCallbackStub = sinon.stub();
28
+ receiveSlot = new ReceiveSlot(MC.MediaType.VideoMain, fakeWcmeSlot, findMemberIdCallbackStub);
29
+ });
30
+
31
+ describe('forwards events from underlying wcme receive slot', () => {
32
+ it('forwards SourceUpdate', () => {
33
+ let eventEmitted = false;
34
+ let eventData;
35
+
36
+ const csi = 10203040;
37
+ const fakeMemberId = '12345678-1234-5678-9012-345678901234';
38
+
39
+ findMemberIdCallbackStub.returns(fakeMemberId);
40
+
41
+ receiveSlot.on(ReceiveSlotEvents.SourceUpdate, (data) => {
42
+ eventEmitted = true;
43
+ eventData = data;
44
+ });
45
+
46
+ fakeWcmeSlot.emit(MC.ReceiveSlotEvents.SourceUpdate, 'live', csi);
47
+
48
+ assert.strictEqual(eventEmitted, true);
49
+ assert.deepEqual(eventData, {
50
+ state: 'live',
51
+ csi,
52
+ memberId: fakeMemberId,
53
+ });
54
+ assert.calledOnce(findMemberIdCallbackStub);
55
+ assert.calledWith(findMemberIdCallbackStub, csi);
56
+ });
57
+ });
58
+
59
+ it('has public properties', () => {
60
+ assert.strictEqual(receiveSlot.id, 'r1');
61
+ assert.strictEqual(receiveSlot.mediaType, MC.MediaType.VideoMain);
62
+ });
63
+
64
+ it("exposes underlying wcme receive slot's properties", () => {
65
+ assert.strictEqual(receiveSlot.stream, fakeStream);
66
+ assert.strictEqual(receiveSlot.wcmeReceiveSlot, fakeWcmeSlot);
67
+ });
68
+
69
+ it("caches some underlying wcme receive slot's properties", () => {
70
+ assert.strictEqual(receiveSlot.memberId, undefined);
71
+ assert.strictEqual(receiveSlot.csi, undefined);
72
+ assert.strictEqual(receiveSlot.sourceState, 'no source');
73
+
74
+ const csi = 987654321;
75
+ const fakeMemberId = '00000001-1234-5678-9012-345678901234';
76
+
77
+ findMemberIdCallbackStub.returns(fakeMemberId);
78
+
79
+ fakeWcmeSlot.emit(MC.ReceiveSlotEvents.SourceUpdate, 'live', csi);
80
+
81
+ assert.strictEqual(receiveSlot.memberId, fakeMemberId);
82
+ assert.strictEqual(receiveSlot.csi, csi);
83
+ assert.strictEqual(receiveSlot.sourceState, 'live');
84
+ });
85
+
86
+ it('resets source related properties when resetSourceState() is called', () => {
87
+ const csi = 123456;
88
+ const fakeMemberId = '00000001-5555-6666-9012-345678901234';
89
+
90
+ findMemberIdCallbackStub.returns(fakeMemberId);
91
+
92
+ fakeWcmeSlot.emit(MC.ReceiveSlotEvents.SourceUpdate, 'live', csi);
93
+
94
+ assert.strictEqual(receiveSlot.memberId, fakeMemberId);
95
+ assert.strictEqual(receiveSlot.csi, csi);
96
+ assert.strictEqual(receiveSlot.sourceState, 'live');
97
+
98
+ receiveSlot.resetSourceState();
99
+
100
+ assert.strictEqual(receiveSlot.memberId, undefined);
101
+ assert.strictEqual(receiveSlot.csi, undefined);
102
+ assert.strictEqual(receiveSlot.sourceState, 'no source');
103
+ });
104
+ });