@webex/plugin-meetings 3.0.0-bnr.5 → 3.0.0-stream-classes.1
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/README.md +46 -8
- package/dist/annotation/annotation.types.js +7 -0
- package/dist/annotation/annotation.types.js.map +1 -0
- package/dist/annotation/constants.js +49 -0
- package/dist/annotation/constants.js.map +1 -0
- package/dist/annotation/index.js +342 -0
- package/dist/annotation/index.js.map +1 -0
- package/dist/breakouts/breakout.js +70 -32
- package/dist/breakouts/breakout.js.map +1 -1
- package/dist/breakouts/events.js +45 -0
- package/dist/breakouts/events.js.map +1 -0
- package/dist/breakouts/index.js +422 -217
- package/dist/breakouts/index.js.map +1 -1
- package/dist/breakouts/utils.js +12 -1
- package/dist/breakouts/utils.js.map +1 -1
- package/dist/common/errors/webex-errors.js +3 -2
- package/dist/common/errors/webex-errors.js.map +1 -1
- package/dist/common/logs/logger-proxy.js +1 -1
- package/dist/common/logs/logger-proxy.js.map +1 -1
- package/dist/common/logs/request.d.ts +1 -1
- package/dist/common/queue.js +24 -9
- package/dist/common/queue.js.map +1 -1
- package/dist/config.js +1 -7
- package/dist/config.js.map +1 -1
- package/dist/constants.js +118 -24
- package/dist/constants.js.map +1 -1
- package/dist/controls-options-manager/enums.js +2 -0
- package/dist/controls-options-manager/enums.js.map +1 -1
- package/dist/controls-options-manager/index.js +19 -14
- package/dist/controls-options-manager/index.js.map +1 -1
- package/dist/controls-options-manager/types.js.map +1 -1
- package/dist/controls-options-manager/util.js +80 -11
- package/dist/controls-options-manager/util.js.map +1 -1
- package/dist/index.js +62 -20
- package/dist/index.js.map +1 -1
- package/dist/interpretation/collection.js +23 -0
- package/dist/interpretation/collection.js.map +1 -0
- package/dist/interpretation/index.js +366 -0
- package/dist/interpretation/index.js.map +1 -0
- package/dist/interpretation/siLanguage.js +25 -0
- package/dist/interpretation/siLanguage.js.map +1 -0
- package/dist/locus-info/controlsUtils.js +71 -1
- package/dist/locus-info/controlsUtils.js.map +1 -1
- package/dist/locus-info/index.js +305 -57
- package/dist/locus-info/index.js.map +1 -1
- package/dist/locus-info/infoUtils.js +7 -1
- package/dist/locus-info/infoUtils.js.map +1 -1
- package/dist/locus-info/mediaSharesUtils.js +43 -1
- package/dist/locus-info/mediaSharesUtils.js.map +1 -1
- package/dist/locus-info/parser.js +219 -63
- package/dist/locus-info/parser.js.map +1 -1
- package/dist/locus-info/selfUtils.js +44 -22
- package/dist/locus-info/selfUtils.js.map +1 -1
- package/dist/media/index.js +57 -104
- package/dist/media/index.js.map +1 -1
- package/dist/media/properties.js +60 -121
- package/dist/media/properties.js.map +1 -1
- package/dist/meeting/in-meeting-actions.js +61 -3
- package/dist/meeting/in-meeting-actions.js.map +1 -1
- package/dist/meeting/index.js +2530 -2534
- package/dist/meeting/index.js.map +1 -1
- package/dist/meeting/locusMediaRequest.js +292 -0
- package/dist/meeting/locusMediaRequest.js.map +1 -0
- package/dist/meeting/muteState.js +125 -205
- package/dist/meeting/muteState.js.map +1 -1
- package/dist/meeting/request.js +150 -150
- package/dist/meeting/request.js.map +1 -1
- package/dist/meeting/util.js +568 -438
- package/dist/meeting/util.js.map +1 -1
- package/dist/meeting-info/index.js +48 -7
- package/dist/meeting-info/index.js.map +1 -1
- package/dist/meeting-info/meeting-info-v2.js +94 -38
- package/dist/meeting-info/meeting-info-v2.js.map +1 -1
- package/dist/meeting-info/utilv2.js +4 -2
- package/dist/meeting-info/utilv2.js.map +1 -1
- package/dist/meetings/index.d.ts +0 -2
- package/dist/meetings/index.js +260 -85
- package/dist/meetings/index.js.map +1 -1
- package/dist/meetings/meetings.types.js +7 -0
- package/dist/meetings/meetings.types.js.map +1 -0
- package/dist/meetings/util.js +42 -7
- package/dist/meetings/util.js.map +1 -1
- package/dist/member/index.d.ts +2 -0
- package/dist/member/index.js +26 -0
- package/dist/member/index.js.map +1 -1
- package/dist/member/member.types.d.ts +11 -0
- package/dist/member/member.types.js +18 -0
- package/dist/member/member.types.js.map +1 -0
- package/dist/member/types.js +11 -1
- package/dist/member/types.js.map +1 -1
- package/dist/member/util.js +60 -23
- package/dist/member/util.js.map +1 -1
- package/dist/members/index.js +4 -1
- package/dist/members/index.js.map +1 -1
- package/dist/members/request.js +75 -45
- package/dist/members/request.js.map +1 -1
- package/dist/members/util.js +308 -317
- package/dist/members/util.js.map +1 -1
- package/dist/metrics/config.js +1 -3
- package/dist/metrics/config.js.map +1 -1
- package/dist/metrics/constants.js +1 -0
- package/dist/metrics/constants.js.map +1 -1
- package/dist/metrics/index.d.ts +1 -1
- package/dist/metrics/index.js +1 -451
- package/dist/metrics/index.js.map +1 -1
- package/dist/multistream/mediaRequestManager.js +136 -40
- package/dist/multistream/mediaRequestManager.js.map +1 -1
- package/dist/multistream/receiveSlot.js.map +1 -1
- package/dist/multistream/receiveSlotManager.js +4 -4
- package/dist/multistream/receiveSlotManager.js.map +1 -1
- package/dist/multistream/remoteMedia.js.map +1 -1
- package/dist/multistream/remoteMediaGroup.js +60 -3
- package/dist/multistream/remoteMediaGroup.js.map +1 -1
- package/dist/multistream/remoteMediaManager.js +36 -0
- package/dist/multistream/remoteMediaManager.js.map +1 -1
- package/dist/multistream/sendSlotManager.js +233 -0
- package/dist/multistream/sendSlotManager.js.map +1 -0
- package/dist/reachability/index.js +18 -3
- package/dist/reachability/index.js.map +1 -1
- package/dist/reachability/request.js +5 -3
- package/dist/reachability/request.js.map +1 -1
- package/dist/reconnection-manager/index.js +181 -153
- package/dist/reconnection-manager/index.js.map +1 -1
- package/dist/recording-controller/index.js +21 -2
- package/dist/recording-controller/index.js.map +1 -1
- package/dist/recording-controller/util.js +9 -8
- package/dist/recording-controller/util.js.map +1 -1
- package/dist/roap/index.js +25 -32
- package/dist/roap/index.js.map +1 -1
- package/dist/roap/request.js +42 -51
- package/dist/roap/request.js.map +1 -1
- package/dist/roap/turnDiscovery.js +97 -38
- package/dist/roap/turnDiscovery.js.map +1 -1
- package/dist/rtcMetrics/constants.js +12 -0
- package/dist/rtcMetrics/constants.js.map +1 -0
- package/dist/rtcMetrics/index.js +117 -0
- package/dist/rtcMetrics/index.js.map +1 -0
- package/dist/statsAnalyzer/index.js +0 -1
- package/dist/statsAnalyzer/index.js.map +1 -1
- package/dist/types/annotation/annotation.types.d.ts +43 -0
- package/dist/types/annotation/constants.d.ts +31 -0
- package/dist/types/annotation/index.d.ts +124 -0
- package/dist/types/breakouts/events.d.ts +2 -0
- package/dist/types/breakouts/utils.d.ts +7 -0
- package/dist/types/common/errors/webex-errors.d.ts +1 -1
- package/dist/types/config.d.ts +0 -6
- package/dist/types/constants.d.ts +51 -21
- package/dist/types/controls-options-manager/enums.d.ts +2 -0
- package/dist/types/controls-options-manager/index.d.ts +1 -1
- package/dist/types/controls-options-manager/types.d.ts +7 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/interpretation/collection.d.ts +5 -0
- package/dist/types/interpretation/index.d.ts +5 -0
- package/dist/types/interpretation/siLanguage.d.ts +5 -0
- package/dist/types/locus-info/index.d.ts +39 -1
- package/dist/types/media/index.d.ts +2 -0
- package/dist/types/media/properties.d.ts +16 -38
- package/dist/types/meeting/in-meeting-actions.d.ts +46 -2
- package/dist/types/meeting/index.d.ts +179 -379
- package/dist/types/meeting/locusMediaRequest.d.ts +70 -0
- package/dist/types/meeting/muteState.d.ts +39 -40
- package/dist/types/meeting/request.d.ts +25 -26
- package/dist/types/meeting/util.d.ts +74 -1
- package/dist/types/meeting-info/meeting-info-v2.d.ts +14 -3
- package/dist/types/meetings/index.d.ts +49 -1
- package/dist/types/meetings/meetings.types.d.ts +4 -0
- package/dist/types/member/index.d.ts +2 -0
- package/dist/types/members/request.d.ts +56 -11
- package/dist/types/members/util.d.ts +209 -1
- package/dist/types/metrics/config.d.ts +26 -2
- package/dist/types/metrics/constants.d.ts +1 -0
- package/dist/types/metrics/index.d.ts +17 -0
- package/dist/types/multistream/mediaRequestManager.d.ts +27 -10
- package/dist/types/multistream/receiveSlot.d.ts +3 -3
- package/dist/types/multistream/remoteMedia.d.ts +2 -2
- package/dist/types/multistream/remoteMediaManager.d.ts +14 -0
- package/dist/types/roap/request.d.ts +6 -8
- package/dist/types/roap/turnDiscovery.d.ts +18 -1
- package/package.json +21 -20
- package/src/annotation/annotation.types.ts +50 -0
- package/src/annotation/constants.ts +36 -0
- package/src/annotation/index.ts +328 -0
- package/src/breakouts/README.md +3 -2
- package/src/breakouts/breakout.ts +62 -27
- package/src/breakouts/events.ts +56 -0
- package/src/breakouts/index.ts +244 -64
- package/src/breakouts/utils.ts +13 -0
- package/src/common/errors/webex-errors.ts +6 -2
- package/src/common/logs/logger-proxy.ts +1 -1
- package/src/common/queue.ts +22 -8
- package/src/config.ts +0 -6
- package/src/constants.ts +111 -19
- package/src/controls-options-manager/enums.ts +2 -0
- package/src/controls-options-manager/index.ts +13 -10
- package/src/controls-options-manager/types.ts +10 -0
- package/src/controls-options-manager/util.ts +82 -11
- package/src/index.ts +18 -11
- package/src/interpretation/README.md +60 -0
- package/src/interpretation/collection.ts +19 -0
- package/src/interpretation/index.ts +332 -0
- package/src/interpretation/siLanguage.ts +18 -0
- package/src/locus-info/controlsUtils.ts +81 -0
- package/src/locus-info/index.ts +318 -57
- package/src/locus-info/infoUtils.ts +10 -2
- package/src/locus-info/mediaSharesUtils.ts +48 -0
- package/src/locus-info/parser.ts +224 -39
- package/src/locus-info/selfUtils.ts +32 -20
- package/src/media/index.ts +94 -108
- package/src/media/properties.ts +69 -109
- package/src/meeting/in-meeting-actions.ts +120 -4
- package/src/meeting/index.ts +1967 -2120
- package/src/meeting/locusMediaRequest.ts +314 -0
- package/src/meeting/muteState.ts +119 -194
- package/src/meeting/request.ts +122 -115
- package/src/meeting/util.ts +549 -413
- package/src/meeting-info/index.ts +54 -8
- package/src/meeting-info/meeting-info-v2.ts +89 -24
- package/src/meeting-info/utilv2.ts +6 -2
- package/src/meetings/index.ts +247 -87
- package/src/meetings/meetings.types.ts +12 -0
- package/src/meetings/util.ts +47 -12
- package/src/member/index.ts +28 -1
- package/src/member/types.ts +14 -0
- package/src/member/util.ts +75 -26
- package/src/members/index.ts +7 -1
- package/src/members/request.ts +61 -21
- package/src/members/util.ts +316 -326
- package/src/metrics/constants.ts +1 -0
- package/src/metrics/index.ts +1 -474
- package/src/multistream/mediaRequestManager.ts +183 -67
- package/src/multistream/receiveSlot.ts +4 -4
- package/src/multistream/receiveSlotManager.ts +4 -4
- package/src/multistream/remoteMedia.ts +2 -2
- package/src/multistream/remoteMediaGroup.ts +59 -0
- package/src/multistream/remoteMediaManager.ts +33 -0
- package/src/multistream/sendSlotManager.ts +170 -0
- package/src/reachability/index.ts +15 -4
- package/src/reachability/request.ts +7 -3
- package/src/reconnection-manager/index.ts +36 -29
- package/src/recording-controller/index.ts +20 -3
- package/src/recording-controller/util.ts +26 -9
- package/src/roap/index.ts +25 -30
- package/src/roap/request.ts +44 -51
- package/src/roap/turnDiscovery.ts +51 -25
- package/src/rtcMetrics/constants.ts +3 -0
- package/src/rtcMetrics/index.ts +100 -0
- package/src/statsAnalyzer/index.ts +0 -1
- package/test/integration/spec/converged-space-meetings.js +60 -3
- package/test/integration/spec/journey.js +336 -259
- package/test/integration/spec/space-meeting.js +76 -3
- package/test/unit/spec/annotation/index.ts +418 -0
- package/test/unit/spec/breakouts/breakout.ts +85 -26
- package/test/unit/spec/breakouts/events.ts +89 -0
- package/test/unit/spec/breakouts/index.ts +636 -98
- package/test/unit/spec/breakouts/utils.js +19 -1
- package/test/unit/spec/common/queue.js +31 -2
- package/test/unit/spec/controls-options-manager/index.js +8 -1
- package/test/unit/spec/controls-options-manager/util.js +576 -397
- package/test/unit/spec/fixture/locus.js +1 -0
- package/test/unit/spec/interpretation/collection.ts +15 -0
- package/test/unit/spec/interpretation/index.ts +589 -0
- package/test/unit/spec/interpretation/siLanguage.ts +28 -0
- package/test/unit/spec/locus-info/controlsUtils.js +195 -1
- package/test/unit/spec/locus-info/index.js +950 -45
- package/test/unit/spec/locus-info/infoUtils.js +37 -15
- package/test/unit/spec/locus-info/mediaSharesUtils.ts +22 -0
- package/test/unit/spec/locus-info/parser.js +62 -22
- package/test/unit/spec/locus-info/selfConstant.js +19 -0
- package/test/unit/spec/locus-info/selfUtils.js +131 -26
- package/test/unit/spec/media/index.ts +82 -79
- package/test/unit/spec/meeting/in-meeting-actions.ts +60 -2
- package/test/unit/spec/meeting/index.js +3208 -1734
- package/test/unit/spec/meeting/locusMediaRequest.ts +443 -0
- package/test/unit/spec/meeting/muteState.js +328 -417
- package/test/unit/spec/meeting/request.js +393 -48
- package/test/unit/spec/meeting/utils.js +552 -76
- package/test/unit/spec/meeting-info/index.js +181 -0
- package/test/unit/spec/meeting-info/meetinginfov2.js +258 -20
- package/test/unit/spec/meeting-info/utilv2.js +21 -0
- package/test/unit/spec/meetings/index.js +631 -145
- package/test/unit/spec/meetings/utils.js +164 -9
- package/test/unit/spec/member/index.js +44 -14
- package/test/unit/spec/member/util.js +296 -155
- package/test/unit/spec/members/index.js +23 -3
- package/test/unit/spec/members/request.js +167 -35
- package/test/unit/spec/metrics/index.js +1 -50
- package/test/unit/spec/multistream/mediaRequestManager.ts +366 -8
- package/test/unit/spec/multistream/receiveSlot.ts +1 -1
- package/test/unit/spec/multistream/remoteMediaGroup.ts +266 -0
- package/test/unit/spec/multistream/remoteMediaManager.ts +123 -0
- package/test/unit/spec/multistream/sendSlotManager.ts +242 -0
- package/test/unit/spec/reachability/index.ts +66 -5
- package/test/unit/spec/reachability/request.js +3 -1
- package/test/unit/spec/reconnection-manager/index.js +55 -5
- package/test/unit/spec/recording-controller/index.js +294 -218
- package/test/unit/spec/recording-controller/util.js +223 -96
- package/test/unit/spec/roap/index.ts +21 -48
- package/test/unit/spec/roap/request.ts +74 -60
- package/test/unit/spec/roap/turnDiscovery.ts +30 -6
- package/test/unit/spec/rtcMetrics/index.ts +68 -0
- package/test/utils/integrationTestUtils.js +46 -0
- package/test/utils/testUtils.js +0 -60
- package/src/metrics/config.ts +0 -487
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import sinon from 'sinon';
|
|
2
2
|
import {assert} from '@webex/test-helper-chai';
|
|
3
3
|
import MeetingUtil from '@webex/plugin-meetings/src/meeting/util';
|
|
4
|
-
import {createMuteState} from '@webex/plugin-meetings/src/meeting/muteState';
|
|
4
|
+
import {createMuteState, MuteState} from '@webex/plugin-meetings/src/meeting/muteState';
|
|
5
5
|
import PermissionError from '@webex/plugin-meetings/src/common/errors/permission';
|
|
6
6
|
import {AUDIO, VIDEO} from '@webex/plugin-meetings/src/constants';
|
|
7
7
|
|
|
@@ -15,20 +15,21 @@ describe('plugin-meetings', () => {
|
|
|
15
15
|
|
|
16
16
|
const fakeLocus = {info: 'this is a fake locus'};
|
|
17
17
|
|
|
18
|
-
const
|
|
18
|
+
const createFakeLocalStream = (id, muted) => {
|
|
19
19
|
return {
|
|
20
20
|
id,
|
|
21
|
-
setMuted: sinon.stub(),
|
|
22
21
|
setServerMuted: sinon.stub(),
|
|
23
22
|
setUnmuteAllowed: sinon.stub(),
|
|
24
|
-
|
|
23
|
+
setMuted: sinon.stub(),
|
|
24
|
+
muted,
|
|
25
|
+
};
|
|
25
26
|
};
|
|
26
27
|
|
|
27
|
-
beforeEach(() => {
|
|
28
|
+
beforeEach(async () => {
|
|
28
29
|
meeting = {
|
|
29
30
|
mediaProperties: {
|
|
30
|
-
|
|
31
|
-
|
|
31
|
+
audioStream: createFakeLocalStream('fake audio stream', false),
|
|
32
|
+
videoStream: createFakeLocalStream('fake video stream', false),
|
|
32
33
|
},
|
|
33
34
|
remoteMuted: false,
|
|
34
35
|
unmuteAllowed: true,
|
|
@@ -36,7 +37,7 @@ describe('plugin-meetings', () => {
|
|
|
36
37
|
unmuteVideoAllowed: true,
|
|
37
38
|
|
|
38
39
|
locusInfo: {
|
|
39
|
-
|
|
40
|
+
handleLocusDelta: sinon.stub(),
|
|
40
41
|
},
|
|
41
42
|
members: {
|
|
42
43
|
selfId: 'fake self id',
|
|
@@ -44,12 +45,14 @@ describe('plugin-meetings', () => {
|
|
|
44
45
|
},
|
|
45
46
|
};
|
|
46
47
|
|
|
47
|
-
audio = createMuteState(AUDIO, meeting, {sendAudio: true}, true);
|
|
48
|
-
video = createMuteState(VIDEO, meeting, {sendVideo: true}, true);
|
|
49
|
-
|
|
50
48
|
originalRemoteUpdateAudioVideo = MeetingUtil.remoteUpdateAudioVideo;
|
|
51
49
|
|
|
52
50
|
MeetingUtil.remoteUpdateAudioVideo = sinon.stub().resolves(fakeLocus);
|
|
51
|
+
|
|
52
|
+
audio = createMuteState(AUDIO, meeting, true);
|
|
53
|
+
video = createMuteState(VIDEO, meeting, true);
|
|
54
|
+
|
|
55
|
+
await testUtils.flushPromises();
|
|
53
56
|
});
|
|
54
57
|
|
|
55
58
|
afterEach(() => {
|
|
@@ -57,33 +60,28 @@ describe('plugin-meetings', () => {
|
|
|
57
60
|
});
|
|
58
61
|
|
|
59
62
|
describe('mute state library', () => {
|
|
60
|
-
it('does not create an audio instance if we are not sending audio', async () => {
|
|
61
|
-
assert.isNull(createMuteState(AUDIO, meeting, {sendAudio: false}, true));
|
|
62
|
-
assert.isNull(createMuteState(AUDIO, meeting, {}, true));
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
it('does not create a video instance if we are not sending video', async () => {
|
|
66
|
-
assert.isNull(createMuteState(VIDEO, meeting, {sendVideo: false}));
|
|
67
|
-
assert.isNull(createMuteState(VIDEO, meeting, {}));
|
|
68
|
-
});
|
|
69
|
-
|
|
70
63
|
it('takes into account current remote mute status when instantiated', async () => {
|
|
71
64
|
// simulate being already remote muted
|
|
72
65
|
meeting.remoteMuted = true;
|
|
73
|
-
|
|
74
|
-
|
|
66
|
+
|
|
67
|
+
// create a new MuteState instance
|
|
68
|
+
audio = createMuteState(AUDIO, meeting, true);
|
|
69
|
+
|
|
70
|
+
await testUtils.flushPromises();
|
|
75
71
|
|
|
76
72
|
assert.isTrue(audio.isMuted());
|
|
77
|
-
assert.
|
|
73
|
+
assert.isTrue(audio.isRemotelyMuted());
|
|
78
74
|
|
|
79
75
|
// now check the opposite case
|
|
80
76
|
meeting.remoteMuted = false;
|
|
81
77
|
|
|
82
|
-
// create a new MuteState
|
|
83
|
-
audio = createMuteState(AUDIO, meeting,
|
|
78
|
+
// create a new MuteState instance
|
|
79
|
+
audio = createMuteState(AUDIO, meeting, true);
|
|
84
80
|
|
|
85
|
-
|
|
86
|
-
|
|
81
|
+
await testUtils.flushPromises();
|
|
82
|
+
|
|
83
|
+
assert.isTrue(audio.isMuted()); // because we start with no stream
|
|
84
|
+
assert.isFalse(audio.isRemotelyMuted());
|
|
87
85
|
});
|
|
88
86
|
|
|
89
87
|
it('initialises correctly for video', async () => {
|
|
@@ -92,100 +90,59 @@ describe('plugin-meetings', () => {
|
|
|
92
90
|
meeting.unmuteVideoAllowed = false;
|
|
93
91
|
|
|
94
92
|
// create a new video MuteState instance
|
|
95
|
-
video = createMuteState(VIDEO, meeting,
|
|
93
|
+
video = createMuteState(VIDEO, meeting, true);
|
|
96
94
|
|
|
97
|
-
|
|
95
|
+
await testUtils.flushPromises();
|
|
96
|
+
|
|
97
|
+
assert.isTrue(video.isMuted()); // because we start with no stream
|
|
98
|
+
assert.isFalse(video.isRemotelyMuted());
|
|
98
99
|
assert.isFalse(video.state.server.remoteMute);
|
|
99
100
|
assert.isFalse(video.state.server.unmuteAllowed);
|
|
100
101
|
});
|
|
101
102
|
|
|
102
103
|
it('takes remote mute into account when reporting current state', async () => {
|
|
103
|
-
assert.isFalse(audio.
|
|
104
|
+
assert.isFalse(audio.isRemotelyMuted());
|
|
104
105
|
|
|
105
106
|
// simulate remote mute
|
|
106
107
|
audio.handleServerRemoteMuteUpdate(meeting, true, true);
|
|
107
108
|
|
|
108
|
-
assert.isTrue(audio.
|
|
109
|
-
assert.isFalse(audio.isSelf());
|
|
109
|
+
assert.isTrue(audio.isRemotelyMuted());
|
|
110
110
|
});
|
|
111
111
|
|
|
112
112
|
it('does local unmute if localAudioUnmuteRequired is received', async () => {
|
|
113
|
-
// first we need to mute
|
|
114
|
-
|
|
113
|
+
// first we need to mute have the local stream muted
|
|
114
|
+
meeting.mediaProperties.audioStream.muted = true;
|
|
115
|
+
audio.handleLocalStreamChange(meeting);
|
|
115
116
|
|
|
116
117
|
assert.isTrue(audio.isMuted());
|
|
117
|
-
assert.isTrue(audio.isSelf());
|
|
118
118
|
|
|
119
119
|
MeetingUtil.remoteUpdateAudioVideo.resetHistory();
|
|
120
120
|
|
|
121
121
|
// now simulate server requiring us to locally unmute
|
|
122
122
|
audio.handleServerLocalUnmuteRequired(meeting);
|
|
123
|
+
|
|
123
124
|
await testUtils.flushPromises();
|
|
124
125
|
|
|
125
|
-
// check that local
|
|
126
|
-
assert.calledWith(
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
assert.calledWith(MeetingUtil.remoteUpdateAudioVideo, false, undefined, meeting);
|
|
131
|
-
|
|
132
|
-
assert.isFalse(audio.isMuted());
|
|
133
|
-
assert.isFalse(audio.isSelf());
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
it('rejects client request in progress if localAudioUnmuteRequired is received', async () => {
|
|
137
|
-
let clientPromiseResolved = false;
|
|
138
|
-
let clientPromiseRejected = false;
|
|
139
|
-
|
|
140
|
-
// first we need to mute and make that request last forever
|
|
141
|
-
let serverResponseResolve;
|
|
142
|
-
|
|
143
|
-
MeetingUtil.remoteUpdateAudioVideo = sinon.stub().returns(
|
|
144
|
-
new Promise((resolve) => {
|
|
145
|
-
serverResponseResolve = resolve;
|
|
146
|
-
})
|
|
126
|
+
// check that local stream was unmuted
|
|
127
|
+
assert.calledWith(
|
|
128
|
+
meeting.mediaProperties.audioStream.setServerMuted,
|
|
129
|
+
false,
|
|
130
|
+
'localUnmuteRequired'
|
|
147
131
|
);
|
|
148
132
|
|
|
149
|
-
|
|
150
|
-
.handleClientRequest(meeting, true)
|
|
151
|
-
.then(() => {
|
|
152
|
-
clientPromiseResolved = true;
|
|
153
|
-
})
|
|
154
|
-
.catch(() => {
|
|
155
|
-
clientPromiseRejected = true;
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
MeetingUtil.remoteUpdateAudioVideo.resetHistory();
|
|
159
|
-
|
|
160
|
-
// now simulate server requiring us to locally unmute
|
|
161
|
-
audio.handleServerLocalUnmuteRequired(meeting);
|
|
162
|
-
await testUtils.flushPromises();
|
|
163
|
-
|
|
164
|
-
// the original client request should have been rejected by now
|
|
165
|
-
assert.isTrue(clientPromiseRejected);
|
|
166
|
-
assert.isFalse(clientPromiseResolved);
|
|
167
|
-
|
|
168
|
-
// now make the server respond to the original mute request
|
|
169
|
-
serverResponseResolve();
|
|
170
|
-
await testUtils.flushPromises();
|
|
171
|
-
|
|
172
|
-
// local unmute should be sent to server
|
|
133
|
+
// and local unmute was sent to server
|
|
173
134
|
assert.calledOnce(MeetingUtil.remoteUpdateAudioVideo);
|
|
174
|
-
assert.calledWith(MeetingUtil.remoteUpdateAudioVideo, false, undefined
|
|
175
|
-
|
|
176
|
-
// and local track should be unmuted
|
|
177
|
-
assert.calledWith(meeting.mediaProperties.audioTrack.setMuted, false);
|
|
135
|
+
assert.calledWith(MeetingUtil.remoteUpdateAudioVideo, meeting, false, undefined);
|
|
178
136
|
|
|
179
137
|
assert.isFalse(audio.isMuted());
|
|
180
|
-
assert.isFalse(audio.isSelf());
|
|
181
138
|
});
|
|
182
139
|
|
|
183
140
|
it('does local video unmute if localVideoUnmuteRequired is received', async () => {
|
|
184
141
|
// first we need to mute
|
|
185
|
-
|
|
142
|
+
meeting.mediaProperties.videoStream.muted = true;
|
|
143
|
+
video.handleLocalStreamChange(meeting);
|
|
186
144
|
|
|
187
145
|
assert.isTrue(video.isMuted());
|
|
188
|
-
assert.isTrue(video.isSelf());
|
|
189
146
|
|
|
190
147
|
MeetingUtil.remoteUpdateAudioVideo.resetHistory();
|
|
191
148
|
|
|
@@ -193,23 +150,31 @@ describe('plugin-meetings', () => {
|
|
|
193
150
|
video.handleServerLocalUnmuteRequired(meeting);
|
|
194
151
|
await testUtils.flushPromises();
|
|
195
152
|
|
|
196
|
-
// check that local
|
|
197
|
-
assert.calledWith(
|
|
153
|
+
// check that local stream was unmuted
|
|
154
|
+
assert.calledWith(
|
|
155
|
+
meeting.mediaProperties.videoStream.setServerMuted,
|
|
156
|
+
false,
|
|
157
|
+
'localUnmuteRequired'
|
|
158
|
+
);
|
|
198
159
|
|
|
199
160
|
// and local unmute was sent to server
|
|
200
161
|
assert.calledOnce(MeetingUtil.remoteUpdateAudioVideo);
|
|
201
|
-
assert.calledWith(MeetingUtil.remoteUpdateAudioVideo, undefined, false
|
|
162
|
+
assert.calledWith(MeetingUtil.remoteUpdateAudioVideo, meeting, undefined, false);
|
|
202
163
|
|
|
203
164
|
assert.isFalse(video.isMuted());
|
|
204
|
-
assert.isFalse(video.isSelf());
|
|
205
165
|
});
|
|
206
166
|
|
|
207
167
|
describe('#isLocallyMuted()', () => {
|
|
208
168
|
it('does not consider remote mute status for audio', async () => {
|
|
209
|
-
// simulate being already remote muted
|
|
169
|
+
// simulate being already remote muted and locally unmuted
|
|
210
170
|
meeting.remoteMuted = true;
|
|
211
|
-
|
|
212
|
-
|
|
171
|
+
meeting.mediaProperties.audioStream.muted = false;
|
|
172
|
+
|
|
173
|
+
// create a new MuteState instance
|
|
174
|
+
audio = createMuteState(AUDIO, meeting, true);
|
|
175
|
+
audio.handleLocalStreamChange(meeting);
|
|
176
|
+
|
|
177
|
+
await testUtils.flushPromises();
|
|
213
178
|
|
|
214
179
|
assert.isFalse(audio.isLocallyMuted());
|
|
215
180
|
});
|
|
@@ -217,62 +182,48 @@ describe('plugin-meetings', () => {
|
|
|
217
182
|
it('does not consider remote mute status for video', async () => {
|
|
218
183
|
// simulate being already remote muted
|
|
219
184
|
meeting.remoteVideoMuted = true;
|
|
220
|
-
|
|
221
|
-
|
|
185
|
+
meeting.mediaProperties.videoStream.muted = false;
|
|
186
|
+
|
|
187
|
+
// create a new MuteState instance
|
|
188
|
+
video = createMuteState(VIDEO, meeting, true);
|
|
189
|
+
video.handleLocalStreamChange(meeting);
|
|
190
|
+
|
|
191
|
+
await testUtils.flushPromises();
|
|
222
192
|
|
|
223
193
|
assert.isFalse(video.isLocallyMuted());
|
|
224
194
|
});
|
|
225
195
|
});
|
|
226
196
|
|
|
227
|
-
describe('
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
assert.calledWith(meeting.mediaProperties.audioTrack.setMuted, true);
|
|
232
|
-
|
|
233
|
-
// even when calling mute when it's already muted should still call setMuted
|
|
234
|
-
audio.handleClientRequest(meeting, true);
|
|
235
|
-
assert.calledWith(meeting.mediaProperties.audioTrack.setMuted, true);
|
|
197
|
+
describe('handling local stream mute events', () => {
|
|
198
|
+
beforeEach(async () => {
|
|
199
|
+
audio.handleLocalStreamChange(meeting);
|
|
200
|
+
video.handleLocalStreamChange(meeting);
|
|
236
201
|
|
|
237
|
-
|
|
238
|
-
audio.handleClientRequest(meeting, false);
|
|
239
|
-
assert.calledWith(meeting.mediaProperties.audioTrack.setMuted, false);
|
|
240
|
-
|
|
241
|
-
// even when calling unmute when it's already unmuted should still call setMuted
|
|
242
|
-
audio.handleClientRequest(meeting, false);
|
|
243
|
-
assert.calledWith(meeting.mediaProperties.audioTrack.setMuted, false);
|
|
202
|
+
await testUtils.flushPromises();
|
|
244
203
|
});
|
|
245
204
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
assert.calledWith(meeting.mediaProperties.videoTrack.setMuted, true);
|
|
205
|
+
const simulateAudioMuteChange = async (muteValue) => {
|
|
206
|
+
meeting.mediaProperties.audioStream.muted = muteValue;
|
|
207
|
+
audio.handleLocalStreamMuteStateChange(meeting, muteValue);
|
|
250
208
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
assert.calledWith(meeting.mediaProperties.videoTrack.setMuted, true);
|
|
209
|
+
await testUtils.flushPromises();
|
|
210
|
+
};
|
|
254
211
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
212
|
+
const simulateVideoMuteChange = async (muteValue) => {
|
|
213
|
+
meeting.mediaProperties.videoStream.muted = muteValue;
|
|
214
|
+
video.handleLocalStreamMuteStateChange(meeting, muteValue);
|
|
258
215
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
assert.calledWith(meeting.mediaProperties.videoTrack.setMuted, false);
|
|
262
|
-
});
|
|
216
|
+
await testUtils.flushPromises();
|
|
217
|
+
};
|
|
263
218
|
|
|
264
|
-
it('returns correct value in isMuted()
|
|
219
|
+
it('returns correct value in isMuted() methods after local stream is muted/unmuted', async () => {
|
|
265
220
|
// mute
|
|
266
|
-
|
|
267
|
-
|
|
221
|
+
await simulateAudioMuteChange(true);
|
|
268
222
|
assert.isTrue(audio.isMuted());
|
|
269
|
-
assert.isTrue(audio.isSelf());
|
|
270
223
|
|
|
271
224
|
// unmute
|
|
272
|
-
|
|
273
|
-
|
|
225
|
+
await simulateAudioMuteChange(false);
|
|
274
226
|
assert.isFalse(audio.isMuted());
|
|
275
|
-
assert.isFalse(audio.isSelf());
|
|
276
227
|
});
|
|
277
228
|
|
|
278
229
|
it('does remote unmute when unmuting and remote mute is on', async () => {
|
|
@@ -280,14 +231,13 @@ describe('plugin-meetings', () => {
|
|
|
280
231
|
audio.handleServerRemoteMuteUpdate(meeting, true, true);
|
|
281
232
|
|
|
282
233
|
// unmute
|
|
283
|
-
await
|
|
234
|
+
await simulateAudioMuteChange(false);
|
|
284
235
|
|
|
285
236
|
// check that remote unmute was sent to server
|
|
286
237
|
assert.calledOnce(meeting.members.muteMember);
|
|
287
238
|
assert.calledWith(meeting.members.muteMember, meeting.members.selfId, false, true);
|
|
288
239
|
|
|
289
240
|
assert.isFalse(audio.isMuted());
|
|
290
|
-
assert.isFalse(audio.isSelf());
|
|
291
241
|
});
|
|
292
242
|
|
|
293
243
|
it('does video remote unmute when unmuting and remote mute is on', async () => {
|
|
@@ -295,14 +245,13 @@ describe('plugin-meetings', () => {
|
|
|
295
245
|
video.handleServerRemoteMuteUpdate(meeting, true, true);
|
|
296
246
|
|
|
297
247
|
// unmute
|
|
298
|
-
await
|
|
248
|
+
await simulateVideoMuteChange(false);
|
|
299
249
|
|
|
300
250
|
// check that remote unmute was sent to server
|
|
301
251
|
assert.calledOnce(meeting.members.muteMember);
|
|
302
252
|
assert.calledWith(meeting.members.muteMember, meeting.members.selfId, false, false);
|
|
303
253
|
|
|
304
254
|
assert.isFalse(video.isMuted());
|
|
305
|
-
assert.isFalse(video.isSelf());
|
|
306
255
|
});
|
|
307
256
|
|
|
308
257
|
it('does not video remote unmute when unmuting and remote mute is off', async () => {
|
|
@@ -310,60 +259,43 @@ describe('plugin-meetings', () => {
|
|
|
310
259
|
video.handleServerRemoteMuteUpdate(meeting, false, true);
|
|
311
260
|
|
|
312
261
|
// unmute
|
|
313
|
-
await
|
|
262
|
+
await simulateVideoMuteChange(false);
|
|
314
263
|
|
|
315
|
-
// check that remote unmute was sent to server
|
|
264
|
+
// check that remote unmute was not sent to server
|
|
316
265
|
assert.notCalled(meeting.members.muteMember);
|
|
317
266
|
|
|
318
267
|
assert.isFalse(video.isMuted());
|
|
319
|
-
assert.isFalse(video.isSelf());
|
|
320
268
|
});
|
|
321
269
|
|
|
322
|
-
it('
|
|
323
|
-
|
|
270
|
+
it('calls setServerMuted with "clientRequestFailed" when server request for local mute fails', async () => {
|
|
271
|
+
MeetingUtil.remoteUpdateAudioVideo = sinon.stub().rejects(new Error('fake error'));
|
|
324
272
|
|
|
325
|
-
|
|
273
|
+
await simulateAudioMuteChange(true);
|
|
326
274
|
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
275
|
+
assert.calledOnceWithExactly(
|
|
276
|
+
meeting.mediaProperties.audioStream.setServerMuted,
|
|
277
|
+
false,
|
|
278
|
+
'clientRequestFailed'
|
|
331
279
|
);
|
|
332
|
-
|
|
333
|
-
audio.handleClientRequest(meeting, true).then(() => {
|
|
334
|
-
clientPromiseResolved = true;
|
|
335
|
-
});
|
|
336
|
-
|
|
337
|
-
// do a small delay to make sure that the client promise doesn't resolve in that time
|
|
338
|
-
await testUtils.waitUntil(200);
|
|
339
|
-
assert.isFalse(clientPromiseResolved);
|
|
340
|
-
|
|
341
|
-
// now allow the server response to arrive, this should trigger the client promise to get resolved
|
|
342
|
-
serverResponseResolve();
|
|
343
|
-
await testUtils.flushPromises();
|
|
344
|
-
|
|
345
|
-
assert.isTrue(clientPromiseResolved);
|
|
346
|
-
});
|
|
347
|
-
|
|
348
|
-
it('rejects client request promise if server request for local mute fails', async () => {
|
|
349
|
-
MeetingUtil.remoteUpdateAudioVideo = sinon.stub().returns(
|
|
350
|
-
new Promise((resolve, reject) => {
|
|
351
|
-
reject();
|
|
352
|
-
})
|
|
353
|
-
);
|
|
354
|
-
|
|
355
|
-
assert.isRejected(audio.handleClientRequest(meeting, true));
|
|
356
280
|
});
|
|
357
281
|
|
|
358
|
-
it('
|
|
282
|
+
it('calls setServerMuted with "clientRequestFailed" if server request for remote mute fails', async () => {
|
|
359
283
|
// we only send remote mute requests when we're unmuting, so first we need to do a remote mute
|
|
360
284
|
audio.handleServerRemoteMuteUpdate(meeting, true, true);
|
|
361
285
|
|
|
286
|
+
await testUtils.flushPromises();
|
|
287
|
+
|
|
362
288
|
// setup the stub to simulate server error response
|
|
363
289
|
meeting.members.muteMember = sinon.stub().rejects();
|
|
290
|
+
meeting.mediaProperties.audioStream.setServerMuted.resetHistory();
|
|
291
|
+
|
|
292
|
+
await simulateAudioMuteChange(false);
|
|
364
293
|
|
|
365
|
-
|
|
366
|
-
|
|
294
|
+
assert.calledOnceWithExactly(
|
|
295
|
+
meeting.mediaProperties.audioStream.setServerMuted,
|
|
296
|
+
true,
|
|
297
|
+
'clientRequestFailed'
|
|
298
|
+
);
|
|
367
299
|
|
|
368
300
|
// even though remote mute update in the server failed, isMuted() should still return true,
|
|
369
301
|
// because of local mute
|
|
@@ -379,12 +311,13 @@ describe('plugin-meetings', () => {
|
|
|
379
311
|
})
|
|
380
312
|
);
|
|
381
313
|
|
|
382
|
-
//
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
314
|
+
// the stream is initially unmuted
|
|
315
|
+
// simulate many mute changes with the last one matching the first one
|
|
316
|
+
await simulateAudioMuteChange(true);
|
|
317
|
+
await simulateAudioMuteChange(false);
|
|
318
|
+
await simulateAudioMuteChange(true);
|
|
319
|
+
await simulateAudioMuteChange(false);
|
|
320
|
+
await simulateAudioMuteChange(true);
|
|
388
321
|
|
|
389
322
|
// so far there should have been only 1 request to server (because our stub hasn't resolved yet
|
|
390
323
|
// and MuteState sends only 1 server request at a time)
|
|
@@ -399,7 +332,7 @@ describe('plugin-meetings', () => {
|
|
|
399
332
|
assert.notCalled(MeetingUtil.remoteUpdateAudioVideo);
|
|
400
333
|
});
|
|
401
334
|
|
|
402
|
-
it('queues up server requests when multiple
|
|
335
|
+
it('queues up server requests when multiple mute changes happen to local stream', async () => {
|
|
403
336
|
let serverResponseResolve;
|
|
404
337
|
|
|
405
338
|
MeetingUtil.remoteUpdateAudioVideo = sinon.stub().returns(
|
|
@@ -408,308 +341,286 @@ describe('plugin-meetings', () => {
|
|
|
408
341
|
})
|
|
409
342
|
);
|
|
410
343
|
|
|
411
|
-
let firstClientPromiseResolved = false;
|
|
412
|
-
let secondClientPromiseResolved = false;
|
|
413
|
-
|
|
414
344
|
// 2 client requests, one after another without waiting for first one to resolve
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
});
|
|
418
|
-
audio.handleClientRequest(meeting, false).then(() => {
|
|
419
|
-
secondClientPromiseResolved = true;
|
|
420
|
-
});
|
|
421
|
-
|
|
422
|
-
await testUtils.flushPromises();
|
|
345
|
+
await simulateAudioMuteChange(true);
|
|
346
|
+
await simulateAudioMuteChange(false);
|
|
423
347
|
|
|
424
348
|
assert.calledOnce(MeetingUtil.remoteUpdateAudioVideo);
|
|
425
|
-
assert.calledWith(MeetingUtil.remoteUpdateAudioVideo, true, undefined
|
|
349
|
+
assert.calledWith(MeetingUtil.remoteUpdateAudioVideo, meeting, true, undefined);
|
|
426
350
|
|
|
427
351
|
// now allow the first request to complete
|
|
428
352
|
serverResponseResolve();
|
|
429
353
|
await testUtils.flushPromises();
|
|
430
|
-
assert.isTrue(firstClientPromiseResolved);
|
|
431
354
|
|
|
432
355
|
// that should trigger the second server request to be sent
|
|
433
356
|
assert.calledTwice(MeetingUtil.remoteUpdateAudioVideo);
|
|
434
|
-
assert.
|
|
435
|
-
|
|
436
|
-
|
|
357
|
+
assert.deepEqual(
|
|
358
|
+
[meeting, false, undefined],
|
|
359
|
+
MeetingUtil.remoteUpdateAudioVideo.getCall(1).args
|
|
360
|
+
);
|
|
437
361
|
|
|
438
362
|
serverResponseResolve();
|
|
439
|
-
await testUtils.flushPromises();
|
|
440
|
-
|
|
441
|
-
assert.isTrue(secondClientPromiseResolved);
|
|
442
|
-
});
|
|
443
|
-
|
|
444
|
-
it('rejects client request to unmute if hard mute is used', (done) => {
|
|
445
|
-
audio.handleServerRemoteMuteUpdate(meeting, true, false);
|
|
446
|
-
|
|
447
|
-
audio
|
|
448
|
-
.handleClientRequest(meeting, false)
|
|
449
|
-
.then(() => {
|
|
450
|
-
done(new Error('expected handleClientRequest to fail, but it did not!'));
|
|
451
|
-
})
|
|
452
|
-
.catch((e) => {
|
|
453
|
-
assert.isTrue(e instanceof PermissionError);
|
|
454
|
-
done();
|
|
455
|
-
});
|
|
456
363
|
});
|
|
457
364
|
|
|
458
365
|
it('does not send remote mute for video', async () => {
|
|
459
366
|
// mute
|
|
460
|
-
await
|
|
367
|
+
await simulateVideoMuteChange(true);
|
|
461
368
|
|
|
462
369
|
assert.isTrue(video.isMuted());
|
|
463
|
-
assert.isTrue(video.isSelf());
|
|
464
370
|
|
|
465
371
|
// check local mute is done, but not remote one
|
|
466
|
-
assert.calledWith(
|
|
467
|
-
assert.calledWith(MeetingUtil.remoteUpdateAudioVideo, undefined, true, meeting);
|
|
372
|
+
assert.calledWith(MeetingUtil.remoteUpdateAudioVideo, meeting, undefined, true);
|
|
468
373
|
assert.notCalled(meeting.members.muteMember);
|
|
469
374
|
|
|
470
|
-
meeting.mediaProperties.videoTrack.setMuted.resetHistory();
|
|
471
375
|
MeetingUtil.remoteUpdateAudioVideo.resetHistory();
|
|
472
376
|
meeting.members.muteMember.resetHistory();
|
|
473
377
|
|
|
474
378
|
// unmute
|
|
475
|
-
await
|
|
379
|
+
await simulateVideoMuteChange(false);
|
|
476
380
|
|
|
477
381
|
assert.isFalse(video.isMuted());
|
|
478
|
-
assert.isFalse(video.isSelf());
|
|
479
382
|
|
|
480
|
-
assert.calledWith(
|
|
481
|
-
assert.calledWith(MeetingUtil.remoteUpdateAudioVideo, undefined, false, meeting);
|
|
383
|
+
assert.calledWith(MeetingUtil.remoteUpdateAudioVideo, meeting, undefined, false);
|
|
482
384
|
assert.notCalled(meeting.members.muteMember);
|
|
483
385
|
});
|
|
484
386
|
|
|
485
|
-
it('sends
|
|
387
|
+
it('sends undefined value for the other media type when sending local mute', async () => {
|
|
486
388
|
// make sure the meeting object has mute state machines for both audio and video
|
|
487
389
|
meeting.audio = audio;
|
|
488
390
|
meeting.video = video;
|
|
489
391
|
|
|
490
|
-
// mute audio ->
|
|
491
|
-
await
|
|
492
|
-
assert.calledWith(MeetingUtil.remoteUpdateAudioVideo,
|
|
392
|
+
// mute audio -> the call to remoteUpdateAudioVideo should have video undefined
|
|
393
|
+
await simulateAudioMuteChange(true);
|
|
394
|
+
assert.calledWith(MeetingUtil.remoteUpdateAudioVideo, meeting, true, undefined);
|
|
493
395
|
MeetingUtil.remoteUpdateAudioVideo.resetHistory();
|
|
494
396
|
|
|
495
|
-
// now mute video ->
|
|
496
|
-
await
|
|
497
|
-
assert.calledWith(MeetingUtil.remoteUpdateAudioVideo,
|
|
397
|
+
// now mute video -> the call to remoteUpdateAudioVideo should have unmute for video and undefined for audio
|
|
398
|
+
await simulateVideoMuteChange(true);
|
|
399
|
+
assert.calledWith(MeetingUtil.remoteUpdateAudioVideo, meeting, undefined, true);
|
|
498
400
|
MeetingUtil.remoteUpdateAudioVideo.resetHistory();
|
|
499
401
|
|
|
500
|
-
// now unmute the audio ->
|
|
501
|
-
await
|
|
502
|
-
assert.calledWith(MeetingUtil.remoteUpdateAudioVideo,
|
|
402
|
+
// now unmute the audio -> the call to remoteUpdateAudioVideo should have video undefined
|
|
403
|
+
await simulateAudioMuteChange(false);
|
|
404
|
+
assert.calledWith(MeetingUtil.remoteUpdateAudioVideo, meeting, false, undefined);
|
|
503
405
|
MeetingUtil.remoteUpdateAudioVideo.resetHistory();
|
|
504
406
|
|
|
505
|
-
// unmute video ->
|
|
506
|
-
await
|
|
507
|
-
assert.calledWith(MeetingUtil.remoteUpdateAudioVideo,
|
|
407
|
+
// unmute video -> the call to remoteUpdateAudioVideo should have audio undefined
|
|
408
|
+
await simulateVideoMuteChange(false);
|
|
409
|
+
assert.calledWith(MeetingUtil.remoteUpdateAudioVideo, meeting, undefined, false);
|
|
508
410
|
});
|
|
509
411
|
});
|
|
510
|
-
});
|
|
511
|
-
});
|
|
512
|
-
|
|
513
|
-
describe('#init, #handleLocalTrackChange', () => {
|
|
514
|
-
let meeting;
|
|
515
|
-
let muteState;
|
|
516
|
-
let setServerMutedSpy;
|
|
517
|
-
let setMutedSpy, setUnmuteAllowedSpy;
|
|
518
|
-
const fakeLocus = {info: 'this is a fake locus'};
|
|
519
|
-
|
|
520
|
-
const createFakeLocalTrack = (id, muted) => {
|
|
521
|
-
return {
|
|
522
|
-
id,
|
|
523
|
-
setMuted: sinon.stub(),
|
|
524
|
-
setServerMuted: sinon.stub(),
|
|
525
|
-
setUnmuteAllowed: sinon.stub(),
|
|
526
|
-
muted,
|
|
527
|
-
};
|
|
528
|
-
};
|
|
529
|
-
|
|
530
|
-
const setup = (mediaType, remoteMuted = false, muted = false, defineTracks = true) => {
|
|
531
|
-
|
|
532
|
-
const remoteMuteField = mediaType === AUDIO ? 'remoteMuted' : 'remoteVideoMuted';
|
|
533
412
|
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
413
|
+
describe('#init, #handleLocalStreamChange', () => {
|
|
414
|
+
let meeting;
|
|
415
|
+
let muteState;
|
|
416
|
+
let setServerMutedSpy;
|
|
417
|
+
let setMutedSpy, setUnmuteAllowedSpy;
|
|
418
|
+
|
|
419
|
+
const setupMeeting = (
|
|
420
|
+
mediaType,
|
|
421
|
+
remoteMuted = false,
|
|
422
|
+
muted = false,
|
|
423
|
+
defineStreams = true
|
|
424
|
+
) => {
|
|
425
|
+
const remoteMuteField = mediaType === AUDIO ? 'remoteMuted' : 'remoteVideoMuted';
|
|
426
|
+
|
|
427
|
+
meeting = {
|
|
428
|
+
mediaProperties: {
|
|
429
|
+
audioStream: defineStreams
|
|
430
|
+
? createFakeLocalStream('fake audio stream', muted)
|
|
431
|
+
: undefined,
|
|
432
|
+
videoStream: defineStreams
|
|
433
|
+
? createFakeLocalStream('fake video stream', muted)
|
|
434
|
+
: undefined,
|
|
435
|
+
},
|
|
436
|
+
[remoteMuteField]: remoteMuted,
|
|
437
|
+
unmuteAllowed: true,
|
|
438
|
+
unmuteVideoAllowed: true,
|
|
439
|
+
|
|
440
|
+
locusInfo: {
|
|
441
|
+
onFullLocus: sinon.stub(),
|
|
442
|
+
},
|
|
443
|
+
members: {
|
|
444
|
+
selfId: 'fake self id',
|
|
445
|
+
muteMember: sinon.stub().resolves(),
|
|
446
|
+
},
|
|
447
|
+
};
|
|
448
|
+
};
|
|
449
|
+
|
|
450
|
+
const setup = async (mediaType, remoteMuted = false, muted = false, defineStreams = true) => {
|
|
451
|
+
setupMeeting(mediaType, remoteMuted, muted, defineStreams);
|
|
452
|
+
|
|
453
|
+
muteState = createMuteState(mediaType, meeting, true);
|
|
454
|
+
muteState.handleLocalStreamChange(meeting);
|
|
542
455
|
|
|
543
|
-
|
|
544
|
-
onFullLocus: sinon.stub(),
|
|
545
|
-
},
|
|
546
|
-
members: {
|
|
547
|
-
selfId: 'fake self id',
|
|
548
|
-
muteMember: sinon.stub().resolves(),
|
|
549
|
-
},
|
|
550
|
-
};
|
|
551
|
-
|
|
552
|
-
const direction = mediaType === AUDIO ? {sendAudio: true} : {sendVideo: true};
|
|
553
|
-
sinon.spy(MeetingUtil, 'remoteUpdateAudioVideo');
|
|
554
|
-
muteState = createMuteState(mediaType, meeting, direction, false);
|
|
555
|
-
}
|
|
556
|
-
|
|
557
|
-
const setupSpies = (mediaType) => {
|
|
558
|
-
setUnmuteAllowedSpy = mediaType === AUDIO ? meeting.mediaProperties.audioTrack?.setUnmuteAllowed : meeting.mediaProperties.videoTrack?.setUnmuteAllowed;
|
|
559
|
-
setServerMutedSpy = mediaType === AUDIO ? meeting.mediaProperties.audioTrack?.setServerMuted : meeting.mediaProperties.videoTrack?.setServerMuted;
|
|
560
|
-
setMutedSpy = mediaType === AUDIO ? meeting.mediaProperties.audioTrack?.setMuted : meeting.mediaProperties.videoTrack?.setMuted;
|
|
456
|
+
await testUtils.flushPromises();
|
|
561
457
|
|
|
562
|
-
|
|
563
|
-
|
|
458
|
+
MeetingUtil.remoteUpdateAudioVideo.resetHistory();
|
|
459
|
+
};
|
|
460
|
+
|
|
461
|
+
const setupSpies = (mediaType) => {
|
|
462
|
+
setUnmuteAllowedSpy =
|
|
463
|
+
mediaType === AUDIO
|
|
464
|
+
? meeting.mediaProperties.audioStream?.setUnmuteAllowed
|
|
465
|
+
: meeting.mediaProperties.videoStream?.setUnmuteAllowed;
|
|
466
|
+
setServerMutedSpy =
|
|
467
|
+
mediaType === AUDIO
|
|
468
|
+
? meeting.mediaProperties.audioStream?.setServerMuted
|
|
469
|
+
: meeting.mediaProperties.videoStream?.setServerMuted;
|
|
470
|
+
setMutedSpy =
|
|
471
|
+
mediaType === AUDIO
|
|
472
|
+
? meeting.mediaProperties.audioStream?.setMuted
|
|
473
|
+
: meeting.mediaProperties.videoStream?.setMuted;
|
|
474
|
+
|
|
475
|
+
clearSpies();
|
|
476
|
+
};
|
|
477
|
+
|
|
478
|
+
const clearSpies = () => {
|
|
479
|
+
setUnmuteAllowedSpy?.resetHistory();
|
|
480
|
+
setServerMutedSpy?.resetHistory();
|
|
481
|
+
setMutedSpy?.resetHistory();
|
|
482
|
+
};
|
|
483
|
+
const tests = [
|
|
484
|
+
{mediaType: AUDIO, title: 'audio'},
|
|
485
|
+
{mediaType: VIDEO, title: 'video'},
|
|
486
|
+
];
|
|
487
|
+
|
|
488
|
+
tests.forEach(({mediaType, title}) =>
|
|
489
|
+
describe(title, () => {
|
|
490
|
+
let originalRemoteUpdateAudioVideo;
|
|
491
|
+
|
|
492
|
+
beforeEach(() => {
|
|
493
|
+
originalRemoteUpdateAudioVideo = MeetingUtil.remoteUpdateAudioVideo;
|
|
494
|
+
MeetingUtil.remoteUpdateAudioVideo = sinon.stub().resolves({info: 'fake locus'});
|
|
495
|
+
});
|
|
564
496
|
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
};
|
|
570
|
-
const tests = [
|
|
571
|
-
{mediaType: AUDIO, title: 'audio'},
|
|
572
|
-
{mediaType: VIDEO, title: 'video'}
|
|
573
|
-
];
|
|
497
|
+
afterEach(() => {
|
|
498
|
+
MeetingUtil.remoteUpdateAudioVideo = originalRemoteUpdateAudioVideo;
|
|
499
|
+
sinon.restore();
|
|
500
|
+
});
|
|
574
501
|
|
|
575
|
-
|
|
576
|
-
|
|
502
|
+
describe('#handleLocalStreamChange', () => {
|
|
503
|
+
it('calls init()', async () => {
|
|
504
|
+
await setup(mediaType);
|
|
505
|
+
const spy = sinon.spy(muteState, 'init');
|
|
506
|
+
muteState.handleLocalStreamChange(meeting);
|
|
507
|
+
assert.calledOnceWithExactly(spy, meeting);
|
|
508
|
+
});
|
|
509
|
+
});
|
|
577
510
|
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
511
|
+
describe('#init', () => {
|
|
512
|
+
// does the setup by calling new MuteState() so that MuteState.init() doesn't get called
|
|
513
|
+
const setupWithoutInit = async (
|
|
514
|
+
mediaType,
|
|
515
|
+
remoteMuted = false,
|
|
516
|
+
muted = false,
|
|
517
|
+
defineStreams = true
|
|
518
|
+
) => {
|
|
519
|
+
setupMeeting(mediaType, remoteMuted, muted, defineStreams);
|
|
581
520
|
|
|
582
|
-
|
|
521
|
+
muteState = new MuteState(mediaType, meeting, true);
|
|
522
|
+
};
|
|
583
523
|
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
muteState.handleLocalTrackChange(meeting);
|
|
588
|
-
assert.calledOnceWithExactly(spy, meeting);
|
|
589
|
-
});
|
|
590
|
-
});
|
|
524
|
+
it('nothing goes bad when stream is undefined', async () => {
|
|
525
|
+
await setupWithoutInit(mediaType, false, false, false);
|
|
526
|
+
setupSpies(mediaType);
|
|
591
527
|
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
afterEach(() => {
|
|
595
|
-
sinon.restore();
|
|
596
|
-
});
|
|
597
|
-
|
|
598
|
-
it('nothing goes bad when track is undefined', async () => {
|
|
599
|
-
setup(mediaType, false, false, false);
|
|
600
|
-
setupSpies(mediaType);
|
|
601
|
-
|
|
602
|
-
muteState.init(meeting);
|
|
603
|
-
|
|
604
|
-
assert.isFalse(muteState.state.client.localMute);
|
|
605
|
-
});
|
|
606
|
-
|
|
607
|
-
it('tests when track muted is true and remoteMuted is false', async () => {
|
|
608
|
-
setup(mediaType, false, true);
|
|
609
|
-
setupSpies(mediaType);
|
|
610
|
-
|
|
611
|
-
muteState.init(meeting);
|
|
612
|
-
|
|
613
|
-
assert.calledWith(setUnmuteAllowedSpy, muteState.state.server.unmuteAllowed);
|
|
614
|
-
assert.notCalled(setServerMutedSpy);
|
|
615
|
-
assert.calledOnce(MeetingUtil.remoteUpdateAudioVideo);
|
|
616
|
-
assert.isTrue(muteState.state.client.localMute);
|
|
617
|
-
});
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
it('tests when track muted is false and remoteMuted is false', async () => {
|
|
621
|
-
setup(mediaType, false, false);
|
|
622
|
-
setupSpies(mediaType);
|
|
623
|
-
muteState.state.server.localMute = true;
|
|
624
|
-
|
|
625
|
-
muteState.init(meeting);
|
|
626
|
-
|
|
627
|
-
assert.calledWith(setUnmuteAllowedSpy, muteState.state.server.unmuteAllowed);
|
|
628
|
-
assert.notCalled(setServerMutedSpy);
|
|
629
|
-
assert.calledOnce(MeetingUtil.remoteUpdateAudioVideo);
|
|
630
|
-
assert.isFalse(muteState.state.client.localMute);
|
|
631
|
-
});
|
|
632
|
-
|
|
633
|
-
it('tests when remoteMuted is true', async () => {
|
|
634
|
-
// testing that muteLocalTrack is called
|
|
635
|
-
setup(mediaType, true);
|
|
636
|
-
setupSpies(mediaType);
|
|
637
|
-
|
|
638
|
-
muteState.init(meeting);
|
|
639
|
-
|
|
640
|
-
assert.calledWith(setUnmuteAllowedSpy, muteState.state.server.unmuteAllowed);
|
|
641
|
-
assert.calledOnceWithExactly(setServerMutedSpy, true, 'remotelyMuted');
|
|
642
|
-
});
|
|
643
|
-
});
|
|
528
|
+
muteState.init(meeting);
|
|
644
529
|
|
|
645
|
-
|
|
530
|
+
assert.isTrue(muteState.state.client.localMute);
|
|
531
|
+
});
|
|
646
532
|
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
533
|
+
it('tests when stream muted is true and remoteMuted is false', async () => {
|
|
534
|
+
await setupWithoutInit(mediaType, false, true);
|
|
535
|
+
setupSpies(mediaType);
|
|
650
536
|
|
|
651
|
-
|
|
652
|
-
setup(mediaType, false, false);
|
|
653
|
-
muteState.ignoreMuteStateChange= true;
|
|
537
|
+
muteState.init(meeting);
|
|
654
538
|
|
|
655
|
-
|
|
656
|
-
|
|
539
|
+
assert.calledWith(setUnmuteAllowedSpy, muteState.state.server.unmuteAllowed);
|
|
540
|
+
assert.notCalled(setServerMutedSpy);
|
|
541
|
+
assert.notCalled(MeetingUtil.remoteUpdateAudioVideo);
|
|
542
|
+
assert.isTrue(muteState.state.client.localMute);
|
|
543
|
+
});
|
|
657
544
|
|
|
658
|
-
|
|
659
|
-
|
|
545
|
+
it('tests when stream muted is false and remoteMuted is false', async () => {
|
|
546
|
+
await setupWithoutInit(mediaType, false, false);
|
|
547
|
+
setupSpies(mediaType);
|
|
660
548
|
|
|
661
|
-
|
|
662
|
-
setup(mediaType, false, true);
|
|
549
|
+
muteState.init(meeting);
|
|
663
550
|
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
551
|
+
assert.calledWith(setUnmuteAllowedSpy, muteState.state.server.unmuteAllowed);
|
|
552
|
+
assert.notCalled(setServerMutedSpy);
|
|
553
|
+
assert.calledOnce(MeetingUtil.remoteUpdateAudioVideo);
|
|
554
|
+
assert.isFalse(muteState.state.client.localMute);
|
|
555
|
+
});
|
|
668
556
|
|
|
669
|
-
|
|
670
|
-
|
|
557
|
+
it('tests when remoteMuted is true', async () => {
|
|
558
|
+
// testing that muteLocalStream is called
|
|
559
|
+
await setupWithoutInit(mediaType, true);
|
|
560
|
+
setupSpies(mediaType);
|
|
671
561
|
|
|
672
|
-
|
|
673
|
-
assert.equal(muteState.state.client.localMute, true);
|
|
674
|
-
assert.called(MeetingUtil.remoteUpdateAudioVideo);
|
|
675
|
-
});
|
|
676
|
-
});
|
|
562
|
+
muteState.init(meeting);
|
|
677
563
|
|
|
678
|
-
|
|
564
|
+
assert.calledWith(setUnmuteAllowedSpy, muteState.state.server.unmuteAllowed);
|
|
565
|
+
assert.calledOnceWithExactly(setServerMutedSpy, true, 'remotelyMuted');
|
|
566
|
+
});
|
|
567
|
+
});
|
|
679
568
|
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
569
|
+
describe('#handleLocalStreamMuteStateChange', () => {
|
|
570
|
+
it('checks when ignoreMuteStateChange is true nothing changes', async () => {
|
|
571
|
+
await setup(mediaType, false, false);
|
|
572
|
+
muteState.ignoreMuteStateChange = true;
|
|
683
573
|
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
setupSpies(mediaType);
|
|
687
|
-
muteState.sdkOwnsLocalTrack= false;
|
|
574
|
+
muteState.handleLocalStreamMuteStateChange(meeting, true);
|
|
575
|
+
assert.notCalled(MeetingUtil.remoteUpdateAudioVideo);
|
|
688
576
|
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
assert.notCalled(setMutedSpy);
|
|
692
|
-
});
|
|
577
|
+
assert.isFalse(muteState.state.client.localMute);
|
|
578
|
+
});
|
|
693
579
|
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
setupSpies(mediaType);
|
|
697
|
-
muteState.sdkOwnsLocalTrack= true;
|
|
580
|
+
it('tests localMute - true to false', async () => {
|
|
581
|
+
await setup(mediaType, false, true);
|
|
698
582
|
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
583
|
+
muteState.handleLocalStreamMuteStateChange(meeting, false);
|
|
584
|
+
assert.equal(muteState.state.client.localMute, false);
|
|
585
|
+
assert.called(MeetingUtil.remoteUpdateAudioVideo);
|
|
586
|
+
});
|
|
703
587
|
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
setupSpies(mediaType);
|
|
707
|
-
muteState.sdkOwnsLocalTrack= true;
|
|
588
|
+
it('tests localMute - false to true', async () => {
|
|
589
|
+
await setup(mediaType, false, false);
|
|
708
590
|
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
591
|
+
muteState.handleLocalStreamMuteStateChange(meeting, true);
|
|
592
|
+
assert.equal(muteState.state.client.localMute, true);
|
|
593
|
+
assert.called(MeetingUtil.remoteUpdateAudioVideo);
|
|
594
|
+
});
|
|
595
|
+
});
|
|
712
596
|
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
597
|
+
describe('#applyClientStateLocally', () => {
|
|
598
|
+
afterEach(() => {
|
|
599
|
+
sinon.restore();
|
|
600
|
+
});
|
|
601
|
+
|
|
602
|
+
it('calls setServerMuted on the stream', async () => {
|
|
603
|
+
await setup(mediaType);
|
|
604
|
+
setupSpies(mediaType);
|
|
605
|
+
|
|
606
|
+
muteState.applyClientStateLocally(meeting, 'somereason');
|
|
607
|
+
assert.calledOnceWithExactly(
|
|
608
|
+
setServerMutedSpy,
|
|
609
|
+
muteState.state.client.localMute,
|
|
610
|
+
'somereason'
|
|
611
|
+
);
|
|
612
|
+
assert.notCalled(setMutedSpy);
|
|
613
|
+
});
|
|
614
|
+
|
|
615
|
+
it('nothing explodes when streams are undefined', async () => {
|
|
616
|
+
await setup(mediaType, false, false, false);
|
|
617
|
+
setupSpies(mediaType);
|
|
618
|
+
|
|
619
|
+
muteState.applyClientStateLocally(meeting, 'somereason');
|
|
620
|
+
});
|
|
621
|
+
});
|
|
622
|
+
})
|
|
623
|
+
);
|
|
624
|
+
});
|
|
625
|
+
});
|
|
626
|
+
});
|