@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.
- package/dist/common/errors/webex-errors.js +5 -29
- package/dist/common/errors/webex-errors.js.map +1 -1
- package/dist/constants.js +15 -74
- package/dist/constants.js.map +1 -1
- package/dist/media/index.js +68 -213
- package/dist/media/index.js.map +1 -1
- package/dist/media/internal-media-core-wrapper.js +22 -0
- package/dist/media/internal-media-core-wrapper.js.map +1 -0
- package/dist/media/properties.js +20 -25
- package/dist/media/properties.js.map +1 -1
- package/dist/media/util.js +0 -27
- package/dist/media/util.js.map +1 -1
- package/dist/meeting/index.js +694 -432
- package/dist/meeting/index.js.map +1 -1
- package/dist/meeting/request.js +1 -0
- package/dist/meeting/request.js.map +1 -1
- package/dist/meeting/util.js +3 -44
- package/dist/meeting/util.js.map +1 -1
- package/dist/meetings/index.js +64 -5
- package/dist/meetings/index.js.map +1 -1
- package/dist/meetings/util.js +24 -1
- package/dist/meetings/util.js.map +1 -1
- package/dist/members/index.js +68 -0
- package/dist/members/index.js.map +1 -1
- package/dist/multistream/mediaRequestManager.js +132 -0
- package/dist/multistream/mediaRequestManager.js.map +1 -0
- package/dist/multistream/multistreamMedia.js +116 -0
- package/dist/multistream/multistreamMedia.js.map +1 -0
- package/dist/multistream/receiveSlot.js +209 -0
- package/dist/multistream/receiveSlot.js.map +1 -0
- package/dist/multistream/receiveSlotManager.js +195 -0
- package/dist/multistream/receiveSlotManager.js.map +1 -0
- package/dist/multistream/remoteMedia.js +284 -0
- package/dist/multistream/remoteMedia.js.map +1 -0
- package/dist/multistream/remoteMediaGroup.js +243 -0
- package/dist/multistream/remoteMediaGroup.js.map +1 -0
- package/dist/multistream/remoteMediaManager.js +1113 -0
- package/dist/multistream/remoteMediaManager.js.map +1 -0
- package/dist/reconnection-manager/index.js +109 -130
- package/dist/reconnection-manager/index.js.map +1 -1
- package/dist/roap/index.js +57 -240
- package/dist/roap/index.js.map +1 -1
- package/dist/roap/request.js +2 -114
- package/dist/roap/request.js.map +1 -1
- package/dist/roap/turnDiscovery.js +11 -5
- package/dist/roap/turnDiscovery.js.map +1 -1
- package/dist/statsAnalyzer/global.js +2 -0
- package/dist/statsAnalyzer/global.js.map +1 -1
- package/dist/statsAnalyzer/index.js +39 -36
- package/dist/statsAnalyzer/index.js.map +1 -1
- package/package.json +20 -19
- package/src/common/errors/webex-errors.js +0 -18
- package/src/constants.ts +139 -180
- package/src/media/index.js +60 -194
- package/src/media/internal-media-core-wrapper.ts +9 -0
- package/src/media/properties.js +19 -25
- package/src/media/util.js +0 -22
- package/src/meeting/index.js +565 -320
- package/src/meeting/request.js +1 -0
- package/src/meeting/util.js +3 -46
- package/src/meetings/index.js +30 -1
- package/src/meetings/util.js +23 -2
- package/src/members/index.js +48 -0
- package/src/multistream/mediaRequestManager.ts +164 -0
- package/src/multistream/multistreamMedia.ts +92 -0
- package/src/multistream/receiveSlot.ts +141 -0
- package/src/multistream/receiveSlotManager.ts +142 -0
- package/src/multistream/remoteMedia.ts +219 -0
- package/src/multistream/remoteMediaGroup.ts +224 -0
- package/src/multistream/remoteMediaManager.ts +911 -0
- package/src/reconnection-manager/index.js +40 -53
- package/src/roap/index.js +47 -207
- package/src/roap/request.js +1 -72
- package/src/roap/turnDiscovery.ts +12 -6
- package/src/statsAnalyzer/global.js +2 -0
- package/src/statsAnalyzer/index.js +32 -46
- package/test/integration/spec/journey.js +1 -1
- package/test/unit/spec/media/index.ts +223 -0
- package/test/unit/spec/media/properties.ts +73 -82
- package/test/unit/spec/meeting/effectsState.js +1 -3
- package/test/unit/spec/meeting/index.js +420 -228
- package/test/unit/spec/meeting/muteState.js +7 -0
- package/test/unit/spec/meeting/utils.js +61 -2
- package/test/unit/spec/meetings/index.js +0 -4
- package/test/unit/spec/members/index.js +164 -2
- package/test/unit/spec/multistream/mediaRequestManager.ts +511 -0
- package/test/unit/spec/multistream/receiveSlot.ts +104 -0
- package/test/unit/spec/multistream/receiveSlotManager.ts +173 -0
- package/test/unit/spec/multistream/remoteMedia.ts +217 -0
- package/test/unit/spec/multistream/remoteMediaGroup.ts +396 -0
- package/test/unit/spec/multistream/remoteMediaManager.ts +1251 -0
- package/test/unit/spec/roap/index.ts +63 -35
- package/test/unit/spec/stats-analyzer/index.js +19 -22
- package/dist/peer-connection-manager/index.js +0 -794
- package/dist/peer-connection-manager/index.js.map +0 -1
- package/dist/roap/collection.js +0 -73
- package/dist/roap/collection.js.map +0 -1
- package/dist/roap/handler.js +0 -337
- package/dist/roap/handler.js.map +0 -1
- package/dist/roap/state.js +0 -164
- package/dist/roap/state.js.map +0 -1
- package/dist/roap/util.js +0 -102
- package/dist/roap/util.js.map +0 -1
- package/src/peer-connection-manager/index.js +0 -723
- package/src/roap/collection.js +0 -63
- package/src/roap/handler.js +0 -252
- package/src/roap/state.js +0 -149
- package/src/roap/util.js +0 -93
- package/test/unit/spec/peerconnection-manager/index.js +0 -188
- package/test/unit/spec/peerconnection-manager/utils.js +0 -48
- 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
|
+
});
|