@webex/plugin-meetings 3.8.0-next.5 → 3.8.0-next.7
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/interpretation/index.js +1 -1
- package/dist/interpretation/siLanguage.js +1 -1
- package/dist/meeting/index.js +38 -0
- package/dist/meeting/index.js.map +1 -1
- package/dist/meeting/locusMediaRequest.js +21 -5
- package/dist/meeting/locusMediaRequest.js.map +1 -1
- package/dist/types/meeting/index.d.ts +22 -0
- package/dist/webinar/index.js +1 -1
- package/package.json +21 -21
- package/src/meeting/index.ts +34 -0
- package/src/meeting/locusMediaRequest.ts +27 -4
- package/test/unit/spec/meeting/index.js +138 -104
- package/test/unit/spec/meeting/locusMediaRequest.ts +96 -58
@@ -1,14 +1,18 @@
|
|
1
1
|
import 'jsdom-global/register';
|
2
2
|
import sinon from 'sinon';
|
3
3
|
import {assert} from '@webex/test-helper-chai';
|
4
|
-
import {
|
5
|
-
|
4
|
+
import {cloneDeep} from 'lodash';
|
5
|
+
import {EventEmitter} from 'events';
|
6
6
|
import MockWebex from '@webex/test-helper-mock-webex';
|
7
7
|
import Meetings from '@webex/plugin-meetings';
|
8
|
-
import {
|
8
|
+
import {
|
9
|
+
LocalMuteRequest,
|
10
|
+
LocusMediaRequest,
|
11
|
+
RoapRequest,
|
12
|
+
} from '@webex/plugin-meetings/src/meeting/locusMediaRequest';
|
9
13
|
import testUtils from '../../../utils/testUtils';
|
10
|
-
import {
|
11
|
-
import {
|
14
|
+
import {Defer} from '@webex/common';
|
15
|
+
import {IP_VERSION} from '../../../../src/constants';
|
12
16
|
|
13
17
|
describe('LocusMediaRequest.send()', () => {
|
14
18
|
let locusMediaRequest: LocusMediaRequest;
|
@@ -16,10 +20,10 @@ describe('LocusMediaRequest.send()', () => {
|
|
16
20
|
let mockWebex;
|
17
21
|
|
18
22
|
const fakeLocusResponse = {
|
19
|
-
locus: {
|
23
|
+
locus: {something: 'whatever'},
|
20
24
|
};
|
21
25
|
|
22
|
-
const exampleRoapRequestBody:RoapRequest = {
|
26
|
+
const exampleRoapRequestBody: RoapRequest = {
|
23
27
|
type: 'RoapMessage',
|
24
28
|
mediaId: 'mediaId',
|
25
29
|
selfUrl: 'fakeMeetingSelfUrl',
|
@@ -31,8 +35,11 @@ describe('LocusMediaRequest.send()', () => {
|
|
31
35
|
tieBreaker: 0xfffffffe,
|
32
36
|
},
|
33
37
|
reachability: {
|
34
|
-
'wjfkm.wjfkm.*': {udp:{reachable: true}, tcp:{reachable:false}},
|
35
|
-
'1eb65fdf-9643-417f-9974-ad72cae0e10f.59268c12-7a04-4b23-a1a1-4c74be03019a.*': {
|
38
|
+
'wjfkm.wjfkm.*': {udp: {reachable: true}, tcp: {reachable: false}},
|
39
|
+
'1eb65fdf-9643-417f-9974-ad72cae0e10f.59268c12-7a04-4b23-a1a1-4c74be03019a.*': {
|
40
|
+
udp: {reachable: false},
|
41
|
+
tcp: {reachable: true},
|
42
|
+
},
|
36
43
|
},
|
37
44
|
clientMediaPreferences: {
|
38
45
|
preferTranscoding: false,
|
@@ -45,19 +52,22 @@ describe('LocusMediaRequest.send()', () => {
|
|
45
52
|
reachability: {
|
46
53
|
version: '1',
|
47
54
|
result: 'some fake reachability result',
|
48
|
-
}
|
49
|
-
}
|
55
|
+
},
|
56
|
+
},
|
50
57
|
};
|
51
58
|
|
52
|
-
const createExpectedRoapBody = (
|
59
|
+
const createExpectedRoapBody = (
|
60
|
+
expectedMessageType,
|
61
|
+
expectedMute: {audioMuted: boolean; videoMuted: boolean}
|
62
|
+
) => {
|
53
63
|
return {
|
54
|
-
device: {
|
64
|
+
device: {url: 'deviceUrl', deviceType: 'deviceType', regionCode: 'regionCode'},
|
55
65
|
correlationId: 'correlationId',
|
56
66
|
localMedias: [
|
57
67
|
{
|
58
68
|
localSdp: `{"audioMuted":${expectedMute.audioMuted},"videoMuted":${expectedMute.videoMuted},"roapMessage":{"messageType":"${expectedMessageType}","sdps":["sdp"],"version":"2","seq":1,"tieBreaker":4294967294},"reachability":{"wjfkm.wjfkm.*":{"udp":{"reachable":true},"tcp":{"reachable":false}},"1eb65fdf-9643-417f-9974-ad72cae0e10f.59268c12-7a04-4b23-a1a1-4c74be03019a.*":{"udp":{"reachable":false},"tcp":{"reachable":true}}}}`,
|
59
|
-
mediaId: 'mediaId'
|
60
|
-
}
|
69
|
+
mediaId: 'mediaId',
|
70
|
+
},
|
61
71
|
],
|
62
72
|
clientMediaPreferences: {
|
63
73
|
preferTranscoding: false,
|
@@ -65,24 +75,27 @@ describe('LocusMediaRequest.send()', () => {
|
|
65
75
|
joinCookie: {
|
66
76
|
anycastEntryPoint: 'aws-eu-west-1',
|
67
77
|
clientIpAddress: 'some ip',
|
68
|
-
timeShot: '2023-05-23T08:03:49Z'
|
78
|
+
timeShot: '2023-05-23T08:03:49Z',
|
69
79
|
},
|
70
80
|
reachability: {
|
71
81
|
version: '1',
|
72
82
|
result: 'some fake reachability result',
|
73
|
-
}
|
74
|
-
}
|
83
|
+
},
|
84
|
+
},
|
75
85
|
};
|
76
86
|
};
|
77
87
|
|
78
|
-
const exampleLocalMuteRequestBody:LocalMuteRequest = {
|
88
|
+
const exampleLocalMuteRequestBody: LocalMuteRequest = {
|
79
89
|
type: 'LocalMute',
|
80
90
|
mediaId: 'mediaId',
|
81
91
|
selfUrl: 'fakeMeetingSelfUrl',
|
82
92
|
muteOptions: {},
|
83
93
|
};
|
84
94
|
|
85
|
-
const createExpectedLocalMuteBody = (
|
95
|
+
const createExpectedLocalMuteBody = (
|
96
|
+
expectedMute: {audioMuted: boolean; videoMuted: boolean},
|
97
|
+
sequence = undefined
|
98
|
+
) => {
|
86
99
|
const body: any = {
|
87
100
|
device: {
|
88
101
|
url: 'deviceUrl',
|
@@ -116,33 +129,37 @@ describe('LocusMediaRequest.send()', () => {
|
|
116
129
|
|
117
130
|
mockWebex.internal = {
|
118
131
|
newMetrics: {
|
119
|
-
submitClientEvent: sinon.stub()
|
132
|
+
submitClientEvent: sinon.stub(),
|
120
133
|
},
|
121
134
|
};
|
122
135
|
|
123
|
-
locusMediaRequest = new LocusMediaRequest(
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
136
|
+
locusMediaRequest = new LocusMediaRequest(
|
137
|
+
{
|
138
|
+
device: {
|
139
|
+
url: 'deviceUrl',
|
140
|
+
deviceType: 'deviceType',
|
141
|
+
regionCode: 'regionCode',
|
142
|
+
},
|
143
|
+
correlationId: 'correlationId',
|
144
|
+
meetingId: 'meetingId',
|
145
|
+
preferTranscoding: true,
|
128
146
|
},
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
parent: mockWebex,
|
134
|
-
});
|
147
|
+
{
|
148
|
+
parent: mockWebex,
|
149
|
+
}
|
150
|
+
);
|
135
151
|
webexRequestStub = sinon.stub(locusMediaRequest, 'request').resolves(fakeLocusResponse);
|
136
|
-
})
|
152
|
+
});
|
137
153
|
|
138
|
-
const sendLocalMute = (muteOptions, overrides={}) =>
|
154
|
+
const sendLocalMute = (muteOptions, overrides = {}) =>
|
155
|
+
locusMediaRequest.send({...exampleLocalMuteRequestBody, ...overrides, muteOptions});
|
139
156
|
|
140
157
|
const sendRoapMessage = (messageType) => {
|
141
158
|
const request = cloneDeep(exampleRoapRequestBody);
|
142
159
|
|
143
160
|
request.roapMessage.messageType = messageType;
|
144
161
|
return locusMediaRequest.send(request);
|
145
|
-
}
|
162
|
+
};
|
146
163
|
|
147
164
|
/** Helper function that makes sure the LocusMediaRequest.confluenceState is 'created' */
|
148
165
|
const ensureConfluenceCreated = async () => {
|
@@ -150,7 +167,7 @@ describe('LocusMediaRequest.send()', () => {
|
|
150
167
|
|
151
168
|
webexRequestStub.resetHistory();
|
152
169
|
mockWebex.internal.newMetrics.submitClientEvent.resetHistory();
|
153
|
-
}
|
170
|
+
};
|
154
171
|
|
155
172
|
const checkMetrics = (expectedMetrics: boolean = true) => {
|
156
173
|
if (expectedMetrics) {
|
@@ -170,7 +187,7 @@ describe('LocusMediaRequest.send()', () => {
|
|
170
187
|
} else {
|
171
188
|
assert.notCalled(mockWebex.internal.newMetrics.submitClientEvent);
|
172
189
|
}
|
173
|
-
}
|
190
|
+
};
|
174
191
|
|
175
192
|
it('sends a roap message', async () => {
|
176
193
|
const result = await sendRoapMessage('OFFER');
|
@@ -181,6 +198,8 @@ describe('LocusMediaRequest.send()', () => {
|
|
181
198
|
method: 'PUT',
|
182
199
|
uri: 'fakeMeetingSelfUrl/media',
|
183
200
|
body: createExpectedRoapBody('OFFER', {audioMuted: true, videoMuted: true}),
|
201
|
+
upload: sinon.match.instanceOf(EventEmitter),
|
202
|
+
download: sinon.match.instanceOf(EventEmitter),
|
184
203
|
});
|
185
204
|
|
186
205
|
checkMetrics();
|
@@ -210,6 +229,8 @@ describe('LocusMediaRequest.send()', () => {
|
|
210
229
|
method: 'PUT',
|
211
230
|
uri: 'fakeMeetingSelfUrl/media',
|
212
231
|
body: createExpectedLocalMuteBody({audioMuted: false, videoMuted: false}),
|
232
|
+
upload: sinon.match.instanceOf(EventEmitter),
|
233
|
+
download: sinon.match.instanceOf(EventEmitter),
|
213
234
|
});
|
214
235
|
|
215
236
|
checkMetrics(false);
|
@@ -228,6 +249,8 @@ describe('LocusMediaRequest.send()', () => {
|
|
228
249
|
method: 'PUT',
|
229
250
|
uri: 'fakeMeetingSelfUrl/media',
|
230
251
|
body: createExpectedLocalMuteBody({audioMuted: false, videoMuted: false}, sequence),
|
252
|
+
upload: sinon.match.instanceOf(EventEmitter),
|
253
|
+
download: sinon.match.instanceOf(EventEmitter),
|
231
254
|
});
|
232
255
|
});
|
233
256
|
|
@@ -237,15 +260,13 @@ describe('LocusMediaRequest.send()', () => {
|
|
237
260
|
let result1;
|
238
261
|
let result2;
|
239
262
|
|
240
|
-
const promise1 = sendLocalMute({audioMuted: true, videoMuted: false})
|
241
|
-
|
242
|
-
|
243
|
-
});
|
263
|
+
const promise1 = sendLocalMute({audioMuted: true, videoMuted: false}).then((result) => {
|
264
|
+
result1 = result;
|
265
|
+
});
|
244
266
|
|
245
|
-
const promise2 = sendLocalMute({audioMuted: false, videoMuted: true})
|
246
|
-
|
247
|
-
|
248
|
-
});
|
267
|
+
const promise2 = sendLocalMute({audioMuted: false, videoMuted: true}).then((result) => {
|
268
|
+
result2 = result;
|
269
|
+
});
|
249
270
|
|
250
271
|
await testUtils.flushPromises();
|
251
272
|
|
@@ -258,6 +279,8 @@ describe('LocusMediaRequest.send()', () => {
|
|
258
279
|
method: 'PUT',
|
259
280
|
uri: 'fakeMeetingSelfUrl/media',
|
260
281
|
body: createExpectedLocalMuteBody({audioMuted: false, videoMuted: true}),
|
282
|
+
upload: sinon.match.instanceOf(EventEmitter),
|
283
|
+
download: sinon.match.instanceOf(EventEmitter),
|
261
284
|
});
|
262
285
|
|
263
286
|
checkMetrics(false);
|
@@ -277,6 +300,8 @@ describe('LocusMediaRequest.send()', () => {
|
|
277
300
|
method: 'PUT',
|
278
301
|
uri: 'fakeMeetingSelfUrl/media',
|
279
302
|
body: createExpectedLocalMuteBody({audioMuted: true, videoMuted: false}),
|
303
|
+
upload: sinon.match.instanceOf(EventEmitter),
|
304
|
+
download: sinon.match.instanceOf(EventEmitter),
|
280
305
|
});
|
281
306
|
|
282
307
|
checkMetrics(false);
|
@@ -296,6 +321,8 @@ describe('LocusMediaRequest.send()', () => {
|
|
296
321
|
method: 'PUT',
|
297
322
|
uri: 'fakeMeetingSelfUrl/media',
|
298
323
|
body: createExpectedRoapBody('OFFER', {audioMuted: true, videoMuted: false}),
|
324
|
+
upload: sinon.match.instanceOf(EventEmitter),
|
325
|
+
download: sinon.match.instanceOf(EventEmitter),
|
299
326
|
});
|
300
327
|
|
301
328
|
checkMetrics();
|
@@ -328,10 +355,10 @@ describe('LocusMediaRequest.send()', () => {
|
|
328
355
|
* after the processing cycle from which it was called is finished.
|
329
356
|
* This helper function waits for this to happen - it's needed, because we're using
|
330
357
|
* fake timers in these tests
|
331
|
-
|
358
|
+
*/
|
332
359
|
const ensureQueueProcessingIsStarted = () => {
|
333
360
|
clock.tick(1);
|
334
|
-
}
|
361
|
+
};
|
335
362
|
it('queues requests if there is one already in progress', async () => {
|
336
363
|
results.push(sendRoapMessage('OFFER'));
|
337
364
|
|
@@ -342,6 +369,8 @@ describe('LocusMediaRequest.send()', () => {
|
|
342
369
|
method: 'PUT',
|
343
370
|
uri: 'fakeMeetingSelfUrl/media',
|
344
371
|
body: createExpectedRoapBody('OFFER', {audioMuted: true, videoMuted: true}),
|
372
|
+
upload: sinon.match.instanceOf(EventEmitter),
|
373
|
+
download: sinon.match.instanceOf(EventEmitter),
|
345
374
|
});
|
346
375
|
|
347
376
|
webexRequestStub.resetHistory();
|
@@ -364,6 +393,8 @@ describe('LocusMediaRequest.send()', () => {
|
|
364
393
|
method: 'PUT',
|
365
394
|
uri: 'fakeMeetingSelfUrl/media',
|
366
395
|
body: createExpectedRoapBody('OK', {audioMuted: true, videoMuted: true}),
|
396
|
+
upload: sinon.match.instanceOf(EventEmitter),
|
397
|
+
download: sinon.match.instanceOf(EventEmitter),
|
367
398
|
});
|
368
399
|
|
369
400
|
// promise returned by the first call to send OFFER should be resolved by now
|
@@ -386,6 +417,8 @@ describe('LocusMediaRequest.send()', () => {
|
|
386
417
|
method: 'PUT',
|
387
418
|
uri: 'fakeMeetingSelfUrl/media',
|
388
419
|
body: createExpectedRoapBody('OFFER', {audioMuted: false, videoMuted: false}),
|
420
|
+
upload: sinon.match.instanceOf(EventEmitter),
|
421
|
+
download: sinon.match.instanceOf(EventEmitter),
|
389
422
|
});
|
390
423
|
|
391
424
|
webexRequestStub.resetHistory();
|
@@ -410,6 +443,8 @@ describe('LocusMediaRequest.send()', () => {
|
|
410
443
|
method: 'PUT',
|
411
444
|
uri: 'fakeMeetingSelfUrl/media',
|
412
445
|
body: createExpectedRoapBody('OK', {audioMuted: false, videoMuted: true}),
|
446
|
+
upload: sinon.match.instanceOf(EventEmitter),
|
447
|
+
download: sinon.match.instanceOf(EventEmitter),
|
413
448
|
});
|
414
449
|
|
415
450
|
// promise returned by the first call to send OFFER should be resolved by now
|
@@ -438,16 +473,17 @@ describe('LocusMediaRequest.send()', () => {
|
|
438
473
|
|
439
474
|
ensureQueueProcessingIsStarted();
|
440
475
|
|
441
|
-
sendLocalMute({audioMuted: false, videoMuted: true})
|
442
|
-
|
443
|
-
|
444
|
-
});
|
476
|
+
sendLocalMute({audioMuted: false, videoMuted: true}).then((response) => {
|
477
|
+
result = response;
|
478
|
+
});
|
445
479
|
|
446
480
|
// only roap offer should have been sent so far
|
447
481
|
assert.calledOnceWithExactly(webexRequestStub, {
|
448
482
|
method: 'PUT',
|
449
483
|
uri: 'fakeMeetingSelfUrl/media',
|
450
484
|
body: createExpectedRoapBody('OFFER', {audioMuted: true, videoMuted: true}),
|
485
|
+
upload: sinon.match.instanceOf(EventEmitter),
|
486
|
+
download: sinon.match.instanceOf(EventEmitter),
|
451
487
|
});
|
452
488
|
assert.equal(result, undefined); // sendLocalMute shouldn't resolve yet, as the request should be queued
|
453
489
|
assert.equal(locusMediaRequest.isConfluenceCreated(), false);
|
@@ -464,10 +500,12 @@ describe('LocusMediaRequest.send()', () => {
|
|
464
500
|
method: 'PUT',
|
465
501
|
uri: 'fakeMeetingSelfUrl/media',
|
466
502
|
body: createExpectedLocalMuteBody({audioMuted: false, videoMuted: true}),
|
503
|
+
upload: sinon.match.instanceOf(EventEmitter),
|
504
|
+
download: sinon.match.instanceOf(EventEmitter),
|
467
505
|
});
|
468
506
|
|
469
507
|
// check also the result once Locus replies to local mute
|
470
|
-
const fakeLocusResponse = {
|
508
|
+
const fakeLocusResponse = {response: 'ok'};
|
471
509
|
requestsToLocus[1].resolve(fakeLocusResponse);
|
472
510
|
await testUtils.flushPromises();
|
473
511
|
assert.deepEqual(result, fakeLocusResponse);
|
@@ -487,10 +525,9 @@ describe('LocusMediaRequest.send()', () => {
|
|
487
525
|
assert.equal(locusMediaRequest.isConfluenceCreated(), true);
|
488
526
|
|
489
527
|
// now send local mute
|
490
|
-
sendLocalMute({audioMuted: false, videoMuted: true})
|
491
|
-
|
492
|
-
|
493
|
-
});
|
528
|
+
sendLocalMute({audioMuted: false, videoMuted: true}).then((response) => {
|
529
|
+
result = response;
|
530
|
+
});
|
494
531
|
|
495
532
|
ensureQueueProcessingIsStarted();
|
496
533
|
|
@@ -499,8 +536,9 @@ describe('LocusMediaRequest.send()', () => {
|
|
499
536
|
method: 'PUT',
|
500
537
|
uri: 'fakeMeetingSelfUrl/media',
|
501
538
|
body: createExpectedLocalMuteBody({audioMuted: false, videoMuted: true}),
|
539
|
+
upload: sinon.match.instanceOf(EventEmitter),
|
540
|
+
download: sinon.match.instanceOf(EventEmitter),
|
502
541
|
});
|
503
542
|
});
|
504
|
-
|
505
543
|
});
|
506
|
-
})
|
544
|
+
});
|