@webex/plugin-meetings 3.0.0-stream-classes.4 → 3.0.0-stream-classes.5
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/constants.js +3 -1
- package/dist/constants.js.map +1 -1
- package/dist/interpretation/index.js +1 -1
- package/dist/interpretation/siLanguage.js +1 -1
- package/dist/locus-info/index.js +25 -1
- package/dist/locus-info/index.js.map +1 -1
- package/dist/locus-info/parser.js +5 -0
- package/dist/locus-info/parser.js.map +1 -1
- package/dist/meeting/index.js +72 -15
- package/dist/meeting/index.js.map +1 -1
- package/dist/meeting/request.js +1 -1
- package/dist/meeting/request.js.map +1 -1
- package/dist/metrics/constants.js +3 -1
- package/dist/metrics/constants.js.map +1 -1
- package/dist/multistream/remoteMediaManager.js +46 -9
- package/dist/multistream/remoteMediaManager.js.map +1 -1
- package/dist/types/constants.d.ts +1 -0
- package/dist/types/meeting/index.d.ts +16 -2
- package/dist/types/meeting/locusMediaRequest.d.ts +1 -2
- package/dist/types/meeting/request.d.ts +2 -1
- package/dist/types/meeting/util.d.ts +9 -1
- package/dist/types/metrics/constants.d.ts +3 -0
- package/dist/types/multistream/remoteMediaManager.d.ts +9 -1
- package/dist/types/reachability/index.d.ts +0 -6
- package/dist/types/reachability/request.d.ts +1 -1
- package/dist/types/roap/request.d.ts +2 -1
- package/package.json +1 -1
- package/src/constants.ts +1 -0
- package/src/locus-info/index.ts +33 -2
- package/src/locus-info/parser.ts +7 -0
- package/src/meeting/index.ts +59 -16
- package/src/meeting/request.ts +1 -1
- package/src/metrics/constants.ts +2 -0
- package/src/multistream/remoteMediaManager.ts +41 -4
- package/test/integration/spec/converged-space-meetings.js +7 -7
- package/test/integration/spec/journey.js +85 -103
- package/test/integration/spec/space-meeting.js +9 -9
- package/test/unit/spec/locus-info/index.js +118 -1
- package/test/unit/spec/meeting/index.js +88 -25
- package/test/unit/spec/meetings/index.js +2 -2
- package/test/unit/spec/multistream/remoteMediaManager.ts +10 -2
- package/test/utils/integrationTestUtils.js +4 -4
|
@@ -1406,9 +1406,10 @@ describe('plugin-meetings', () => {
|
|
|
1406
1406
|
});
|
|
1407
1407
|
|
|
1408
1408
|
it('should reject if waitForMediaConnectionConnected() rejects', async () => {
|
|
1409
|
-
|
|
1409
|
+
const FAKE_ERROR = {fatal: true};
|
|
1410
|
+
const getErrorPayloadForClientErrorCodeStub = webex.internal.newMetrics.callDiagnosticMetrics.getErrorPayloadForClientErrorCode = sinon
|
|
1410
1411
|
.stub()
|
|
1411
|
-
.returns(
|
|
1412
|
+
.returns(FAKE_ERROR);
|
|
1412
1413
|
meeting.meetingState = 'ACTIVE';
|
|
1413
1414
|
meeting.mediaProperties.waitForMediaConnectionConnected.rejects(new Error('fake error'));
|
|
1414
1415
|
|
|
@@ -1422,14 +1423,14 @@ describe('plugin-meetings', () => {
|
|
|
1422
1423
|
errorThrown = true;
|
|
1423
1424
|
});
|
|
1424
1425
|
|
|
1426
|
+
assert.calledOnceWithExactly(getErrorPayloadForClientErrorCodeStub, {clientErrorCode: 2004});
|
|
1425
1427
|
assert.calledTwice(webex.internal.newMetrics.submitClientEvent);
|
|
1426
|
-
|
|
1427
1428
|
assert.calledWithMatch(webex.internal.newMetrics.submitClientEvent, {
|
|
1428
1429
|
name: 'client.ice.end',
|
|
1429
1430
|
payload: {
|
|
1430
1431
|
canProceed: false,
|
|
1431
1432
|
icePhase: 'JOIN_MEETING_FINAL',
|
|
1432
|
-
errors: [
|
|
1433
|
+
errors: [FAKE_ERROR],
|
|
1433
1434
|
},
|
|
1434
1435
|
options: {
|
|
1435
1436
|
meetingId: meeting.id,
|
|
@@ -4487,20 +4488,22 @@ describe('plugin-meetings', () => {
|
|
|
4487
4488
|
|
|
4488
4489
|
describe('submitClientEvent on connectionFailed', () => {
|
|
4489
4490
|
it('sends client.ice.end when connectionFailed on CONNECTION_STATE_CHANGED event', () => {
|
|
4490
|
-
|
|
4491
|
-
|
|
4491
|
+
const FAKE_ERROR = {fatal: true};
|
|
4492
|
+
const getErrorPayloadForClientErrorCodeStub = webex.internal.newMetrics.callDiagnosticMetrics.getErrorPayloadForClientErrorCode = sinon
|
|
4493
|
+
.stub()
|
|
4494
|
+
.returns(FAKE_ERROR);
|
|
4492
4495
|
meeting.setupMediaConnectionListeners();
|
|
4493
4496
|
eventListeners[Event.CONNECTION_STATE_CHANGED]({
|
|
4494
4497
|
state: 'Failed',
|
|
4495
4498
|
});
|
|
4499
|
+
assert.calledOnceWithExactly(getErrorPayloadForClientErrorCodeStub, {clientErrorCode: 2004});
|
|
4496
4500
|
assert.calledOnce(webex.internal.newMetrics.submitClientEvent);
|
|
4497
|
-
|
|
4498
4501
|
assert.calledWithMatch(webex.internal.newMetrics.submitClientEvent, {
|
|
4499
4502
|
name: 'client.ice.end',
|
|
4500
4503
|
payload: {
|
|
4501
4504
|
canProceed: false,
|
|
4502
4505
|
icePhase: 'IN_MEETING',
|
|
4503
|
-
errors: [
|
|
4506
|
+
errors: [FAKE_ERROR],
|
|
4504
4507
|
},
|
|
4505
4508
|
options: {
|
|
4506
4509
|
meetingId: meeting.id,
|
|
@@ -5559,29 +5562,40 @@ describe('plugin-meetings', () => {
|
|
|
5559
5562
|
});
|
|
5560
5563
|
});
|
|
5561
5564
|
|
|
5565
|
+
describe('#setPermissionTokenPayload', () => {
|
|
5566
|
+
it('sets correctly', () => {
|
|
5567
|
+
assert.notOk(meeting.permissionTokenPayload);
|
|
5568
|
+
|
|
5569
|
+
const permissionTokenPayloadData = {permission: {userPolicies: {a: true}}, exp: '1234'};
|
|
5570
|
+
|
|
5571
|
+
const jwtDecodeStub = sinon.stub(jwt, 'decode').returns(permissionTokenPayloadData);
|
|
5572
|
+
|
|
5573
|
+
meeting.setPermissionTokenPayload();
|
|
5574
|
+
|
|
5575
|
+
assert.calledOnce(jwtDecodeStub);
|
|
5576
|
+
assert.deepEqual(meeting.permissionTokenPayload, permissionTokenPayloadData);
|
|
5577
|
+
});
|
|
5578
|
+
});
|
|
5579
|
+
|
|
5562
5580
|
describe('#setSelfUserPolicies', () => {
|
|
5563
5581
|
it('sets correctly when policy data is present in token', () => {
|
|
5564
5582
|
assert.notOk(meeting.selfUserPolicies);
|
|
5565
5583
|
|
|
5566
|
-
const dummyToken = 'some data';
|
|
5567
5584
|
const policyData = {permission: {userPolicies: {a: true}}};
|
|
5585
|
+
meeting.permissionTokenPayload = policyData;
|
|
5568
5586
|
|
|
5569
|
-
|
|
5570
|
-
|
|
5571
|
-
meeting.setSelfUserPolicies(dummyToken);
|
|
5587
|
+
meeting.setSelfUserPolicies();
|
|
5572
5588
|
|
|
5573
|
-
assert.deepEqual(meeting.selfUserPolicies,
|
|
5589
|
+
assert.deepEqual(meeting.selfUserPolicies, policyData.permission.userPolicies);
|
|
5574
5590
|
});
|
|
5575
5591
|
|
|
5576
5592
|
it('handles missing permission data', () => {
|
|
5577
5593
|
assert.notOk(meeting.selfUserPolicies);
|
|
5578
5594
|
|
|
5579
|
-
const dummyToken = 'some data';
|
|
5580
5595
|
const policyData = {};
|
|
5596
|
+
meeting.permissionTokenPayload = policyData;
|
|
5581
5597
|
|
|
5582
|
-
|
|
5583
|
-
|
|
5584
|
-
meeting.setSelfUserPolicies(dummyToken);
|
|
5598
|
+
meeting.setSelfUserPolicies();
|
|
5585
5599
|
|
|
5586
5600
|
assert.deepEqual(meeting.selfUserPolicies, undefined);
|
|
5587
5601
|
});
|
|
@@ -5589,12 +5603,10 @@ describe('plugin-meetings', () => {
|
|
|
5589
5603
|
it('handles missing policy data', () => {
|
|
5590
5604
|
assert.notOk(meeting.selfUserPolicies);
|
|
5591
5605
|
|
|
5592
|
-
const dummyToken = 'some data';
|
|
5593
5606
|
const policyData = {permission: {}};
|
|
5607
|
+
meeting.permissionTokenPayload = policyData;
|
|
5594
5608
|
|
|
5595
|
-
|
|
5596
|
-
|
|
5597
|
-
meeting.setSelfUserPolicies(dummyToken);
|
|
5609
|
+
meeting.setSelfUserPolicies();
|
|
5598
5610
|
|
|
5599
5611
|
assert.deepEqual(meeting.selfUserPolicies, undefined);
|
|
5600
5612
|
});
|
|
@@ -5654,19 +5666,37 @@ describe('plugin-meetings', () => {
|
|
|
5654
5666
|
assert.equal(meeting.owner, expectedInfoToParse.owner);
|
|
5655
5667
|
assert.equal(meeting.permissionToken, expectedInfoToParse.permissionToken);
|
|
5656
5668
|
assert.deepEqual(meeting.selfUserPolicies, expectedInfoToParse.selfUserPolicies);
|
|
5669
|
+
|
|
5670
|
+
if(expectedInfoToParse.permissionTokenPayload) {
|
|
5671
|
+
assert.deepEqual(meeting.permissionTokenPayload, expectedInfoToParse.permissionTokenPayload);
|
|
5672
|
+
}
|
|
5657
5673
|
};
|
|
5658
5674
|
|
|
5659
5675
|
it('should parse meeting info from api return when locus meeting object is not available, set values, and return null', () => {
|
|
5660
5676
|
meeting.config.experimental = {enableMediaNegotiatedEvent: true};
|
|
5661
5677
|
meeting.config.experimental.enableUnifiedMeetings = true;
|
|
5678
|
+
|
|
5679
|
+
const expectedPermissionTokenPayload = {
|
|
5680
|
+
exp: "123456",
|
|
5681
|
+
permission: {
|
|
5682
|
+
userPolicies: {
|
|
5683
|
+
a: true
|
|
5684
|
+
}
|
|
5685
|
+
}
|
|
5686
|
+
};
|
|
5687
|
+
|
|
5688
|
+
// generated permissionToken with secret `secret` and
|
|
5689
|
+
// value `JSON.stringify(expectedPermissionTokenPayload)`
|
|
5690
|
+
const permissionToken =
|
|
5691
|
+
'eyJhbGciOiJIUzI1NiJ9.eyJleHAiOiIxMjM0NTYiLCJwZXJtaXNzaW9uIjp7InVzZXJQb2xpY2llcyI6eyJhIjp0cnVlfX19.wkTk0Hp8sUlq2wi2nP4-Ym4Xb7aEUHzyXA1kzk6f0V0';
|
|
5692
|
+
|
|
5662
5693
|
const FAKE_MEETING_INFO = {
|
|
5663
5694
|
body: {
|
|
5664
5695
|
conversationUrl: uuid1,
|
|
5665
5696
|
locusUrl: url1,
|
|
5666
5697
|
meetingJoinUrl: url2,
|
|
5667
5698
|
meetingNumber: '12345',
|
|
5668
|
-
permissionToken
|
|
5669
|
-
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJwZXJtaXNzaW9uIjp7InVzZXJQb2xpY2llcyI6eyJhIjp0cnVlfX0sImlhdCI6MTY4OTE2NDEwMn0.9uL_U7QUdYyMerrgHC_gCKOax2j_bz04u8Ikbv9KiXU',
|
|
5699
|
+
permissionToken,
|
|
5670
5700
|
sipMeetingUri: test1,
|
|
5671
5701
|
sipUrl: test1,
|
|
5672
5702
|
owner: test2,
|
|
@@ -5674,6 +5704,7 @@ describe('plugin-meetings', () => {
|
|
|
5674
5704
|
};
|
|
5675
5705
|
|
|
5676
5706
|
meeting.parseMeetingInfo(FAKE_MEETING_INFO);
|
|
5707
|
+
|
|
5677
5708
|
const expectedInfoToParse = {
|
|
5678
5709
|
conversationUrl: uuid1,
|
|
5679
5710
|
locusUrl: url1,
|
|
@@ -5682,8 +5713,8 @@ describe('plugin-meetings', () => {
|
|
|
5682
5713
|
meetingJoinUrl: url2,
|
|
5683
5714
|
owner: test2,
|
|
5684
5715
|
selfUserPolicies: {a: true},
|
|
5685
|
-
permissionToken
|
|
5686
|
-
|
|
5716
|
+
permissionToken,
|
|
5717
|
+
permissionTokenPayload: expectedPermissionTokenPayload
|
|
5687
5718
|
};
|
|
5688
5719
|
|
|
5689
5720
|
checkParseMeetingInfo(expectedInfoToParse);
|
|
@@ -7993,4 +8024,36 @@ describe('plugin-meetings', () => {
|
|
|
7993
8024
|
});
|
|
7994
8025
|
});
|
|
7995
8026
|
});
|
|
8027
|
+
|
|
8028
|
+
describe('#getPermissionTokenTimeLeftInSec', () => {
|
|
8029
|
+
let now;
|
|
8030
|
+
let clock;
|
|
8031
|
+
|
|
8032
|
+
beforeEach(() => {
|
|
8033
|
+
now = Date.now();
|
|
8034
|
+
|
|
8035
|
+
// mock `new Date()` with constant `now`
|
|
8036
|
+
clock = sinon.useFakeTimers(now);
|
|
8037
|
+
});
|
|
8038
|
+
|
|
8039
|
+
afterEach(() => {
|
|
8040
|
+
clock.restore();
|
|
8041
|
+
})
|
|
8042
|
+
|
|
8043
|
+
it('should return undefined if exp is undefined', () => {
|
|
8044
|
+
assert.equal(meeting.getPermissionTokenTimeLeftInSec(), undefined)
|
|
8045
|
+
});
|
|
8046
|
+
|
|
8047
|
+
it('should return the expected positive exp', () => {
|
|
8048
|
+
// set permission token as now + 1 sec
|
|
8049
|
+
meeting.permissionTokenPayload = {exp: (now + 1000).toString()};
|
|
8050
|
+
assert.equal(meeting.getPermissionTokenTimeLeftInSec(), 1);
|
|
8051
|
+
});
|
|
8052
|
+
|
|
8053
|
+
it('should return the expected negative exp', () => {
|
|
8054
|
+
// set permission token as now - 1 sec
|
|
8055
|
+
meeting.permissionTokenPayload = {exp: (now - 1000).toString()};
|
|
8056
|
+
assert.equal(meeting.getPermissionTokenTimeLeftInSec(), -1);
|
|
8057
|
+
});
|
|
8058
|
+
});
|
|
7996
8059
|
});
|
|
@@ -370,7 +370,7 @@ describe('plugin-meetings', () => {
|
|
|
370
370
|
|
|
371
371
|
assert.exists(result);
|
|
372
372
|
assert.instanceOf(result, VirtualBackgroundEffect);
|
|
373
|
-
assert.containsAllKeys(result, ['loadModel', 'isEnabled', '
|
|
373
|
+
assert.containsAllKeys(result, ['loadModel', 'isEnabled', 'options']);
|
|
374
374
|
assert.deepEqual(result.options, {
|
|
375
375
|
mode: 'BLUR',
|
|
376
376
|
blurStrength: 'STRONG',
|
|
@@ -399,7 +399,7 @@ describe('plugin-meetings', () => {
|
|
|
399
399
|
|
|
400
400
|
assert.exists(result);
|
|
401
401
|
assert.instanceOf(result, VirtualBackgroundEffect);
|
|
402
|
-
assert.containsAllKeys(result, ['loadModel', 'isEnabled', '
|
|
402
|
+
assert.containsAllKeys(result, ['loadModel', 'isEnabled', 'options']);
|
|
403
403
|
assert.deepEqual(result.options, {...effectOptions, authToken: "fake_token"});
|
|
404
404
|
assert.exists(result.enable);
|
|
405
405
|
assert.exists(result.disable);
|
|
@@ -747,7 +747,11 @@ describe('RemoteMediaManager', () => {
|
|
|
747
747
|
|
|
748
748
|
assert.calledWith(
|
|
749
749
|
logger.log,
|
|
750
|
-
'RemoteMediaManager#
|
|
750
|
+
'RemoteMediaManager#setLayout --> new layout selected: Stage'
|
|
751
|
+
);
|
|
752
|
+
assert.calledWith(
|
|
753
|
+
logger.log,
|
|
754
|
+
'RemoteMediaManager#logMainVideoReceiveSlots --> MAIN VIDEO receive slots: unused=0, activeSpeaker=6, receiverSelected=4\ngroup: thumbnails\nfake video slot, fake video slot, fake video slot, fake video slot, fake video slot, fake video slot\nreceiverSelected:\n stage-1: fake video slot\n stage-2: fake video slot\n stage-3: fake video slot\n stage-4: fake video slot\n'
|
|
751
755
|
);
|
|
752
756
|
});
|
|
753
757
|
|
|
@@ -769,7 +773,11 @@ describe('RemoteMediaManager', () => {
|
|
|
769
773
|
|
|
770
774
|
assert.calledWith(
|
|
771
775
|
logger.log,
|
|
772
|
-
'RemoteMediaManager#
|
|
776
|
+
'RemoteMediaManager#setLayout --> new layout selected: AllEqual'
|
|
777
|
+
);
|
|
778
|
+
assert.calledWith(
|
|
779
|
+
logger.log,
|
|
780
|
+
'RemoteMediaManager#logMainVideoReceiveSlots --> MAIN VIDEO receive slots: unused=0, activeSpeaker=9, receiverSelected=0\ngroup: main\nfake video slot, fake video slot, fake video slot, fake video slot, fake video slot, fake video slot, fake video slot, fake video slot, fake video slot\nreceiverSelected:\n'
|
|
773
781
|
);
|
|
774
782
|
});
|
|
775
783
|
|
|
@@ -6,7 +6,7 @@ const addMedia = async (user, options = {}) => {
|
|
|
6
6
|
const {microphone, camera} = options;
|
|
7
7
|
|
|
8
8
|
if (options.multistream) {
|
|
9
|
-
await user.meeting.addMedia({
|
|
9
|
+
await user.meeting.addMedia({localStreams: {microphone, camera}});
|
|
10
10
|
} else {
|
|
11
11
|
const mediaReadyPromises = Array.isArray(options.expectedMediaReadyTypes)
|
|
12
12
|
? options.expectedMediaReadyTypes.reduce((output, expectedMediaReadyType) => {
|
|
@@ -31,13 +31,13 @@ const addMedia = async (user, options = {}) => {
|
|
|
31
31
|
|
|
32
32
|
user.meeting.on('media:ready', mediaReady);
|
|
33
33
|
|
|
34
|
-
await user.meeting.addMedia({
|
|
34
|
+
await user.meeting.addMedia({localStreams: {microphone, camera}});
|
|
35
35
|
await Promise.all(Object.values(mediaReadyPromises).map((defer) => defer.promise));
|
|
36
36
|
};
|
|
37
37
|
|
|
38
38
|
|
|
39
|
-
assert.exists(user.meeting.mediaProperties.
|
|
40
|
-
assert.exists(user.meeting.mediaProperties.
|
|
39
|
+
assert.exists(user.meeting.mediaProperties.audioStream, 'audioStream not present');
|
|
40
|
+
assert.exists(user.meeting.mediaProperties.videoStream, 'videoStream not present');
|
|
41
41
|
|
|
42
42
|
};
|
|
43
43
|
|