@webex/plugin-meetings 3.0.0 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/breakouts/breakout.js +1 -1
- package/dist/breakouts/index.js +1 -1
- package/dist/config.d.ts +1 -0
- package/dist/config.js +2 -1
- package/dist/config.js.map +1 -1
- package/dist/constants.d.ts +5 -4
- package/dist/constants.js +8 -4
- package/dist/constants.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/interpretation/index.js +16 -2
- package/dist/interpretation/index.js.map +1 -1
- package/dist/interpretation/siLanguage.js +1 -1
- package/dist/locus-info/mediaSharesUtils.js +15 -1
- package/dist/locus-info/mediaSharesUtils.js.map +1 -1
- package/dist/locus-info/selfUtils.js +5 -0
- package/dist/locus-info/selfUtils.js.map +1 -1
- package/dist/media/MediaConnectionAwaiter.d.ts +61 -0
- package/dist/media/MediaConnectionAwaiter.js +163 -0
- package/dist/media/MediaConnectionAwaiter.js.map +1 -0
- package/dist/media/index.js +4 -1
- package/dist/media/index.js.map +1 -1
- package/dist/media/properties.js +4 -24
- package/dist/media/properties.js.map +1 -1
- package/dist/meeting/index.d.ts +26 -7
- package/dist/meeting/index.js +893 -677
- package/dist/meeting/index.js.map +1 -1
- package/dist/meeting/muteState.d.ts +2 -8
- package/dist/meeting/muteState.js +37 -25
- package/dist/meeting/muteState.js.map +1 -1
- package/dist/meeting/request.d.ts +3 -0
- package/dist/meeting/request.js +32 -23
- package/dist/meeting/request.js.map +1 -1
- package/dist/meeting/util.js +1 -0
- package/dist/meeting/util.js.map +1 -1
- package/dist/meeting-info/utilv2.js +4 -1
- package/dist/meeting-info/utilv2.js.map +1 -1
- package/dist/meetings/index.d.ts +8 -0
- package/dist/meetings/index.js +20 -0
- package/dist/meetings/index.js.map +1 -1
- package/dist/multistream/mediaRequestManager.d.ts +2 -1
- package/dist/multistream/mediaRequestManager.js +1 -1
- package/dist/multistream/mediaRequestManager.js.map +1 -1
- package/dist/multistream/remoteMediaGroup.d.ts +2 -0
- package/dist/multistream/remoteMediaGroup.js +16 -2
- package/dist/multistream/remoteMediaGroup.js.map +1 -1
- package/dist/multistream/remoteMediaManager.d.ts +15 -0
- package/dist/multistream/remoteMediaManager.js +179 -65
- package/dist/multistream/remoteMediaManager.js.map +1 -1
- package/dist/multistream/sendSlotManager.d.ts +9 -1
- package/dist/multistream/sendSlotManager.js +22 -0
- package/dist/multistream/sendSlotManager.js.map +1 -1
- package/dist/reachability/clusterReachability.d.ts +1 -0
- package/dist/reachability/clusterReachability.js +29 -15
- package/dist/reachability/clusterReachability.js.map +1 -1
- package/dist/reachability/index.d.ts +4 -0
- package/dist/reachability/index.js +18 -2
- package/dist/reachability/index.js.map +1 -1
- package/dist/reachability/request.js +12 -10
- package/dist/reachability/request.js.map +1 -1
- package/dist/reachability/util.d.ts +7 -0
- package/dist/reachability/util.js +19 -0
- package/dist/reachability/util.js.map +1 -1
- package/dist/reconnection-manager/index.js +2 -1
- package/dist/reconnection-manager/index.js.map +1 -1
- package/dist/roap/index.d.ts +10 -2
- package/dist/roap/index.js +15 -0
- package/dist/roap/index.js.map +1 -1
- package/dist/roap/request.js +3 -3
- package/dist/roap/request.js.map +1 -1
- package/dist/roap/turnDiscovery.d.ts +64 -17
- package/dist/roap/turnDiscovery.js +307 -126
- package/dist/roap/turnDiscovery.js.map +1 -1
- package/dist/statsAnalyzer/index.js +53 -30
- package/dist/statsAnalyzer/index.js.map +1 -1
- package/dist/webinar/index.js +1 -1
- package/package.json +22 -22
- package/src/config.ts +1 -0
- package/src/constants.ts +7 -3
- package/src/index.ts +1 -0
- package/src/interpretation/index.ts +18 -1
- package/src/locus-info/mediaSharesUtils.ts +16 -0
- package/src/locus-info/selfUtils.ts +5 -0
- package/src/media/MediaConnectionAwaiter.ts +174 -0
- package/src/media/index.ts +3 -1
- package/src/media/properties.ts +6 -31
- package/src/meeting/index.ts +321 -106
- package/src/meeting/muteState.ts +34 -20
- package/src/meeting/request.ts +18 -2
- package/src/meeting/util.ts +1 -0
- package/src/meeting-info/utilv2.ts +2 -1
- package/src/meetings/index.ts +18 -0
- package/src/multistream/mediaRequestManager.ts +4 -1
- package/src/multistream/remoteMediaGroup.ts +19 -0
- package/src/multistream/remoteMediaManager.ts +101 -16
- package/src/multistream/sendSlotManager.ts +28 -0
- package/src/reachability/clusterReachability.ts +20 -5
- package/src/reachability/index.ts +24 -1
- package/src/reachability/request.ts +15 -11
- package/src/reachability/util.ts +21 -0
- package/src/reconnection-manager/index.ts +1 -1
- package/src/roap/index.ts +25 -3
- package/src/roap/request.ts +3 -3
- package/src/roap/turnDiscovery.ts +244 -78
- package/src/statsAnalyzer/index.ts +63 -27
- package/test/integration/spec/journey.js +14 -14
- package/test/integration/spec/space-meeting.js +1 -1
- package/test/unit/spec/interpretation/index.ts +39 -3
- package/test/unit/spec/locus-info/index.js +28 -19
- package/test/unit/spec/locus-info/mediaSharesUtils.ts +9 -0
- package/test/unit/spec/locus-info/selfUtils.js +42 -12
- package/test/unit/spec/media/MediaConnectionAwaiter.ts +344 -0
- package/test/unit/spec/media/index.ts +89 -78
- package/test/unit/spec/media/properties.ts +16 -70
- package/test/unit/spec/meeting/index.js +638 -139
- package/test/unit/spec/meeting/muteState.js +219 -67
- package/test/unit/spec/meeting/request.js +21 -0
- package/test/unit/spec/meeting/utils.js +6 -1
- package/test/unit/spec/meeting-info/utilv2.js +6 -0
- package/test/unit/spec/meetings/index.js +40 -20
- package/test/unit/spec/multistream/mediaRequestManager.ts +20 -2
- package/test/unit/spec/multistream/remoteMediaGroup.ts +79 -1
- package/test/unit/spec/multistream/remoteMediaManager.ts +199 -1
- package/test/unit/spec/multistream/sendSlotManager.ts +50 -18
- package/test/unit/spec/reachability/clusterReachability.ts +86 -22
- package/test/unit/spec/reachability/index.ts +197 -60
- package/test/unit/spec/reachability/request.js +15 -7
- package/test/unit/spec/reachability/util.ts +32 -2
- package/test/unit/spec/reconnection-manager/index.js +28 -0
- package/test/unit/spec/roap/index.ts +61 -6
- package/test/unit/spec/roap/turnDiscovery.ts +298 -16
- package/test/unit/spec/stats-analyzer/index.js +179 -0
- package/dist/member/member.types.d.ts +0 -11
- package/dist/member/member.types.js +0 -17
- package/dist/member/member.types.js.map +0 -1
- package/src/member/member.types.ts +0 -13
- /package/test/unit/spec/locus-info/{lib/selfConstant.js → selfConstant.js} +0 -0
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
import {assert} from '@webex/test-helper-chai';
|
|
2
|
+
import sinon from 'sinon';
|
|
3
|
+
import {ConnectionState, Event} from '@webex/internal-media-core';
|
|
4
|
+
import testUtils from '../../../utils/testUtils';
|
|
5
|
+
import {ICE_AND_DTLS_CONNECTION_TIMEOUT} from '@webex/plugin-meetings/src/constants';
|
|
6
|
+
import MediaConnectionAwaiter from '../../../../src/media/MediaConnectionAwaiter';
|
|
7
|
+
|
|
8
|
+
describe('MediaConnectionAwaiter', () => {
|
|
9
|
+
let mediaConnectionAwaiter;
|
|
10
|
+
let mockMC;
|
|
11
|
+
let clock;
|
|
12
|
+
|
|
13
|
+
beforeEach(() => {
|
|
14
|
+
clock = sinon.useFakeTimers();
|
|
15
|
+
|
|
16
|
+
mockMC = {
|
|
17
|
+
getStats: sinon.stub().resolves([]),
|
|
18
|
+
on: sinon.stub(),
|
|
19
|
+
off: sinon.stub(),
|
|
20
|
+
getConnectionState: sinon.stub().returns(ConnectionState.New),
|
|
21
|
+
getIceGatheringState: sinon.stub().returns('new'),
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
mediaConnectionAwaiter = new MediaConnectionAwaiter({
|
|
25
|
+
webrtcMediaConnection: mockMC,
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
afterEach(() => {
|
|
30
|
+
clock.restore();
|
|
31
|
+
sinon.restore();
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
describe('waitForMediaConnectionConnected', () => {
|
|
35
|
+
it('resolves immediately if connection state is connected', async () => {
|
|
36
|
+
mockMC.getConnectionState.returns(ConnectionState.Connected);
|
|
37
|
+
|
|
38
|
+
await mediaConnectionAwaiter.waitForMediaConnectionConnected();
|
|
39
|
+
|
|
40
|
+
assert.neverCalledWith(mockMC.on);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('rejects after timeout if ice state is not connected', async () => {
|
|
44
|
+
mockMC.getConnectionState.returns(ConnectionState.Connecting);
|
|
45
|
+
mockMC.getIceGatheringState.returns('gathering');
|
|
46
|
+
|
|
47
|
+
let promiseResolved = false;
|
|
48
|
+
let promiseRejected = false;
|
|
49
|
+
|
|
50
|
+
mediaConnectionAwaiter
|
|
51
|
+
.waitForMediaConnectionConnected()
|
|
52
|
+
.then(() => {
|
|
53
|
+
promiseResolved = true;
|
|
54
|
+
})
|
|
55
|
+
.catch(() => {
|
|
56
|
+
promiseRejected = true;
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
await testUtils.flushPromises();
|
|
60
|
+
assert.equal(promiseResolved, false);
|
|
61
|
+
assert.equal(promiseRejected, false);
|
|
62
|
+
|
|
63
|
+
// check the right listener was registered
|
|
64
|
+
assert.calledTwice(mockMC.on);
|
|
65
|
+
assert.equal(mockMC.on.getCall(0).args[0], Event.CONNECTION_STATE_CHANGED);
|
|
66
|
+
assert.equal(mockMC.on.getCall(1).args[0], Event.ICE_GATHERING_STATE_CHANGED);
|
|
67
|
+
const listener = mockMC.on.getCall(1).args[1];
|
|
68
|
+
|
|
69
|
+
mockMC.getIceGatheringState.returns('complete');
|
|
70
|
+
listener();
|
|
71
|
+
|
|
72
|
+
await clock.tickAsync(ICE_AND_DTLS_CONNECTION_TIMEOUT);
|
|
73
|
+
await testUtils.flushPromises();
|
|
74
|
+
|
|
75
|
+
assert.equal(promiseResolved, false);
|
|
76
|
+
assert.equal(promiseRejected, true);
|
|
77
|
+
|
|
78
|
+
assert.calledTwice(mockMC.off);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it('resolves after timeout if connection state reach connected/completed', async () => {
|
|
82
|
+
mockMC.getConnectionState.returns(ConnectionState.Connecting);
|
|
83
|
+
mockMC.getIceGatheringState.returns('gathering');
|
|
84
|
+
|
|
85
|
+
let promiseResolved = false;
|
|
86
|
+
let promiseRejected = false;
|
|
87
|
+
|
|
88
|
+
mediaConnectionAwaiter
|
|
89
|
+
.waitForMediaConnectionConnected()
|
|
90
|
+
.then(() => {
|
|
91
|
+
promiseResolved = true;
|
|
92
|
+
})
|
|
93
|
+
.catch(() => {
|
|
94
|
+
promiseRejected = true;
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
await testUtils.flushPromises();
|
|
98
|
+
assert.equal(promiseResolved, false);
|
|
99
|
+
assert.equal(promiseRejected, false);
|
|
100
|
+
|
|
101
|
+
// check the right listener was registered
|
|
102
|
+
assert.calledTwice(mockMC.on);
|
|
103
|
+
assert.equal(mockMC.on.getCall(0).args[0], Event.CONNECTION_STATE_CHANGED);
|
|
104
|
+
assert.equal(mockMC.on.getCall(1).args[0], Event.ICE_GATHERING_STATE_CHANGED);
|
|
105
|
+
|
|
106
|
+
mockMC.getConnectionState.returns(ConnectionState.Connected);
|
|
107
|
+
|
|
108
|
+
await clock.tickAsync(ICE_AND_DTLS_CONNECTION_TIMEOUT);
|
|
109
|
+
await testUtils.flushPromises();
|
|
110
|
+
|
|
111
|
+
assert.equal(promiseResolved, true);
|
|
112
|
+
assert.equal(promiseRejected, false);
|
|
113
|
+
|
|
114
|
+
assert.calledTwice(mockMC.off);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it(`resolves when media connection reaches "connected" state`, async () => {
|
|
118
|
+
mockMC.getConnectionState.returns(ConnectionState.Connecting);
|
|
119
|
+
mockMC.getIceGatheringState.returns('gathering');
|
|
120
|
+
|
|
121
|
+
const clearTimeoutSpy = sinon.spy(clock, 'clearTimeout');
|
|
122
|
+
|
|
123
|
+
let promiseResolved = false;
|
|
124
|
+
let promiseRejected = false;
|
|
125
|
+
|
|
126
|
+
mediaConnectionAwaiter
|
|
127
|
+
.waitForMediaConnectionConnected()
|
|
128
|
+
.then(() => {
|
|
129
|
+
promiseResolved = true;
|
|
130
|
+
})
|
|
131
|
+
.catch(() => {
|
|
132
|
+
promiseRejected = true;
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
await testUtils.flushPromises();
|
|
136
|
+
assert.equal(promiseResolved, false);
|
|
137
|
+
assert.equal(promiseRejected, false);
|
|
138
|
+
|
|
139
|
+
// check the right listener was registered
|
|
140
|
+
assert.calledTwice(mockMC.on);
|
|
141
|
+
assert.equal(mockMC.on.getCall(0).args[0], Event.CONNECTION_STATE_CHANGED);
|
|
142
|
+
assert.equal(mockMC.on.getCall(1).args[0], Event.ICE_GATHERING_STATE_CHANGED);
|
|
143
|
+
const listener = mockMC.on.getCall(0).args[1];
|
|
144
|
+
|
|
145
|
+
// call the listener and pretend we are now connected
|
|
146
|
+
mockMC.getConnectionState.returns(ConnectionState.Connected);
|
|
147
|
+
listener();
|
|
148
|
+
await testUtils.flushPromises();
|
|
149
|
+
|
|
150
|
+
assert.equal(promiseResolved, true);
|
|
151
|
+
assert.equal(promiseRejected, false);
|
|
152
|
+
|
|
153
|
+
// check that listener was removed
|
|
154
|
+
assert.calledTwice(mockMC.off);
|
|
155
|
+
|
|
156
|
+
assert.calledOnce(clearTimeoutSpy);
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it(`ice gathering state update to "gathering" state does not update timer`, async () => {
|
|
160
|
+
mockMC.getConnectionState.returns(ConnectionState.Connecting);
|
|
161
|
+
mockMC.getIceGatheringState.returns('new');
|
|
162
|
+
|
|
163
|
+
const clearTimeoutSpy = sinon.spy(clock, 'clearTimeout');
|
|
164
|
+
|
|
165
|
+
let promiseResolved = false;
|
|
166
|
+
let promiseRejected = false;
|
|
167
|
+
|
|
168
|
+
mediaConnectionAwaiter
|
|
169
|
+
.waitForMediaConnectionConnected()
|
|
170
|
+
.then(() => {
|
|
171
|
+
promiseResolved = true;
|
|
172
|
+
})
|
|
173
|
+
.catch(() => {
|
|
174
|
+
promiseRejected = true;
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
await testUtils.flushPromises();
|
|
178
|
+
assert.equal(promiseResolved, false);
|
|
179
|
+
assert.equal(promiseRejected, false);
|
|
180
|
+
|
|
181
|
+
// check the right listener was registered
|
|
182
|
+
assert.calledTwice(mockMC.on);
|
|
183
|
+
assert.equal(mockMC.on.getCall(0).args[0], Event.CONNECTION_STATE_CHANGED);
|
|
184
|
+
assert.equal(mockMC.on.getCall(1).args[0], Event.ICE_GATHERING_STATE_CHANGED);
|
|
185
|
+
const listener = mockMC.on.getCall(1).args[1];
|
|
186
|
+
|
|
187
|
+
// call the listener and pretend we are now connected
|
|
188
|
+
mockMC.getIceGatheringState.returns('gathering');
|
|
189
|
+
listener();
|
|
190
|
+
|
|
191
|
+
mockMC.getConnectionState.returns(ConnectionState.Connected);
|
|
192
|
+
|
|
193
|
+
await clock.tickAsync(ICE_AND_DTLS_CONNECTION_TIMEOUT);
|
|
194
|
+
await testUtils.flushPromises();
|
|
195
|
+
|
|
196
|
+
assert.equal(promiseResolved, true);
|
|
197
|
+
assert.equal(promiseRejected, false);
|
|
198
|
+
|
|
199
|
+
// check that listener was removed
|
|
200
|
+
assert.calledTwice(mockMC.off);
|
|
201
|
+
|
|
202
|
+
assert.neverCalledWith(clearTimeoutSpy);
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
it(`ice gathering update to 'complete' state restarts the timer`, async () => {
|
|
206
|
+
mockMC.getConnectionState.returns(ConnectionState.Connecting);
|
|
207
|
+
mockMC.getIceGatheringState.returns('new');
|
|
208
|
+
|
|
209
|
+
const setTimeoutSpy = sinon.spy(clock, 'setTimeout');
|
|
210
|
+
const clearTimeoutSpy = sinon.spy(clock, 'clearTimeout');
|
|
211
|
+
|
|
212
|
+
let promiseResolved = false;
|
|
213
|
+
let promiseRejected = false;
|
|
214
|
+
|
|
215
|
+
mediaConnectionAwaiter
|
|
216
|
+
.waitForMediaConnectionConnected()
|
|
217
|
+
.then(() => {
|
|
218
|
+
promiseResolved = true;
|
|
219
|
+
})
|
|
220
|
+
.catch(() => {
|
|
221
|
+
promiseRejected = true;
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
await testUtils.flushPromises();
|
|
225
|
+
assert.equal(promiseResolved, false);
|
|
226
|
+
assert.equal(promiseRejected, false);
|
|
227
|
+
|
|
228
|
+
assert.calledOnce(setTimeoutSpy);
|
|
229
|
+
|
|
230
|
+
// check the right listener was registered
|
|
231
|
+
assert.calledTwice(mockMC.on);
|
|
232
|
+
assert.equal(mockMC.on.getCall(0).args[0], Event.CONNECTION_STATE_CHANGED);
|
|
233
|
+
assert.equal(mockMC.on.getCall(1).args[0], Event.ICE_GATHERING_STATE_CHANGED);
|
|
234
|
+
const listener = mockMC.on.getCall(1).args[1];
|
|
235
|
+
|
|
236
|
+
// call the listener and pretend we are now connected
|
|
237
|
+
mockMC.getIceGatheringState.returns('complete');
|
|
238
|
+
listener();
|
|
239
|
+
|
|
240
|
+
assert.calledOnce(clearTimeoutSpy);
|
|
241
|
+
assert.calledTwice(setTimeoutSpy);
|
|
242
|
+
|
|
243
|
+
mockMC.getConnectionState.returns(ConnectionState.Connected);
|
|
244
|
+
|
|
245
|
+
await clock.tickAsync(ICE_AND_DTLS_CONNECTION_TIMEOUT);
|
|
246
|
+
await testUtils.flushPromises();
|
|
247
|
+
|
|
248
|
+
assert.equal(promiseResolved, true);
|
|
249
|
+
assert.equal(promiseRejected, false);
|
|
250
|
+
|
|
251
|
+
// check that listener was removed
|
|
252
|
+
assert.calledTwice(mockMC.off);
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
it(`reject with restart timer once if gathering state is not complete`, async () => {
|
|
256
|
+
mockMC.getConnectionState.returns(ConnectionState.Connecting);
|
|
257
|
+
mockMC.getIceGatheringState.returns('new');
|
|
258
|
+
|
|
259
|
+
const setTimeoutSpy = sinon.spy(clock, 'setTimeout');
|
|
260
|
+
const clearTimeoutSpy = sinon.spy(clock, 'clearTimeout');
|
|
261
|
+
|
|
262
|
+
let promiseResolved = false;
|
|
263
|
+
let promiseRejected = false;
|
|
264
|
+
|
|
265
|
+
mediaConnectionAwaiter
|
|
266
|
+
.waitForMediaConnectionConnected()
|
|
267
|
+
.then(() => {
|
|
268
|
+
promiseResolved = true;
|
|
269
|
+
})
|
|
270
|
+
.catch(() => {
|
|
271
|
+
promiseRejected = true;
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
await testUtils.flushPromises();
|
|
275
|
+
assert.equal(promiseResolved, false);
|
|
276
|
+
assert.equal(promiseRejected, false);
|
|
277
|
+
|
|
278
|
+
// check the right listener was registered
|
|
279
|
+
assert.calledTwice(mockMC.on);
|
|
280
|
+
assert.equal(mockMC.on.getCall(0).args[0], Event.CONNECTION_STATE_CHANGED);
|
|
281
|
+
assert.equal(mockMC.on.getCall(1).args[0], Event.ICE_GATHERING_STATE_CHANGED);
|
|
282
|
+
|
|
283
|
+
await clock.tickAsync(ICE_AND_DTLS_CONNECTION_TIMEOUT * 2);
|
|
284
|
+
await testUtils.flushPromises();
|
|
285
|
+
|
|
286
|
+
assert.equal(promiseResolved, false);
|
|
287
|
+
assert.equal(promiseRejected, true);
|
|
288
|
+
|
|
289
|
+
// check that listener was removed
|
|
290
|
+
assert.calledTwice(mockMC.off);
|
|
291
|
+
|
|
292
|
+
assert.calledOnce(clearTimeoutSpy);
|
|
293
|
+
assert.calledTwice(setTimeoutSpy);
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
it(`resolves gathering and connection state complete right after`, async () => {
|
|
297
|
+
mockMC.getConnectionState.returns(ConnectionState.Connecting);
|
|
298
|
+
mockMC.getIceGatheringState.returns('new');
|
|
299
|
+
|
|
300
|
+
const setTimeoutSpy = sinon.spy(clock, 'setTimeout');
|
|
301
|
+
const clearTimeoutSpy = sinon.spy(clock, 'clearTimeout');
|
|
302
|
+
|
|
303
|
+
let promiseResolved = false;
|
|
304
|
+
let promiseRejected = false;
|
|
305
|
+
|
|
306
|
+
mediaConnectionAwaiter
|
|
307
|
+
.waitForMediaConnectionConnected()
|
|
308
|
+
.then(() => {
|
|
309
|
+
promiseResolved = true;
|
|
310
|
+
})
|
|
311
|
+
.catch(() => {
|
|
312
|
+
promiseRejected = true;
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
await testUtils.flushPromises();
|
|
316
|
+
assert.equal(promiseResolved, false);
|
|
317
|
+
assert.equal(promiseRejected, false);
|
|
318
|
+
|
|
319
|
+
// check the right listener was registered
|
|
320
|
+
assert.calledTwice(mockMC.on);
|
|
321
|
+
assert.equal(mockMC.on.getCall(0).args[0], Event.CONNECTION_STATE_CHANGED);
|
|
322
|
+
assert.equal(mockMC.on.getCall(1).args[0], Event.ICE_GATHERING_STATE_CHANGED);
|
|
323
|
+
const connectionStateListener = mockMC.on.getCall(0).args[1];
|
|
324
|
+
const iceGatheringListener = mockMC.on.getCall(1).args[1];
|
|
325
|
+
|
|
326
|
+
mockMC.getIceGatheringState.returns('complete');
|
|
327
|
+
iceGatheringListener();
|
|
328
|
+
|
|
329
|
+
mockMC.getConnectionState.returns(ConnectionState.Connected);
|
|
330
|
+
connectionStateListener();
|
|
331
|
+
|
|
332
|
+
await testUtils.flushPromises();
|
|
333
|
+
|
|
334
|
+
assert.equal(promiseResolved, true);
|
|
335
|
+
assert.equal(promiseRejected, false);
|
|
336
|
+
|
|
337
|
+
// check that listener was removed
|
|
338
|
+
assert.calledTwice(mockMC.off);
|
|
339
|
+
|
|
340
|
+
assert.calledTwice(clearTimeoutSpy);
|
|
341
|
+
assert.calledTwice(setTimeoutSpy);
|
|
342
|
+
});
|
|
343
|
+
});
|
|
344
|
+
});
|
|
@@ -170,37 +170,15 @@ describe('createMediaConnection', () => {
|
|
|
170
170
|
);
|
|
171
171
|
});
|
|
172
172
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
Media.createMediaConnection(true, 'debug string', webex, 'meeting id', 'correlationId', {
|
|
179
|
-
mediaProperties: {
|
|
180
|
-
mediaDirection: {
|
|
181
|
-
sendAudio: true,
|
|
182
|
-
sendVideo: true,
|
|
183
|
-
sendShare: false,
|
|
184
|
-
receiveAudio: true,
|
|
185
|
-
receiveVideo: true,
|
|
186
|
-
receiveShare: true,
|
|
187
|
-
},
|
|
188
|
-
},
|
|
189
|
-
});
|
|
190
|
-
assert.calledOnce(multistreamRoapMediaConnectionConstructorStub);
|
|
191
|
-
assert.calledWith(
|
|
192
|
-
multistreamRoapMediaConnectionConstructorStub,
|
|
193
|
-
{
|
|
194
|
-
iceServers: [],
|
|
195
|
-
},
|
|
196
|
-
'meeting id'
|
|
197
|
-
);
|
|
198
|
-
|
|
199
|
-
it('does not pass bundlePolicy to MultistreamRoapMediaConnection if bundlePolicy is undefined', () => {
|
|
173
|
+
[
|
|
174
|
+
{testCase: 'turnServerInfo is undefined', turnServerInfo: undefined},
|
|
175
|
+
{testCase: 'turnServerInfo.url is empty string', turnServerInfo: {url: '', username: 'turn username', password: 'turn password'}},
|
|
176
|
+
].forEach(({testCase, turnServerInfo}) => {
|
|
177
|
+
it(`passes empty ICE servers array to MultistreamRoapMediaConnection if ${testCase} (multistream enabled)`, () => {
|
|
200
178
|
const multistreamRoapMediaConnectionConstructorStub = sinon
|
|
201
179
|
.stub(internalMediaModule, 'MultistreamRoapMediaConnection')
|
|
202
180
|
.returns(fakeRoapMediaConnection);
|
|
203
|
-
|
|
181
|
+
|
|
204
182
|
Media.createMediaConnection(true, 'debug string', webex, 'meeting id', 'correlationId', {
|
|
205
183
|
mediaProperties: {
|
|
206
184
|
mediaDirection: {
|
|
@@ -212,7 +190,7 @@ describe('createMediaConnection', () => {
|
|
|
212
190
|
receiveShare: true,
|
|
213
191
|
},
|
|
214
192
|
},
|
|
215
|
-
|
|
193
|
+
turnServerInfo,
|
|
216
194
|
});
|
|
217
195
|
assert.calledOnce(multistreamRoapMediaConnectionConstructorStub);
|
|
218
196
|
assert.calledWith(
|
|
@@ -221,75 +199,108 @@ describe('createMediaConnection', () => {
|
|
|
221
199
|
iceServers: [],
|
|
222
200
|
},
|
|
223
201
|
'meeting id'
|
|
224
|
-
|
|
202
|
+
);
|
|
225
203
|
});
|
|
226
204
|
});
|
|
227
|
-
|
|
228
|
-
it('
|
|
229
|
-
const
|
|
230
|
-
.stub(internalMediaModule, '
|
|
205
|
+
|
|
206
|
+
it('does not pass bundlePolicy to MultistreamRoapMediaConnection if bundlePolicy is undefined', () => {
|
|
207
|
+
const multistreamRoapMediaConnectionConstructorStub = sinon
|
|
208
|
+
.stub(internalMediaModule, 'MultistreamRoapMediaConnection')
|
|
231
209
|
.returns(fakeRoapMediaConnection);
|
|
232
210
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
const ENABLE_EXTMAP = false;
|
|
236
|
-
const ENABLE_RTX = true;
|
|
237
|
-
|
|
238
|
-
Media.createMediaConnection(false, 'some debug id', webex, 'meeting id', 'correlationId', {
|
|
211
|
+
Media.createMediaConnection(true, 'debug string', webex, 'meeting id', 'correlationId', {
|
|
239
212
|
mediaProperties: {
|
|
240
213
|
mediaDirection: {
|
|
241
214
|
sendAudio: true,
|
|
242
215
|
sendVideo: true,
|
|
243
|
-
sendShare:
|
|
216
|
+
sendShare: false,
|
|
244
217
|
receiveAudio: true,
|
|
245
218
|
receiveVideo: true,
|
|
246
219
|
receiveShare: true,
|
|
247
220
|
},
|
|
248
|
-
audioStream: fakeAudioStream,
|
|
249
|
-
videoStream: null,
|
|
250
|
-
shareVideoStream: fakeShareVideoStream,
|
|
251
|
-
shareAudioStream: fakeShareAudioStream,
|
|
252
221
|
},
|
|
253
|
-
|
|
254
|
-
enableRtx: ENABLE_RTX,
|
|
255
|
-
enableExtmap: ENABLE_EXTMAP,
|
|
256
|
-
turnServerInfo: undefined,
|
|
222
|
+
bundlePolicy: undefined,
|
|
257
223
|
});
|
|
258
|
-
assert.calledOnce(
|
|
224
|
+
assert.calledOnce(multistreamRoapMediaConnectionConstructorStub);
|
|
259
225
|
assert.calledWith(
|
|
260
|
-
|
|
226
|
+
multistreamRoapMediaConnectionConstructorStub,
|
|
261
227
|
{
|
|
262
228
|
iceServers: [],
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
229
|
+
},
|
|
230
|
+
'meeting id'
|
|
231
|
+
);
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
[
|
|
235
|
+
{testCase: 'turnServerInfo is undefined', turnServerInfo: undefined},
|
|
236
|
+
{testCase: 'turnServerInfo.url is empty string', turnServerInfo: {url: '', username: 'turn username', password: 'turn password'}},
|
|
237
|
+
].forEach(({testCase, turnServerInfo}) => {
|
|
238
|
+
it(`passes empty ICE servers array to RoapMediaConnection if ${testCase} (multistream disabled)`, () => {
|
|
239
|
+
const roapMediaConnectionConstructorStub = sinon
|
|
240
|
+
.stub(internalMediaModule, 'RoapMediaConnection')
|
|
241
|
+
.returns(fakeRoapMediaConnection);
|
|
242
|
+
|
|
243
|
+
StaticConfig.set({bandwidth: {audio: 123, video: 456, startBitrate: 999}});
|
|
244
|
+
|
|
245
|
+
const ENABLE_EXTMAP = false;
|
|
246
|
+
const ENABLE_RTX = true;
|
|
247
|
+
|
|
248
|
+
Media.createMediaConnection(false, 'some debug id', webex, 'meeting id', 'correlationId', {
|
|
249
|
+
mediaProperties: {
|
|
250
|
+
mediaDirection: {
|
|
251
|
+
sendAudio: true,
|
|
252
|
+
sendVideo: true,
|
|
253
|
+
sendShare: true,
|
|
254
|
+
receiveAudio: true,
|
|
255
|
+
receiveVideo: true,
|
|
256
|
+
receiveShare: true,
|
|
271
257
|
},
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
258
|
+
audioStream: fakeAudioStream,
|
|
259
|
+
videoStream: null,
|
|
260
|
+
shareVideoStream: fakeShareVideoStream,
|
|
261
|
+
shareAudioStream: fakeShareAudioStream,
|
|
276
262
|
},
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
263
|
+
remoteQualityLevel: 'HIGH',
|
|
264
|
+
enableRtx: ENABLE_RTX,
|
|
265
|
+
enableExtmap: ENABLE_EXTMAP,
|
|
266
|
+
turnServerInfo,
|
|
267
|
+
});
|
|
268
|
+
assert.calledOnce(roapMediaConnectionConstructorStub);
|
|
269
|
+
assert.calledWith(
|
|
270
|
+
roapMediaConnectionConstructorStub,
|
|
271
|
+
{
|
|
272
|
+
iceServers: [],
|
|
273
|
+
skipInactiveTransceivers: false,
|
|
274
|
+
requireH264: true,
|
|
275
|
+
sdpMunging: {
|
|
276
|
+
convertPort9to0: false,
|
|
277
|
+
addContentSlides: true,
|
|
278
|
+
bandwidthLimits: {
|
|
279
|
+
audio: 123,
|
|
280
|
+
video: 456,
|
|
281
|
+
},
|
|
282
|
+
startBitrate: 999,
|
|
283
|
+
periodicKeyframes: 20,
|
|
284
|
+
disableExtmap: !ENABLE_EXTMAP,
|
|
285
|
+
disableRtx: !ENABLE_RTX,
|
|
286
|
+
},
|
|
284
287
|
},
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
288
|
+
{
|
|
289
|
+
localTracks: {
|
|
290
|
+
audio: fakeTrack,
|
|
291
|
+
video: undefined,
|
|
292
|
+
screenShareVideo: fakeTrack,
|
|
293
|
+
screenShareAudio: fakeTrack,
|
|
294
|
+
},
|
|
295
|
+
direction: {
|
|
296
|
+
audio: 'sendrecv',
|
|
297
|
+
video: 'sendrecv',
|
|
298
|
+
screenShareVideo: 'sendrecv',
|
|
299
|
+
},
|
|
300
|
+
remoteQualityLevel: 'HIGH',
|
|
289
301
|
},
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
);
|
|
302
|
+
'some debug id'
|
|
303
|
+
);
|
|
304
|
+
});
|
|
294
305
|
});
|
|
295
306
|
});
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import {assert} from '@webex/test-helper-chai';
|
|
2
2
|
import sinon from 'sinon';
|
|
3
|
-
import {ConnectionState
|
|
3
|
+
import {ConnectionState} from '@webex/internal-media-core';
|
|
4
4
|
import MediaProperties from '@webex/plugin-meetings/src/media/properties';
|
|
5
|
-
import MediaUtil from '@webex/plugin-meetings/src/media/util';
|
|
6
5
|
import testUtils from '../../../utils/testUtils';
|
|
7
|
-
import {ICE_AND_DTLS_CONNECTION_TIMEOUT} from '@webex/plugin-meetings/src/constants';
|
|
8
6
|
import {Defer} from '@webex/common';
|
|
7
|
+
import MediaConnectionAwaiter from '../../../../src/media/MediaConnectionAwaiter';
|
|
9
8
|
|
|
10
9
|
describe('MediaProperties', () => {
|
|
11
10
|
let mediaProperties;
|
|
@@ -31,80 +30,27 @@ describe('MediaProperties', () => {
|
|
|
31
30
|
sinon.restore();
|
|
32
31
|
});
|
|
33
32
|
describe('waitForMediaConnectionConnected', () => {
|
|
34
|
-
it('resolves
|
|
35
|
-
|
|
36
|
-
});
|
|
37
|
-
it('rejects after timeout if ice state does not reach connected/completed', async () => {
|
|
38
|
-
mockMC.getConnectionState.returns(ConnectionState.Connecting);
|
|
39
|
-
|
|
40
|
-
let promiseResolved = false;
|
|
41
|
-
let promiseRejected = false;
|
|
42
|
-
|
|
43
|
-
mediaProperties
|
|
44
|
-
.waitForMediaConnectionConnected()
|
|
45
|
-
.then(() => {
|
|
46
|
-
promiseResolved = true;
|
|
47
|
-
})
|
|
48
|
-
.catch(() => {
|
|
49
|
-
promiseRejected = true;
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
assert.equal(promiseResolved, false);
|
|
53
|
-
assert.equal(promiseRejected, false);
|
|
54
|
-
|
|
55
|
-
await clock.tickAsync(ICE_AND_DTLS_CONNECTION_TIMEOUT);
|
|
56
|
-
await testUtils.flushPromises();
|
|
33
|
+
it('resolves if media connection is connected', async () => {
|
|
34
|
+
const waitForMediaConnectionConnectedResult = new Defer();
|
|
57
35
|
|
|
58
|
-
|
|
59
|
-
|
|
36
|
+
sinon
|
|
37
|
+
.stub(MediaConnectionAwaiter.prototype, 'waitForMediaConnectionConnected')
|
|
38
|
+
.returns(waitForMediaConnectionConnectedResult.promise);
|
|
60
39
|
|
|
61
|
-
|
|
62
|
-
assert.calledOnce(mockMC.on);
|
|
63
|
-
assert.equal(mockMC.on.getCall(0).args[0], Event.CONNECTION_STATE_CHANGED);
|
|
64
|
-
const listener = mockMC.on.getCall(0).args[1];
|
|
40
|
+
waitForMediaConnectionConnectedResult.resolve();
|
|
65
41
|
|
|
66
|
-
|
|
67
|
-
assert.calledWith(mockMC.off, Event.CONNECTION_STATE_CHANGED, listener);
|
|
42
|
+
await mediaProperties.waitForMediaConnectionConnected();
|
|
68
43
|
});
|
|
44
|
+
it('rejects if media connection is not connected', async () => {
|
|
45
|
+
const waitForMediaConnectionConnectedResult = new Defer();
|
|
69
46
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
const clearTimeoutSpy = sinon.spy(clock, 'clearTimeout');
|
|
74
|
-
|
|
75
|
-
let promiseResolved = false;
|
|
76
|
-
let promiseRejected = false;
|
|
77
|
-
|
|
78
|
-
mediaProperties
|
|
79
|
-
.waitForMediaConnectionConnected()
|
|
80
|
-
.then(() => {
|
|
81
|
-
promiseResolved = true;
|
|
82
|
-
})
|
|
83
|
-
.catch(() => {
|
|
84
|
-
promiseRejected = true;
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
assert.equal(promiseResolved, false);
|
|
88
|
-
assert.equal(promiseRejected, false);
|
|
89
|
-
|
|
90
|
-
// check the right listener was registered
|
|
91
|
-
assert.calledOnce(mockMC.on);
|
|
92
|
-
assert.equal(mockMC.on.getCall(0).args[0], Event.CONNECTION_STATE_CHANGED);
|
|
93
|
-
const listener = mockMC.on.getCall(0).args[1];
|
|
94
|
-
|
|
95
|
-
// call the listener and pretend we are now connected
|
|
96
|
-
mockMC.getConnectionState.returns(ConnectionState.Connected);
|
|
97
|
-
listener();
|
|
98
|
-
await testUtils.flushPromises();
|
|
99
|
-
|
|
100
|
-
assert.equal(promiseResolved, true);
|
|
101
|
-
assert.equal(promiseRejected, false);
|
|
47
|
+
sinon
|
|
48
|
+
.stub(MediaConnectionAwaiter.prototype, 'waitForMediaConnectionConnected')
|
|
49
|
+
.returns(waitForMediaConnectionConnectedResult.promise);
|
|
102
50
|
|
|
103
|
-
|
|
104
|
-
assert.calledOnce(mockMC.off);
|
|
105
|
-
assert.calledWith(mockMC.off, Event.CONNECTION_STATE_CHANGED, listener);
|
|
51
|
+
waitForMediaConnectionConnectedResult.reject();
|
|
106
52
|
|
|
107
|
-
assert.
|
|
53
|
+
await assert.isRejected(mediaProperties.waitForMediaConnectionConnected());
|
|
108
54
|
});
|
|
109
55
|
});
|
|
110
56
|
|