@webex/plugin-meetings 3.0.0-beta.34 → 3.0.0-beta.36
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/edit-lock-error.js +52 -0
- package/dist/breakouts/edit-lock-error.js.map +1 -0
- package/dist/breakouts/index.js +86 -2
- package/dist/breakouts/index.js.map +1 -1
- package/dist/constants.js +14 -2
- package/dist/constants.js.map +1 -1
- package/dist/media/index.js +4 -18
- package/dist/media/index.js.map +1 -1
- package/dist/media/properties.js +3 -3
- package/dist/media/properties.js.map +1 -1
- package/dist/meeting/index.js +194 -306
- package/dist/meeting/index.js.map +1 -1
- package/dist/meeting/muteState.js +7 -2
- package/dist/meeting/muteState.js.map +1 -1
- package/dist/meeting/request.js +135 -85
- package/dist/meeting/request.js.map +1 -1
- package/dist/meeting/util.js +2 -2
- package/dist/meeting/util.js.map +1 -1
- package/dist/metrics/constants.js +0 -4
- package/dist/metrics/constants.js.map +1 -1
- package/dist/reachability/index.js +25 -17
- package/dist/reachability/index.js.map +1 -1
- package/dist/reachability/request.js +12 -5
- package/dist/reachability/request.js.map +1 -1
- package/dist/reconnection-manager/index.js +1 -2
- package/dist/reconnection-manager/index.js.map +1 -1
- package/dist/roap/request.js +114 -83
- package/dist/roap/request.js.map +1 -1
- package/dist/types/breakouts/edit-lock-error.d.ts +15 -0
- package/dist/types/constants.d.ts +13 -1
- package/dist/types/media/properties.d.ts +7 -6
- package/dist/types/meeting/index.d.ts +11 -36
- package/dist/types/meeting/request.d.ts +10 -0
- package/dist/types/metrics/constants.d.ts +0 -4
- package/dist/types/reachability/request.d.ts +5 -3
- package/dist/types/roap/request.d.ts +6 -3
- package/package.json +19 -19
- package/src/breakouts/README.md +8 -2
- package/src/breakouts/edit-lock-error.ts +25 -0
- package/src/breakouts/index.ts +73 -0
- package/src/constants.ts +13 -1
- package/src/media/index.ts +14 -24
- package/src/media/properties.ts +16 -10
- package/src/meeting/index.ts +122 -204
- package/src/meeting/muteState.ts +5 -5
- package/src/meeting/request.ts +35 -1
- package/src/meeting/util.ts +5 -4
- package/src/metrics/constants.ts +0 -4
- package/src/reachability/index.ts +12 -4
- package/src/reachability/request.ts +10 -5
- package/src/reconnection-manager/index.ts +1 -1
- package/src/roap/request.ts +93 -78
- package/test/integration/spec/converged-space-meetings.js +3 -3
- package/test/integration/spec/journey.js +3 -3
- package/test/unit/spec/breakouts/edit-lock-error.ts +30 -0
- package/test/unit/spec/breakouts/index.ts +92 -1
- package/test/unit/spec/media/index.ts +8 -6
- package/test/unit/spec/meeting/index.js +87 -114
- package/test/unit/spec/meeting/muteState.js +21 -22
- package/test/unit/spec/meeting/request.js +27 -0
- package/test/unit/spec/meeting/utils.js +3 -1
- package/test/unit/spec/reachability/index.ts +18 -7
- package/test/unit/spec/reachability/request.js +66 -0
- package/test/unit/spec/roap/request.ts +187 -84
- package/test/utils/testUtils.js +30 -25
- package/dist/meeting/effectsState.js +0 -262
- package/dist/meeting/effectsState.js.map +0 -1
- package/dist/types/meeting/effectsState.d.ts +0 -42
- package/src/meeting/effectsState.ts +0 -211
- package/test/unit/spec/meeting/effectsState.js +0 -285
|
@@ -22,7 +22,8 @@ import {
|
|
|
22
22
|
LOCUSINFO,
|
|
23
23
|
PC_BAIL_TIMEOUT,
|
|
24
24
|
} from '@webex/plugin-meetings/src/constants';
|
|
25
|
-
import
|
|
25
|
+
import * as InternalMediaCoreModule from '@webex/internal-media-core';
|
|
26
|
+
import {ConnectionState, Event, Errors, ErrorType, LocalTrackEvents, RemoteTrackType} from '@webex/internal-media-core';
|
|
26
27
|
import * as StatsAnalyzerModule from '@webex/plugin-meetings/src/statsAnalyzer';
|
|
27
28
|
import * as MuteStateModule from '@webex/plugin-meetings/src/meeting/muteState';
|
|
28
29
|
import EventsScope from '@webex/plugin-meetings/src/common/events/events-scope';
|
|
@@ -194,7 +195,11 @@ describe('plugin-meetings', () => {
|
|
|
194
195
|
TriggerProxy.trigger = sinon.stub().returns(true);
|
|
195
196
|
Metrics.postEvent = sinon.stub();
|
|
196
197
|
Metrics.initialSetup(null, webex);
|
|
197
|
-
MediaUtil.createMediaStream = sinon.stub().
|
|
198
|
+
MediaUtil.createMediaStream = sinon.stub().callsFake((tracks) => {
|
|
199
|
+
return {
|
|
200
|
+
getTracks: () => tracks
|
|
201
|
+
};
|
|
202
|
+
});;
|
|
198
203
|
|
|
199
204
|
uuid1 = uuid.v4();
|
|
200
205
|
uuid2 = uuid.v4();
|
|
@@ -483,85 +488,6 @@ describe('plugin-meetings', () => {
|
|
|
483
488
|
});
|
|
484
489
|
});
|
|
485
490
|
});
|
|
486
|
-
describe('#enableBNR', () => {
|
|
487
|
-
it('should have #enableBnr', () => {
|
|
488
|
-
assert.exists(meeting.enableBNR);
|
|
489
|
-
});
|
|
490
|
-
|
|
491
|
-
describe('before audio attached to meeting', () => {
|
|
492
|
-
it('should throw no audio error', async () => {
|
|
493
|
-
await meeting.enableBNR().catch((err) => {
|
|
494
|
-
assert.equal(err.toString(), "Error: Meeting doesn't have an audioTrack attached");
|
|
495
|
-
});
|
|
496
|
-
});
|
|
497
|
-
});
|
|
498
|
-
|
|
499
|
-
describe('after audio attached to meeting', () => {
|
|
500
|
-
let handleClientRequest;
|
|
501
|
-
|
|
502
|
-
beforeEach(async () => {
|
|
503
|
-
await meeting.getMediaStreams();
|
|
504
|
-
await meeting.addMedia();
|
|
505
|
-
});
|
|
506
|
-
|
|
507
|
-
it('should throw error if meeting audio is muted', async () => {
|
|
508
|
-
const handleClientRequest = (meeting, mute) => {
|
|
509
|
-
meeting.mediaProperties.audioTrack.enabled = !mute;
|
|
510
|
-
|
|
511
|
-
return Promise.resolve();
|
|
512
|
-
};
|
|
513
|
-
const isMuted = () => !meeting.mediaProperties.audioTrack.enabled;
|
|
514
|
-
|
|
515
|
-
meeting.locusInfo.parsedLocus = {self: {state: 'JOINED'}};
|
|
516
|
-
meeting.mediaId = 'mediaId';
|
|
517
|
-
meeting.audio = {handleClientRequest, isMuted};
|
|
518
|
-
await meeting.muteAudio();
|
|
519
|
-
await meeting.enableBNR().catch((err) => {
|
|
520
|
-
assert.equal(err.message, 'Cannot enable BNR while meeting is muted');
|
|
521
|
-
});
|
|
522
|
-
});
|
|
523
|
-
|
|
524
|
-
it('should return true on enable bnr success', async () => {
|
|
525
|
-
handleClientRequest = sinon.stub().returns(Promise.resolve(true));
|
|
526
|
-
meeting.effects = {handleClientRequest};
|
|
527
|
-
const response = await meeting.enableBNR();
|
|
528
|
-
|
|
529
|
-
assert.equal(response, true);
|
|
530
|
-
});
|
|
531
|
-
});
|
|
532
|
-
});
|
|
533
|
-
|
|
534
|
-
describe('#disableBNR', () => {
|
|
535
|
-
describe('before audio attached to meeting', () => {
|
|
536
|
-
it('should have #disableBnr', () => {
|
|
537
|
-
assert.exists(meeting.disableBNR);
|
|
538
|
-
});
|
|
539
|
-
|
|
540
|
-
it('should throw no audio error', async () => {
|
|
541
|
-
await meeting.disableBNR().catch((err) => {
|
|
542
|
-
assert.equal(err.toString(), "Error: Meeting doesn't have an audioTrack attached");
|
|
543
|
-
});
|
|
544
|
-
});
|
|
545
|
-
});
|
|
546
|
-
describe('after audio attached to meeting', () => {
|
|
547
|
-
beforeEach(async () => {
|
|
548
|
-
await meeting.getMediaStreams();
|
|
549
|
-
await meeting.addMedia();
|
|
550
|
-
});
|
|
551
|
-
|
|
552
|
-
let handleClientRequest;
|
|
553
|
-
let isBnrEnabled;
|
|
554
|
-
|
|
555
|
-
it('should return true on disable bnr success', async () => {
|
|
556
|
-
handleClientRequest = sinon.stub().returns(Promise.resolve(true));
|
|
557
|
-
isBnrEnabled = sinon.stub().returns(Promise.resolve(true));
|
|
558
|
-
meeting.effects = {handleClientRequest, isBnrEnabled};
|
|
559
|
-
const response = await meeting.disableBNR();
|
|
560
|
-
|
|
561
|
-
assert.equal(response, true);
|
|
562
|
-
});
|
|
563
|
-
});
|
|
564
|
-
});
|
|
565
491
|
});
|
|
566
492
|
describe('#muteVideo', () => {
|
|
567
493
|
it('should have #muteVideo', () => {
|
|
@@ -1311,8 +1237,7 @@ describe('plugin-meetings', () => {
|
|
|
1311
1237
|
.addMedia({
|
|
1312
1238
|
mediaSettings: {},
|
|
1313
1239
|
})
|
|
1314
|
-
.catch((
|
|
1315
|
-
assert.equal(error.code, IceGatheringFailed.CODE);
|
|
1240
|
+
.catch(() => {
|
|
1316
1241
|
errorThrown = true;
|
|
1317
1242
|
});
|
|
1318
1243
|
|
|
@@ -1700,26 +1625,30 @@ describe('plugin-meetings', () => {
|
|
|
1700
1625
|
|
|
1701
1626
|
it('skips canUpdateMedia() check on contentTracks.onended', () => {
|
|
1702
1627
|
const {mediaProperties} = meeting;
|
|
1703
|
-
let registeredListener = null;
|
|
1704
1628
|
const fakeTrack = {
|
|
1705
1629
|
getSettings: sinon.stub().returns({}),
|
|
1706
|
-
onended: sinon.stub(),
|
|
1707
|
-
addEventListener: sinon.stub().callsFake((event, listener) => {
|
|
1708
|
-
registeredListener = listener;
|
|
1709
|
-
}),
|
|
1710
1630
|
};
|
|
1711
1631
|
|
|
1632
|
+
const listeners = {};
|
|
1633
|
+
|
|
1634
|
+
const fakeLocalDisplayTrack = {
|
|
1635
|
+
on: sinon.stub().callsFake((event, listener) => {
|
|
1636
|
+
listeners[event] = listener;
|
|
1637
|
+
})
|
|
1638
|
+
};
|
|
1639
|
+
sinon.stub(InternalMediaCoreModule, 'LocalDisplayTrack').returns(fakeLocalDisplayTrack);
|
|
1640
|
+
|
|
1641
|
+
|
|
1712
1642
|
sandbox.stub(mediaProperties, 'setLocalShareTrack');
|
|
1713
|
-
sandbox.stub(mediaProperties, 'shareTrack').value(fakeTrack);
|
|
1714
1643
|
sandbox.stub(mediaProperties, 'setMediaSettings');
|
|
1715
1644
|
sandbox.stub(meeting, 'stopShare').resolves(true);
|
|
1716
1645
|
meeting.setLocalShareTrack(fakeTrack);
|
|
1717
1646
|
|
|
1718
|
-
assert.calledOnce(
|
|
1719
|
-
assert.calledWith(
|
|
1720
|
-
assert.isNotNull(
|
|
1647
|
+
assert.calledOnce(fakeLocalDisplayTrack.on);
|
|
1648
|
+
assert.calledWith(fakeLocalDisplayTrack.on, LocalTrackEvents.Ended, sinon.match.any);
|
|
1649
|
+
assert.isNotNull(listeners[LocalTrackEvents.Ended]);
|
|
1721
1650
|
|
|
1722
|
-
|
|
1651
|
+
listeners[LocalTrackEvents.Ended]();
|
|
1723
1652
|
|
|
1724
1653
|
assert.calledWith(meeting.stopShare, {skipSignalingCheck: true});
|
|
1725
1654
|
});
|
|
@@ -2135,7 +2064,7 @@ describe('plugin-meetings', () => {
|
|
|
2135
2064
|
screenshareVideo: {
|
|
2136
2065
|
id: 'fake share track',
|
|
2137
2066
|
getSettings: sinon.stub().returns({}),
|
|
2138
|
-
|
|
2067
|
+
on: sinon.stub()
|
|
2139
2068
|
},
|
|
2140
2069
|
};
|
|
2141
2070
|
|
|
@@ -2297,7 +2226,7 @@ describe('plugin-meetings', () => {
|
|
|
2297
2226
|
screenshareVideo: {
|
|
2298
2227
|
id: 'fake share track',
|
|
2299
2228
|
getSettings: sinon.stub().returns({}),
|
|
2300
|
-
|
|
2229
|
+
on: sinon.stub(),
|
|
2301
2230
|
},
|
|
2302
2231
|
};
|
|
2303
2232
|
|
|
@@ -3582,6 +3511,12 @@ describe('plugin-meetings', () => {
|
|
|
3582
3511
|
let videoTrack;
|
|
3583
3512
|
let videoShareTrack;
|
|
3584
3513
|
let createMuteStateStub;
|
|
3514
|
+
let LocalDisplayTrackConstructorStub;
|
|
3515
|
+
let LocalMicrophoneTrackConstructorStub;
|
|
3516
|
+
let LocalCameraTrackConstructorStub;
|
|
3517
|
+
let fakeLocalDisplayTrack;
|
|
3518
|
+
let fakeLocalMicrophoneTrack;
|
|
3519
|
+
let fakeLocalCameraTrack;
|
|
3585
3520
|
|
|
3586
3521
|
beforeEach(() => {
|
|
3587
3522
|
audioTrack = {
|
|
@@ -3594,7 +3529,7 @@ describe('plugin-meetings', () => {
|
|
|
3594
3529
|
};
|
|
3595
3530
|
videoShareTrack = {
|
|
3596
3531
|
id: 'share track',
|
|
3597
|
-
|
|
3532
|
+
on: sinon.stub(),
|
|
3598
3533
|
removeEventListener: sinon.stub(),
|
|
3599
3534
|
getSettings: sinon.stub().returns({}),
|
|
3600
3535
|
};
|
|
@@ -3606,6 +3541,28 @@ describe('plugin-meetings', () => {
|
|
|
3606
3541
|
unpublishTrack: sinon.stub().resolves({}),
|
|
3607
3542
|
};
|
|
3608
3543
|
|
|
3544
|
+
const createFakeLocalTrack = (originalTrack) => ({
|
|
3545
|
+
on: sinon.stub(),
|
|
3546
|
+
off: sinon.stub(),
|
|
3547
|
+
stop: sinon.stub(),
|
|
3548
|
+
originalTrack
|
|
3549
|
+
});
|
|
3550
|
+
|
|
3551
|
+
// setup mock constructors for webrtc-core local track classes in such a way
|
|
3552
|
+
// that they return the original track correctly (this is needed for unpublish() API tests)
|
|
3553
|
+
LocalDisplayTrackConstructorStub = sinon.stub(InternalMediaCoreModule, 'LocalDisplayTrack').callsFake((stream) => {
|
|
3554
|
+
fakeLocalDisplayTrack = createFakeLocalTrack(stream.getTracks()[0])
|
|
3555
|
+
return fakeLocalDisplayTrack;
|
|
3556
|
+
});
|
|
3557
|
+
LocalMicrophoneTrackConstructorStub = sinon.stub(InternalMediaCoreModule, 'LocalMicrophoneTrack').callsFake((stream) => {
|
|
3558
|
+
fakeLocalMicrophoneTrack = createFakeLocalTrack(stream.getTracks()[0])
|
|
3559
|
+
return fakeLocalMicrophoneTrack;
|
|
3560
|
+
});
|
|
3561
|
+
LocalCameraTrackConstructorStub = sinon.stub(InternalMediaCoreModule, 'LocalCameraTrack').callsFake((stream) => {
|
|
3562
|
+
fakeLocalCameraTrack = createFakeLocalTrack(stream.getTracks()[0])
|
|
3563
|
+
return fakeLocalCameraTrack;
|
|
3564
|
+
});
|
|
3565
|
+
|
|
3609
3566
|
createMuteStateStub = sinon.stub(MuteStateModule, 'createMuteState').returns({id: 'fake mute state instance'});
|
|
3610
3567
|
})
|
|
3611
3568
|
describe('#publishTracks', () => {
|
|
@@ -3615,23 +3572,33 @@ describe('plugin-meetings', () => {
|
|
|
3615
3572
|
});
|
|
3616
3573
|
|
|
3617
3574
|
const checkAudioPublished = () => {
|
|
3575
|
+
assert.calledWith(MediaUtil.createMediaStream, [audioTrack]);
|
|
3576
|
+
assert.calledOnce(LocalMicrophoneTrackConstructorStub);
|
|
3577
|
+
|
|
3618
3578
|
assert.calledWith(createMuteStateStub, 'audio', meeting, meeting.mediaProperties.mediaDirection);
|
|
3619
|
-
assert.calledWith(meeting.mediaProperties.webrtcMediaConnection.publishTrack,
|
|
3620
|
-
assert.equal(meeting.mediaProperties.audioTrack,
|
|
3579
|
+
assert.calledWith(meeting.mediaProperties.webrtcMediaConnection.publishTrack, fakeLocalMicrophoneTrack);
|
|
3580
|
+
assert.equal(meeting.mediaProperties.audioTrack, fakeLocalMicrophoneTrack);
|
|
3621
3581
|
assert.equal(meeting.mediaProperties.mediaDirection.sendAudio, true);
|
|
3622
3582
|
}
|
|
3623
3583
|
|
|
3624
3584
|
const checkVideoPublished = () => {
|
|
3585
|
+
assert.calledWith(MediaUtil.createMediaStream, [videoTrack]);
|
|
3586
|
+
assert.calledOnce(LocalCameraTrackConstructorStub);
|
|
3587
|
+
|
|
3625
3588
|
assert.calledWith(createMuteStateStub, 'video', meeting, meeting.mediaProperties.mediaDirection);
|
|
3626
|
-
assert.calledWith(meeting.mediaProperties.webrtcMediaConnection.publishTrack,
|
|
3627
|
-
assert.equal(meeting.mediaProperties.videoTrack,
|
|
3589
|
+
assert.calledWith(meeting.mediaProperties.webrtcMediaConnection.publishTrack, fakeLocalCameraTrack);
|
|
3590
|
+
assert.equal(meeting.mediaProperties.videoTrack, fakeLocalCameraTrack);
|
|
3628
3591
|
assert.equal(meeting.mediaProperties.mediaDirection.sendVideo, true);
|
|
3629
3592
|
}
|
|
3630
3593
|
|
|
3631
3594
|
const checkScreenShareVideoPublished = () => {
|
|
3632
3595
|
assert.calledOnce(meeting.requestScreenShareFloor);
|
|
3633
|
-
|
|
3634
|
-
assert.
|
|
3596
|
+
|
|
3597
|
+
assert.calledWith(MediaUtil.createMediaStream, [videoShareTrack]);
|
|
3598
|
+
assert.calledOnce(LocalDisplayTrackConstructorStub);
|
|
3599
|
+
|
|
3600
|
+
assert.calledWith(meeting.mediaProperties.webrtcMediaConnection.publishTrack, fakeLocalDisplayTrack);
|
|
3601
|
+
assert.equal(meeting.mediaProperties.shareTrack, fakeLocalDisplayTrack);
|
|
3635
3602
|
assert.equal(meeting.mediaProperties.mediaDirection.sendShare, true);
|
|
3636
3603
|
}
|
|
3637
3604
|
|
|
@@ -3685,21 +3652,21 @@ describe('plugin-meetings', () => {
|
|
|
3685
3652
|
});
|
|
3686
3653
|
|
|
3687
3654
|
const checkAudioUnpublished = () => {
|
|
3688
|
-
assert.calledWith(meeting.mediaProperties.webrtcMediaConnection.unpublishTrack,
|
|
3655
|
+
assert.calledWith(meeting.mediaProperties.webrtcMediaConnection.unpublishTrack, fakeLocalMicrophoneTrack);
|
|
3689
3656
|
|
|
3690
3657
|
assert.equal(meeting.mediaProperties.audioTrack, null);
|
|
3691
3658
|
assert.equal(meeting.mediaProperties.mediaDirection.sendAudio, false);
|
|
3692
3659
|
};
|
|
3693
3660
|
|
|
3694
3661
|
const checkVideoUnpublished = () => {
|
|
3695
|
-
assert.calledWith(meeting.mediaProperties.webrtcMediaConnection.unpublishTrack,
|
|
3662
|
+
assert.calledWith(meeting.mediaProperties.webrtcMediaConnection.unpublishTrack, fakeLocalCameraTrack);
|
|
3696
3663
|
|
|
3697
3664
|
assert.equal(meeting.mediaProperties.videoTrack, null);
|
|
3698
3665
|
assert.equal(meeting.mediaProperties.mediaDirection.sendVideo, false);
|
|
3699
3666
|
}
|
|
3700
3667
|
|
|
3701
3668
|
const checkScreenShareVideoUnpublished = () => {
|
|
3702
|
-
assert.calledWith(meeting.mediaProperties.webrtcMediaConnection.unpublishTrack,
|
|
3669
|
+
assert.calledWith(meeting.mediaProperties.webrtcMediaConnection.unpublishTrack, fakeLocalDisplayTrack);
|
|
3703
3670
|
|
|
3704
3671
|
assert.calledOnce(meeting.requestScreenShareFloor);
|
|
3705
3672
|
|
|
@@ -3924,7 +3891,6 @@ describe('plugin-meetings', () => {
|
|
|
3924
3891
|
});
|
|
3925
3892
|
describe('#setLocalShareTrack', () => {
|
|
3926
3893
|
it('should trigger a media:ready event with local share stream', () => {
|
|
3927
|
-
let registeredListener = null;
|
|
3928
3894
|
const track = {
|
|
3929
3895
|
getSettings: sinon.stub().returns({
|
|
3930
3896
|
aspectRatio: '1.7',
|
|
@@ -3934,11 +3900,17 @@ describe('plugin-meetings', () => {
|
|
|
3934
3900
|
displaySurface: true,
|
|
3935
3901
|
cursor: true,
|
|
3936
3902
|
}),
|
|
3937
|
-
addEventListener: sinon.stub().callsFake((event, listener) => {
|
|
3938
|
-
registeredListener = listener;
|
|
3939
|
-
}),
|
|
3940
3903
|
};
|
|
3941
3904
|
|
|
3905
|
+
const listeners = {};
|
|
3906
|
+
const fakeLocalDisplayTrack = {
|
|
3907
|
+
on: sinon.stub().callsFake((event, listener) => {
|
|
3908
|
+
listeners[event] = listener;
|
|
3909
|
+
})
|
|
3910
|
+
};
|
|
3911
|
+
sinon.stub(InternalMediaCoreModule, 'LocalDisplayTrack').returns(fakeLocalDisplayTrack);
|
|
3912
|
+
|
|
3913
|
+
|
|
3942
3914
|
meeting.mediaProperties.setLocalShareTrack = sinon.stub().returns(true);
|
|
3943
3915
|
meeting.stopShare = sinon.stub().resolves(true);
|
|
3944
3916
|
meeting.mediaProperties.mediaDirection = {};
|
|
@@ -3952,8 +3924,8 @@ describe('plugin-meetings', () => {
|
|
|
3952
3924
|
);
|
|
3953
3925
|
assert.calledOnce(meeting.mediaProperties.setLocalShareTrack);
|
|
3954
3926
|
assert.equal(meeting.mediaProperties.localStream, undefined);
|
|
3955
|
-
assert.isNotNull(
|
|
3956
|
-
|
|
3927
|
+
assert.isNotNull(listeners[LocalTrackEvents.Ended]);
|
|
3928
|
+
listeners[LocalTrackEvents.Ended]();
|
|
3957
3929
|
assert.calledOnce(meeting.stopShare);
|
|
3958
3930
|
});
|
|
3959
3931
|
});
|
|
@@ -3969,6 +3941,7 @@ describe('plugin-meetings', () => {
|
|
|
3969
3941
|
eventListeners[event] = listener;
|
|
3970
3942
|
}),
|
|
3971
3943
|
};
|
|
3944
|
+
MediaUtil.createMediaStream.returns({id: 'stream'});
|
|
3972
3945
|
});
|
|
3973
3946
|
|
|
3974
3947
|
it('should register for all the correct RoapMediaConnection events', () => {
|
|
@@ -3990,7 +3963,7 @@ describe('plugin-meetings', () => {
|
|
|
3990
3963
|
assert.equal(TriggerProxy.trigger.getCall(1).args[2], 'media:ready');
|
|
3991
3964
|
assert.deepEqual(TriggerProxy.trigger.getCall(1).args[3], {
|
|
3992
3965
|
type: 'remoteAudio',
|
|
3993
|
-
stream:
|
|
3966
|
+
stream: {id: 'stream'},
|
|
3994
3967
|
});
|
|
3995
3968
|
|
|
3996
3969
|
eventListeners[Event.REMOTE_TRACK_ADDED]({
|
|
@@ -4000,7 +3973,7 @@ describe('plugin-meetings', () => {
|
|
|
4000
3973
|
assert.equal(TriggerProxy.trigger.getCall(2).args[2], 'media:ready');
|
|
4001
3974
|
assert.deepEqual(TriggerProxy.trigger.getCall(2).args[3], {
|
|
4002
3975
|
type: 'remoteVideo',
|
|
4003
|
-
stream:
|
|
3976
|
+
stream: {id: 'stream'},
|
|
4004
3977
|
});
|
|
4005
3978
|
|
|
4006
3979
|
eventListeners[Event.REMOTE_TRACK_ADDED]({
|
|
@@ -4010,7 +3983,7 @@ describe('plugin-meetings', () => {
|
|
|
4010
3983
|
assert.equal(TriggerProxy.trigger.getCall(3).args[2], 'media:ready');
|
|
4011
3984
|
assert.deepEqual(TriggerProxy.trigger.getCall(3).args[3], {
|
|
4012
3985
|
type: 'remoteShare',
|
|
4013
|
-
stream:
|
|
3986
|
+
stream: {id: 'stream'},
|
|
4014
3987
|
});
|
|
4015
3988
|
});
|
|
4016
3989
|
|
|
@@ -19,8 +19,8 @@ describe('plugin-meetings', () => {
|
|
|
19
19
|
beforeEach(() => {
|
|
20
20
|
meeting = {
|
|
21
21
|
mediaProperties: {
|
|
22
|
-
audioTrack: 'fake audio track',
|
|
23
|
-
videoTrack: 'fake video track',
|
|
22
|
+
audioTrack: {id: 'fake audio track', setMuted: sinon.stub()},
|
|
23
|
+
videoTrack: {id: 'fake video track', setMuted: sinon.stub()},
|
|
24
24
|
},
|
|
25
25
|
remoteMuted: false,
|
|
26
26
|
unmuteAllowed: true,
|
|
@@ -38,7 +38,6 @@ describe('plugin-meetings', () => {
|
|
|
38
38
|
originalRemoteUpdateAudioVideo = MeetingUtil.remoteUpdateAudioVideo;
|
|
39
39
|
|
|
40
40
|
MeetingUtil.remoteUpdateAudioVideo = sinon.stub().resolves(fakeLocus);
|
|
41
|
-
Media.setLocalTrack = sinon.stub();
|
|
42
41
|
});
|
|
43
42
|
|
|
44
43
|
afterEach(() => {
|
|
@@ -110,8 +109,8 @@ describe('plugin-meetings', () => {
|
|
|
110
109
|
audio.handleServerLocalUnmuteRequired(meeting);
|
|
111
110
|
await testUtils.flushPromises();
|
|
112
111
|
|
|
113
|
-
// check that local track was
|
|
114
|
-
assert.calledWith(
|
|
112
|
+
// check that local track was unmuted
|
|
113
|
+
assert.calledWith(meeting.mediaProperties.audioTrack.setMuted, false);
|
|
115
114
|
|
|
116
115
|
// and local unmute was sent to server
|
|
117
116
|
assert.calledOnce(MeetingUtil.remoteUpdateAudioVideo);
|
|
@@ -161,8 +160,8 @@ describe('plugin-meetings', () => {
|
|
|
161
160
|
assert.calledOnce(MeetingUtil.remoteUpdateAudioVideo);
|
|
162
161
|
assert.calledWith(MeetingUtil.remoteUpdateAudioVideo, false, undefined, meeting);
|
|
163
162
|
|
|
164
|
-
// and local track should be
|
|
165
|
-
assert.calledWith(
|
|
163
|
+
// and local track should be unmuted
|
|
164
|
+
assert.calledWith(meeting.mediaProperties.audioTrack.setMuted, false);
|
|
166
165
|
|
|
167
166
|
assert.isFalse(audio.isMuted());
|
|
168
167
|
assert.isFalse(audio.isSelf());
|
|
@@ -183,37 +182,37 @@ describe('plugin-meetings', () => {
|
|
|
183
182
|
it('disables/enables the local audio track when audio is muted/unmuted', async () => {
|
|
184
183
|
// mute
|
|
185
184
|
audio.handleClientRequest(meeting, true);
|
|
186
|
-
assert.calledWith(
|
|
185
|
+
assert.calledWith(meeting.mediaProperties.audioTrack.setMuted, true);
|
|
187
186
|
|
|
188
|
-
// even when calling mute when it's already muted should still call
|
|
187
|
+
// even when calling mute when it's already muted should still call setMuted
|
|
189
188
|
audio.handleClientRequest(meeting, true);
|
|
190
|
-
assert.calledWith(
|
|
189
|
+
assert.calledWith(meeting.mediaProperties.audioTrack.setMuted, true);
|
|
191
190
|
|
|
192
191
|
// unmute
|
|
193
192
|
audio.handleClientRequest(meeting, false);
|
|
194
|
-
assert.calledWith(
|
|
193
|
+
assert.calledWith(meeting.mediaProperties.audioTrack.setMuted, false);
|
|
195
194
|
|
|
196
|
-
// even when calling unmute when it's already unmuted should still call
|
|
195
|
+
// even when calling unmute when it's already unmuted should still call setMuted
|
|
197
196
|
audio.handleClientRequest(meeting, false);
|
|
198
|
-
assert.calledWith(
|
|
197
|
+
assert.calledWith(meeting.mediaProperties.audioTrack.setMuted, false);
|
|
199
198
|
});
|
|
200
199
|
|
|
201
200
|
it('disables/enables the local video track when video is muted/unmuted', async () => {
|
|
202
201
|
// mute
|
|
203
202
|
video.handleClientRequest(meeting, true);
|
|
204
|
-
assert.calledWith(
|
|
203
|
+
assert.calledWith(meeting.mediaProperties.videoTrack.setMuted, true);
|
|
205
204
|
|
|
206
|
-
// even when calling mute when it's already muted should still call
|
|
205
|
+
// even when calling mute when it's already muted should still call setMuted
|
|
207
206
|
video.handleClientRequest(meeting, false);
|
|
208
|
-
assert.calledWith(
|
|
207
|
+
assert.calledWith(meeting.mediaProperties.videoTrack.setMuted, true);
|
|
209
208
|
|
|
210
209
|
// unmute
|
|
211
210
|
video.handleClientRequest(meeting, false);
|
|
212
|
-
assert.calledWith(
|
|
211
|
+
assert.calledWith(meeting.mediaProperties.videoTrack.setMuted, false);
|
|
213
212
|
|
|
214
|
-
// even when calling unmute when it's already unmuted should still call
|
|
213
|
+
// even when calling unmute when it's already unmuted should still call setMuted
|
|
215
214
|
video.handleClientRequest(meeting, false);
|
|
216
|
-
assert.calledWith(
|
|
215
|
+
assert.calledWith(meeting.mediaProperties.videoTrack.setMuted, false);
|
|
217
216
|
});
|
|
218
217
|
|
|
219
218
|
it('returns correct value in isMuted()/isSelf() methods after client mute/unmute requests', async () => {
|
|
@@ -389,11 +388,11 @@ describe('plugin-meetings', () => {
|
|
|
389
388
|
assert.isTrue(video.isSelf());
|
|
390
389
|
|
|
391
390
|
// check local mute is done, but not remote one
|
|
392
|
-
assert.calledWith(
|
|
391
|
+
assert.calledWith(meeting.mediaProperties.videoTrack.setMuted, true);
|
|
393
392
|
assert.calledWith(MeetingUtil.remoteUpdateAudioVideo, undefined, true, meeting);
|
|
394
393
|
assert.notCalled(meeting.members.muteMember);
|
|
395
394
|
|
|
396
|
-
|
|
395
|
+
meeting.mediaProperties.videoTrack.setMuted.resetHistory();
|
|
397
396
|
MeetingUtil.remoteUpdateAudioVideo.resetHistory();
|
|
398
397
|
meeting.members.muteMember.resetHistory();
|
|
399
398
|
|
|
@@ -403,7 +402,7 @@ describe('plugin-meetings', () => {
|
|
|
403
402
|
assert.isFalse(video.isMuted());
|
|
404
403
|
assert.isFalse(video.isSelf());
|
|
405
404
|
|
|
406
|
-
assert.calledWith(
|
|
405
|
+
assert.calledWith(meeting.mediaProperties.videoTrack.setMuted, false);
|
|
407
406
|
assert.calledWith(MeetingUtil.remoteUpdateAudioVideo, undefined, false, meeting);
|
|
408
407
|
assert.notCalled(meeting.members.muteMember);
|
|
409
408
|
});
|
|
@@ -26,6 +26,8 @@ describe('plugin-meetings', () => {
|
|
|
26
26
|
},
|
|
27
27
|
};
|
|
28
28
|
|
|
29
|
+
webex.boundedStorage.get = sinon.mock().returns(Promise.resolve(JSON.stringify({anycastEntryPoint: "aws-eu-west-1"})))
|
|
30
|
+
|
|
29
31
|
meetingsRequest = new MeetingRequest(
|
|
30
32
|
{},
|
|
31
33
|
{
|
|
@@ -206,6 +208,31 @@ describe('plugin-meetings', () => {
|
|
|
206
208
|
const requestParams = meetingsRequest.request.getCall(0).args[0];
|
|
207
209
|
|
|
208
210
|
assert.deepEqual(requestParams.body.deviceCapabilities, undefined);
|
|
211
|
+
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
it('includes joinCookie correctly', async () => {
|
|
215
|
+
const locusUrl = 'locusURL';
|
|
216
|
+
const deviceUrl = 'deviceUrl';
|
|
217
|
+
const correlationId = 'random-uuid';
|
|
218
|
+
const roapMessage = 'roap-message';
|
|
219
|
+
const permissionToken = 'permission-token';
|
|
220
|
+
|
|
221
|
+
await meetingsRequest.joinMeeting({
|
|
222
|
+
locusUrl,
|
|
223
|
+
deviceUrl,
|
|
224
|
+
correlationId,
|
|
225
|
+
roapMessage,
|
|
226
|
+
permissionToken,
|
|
227
|
+
});
|
|
228
|
+
const requestParams = meetingsRequest.request.getCall(0).args[0];
|
|
229
|
+
|
|
230
|
+
assert.equal(requestParams.method, 'POST');
|
|
231
|
+
assert.equal(requestParams.uri, `${locusUrl}/participant?alternateRedirect=true`);
|
|
232
|
+
assert.deepEqual(requestParams.body.clientMediaPreferences, {
|
|
233
|
+
"joinCookie": {anycastEntryPoint: "aws-eu-west-1"},
|
|
234
|
+
"preferTranscoding": true
|
|
235
|
+
});
|
|
209
236
|
});
|
|
210
237
|
});
|
|
211
238
|
|
|
@@ -22,8 +22,8 @@ describe('isAnyClusterReachable', () => {
|
|
|
22
22
|
|
|
23
23
|
const result = await reachability.isAnyClusterReachable();
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
assert.equal(result, expectedValue);
|
|
26
|
+
};
|
|
27
27
|
|
|
28
28
|
it('returns true when udp is reachable', async () => {
|
|
29
29
|
await checkIsClusterReachable({x: {udp: {reachable: 'true'}, tcp: {reachable: 'false'}}}, true);
|
|
@@ -66,19 +66,30 @@ describe('gatherReachability', () => {
|
|
|
66
66
|
it('stores the reachability', async () => {
|
|
67
67
|
const reachability = new Reachability(webex);
|
|
68
68
|
|
|
69
|
-
const
|
|
70
|
-
|
|
69
|
+
const reachabilityResults = {
|
|
70
|
+
clusters: {
|
|
71
|
+
clusterId: {
|
|
72
|
+
udp: 'testUDP',
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
}
|
|
76
|
+
const getClustersResult = {
|
|
77
|
+
clusters: {clusterId: 'cluster'},
|
|
78
|
+
joinCookie: {id: 'id'}
|
|
79
|
+
};
|
|
71
80
|
|
|
72
|
-
reachability.reachabilityRequest.getClusters = sinon.stub().returns(
|
|
81
|
+
reachability.reachabilityRequest.getClusters = sinon.stub().returns(getClustersResult);
|
|
73
82
|
(reachability as any).performReachabilityCheck = sinon.stub().returns(reachabilityResults)
|
|
74
83
|
|
|
75
84
|
const result = await reachability.gatherReachability();
|
|
76
85
|
|
|
77
86
|
assert.equal(result, reachabilityResults);
|
|
78
87
|
|
|
79
|
-
const
|
|
88
|
+
const storedResultForReachabilityResult = await webex.boundedStorage.get('Reachability', 'reachability.result');
|
|
89
|
+
const storedResultForJoinCookie = await webex.boundedStorage.get('Reachability', 'reachability.joinCookie');
|
|
80
90
|
|
|
81
|
-
assert.equal(JSON.stringify(result),
|
|
91
|
+
assert.equal(JSON.stringify(result), storedResultForReachabilityResult);
|
|
92
|
+
assert.equal(JSON.stringify(getClustersResult.joinCookie), storedResultForJoinCookie);
|
|
82
93
|
});
|
|
83
94
|
|
|
84
95
|
});
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import sinon from 'sinon';
|
|
2
|
+
import {assert} from '@webex/test-helper-chai';
|
|
3
|
+
import MockWebex from '@webex/test-helper-mock-webex';
|
|
4
|
+
import Meetings from '@webex/plugin-meetings';
|
|
5
|
+
import ReachabilityRequest from '@webex/plugin-meetings/src/reachability/request';
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
describe('plugin-meetings/reachability', () => {
|
|
9
|
+
let reachabilityRequest;
|
|
10
|
+
let webex;
|
|
11
|
+
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
webex = new MockWebex({
|
|
14
|
+
children: {
|
|
15
|
+
meetings: Meetings,
|
|
16
|
+
},
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
webex.meetings.clientRegion = {
|
|
20
|
+
countryCode: 'US',
|
|
21
|
+
regionCode: 'WEST-COAST',
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
webex.internal = {
|
|
25
|
+
services: {
|
|
26
|
+
get: sinon.mock().returns('locusUrl'),
|
|
27
|
+
waitForCatalog: sinon.mock().returns(Promise.resolve({})),
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
reachabilityRequest = new ReachabilityRequest(webex);
|
|
33
|
+
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
describe('#getClusters', () => {
|
|
37
|
+
it('sends a GET request with the correct params', async () => {
|
|
38
|
+
webex.request = sinon.mock().returns(Promise.resolve({
|
|
39
|
+
body: {
|
|
40
|
+
clusterClasses: {
|
|
41
|
+
hybridMedia: ["clusterId"]
|
|
42
|
+
},
|
|
43
|
+
clusters: {"clusterId": {
|
|
44
|
+
udp: "testUDP"
|
|
45
|
+
}},
|
|
46
|
+
joinCookie: {anycastEntryPoint: "aws-eu-west-1"}
|
|
47
|
+
}
|
|
48
|
+
}));
|
|
49
|
+
|
|
50
|
+
const res = await reachabilityRequest.getClusters();
|
|
51
|
+
|
|
52
|
+
const requestParams = webex.request.getCall(0).args[0];
|
|
53
|
+
|
|
54
|
+
assert.equal(requestParams.method, 'GET');
|
|
55
|
+
assert.equal(requestParams.resource, `clusters`);
|
|
56
|
+
assert.equal(requestParams.api, 'calliopeDiscovery');
|
|
57
|
+
assert.equal(requestParams.shouldRefreshAccessToken, false);
|
|
58
|
+
|
|
59
|
+
assert.deepEqual(requestParams.qs, {
|
|
60
|
+
JCSupport: 1,
|
|
61
|
+
});
|
|
62
|
+
assert.deepEqual(res.clusters.clusterId, {udp: "testUDP", isVideoMesh: true})
|
|
63
|
+
assert.deepEqual(res.joinCookie, {anycastEntryPoint: "aws-eu-west-1"})
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
});
|