@webex/plugin-meetings 3.0.0 → 3.1.0
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/breakouts/breakout.js +1 -1
- package/dist/breakouts/index.js +1 -1
- package/dist/config.d.ts +1 -0
- package/dist/config.js +2 -1
- package/dist/config.js.map +1 -1
- package/dist/constants.d.ts +5 -4
- package/dist/constants.js +8 -4
- package/dist/constants.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/interpretation/index.js +16 -2
- package/dist/interpretation/index.js.map +1 -1
- package/dist/interpretation/siLanguage.js +1 -1
- package/dist/locus-info/mediaSharesUtils.js +15 -1
- package/dist/locus-info/mediaSharesUtils.js.map +1 -1
- package/dist/locus-info/selfUtils.js +5 -0
- package/dist/locus-info/selfUtils.js.map +1 -1
- package/dist/media/MediaConnectionAwaiter.d.ts +61 -0
- package/dist/media/MediaConnectionAwaiter.js +163 -0
- package/dist/media/MediaConnectionAwaiter.js.map +1 -0
- package/dist/media/index.js +4 -1
- package/dist/media/index.js.map +1 -1
- package/dist/media/properties.js +4 -24
- package/dist/media/properties.js.map +1 -1
- package/dist/meeting/index.d.ts +26 -7
- package/dist/meeting/index.js +893 -677
- package/dist/meeting/index.js.map +1 -1
- package/dist/meeting/muteState.d.ts +2 -8
- package/dist/meeting/muteState.js +37 -25
- package/dist/meeting/muteState.js.map +1 -1
- package/dist/meeting/request.d.ts +3 -0
- package/dist/meeting/request.js +32 -23
- package/dist/meeting/request.js.map +1 -1
- package/dist/meeting/util.js +1 -0
- package/dist/meeting/util.js.map +1 -1
- package/dist/meeting-info/utilv2.js +4 -1
- package/dist/meeting-info/utilv2.js.map +1 -1
- package/dist/meetings/index.d.ts +8 -0
- package/dist/meetings/index.js +20 -0
- package/dist/meetings/index.js.map +1 -1
- package/dist/multistream/mediaRequestManager.d.ts +2 -1
- package/dist/multistream/mediaRequestManager.js +1 -1
- package/dist/multistream/mediaRequestManager.js.map +1 -1
- package/dist/multistream/remoteMediaGroup.d.ts +2 -0
- package/dist/multistream/remoteMediaGroup.js +16 -2
- package/dist/multistream/remoteMediaGroup.js.map +1 -1
- package/dist/multistream/remoteMediaManager.d.ts +15 -0
- package/dist/multistream/remoteMediaManager.js +179 -65
- package/dist/multistream/remoteMediaManager.js.map +1 -1
- package/dist/multistream/sendSlotManager.d.ts +9 -1
- package/dist/multistream/sendSlotManager.js +22 -0
- package/dist/multistream/sendSlotManager.js.map +1 -1
- package/dist/reachability/clusterReachability.d.ts +1 -0
- package/dist/reachability/clusterReachability.js +29 -15
- package/dist/reachability/clusterReachability.js.map +1 -1
- package/dist/reachability/index.d.ts +4 -0
- package/dist/reachability/index.js +18 -2
- package/dist/reachability/index.js.map +1 -1
- package/dist/reachability/request.js +12 -10
- package/dist/reachability/request.js.map +1 -1
- package/dist/reachability/util.d.ts +7 -0
- package/dist/reachability/util.js +19 -0
- package/dist/reachability/util.js.map +1 -1
- package/dist/reconnection-manager/index.js +2 -1
- package/dist/reconnection-manager/index.js.map +1 -1
- package/dist/roap/index.d.ts +10 -2
- package/dist/roap/index.js +15 -0
- package/dist/roap/index.js.map +1 -1
- package/dist/roap/request.js +3 -3
- package/dist/roap/request.js.map +1 -1
- package/dist/roap/turnDiscovery.d.ts +64 -17
- package/dist/roap/turnDiscovery.js +307 -126
- package/dist/roap/turnDiscovery.js.map +1 -1
- package/dist/statsAnalyzer/index.js +53 -30
- package/dist/statsAnalyzer/index.js.map +1 -1
- package/dist/webinar/index.js +1 -1
- package/package.json +22 -22
- package/src/config.ts +1 -0
- package/src/constants.ts +7 -3
- package/src/index.ts +1 -0
- package/src/interpretation/index.ts +18 -1
- package/src/locus-info/mediaSharesUtils.ts +16 -0
- package/src/locus-info/selfUtils.ts +5 -0
- package/src/media/MediaConnectionAwaiter.ts +174 -0
- package/src/media/index.ts +3 -1
- package/src/media/properties.ts +6 -31
- package/src/meeting/index.ts +321 -106
- package/src/meeting/muteState.ts +34 -20
- package/src/meeting/request.ts +18 -2
- package/src/meeting/util.ts +1 -0
- package/src/meeting-info/utilv2.ts +2 -1
- package/src/meetings/index.ts +18 -0
- package/src/multistream/mediaRequestManager.ts +4 -1
- package/src/multistream/remoteMediaGroup.ts +19 -0
- package/src/multistream/remoteMediaManager.ts +101 -16
- package/src/multistream/sendSlotManager.ts +28 -0
- package/src/reachability/clusterReachability.ts +20 -5
- package/src/reachability/index.ts +24 -1
- package/src/reachability/request.ts +15 -11
- package/src/reachability/util.ts +21 -0
- package/src/reconnection-manager/index.ts +1 -1
- package/src/roap/index.ts +25 -3
- package/src/roap/request.ts +3 -3
- package/src/roap/turnDiscovery.ts +244 -78
- package/src/statsAnalyzer/index.ts +63 -27
- package/test/integration/spec/journey.js +14 -14
- package/test/integration/spec/space-meeting.js +1 -1
- package/test/unit/spec/interpretation/index.ts +39 -3
- package/test/unit/spec/locus-info/index.js +28 -19
- package/test/unit/spec/locus-info/mediaSharesUtils.ts +9 -0
- package/test/unit/spec/locus-info/selfUtils.js +42 -12
- package/test/unit/spec/media/MediaConnectionAwaiter.ts +344 -0
- package/test/unit/spec/media/index.ts +89 -78
- package/test/unit/spec/media/properties.ts +16 -70
- package/test/unit/spec/meeting/index.js +638 -139
- package/test/unit/spec/meeting/muteState.js +219 -67
- package/test/unit/spec/meeting/request.js +21 -0
- package/test/unit/spec/meeting/utils.js +6 -1
- package/test/unit/spec/meeting-info/utilv2.js +6 -0
- package/test/unit/spec/meetings/index.js +40 -20
- package/test/unit/spec/multistream/mediaRequestManager.ts +20 -2
- package/test/unit/spec/multistream/remoteMediaGroup.ts +79 -1
- package/test/unit/spec/multistream/remoteMediaManager.ts +199 -1
- package/test/unit/spec/multistream/sendSlotManager.ts +50 -18
- package/test/unit/spec/reachability/clusterReachability.ts +86 -22
- package/test/unit/spec/reachability/index.ts +197 -60
- package/test/unit/spec/reachability/request.js +15 -7
- package/test/unit/spec/reachability/util.ts +32 -2
- package/test/unit/spec/reconnection-manager/index.js +28 -0
- package/test/unit/spec/roap/index.ts +61 -6
- package/test/unit/spec/roap/turnDiscovery.ts +298 -16
- package/test/unit/spec/stats-analyzer/index.js +179 -0
- package/dist/member/member.types.d.ts +0 -11
- package/dist/member/member.types.js +0 -17
- package/dist/member/member.types.js.map +0 -1
- package/src/member/member.types.ts +0 -13
- /package/test/unit/spec/locus-info/{lib/selfConstant.js → selfConstant.js} +0 -0
|
@@ -253,6 +253,19 @@ describe('plugin-meetings', () => {
|
|
|
253
253
|
});
|
|
254
254
|
});
|
|
255
255
|
|
|
256
|
+
describe('#_toggleTlsReachability', () => {
|
|
257
|
+
it('should have _toggleTlsReachability', () => {
|
|
258
|
+
assert.equal(typeof webex.meetings._toggleTlsReachability, 'function');
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
describe('success', () => {
|
|
262
|
+
it('should update meetings to do TLS reachability', () => {
|
|
263
|
+
webex.meetings._toggleTlsReachability(true);
|
|
264
|
+
assert.equal(webex.meetings.config.experimental.enableTlsReachability, true);
|
|
265
|
+
});
|
|
266
|
+
});
|
|
267
|
+
});
|
|
268
|
+
|
|
256
269
|
describe('Public API Contracts', () => {
|
|
257
270
|
describe('#register', () => {
|
|
258
271
|
it('emits an event and resolves when register succeeds', async () => {
|
|
@@ -412,9 +425,13 @@ describe('plugin-meetings', () => {
|
|
|
412
425
|
assert.exists(result);
|
|
413
426
|
assert.instanceOf(result, NoiseReductionEffect);
|
|
414
427
|
assert.containsAllKeys(result, ['audioContext', 'isEnabled', 'isReady', 'options']);
|
|
428
|
+
assert.equal(result.options.authToken, 'fake_token');
|
|
415
429
|
assert.deepEqual(result.options, {
|
|
416
|
-
authToken: 'fake_token',
|
|
417
430
|
audioContext: {},
|
|
431
|
+
authToken: 'fake_token',
|
|
432
|
+
mode: 'WORKLET',
|
|
433
|
+
env: 'prod',
|
|
434
|
+
avoidSimd: false,
|
|
418
435
|
});
|
|
419
436
|
assert.exists(result.enable);
|
|
420
437
|
assert.exists(result.disable);
|
|
@@ -424,8 +441,9 @@ describe('plugin-meetings', () => {
|
|
|
424
441
|
it('creates noise reduction effect with custom options passed', async () => {
|
|
425
442
|
const effectOptions = {
|
|
426
443
|
audioContext: {},
|
|
427
|
-
mode: '
|
|
428
|
-
env: '
|
|
444
|
+
mode: 'LEGACY',
|
|
445
|
+
env: 'int',
|
|
446
|
+
avoidSimd: true,
|
|
429
447
|
};
|
|
430
448
|
|
|
431
449
|
const result = await webex.meetings.createNoiseReductionEffect(effectOptions);
|
|
@@ -2003,24 +2021,27 @@ describe('plugin-meetings', () => {
|
|
|
2003
2021
|
assert.notCalled(loggerProxySpy);
|
|
2004
2022
|
});
|
|
2005
2023
|
|
|
2006
|
-
forEach(
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2024
|
+
forEach(
|
|
2025
|
+
[
|
|
2026
|
+
{user: undefined},
|
|
2027
|
+
{user: {userPreferences: {}}},
|
|
2028
|
+
{user: {userPreferences: {userPreferencesItems: {}}}},
|
|
2029
|
+
{user: {userPreferences: {userPreferencesItems: {preferredWebExSite: undefined}}}},
|
|
2030
|
+
],
|
|
2031
|
+
({user}) => {
|
|
2032
|
+
it(`should handle invalid user data ${user}`, async () => {
|
|
2033
|
+
setup({user});
|
|
2014
2034
|
|
|
2015
|
-
|
|
2035
|
+
await webex.meetings.fetchUserPreferredWebexSite();
|
|
2016
2036
|
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2037
|
+
assert.equal(webex.meetings.preferredWebexSite, '');
|
|
2038
|
+
assert.calledOnceWithExactly(
|
|
2039
|
+
loggerProxySpy,
|
|
2040
|
+
'Failed to fetch preferred site from user - no site will be set'
|
|
2041
|
+
);
|
|
2042
|
+
});
|
|
2043
|
+
}
|
|
2044
|
+
);
|
|
2024
2045
|
|
|
2025
2046
|
it('should handle a get user failure', async () => {
|
|
2026
2047
|
setup();
|
|
@@ -2035,7 +2056,6 @@ describe('plugin-meetings', () => {
|
|
|
2035
2056
|
'Failed to fetch preferred site from user - no site will be set'
|
|
2036
2057
|
);
|
|
2037
2058
|
});
|
|
2038
|
-
|
|
2039
2059
|
});
|
|
2040
2060
|
});
|
|
2041
2061
|
|
|
@@ -14,6 +14,7 @@ type ExpectedActiveSpeaker = {
|
|
|
14
14
|
receiveSlots: Array<ReceiveSlot>;
|
|
15
15
|
maxFs?: number;
|
|
16
16
|
maxMbps?: number;
|
|
17
|
+
namedMediaGroups?:[{type: number, value: number}];
|
|
17
18
|
};
|
|
18
19
|
type ExpectedReceiverSelected = {
|
|
19
20
|
policy: 'receiver-selected';
|
|
@@ -80,7 +81,7 @@ describe('MediaRequestManager', () => {
|
|
|
80
81
|
});
|
|
81
82
|
|
|
82
83
|
// helper function for adding an active speaker request
|
|
83
|
-
const addActiveSpeakerRequest = (priority, receiveSlots, maxFs, commit = false, preferLiveVideo = true) =>
|
|
84
|
+
const addActiveSpeakerRequest = (priority, receiveSlots, maxFs, commit = false, preferLiveVideo = true, namedMediaGroups = undefined) =>
|
|
84
85
|
mediaRequestManager.addRequest(
|
|
85
86
|
{
|
|
86
87
|
policyInfo: {
|
|
@@ -89,6 +90,7 @@ describe('MediaRequestManager', () => {
|
|
|
89
90
|
crossPriorityDuplication: CROSS_PRIORITY_DUPLICATION,
|
|
90
91
|
crossPolicyDuplication: CROSS_POLICY_DUPLICATION,
|
|
91
92
|
preferLiveVideo,
|
|
93
|
+
namedMediaGroups,
|
|
92
94
|
},
|
|
93
95
|
receiveSlots,
|
|
94
96
|
codecInfo: {
|
|
@@ -590,7 +592,14 @@ describe('MediaRequestManager', () => {
|
|
|
590
592
|
MAX_FS_720p,
|
|
591
593
|
false
|
|
592
594
|
);
|
|
593
|
-
|
|
595
|
+
addActiveSpeakerRequest(
|
|
596
|
+
254,
|
|
597
|
+
[fakeReceiveSlots[8], fakeReceiveSlots[9], fakeReceiveSlots[10]],
|
|
598
|
+
MAX_FS_720p,
|
|
599
|
+
false,
|
|
600
|
+
true,
|
|
601
|
+
[{type: 1, value: 20}],
|
|
602
|
+
);
|
|
594
603
|
// nothing should be sent out as we didn't commit the requests
|
|
595
604
|
assert.notCalled(sendMediaRequestsCallback);
|
|
596
605
|
|
|
@@ -631,6 +640,15 @@ describe('MediaRequestManager', () => {
|
|
|
631
640
|
maxFs: MAX_FS_720p,
|
|
632
641
|
maxMbps: MAX_MBPS_720p,
|
|
633
642
|
},
|
|
643
|
+
{
|
|
644
|
+
policy: 'active-speaker',
|
|
645
|
+
priority: 254,
|
|
646
|
+
receiveSlots: [fakeWcmeSlots[8], fakeWcmeSlots[9], fakeWcmeSlots[10]],
|
|
647
|
+
maxPayloadBitsPerSecond: MAX_PAYLOADBITSPS_720p,
|
|
648
|
+
maxFs: MAX_FS_720p,
|
|
649
|
+
maxMbps: MAX_MBPS_720p,
|
|
650
|
+
namedMediaGroups: [{type: 1, value: 20}],
|
|
651
|
+
},
|
|
634
652
|
]);
|
|
635
653
|
});
|
|
636
654
|
|
|
@@ -24,6 +24,7 @@ describe('RemoteMediaGroup', () => {
|
|
|
24
24
|
|
|
25
25
|
let fakeMediaRequestManager;
|
|
26
26
|
let fakeReceiveSlots;
|
|
27
|
+
let fakeNamedMediaSlots;
|
|
27
28
|
|
|
28
29
|
let activeSpeakerRequestCounter;
|
|
29
30
|
let receiverSelectedRequestCounter;
|
|
@@ -50,6 +51,10 @@ describe('RemoteMediaGroup', () => {
|
|
|
50
51
|
fakeReceiveSlots = Array(NUM_SLOTS)
|
|
51
52
|
.fill(null)
|
|
52
53
|
.map((_, index) => new FakeSlot(MediaType.VideoMain, `fake receive slot ${index}`));
|
|
54
|
+
|
|
55
|
+
fakeNamedMediaSlots = Array(1)
|
|
56
|
+
.fill(null)
|
|
57
|
+
.map((_, index) => new FakeSlot(MediaType.AudioMain, `fake named media receive slot ${index}`));
|
|
53
58
|
});
|
|
54
59
|
|
|
55
60
|
const getLastActiveSpeakerRequestId = () =>
|
|
@@ -144,6 +149,79 @@ describe('RemoteMediaGroup', () => {
|
|
|
144
149
|
|
|
145
150
|
});
|
|
146
151
|
|
|
152
|
+
describe('setNamedMediaGroup', () => {
|
|
153
|
+
it('updates named media group', () => {
|
|
154
|
+
|
|
155
|
+
const nameGroup1 = { type: 1, value: 20 };
|
|
156
|
+
const nameGroup2 = { type: 1, value: 24 };
|
|
157
|
+
const group = new RemoteMediaGroup(fakeMediaRequestManager, fakeNamedMediaSlots, 255, true, {
|
|
158
|
+
namedMediaGroup: nameGroup1,
|
|
159
|
+
});
|
|
160
|
+
fakeMediaRequestManager.addRequest.resetHistory();
|
|
161
|
+
group.setNamedMediaGroup(nameGroup2, false);
|
|
162
|
+
|
|
163
|
+
assert.calledOnce(fakeMediaRequestManager.cancelRequest);
|
|
164
|
+
|
|
165
|
+
assert.calledOnce(fakeMediaRequestManager.addRequest);
|
|
166
|
+
|
|
167
|
+
assert.calledWith(
|
|
168
|
+
fakeMediaRequestManager.addRequest,
|
|
169
|
+
sinon.match({
|
|
170
|
+
policyInfo: sinon.match({
|
|
171
|
+
policy: 'active-speaker',
|
|
172
|
+
priority: 255,
|
|
173
|
+
namedMediaGroups: sinon.match([{type: 1, value: 24}]),
|
|
174
|
+
}),
|
|
175
|
+
receiveSlots: fakeNamedMediaSlots,
|
|
176
|
+
codecInfo: undefined,
|
|
177
|
+
}),
|
|
178
|
+
false,
|
|
179
|
+
);
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
it('does not call add request when named media group has not changed', () => {
|
|
183
|
+
const group = new RemoteMediaGroup(fakeMediaRequestManager, fakeNamedMediaSlots, 255, true, {
|
|
184
|
+
namedMediaGroup: { type: 1, value: 20 },
|
|
185
|
+
});
|
|
186
|
+
fakeMediaRequestManager.addRequest.resetHistory();
|
|
187
|
+
group.setNamedMediaGroup({ type: 1, value: 20 }, false);
|
|
188
|
+
|
|
189
|
+
assert.notCalled(fakeMediaRequestManager.cancelRequest);
|
|
190
|
+
|
|
191
|
+
assert.notCalled(fakeMediaRequestManager.addRequest);
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
it('remove named media group', () => {
|
|
195
|
+
|
|
196
|
+
const nameGroup1 = { type: 1, value: 20 };
|
|
197
|
+
const nameGroup2 = { type: 1, value: 0 };
|
|
198
|
+
const group = new RemoteMediaGroup(fakeMediaRequestManager, fakeNamedMediaSlots, 255, true, {
|
|
199
|
+
namedMediaGroup: nameGroup1,
|
|
200
|
+
});
|
|
201
|
+
fakeMediaRequestManager.addRequest.resetHistory();
|
|
202
|
+
group.setNamedMediaGroup(nameGroup2, true);
|
|
203
|
+
|
|
204
|
+
assert.calledOnce(fakeMediaRequestManager.cancelRequest);
|
|
205
|
+
|
|
206
|
+
assert.calledOnce(fakeMediaRequestManager.addRequest);
|
|
207
|
+
|
|
208
|
+
assert.calledWith(
|
|
209
|
+
fakeMediaRequestManager.addRequest,
|
|
210
|
+
sinon.match({
|
|
211
|
+
policyInfo: sinon.match({
|
|
212
|
+
policy: 'active-speaker',
|
|
213
|
+
priority: 255,
|
|
214
|
+
nameMediaGroups: undefined,
|
|
215
|
+
}),
|
|
216
|
+
receiveSlots: fakeNamedMediaSlots,
|
|
217
|
+
codecInfo: undefined,
|
|
218
|
+
}),
|
|
219
|
+
true,
|
|
220
|
+
);
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
});
|
|
224
|
+
|
|
147
225
|
describe('setActiveSpeakerCsis', () => {
|
|
148
226
|
it('checks when there is a csi and remote media is not in pinned array', () => {
|
|
149
227
|
const PINNED_INDEX = 2;
|
|
@@ -251,7 +329,7 @@ describe('RemoteMediaGroup', () => {
|
|
|
251
329
|
assert.strictEqual(group.getRemoteMedia('pinned').length, 1);
|
|
252
330
|
|
|
253
331
|
assert.strictEqual(group.isPinned(remoteMedia), true);
|
|
254
|
-
|
|
332
|
+
|
|
255
333
|
assert.calledTwice(fakeMediaRequestManager.cancelRequest);
|
|
256
334
|
assert.calledWith(fakeMediaRequestManager.cancelRequest, 'fake receiver selected request 1');
|
|
257
335
|
|
|
@@ -299,6 +299,204 @@ describe('RemoteMediaManager', () => {
|
|
|
299
299
|
);
|
|
300
300
|
});
|
|
301
301
|
|
|
302
|
+
it('creates a RemoteMediaGroup for named media group audio correctly', async () => {
|
|
303
|
+
let createdInterpretationAudioGroup: RemoteMediaGroup | null = null;
|
|
304
|
+
// create a config with just audio, no video at all and no screen share
|
|
305
|
+
const config: Configuration = {
|
|
306
|
+
audio: {
|
|
307
|
+
numOfActiveSpeakerStreams: 3,
|
|
308
|
+
numOfScreenShareStreams: 0,
|
|
309
|
+
},
|
|
310
|
+
video: {
|
|
311
|
+
preferLiveVideo: false,
|
|
312
|
+
initialLayoutId: 'empty',
|
|
313
|
+
layouts: {
|
|
314
|
+
empty: {},
|
|
315
|
+
},
|
|
316
|
+
},
|
|
317
|
+
namedMediaGroup: {type: 1, value: 20},
|
|
318
|
+
};
|
|
319
|
+
|
|
320
|
+
remoteMediaManager = new RemoteMediaManager(
|
|
321
|
+
fakeReceiveSlotManager,
|
|
322
|
+
fakeMediaRequestManagers,
|
|
323
|
+
config
|
|
324
|
+
);
|
|
325
|
+
|
|
326
|
+
remoteMediaManager.on(Event.InterpretationAudioCreated, (audio: RemoteMediaGroup) => {
|
|
327
|
+
createdInterpretationAudioGroup = audio;
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
remoteMediaManager.start();
|
|
331
|
+
|
|
332
|
+
await testUtils.flushPromises();
|
|
333
|
+
|
|
334
|
+
assert.callCount(fakeReceiveSlotManager.allocateSlot, 4);
|
|
335
|
+
assert.alwaysCalledWith(fakeReceiveSlotManager.allocateSlot, MediaType.AudioMain);
|
|
336
|
+
|
|
337
|
+
assert.isNotNull(createdInterpretationAudioGroup);
|
|
338
|
+
if (createdInterpretationAudioGroup) {
|
|
339
|
+
assert.strictEqual(createdInterpretationAudioGroup.getRemoteMedia().length, 1);
|
|
340
|
+
assert.isTrue(
|
|
341
|
+
createdInterpretationAudioGroup
|
|
342
|
+
.getRemoteMedia()
|
|
343
|
+
.every((remoteMedia) => remoteMedia.mediaType === MediaType.AudioMain)
|
|
344
|
+
);
|
|
345
|
+
assert.strictEqual(createdInterpretationAudioGroup.getRemoteMedia('pinned').length, 0);
|
|
346
|
+
assert.calledTwice(fakeMediaRequestManagers.audio.addRequest);
|
|
347
|
+
assert.calledWith(
|
|
348
|
+
fakeMediaRequestManagers.audio.addRequest,
|
|
349
|
+
sinon.match({
|
|
350
|
+
policyInfo: sinon.match({
|
|
351
|
+
policy: 'active-speaker',
|
|
352
|
+
priority: 255,
|
|
353
|
+
namedMediaGroups: sinon.match([{type: 1, value: 20}]),
|
|
354
|
+
}),
|
|
355
|
+
receiveSlots: Array(1).fill(fakeAudioSlot),
|
|
356
|
+
codecInfo: undefined,
|
|
357
|
+
}),
|
|
358
|
+
false,
|
|
359
|
+
);
|
|
360
|
+
}
|
|
361
|
+
});
|
|
362
|
+
|
|
363
|
+
it('creates new media request when call setReceiveNamedMediaGroup', async () => {
|
|
364
|
+
let createdInterpretationAudioGroup: RemoteMediaGroup | null = null;
|
|
365
|
+
// create a config with just audio, no video at all and no screen share
|
|
366
|
+
const config: Configuration = {
|
|
367
|
+
audio: {
|
|
368
|
+
numOfActiveSpeakerStreams: 3,
|
|
369
|
+
numOfScreenShareStreams: 0,
|
|
370
|
+
},
|
|
371
|
+
video: {
|
|
372
|
+
preferLiveVideo: false,
|
|
373
|
+
initialLayoutId: 'empty',
|
|
374
|
+
layouts: {
|
|
375
|
+
empty: {},
|
|
376
|
+
},
|
|
377
|
+
},
|
|
378
|
+
namedMediaGroup: {type: 1, value: 24},
|
|
379
|
+
};
|
|
380
|
+
|
|
381
|
+
remoteMediaManager = new RemoteMediaManager(
|
|
382
|
+
fakeReceiveSlotManager,
|
|
383
|
+
fakeMediaRequestManagers,
|
|
384
|
+
config
|
|
385
|
+
);
|
|
386
|
+
|
|
387
|
+
remoteMediaManager.on(Event.InterpretationAudioCreated, (audio: RemoteMediaGroup) => {
|
|
388
|
+
createdInterpretationAudioGroup = audio;
|
|
389
|
+
createdInterpretationAudioGroup.setNamedMediaGroup = sinon.stub();
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
await remoteMediaManager.start();
|
|
393
|
+
|
|
394
|
+
// requires 3 main audio slots and one interpretation audio slot
|
|
395
|
+
assert.callCount(fakeReceiveSlotManager.allocateSlot, 4);
|
|
396
|
+
|
|
397
|
+
|
|
398
|
+
resetHistory();
|
|
399
|
+
|
|
400
|
+
|
|
401
|
+
remoteMediaManager.setReceiveNamedMediaGroup(MediaType.AudioMain, 28);
|
|
402
|
+
|
|
403
|
+
// check that setNamedMediaGroup has been called
|
|
404
|
+
assert.calledOnce(createdInterpretationAudioGroup.setNamedMediaGroup);
|
|
405
|
+
assert.calledWith(
|
|
406
|
+
createdInterpretationAudioGroup.setNamedMediaGroup,
|
|
407
|
+
{type: 1, value: 28},
|
|
408
|
+
true,
|
|
409
|
+
);
|
|
410
|
+
|
|
411
|
+
});
|
|
412
|
+
|
|
413
|
+
it('ignore duplicated group when call setReceiveNamedMediaGroup', async () => {
|
|
414
|
+
let createdAudioGroup: RemoteMediaGroup | null = null;
|
|
415
|
+
let audioStopStub;
|
|
416
|
+
// create a config with just audio, no video at all and no screen share
|
|
417
|
+
const config: Configuration = {
|
|
418
|
+
audio: {
|
|
419
|
+
numOfActiveSpeakerStreams: 3,
|
|
420
|
+
numOfScreenShareStreams: 0,
|
|
421
|
+
},
|
|
422
|
+
video: {
|
|
423
|
+
preferLiveVideo: false,
|
|
424
|
+
initialLayoutId: 'empty',
|
|
425
|
+
layouts: {
|
|
426
|
+
empty: {},
|
|
427
|
+
},
|
|
428
|
+
},
|
|
429
|
+
namedMediaGroup: {type: 1, value: 24},
|
|
430
|
+
};
|
|
431
|
+
|
|
432
|
+
remoteMediaManager = new RemoteMediaManager(
|
|
433
|
+
fakeReceiveSlotManager,
|
|
434
|
+
fakeMediaRequestManagers,
|
|
435
|
+
config
|
|
436
|
+
);
|
|
437
|
+
|
|
438
|
+
remoteMediaManager.on(Event.AudioCreated, (audio: RemoteMediaGroup) => {
|
|
439
|
+
audioStopStub = sinon.stub(audio, 'stop');
|
|
440
|
+
});
|
|
441
|
+
|
|
442
|
+
await remoteMediaManager.start();
|
|
443
|
+
|
|
444
|
+
// we're using the default config that requires 3 main audio slots
|
|
445
|
+
assert.callCount(fakeReceiveSlotManager.allocateSlot, 4);
|
|
446
|
+
|
|
447
|
+
|
|
448
|
+
resetHistory();
|
|
449
|
+
|
|
450
|
+
remoteMediaManager.setReceiveNamedMediaGroup(MediaType.AudioMain, 24);
|
|
451
|
+
|
|
452
|
+
assert.notCalled(audioStopStub);
|
|
453
|
+
assert.callCount(fakeReceiveSlotManager.releaseSlot, 0);
|
|
454
|
+
|
|
455
|
+
await testUtils.flushPromises();
|
|
456
|
+
assert.callCount(fakeReceiveSlotManager.allocateSlot, 0);
|
|
457
|
+
assert.notCalled(fakeReceiveSlotManager.allocateSlot);
|
|
458
|
+
|
|
459
|
+
});
|
|
460
|
+
|
|
461
|
+
|
|
462
|
+
it('should throw error if set receive named media group which type is not audio', async () => {
|
|
463
|
+
let createdAudioGroup: RemoteMediaGroup | null = null;
|
|
464
|
+
let audioStopStub;
|
|
465
|
+
// create a config with just audio, no video at all and no screen share
|
|
466
|
+
const config: Configuration = {
|
|
467
|
+
audio: {
|
|
468
|
+
numOfActiveSpeakerStreams: 3,
|
|
469
|
+
numOfScreenShareStreams: 0,
|
|
470
|
+
},
|
|
471
|
+
video: {
|
|
472
|
+
preferLiveVideo: false,
|
|
473
|
+
initialLayoutId: 'empty',
|
|
474
|
+
layouts: {
|
|
475
|
+
empty: {},
|
|
476
|
+
},
|
|
477
|
+
},
|
|
478
|
+
namedMediaGroup: {type: 1, value: 24},
|
|
479
|
+
};
|
|
480
|
+
|
|
481
|
+
remoteMediaManager = new RemoteMediaManager(
|
|
482
|
+
fakeReceiveSlotManager,
|
|
483
|
+
fakeMediaRequestManagers,
|
|
484
|
+
config
|
|
485
|
+
);
|
|
486
|
+
|
|
487
|
+
// Assuming setReceiveNamedMediaGroup returns a promise
|
|
488
|
+
it('should throw error when media type is not audio-main', async () => {
|
|
489
|
+
try {
|
|
490
|
+
await remoteMediaManager.setReceiveNamedMediaGroup(MediaType.VideoMain, 0);
|
|
491
|
+
// If the promise resolves successfully, we should fail the test
|
|
492
|
+
throw new Error('Expected an error but none was thrown');
|
|
493
|
+
} catch (error) {
|
|
494
|
+
// Check if the error message matches the expected one
|
|
495
|
+
expect(error.message).to.equal('cannot set receive named media group which media type is not audio-main');
|
|
496
|
+
}
|
|
497
|
+
});
|
|
498
|
+
});
|
|
499
|
+
|
|
302
500
|
it('pre-allocates receive slots based on the biggest layout', async () => {
|
|
303
501
|
const config = cloneDeep(DefaultTestConfiguration);
|
|
304
502
|
|
|
@@ -693,7 +891,7 @@ describe('RemoteMediaManager', () => {
|
|
|
693
891
|
});
|
|
694
892
|
|
|
695
893
|
expect(config.video.preferLiveVideo).to.equal(true);
|
|
696
|
-
|
|
894
|
+
|
|
697
895
|
assert.calledOnce(fakeMediaRequestManagers.video.commit);
|
|
698
896
|
});
|
|
699
897
|
});
|
|
@@ -10,11 +10,11 @@ describe('SendSlotsManager', () => {
|
|
|
10
10
|
info: sinon.stub(),
|
|
11
11
|
},
|
|
12
12
|
};
|
|
13
|
-
|
|
13
|
+
|
|
14
14
|
beforeEach(() => {
|
|
15
15
|
sendSlotsManager = new SendSlotManager(LoggerProxy);
|
|
16
16
|
});
|
|
17
|
-
|
|
17
|
+
|
|
18
18
|
describe('createSlot', () => {
|
|
19
19
|
let mediaConnection;
|
|
20
20
|
const mediaType = MediaType.AudioMain;
|
|
@@ -27,19 +27,19 @@ describe('SendSlotsManager', () => {
|
|
|
27
27
|
|
|
28
28
|
it('should create a slot for the given mediaType', () => {
|
|
29
29
|
sendSlotsManager.createSlot(mediaConnection, mediaType);
|
|
30
|
-
|
|
30
|
+
|
|
31
31
|
expect(mediaConnection.createSendSlot.calledWith(mediaType, true));
|
|
32
32
|
});
|
|
33
33
|
|
|
34
34
|
it('should create a slot for the given mediaType & active state', () => {
|
|
35
35
|
sendSlotsManager.createSlot(mediaConnection, mediaType, false);
|
|
36
|
-
|
|
36
|
+
|
|
37
37
|
expect(mediaConnection.createSendSlot.calledWith(mediaType, false));
|
|
38
38
|
});
|
|
39
|
-
|
|
39
|
+
|
|
40
40
|
it('should throw an error if a slot for the given mediaType already exists', () => {
|
|
41
41
|
sendSlotsManager.createSlot(mediaConnection, mediaType);
|
|
42
|
-
|
|
42
|
+
|
|
43
43
|
expect(() => sendSlotsManager.createSlot(mediaConnection, mediaType)).to.throw(`Slot for ${mediaType} already exists`);
|
|
44
44
|
});
|
|
45
45
|
});
|
|
@@ -56,7 +56,7 @@ describe('SendSlotsManager', () => {
|
|
|
56
56
|
|
|
57
57
|
it('should return the slot for the given mediaType', () => {
|
|
58
58
|
const slot = sendSlotsManager.createSlot(mediaConnection,mediaType);
|
|
59
|
-
|
|
59
|
+
|
|
60
60
|
expect(sendSlotsManager.getSlot(mediaType)).to.equal(slot);
|
|
61
61
|
});
|
|
62
62
|
|
|
@@ -64,7 +64,7 @@ describe('SendSlotsManager', () => {
|
|
|
64
64
|
expect(() => sendSlotsManager.getSlot(mediaType)).to.throw(`Slot for ${mediaType} does not exist`);
|
|
65
65
|
});
|
|
66
66
|
});
|
|
67
|
-
|
|
67
|
+
|
|
68
68
|
describe('publishStream', () => {
|
|
69
69
|
let mediaConnection;
|
|
70
70
|
const mediaType = MediaType.AudioMain;
|
|
@@ -82,9 +82,9 @@ describe('SendSlotsManager', () => {
|
|
|
82
82
|
};
|
|
83
83
|
mediaConnection.createSendSlot.returns(slot);
|
|
84
84
|
sendSlotsManager.createSlot(mediaConnection, mediaType);
|
|
85
|
-
|
|
85
|
+
|
|
86
86
|
await sendSlotsManager.publishStream(mediaType, stream);
|
|
87
|
-
|
|
87
|
+
|
|
88
88
|
expect(slot.publishStream.calledWith(stream));
|
|
89
89
|
});
|
|
90
90
|
|
|
@@ -112,9 +112,9 @@ describe('SendSlotsManager', () => {
|
|
|
112
112
|
};
|
|
113
113
|
mediaConnection.createSendSlot.returns(slot);
|
|
114
114
|
sendSlotsManager.createSlot(mediaConnection, mediaType);
|
|
115
|
-
|
|
115
|
+
|
|
116
116
|
await sendSlotsManager.unpublishStream(mediaType);
|
|
117
|
-
|
|
117
|
+
|
|
118
118
|
expect(slot.unpublishStream.called);
|
|
119
119
|
});
|
|
120
120
|
|
|
@@ -126,6 +126,38 @@ describe('SendSlotsManager', () => {
|
|
|
126
126
|
});
|
|
127
127
|
});
|
|
128
128
|
|
|
129
|
+
describe('setNamedMediaGroups', () => {
|
|
130
|
+
let mediaConnection;
|
|
131
|
+
const mediaType = MediaType.AudioMain;
|
|
132
|
+
const groups = [{type: 1, value: 20}];
|
|
133
|
+
|
|
134
|
+
beforeEach(() => {
|
|
135
|
+
mediaConnection = {
|
|
136
|
+
createSendSlot: sinon.stub(),
|
|
137
|
+
} as MultistreamRoapMediaConnection;
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it('should publish the given stream to the sendSlot for the given mediaType', async () => {
|
|
141
|
+
const slot = {
|
|
142
|
+
setNamedMediaGroups: sinon.stub().resolves(),
|
|
143
|
+
};
|
|
144
|
+
mediaConnection.createSendSlot.returns(slot);
|
|
145
|
+
sendSlotsManager.createSlot(mediaConnection, mediaType);
|
|
146
|
+
|
|
147
|
+
await sendSlotsManager.setNamedMediaGroups(mediaType, groups);
|
|
148
|
+
|
|
149
|
+
expect(slot.setNamedMediaGroups.calledWith(groups));
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
it('should throw an error if the given mediaType is not audio', () => {
|
|
153
|
+
expect(() => sendSlotsManager.setNamedMediaGroups(MediaType.VideoMain, groups)).to.throw(`sendSlotManager cannot set named media group which media type is ${MediaType.VideoMain}`)
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
it('should throw an error if a slot for the given mediaType does not exist', () => {
|
|
157
|
+
expect(() => sendSlotsManager.setNamedMediaGroups(mediaType, groups)).to.throw(`Slot for ${mediaType} does not exist`)
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
|
|
129
161
|
describe('setActive', () => {
|
|
130
162
|
let mediaConnection;
|
|
131
163
|
const mediaType = MediaType.AudioMain;
|
|
@@ -142,9 +174,9 @@ describe('SendSlotsManager', () => {
|
|
|
142
174
|
};
|
|
143
175
|
mediaConnection.createSendSlot.returns(slot);
|
|
144
176
|
sendSlotsManager.createSlot(mediaConnection, mediaType);
|
|
145
|
-
|
|
177
|
+
|
|
146
178
|
await sendSlotsManager.setActive(mediaType,true);
|
|
147
|
-
|
|
179
|
+
|
|
148
180
|
expect(slot.setActive.called);
|
|
149
181
|
});
|
|
150
182
|
|
|
@@ -170,9 +202,9 @@ describe('SendSlotsManager', () => {
|
|
|
170
202
|
};
|
|
171
203
|
mediaConnection.createSendSlot.returns(slot);
|
|
172
204
|
sendSlotsManager.createSlot(mediaConnection, mediaType);
|
|
173
|
-
|
|
205
|
+
|
|
174
206
|
await sendSlotsManager.setCodecParameters(mediaType, codecParameters);
|
|
175
|
-
|
|
207
|
+
|
|
176
208
|
expect(slot.setCodecParameters.calledWith(codecParameters));
|
|
177
209
|
});
|
|
178
210
|
|
|
@@ -200,9 +232,9 @@ describe('SendSlotsManager', () => {
|
|
|
200
232
|
};
|
|
201
233
|
mediaConnection.createSendSlot.returns(slot);
|
|
202
234
|
sendSlotsManager.createSlot(mediaConnection, mediaType);
|
|
203
|
-
|
|
235
|
+
|
|
204
236
|
await sendSlotsManager.deleteCodecParameters(mediaType,[]);
|
|
205
|
-
|
|
237
|
+
|
|
206
238
|
expect(slot.deleteCodecParameters.called);
|
|
207
239
|
});
|
|
208
240
|
|