@webex/plugin-meetings 3.4.0 → 3.5.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/interpretation/index.js +1 -1
- package/dist/interpretation/siLanguage.js +1 -1
- package/dist/media/index.js +6 -9
- package/dist/media/index.js.map +1 -1
- package/dist/meeting/index.js +122 -49
- package/dist/meeting/index.js.map +1 -1
- package/dist/meeting/util.js +1 -0
- package/dist/meeting/util.js.map +1 -1
- package/dist/meetings/index.js +4 -2
- package/dist/meetings/index.js.map +1 -1
- package/dist/reachability/index.js +175 -103
- package/dist/reachability/index.js.map +1 -1
- package/dist/reconnection-manager/index.js +1 -1
- package/dist/reconnection-manager/index.js.map +1 -1
- package/dist/rtcMetrics/index.js +26 -6
- package/dist/rtcMetrics/index.js.map +1 -1
- package/dist/types/meeting/index.d.ts +11 -2
- package/dist/types/meetings/index.d.ts +2 -1
- package/dist/types/reachability/index.d.ts +14 -2
- package/dist/types/rtcMetrics/index.d.ts +11 -1
- package/dist/webinar/index.js +1 -1
- package/package.json +22 -22
- package/src/media/index.ts +5 -9
- package/src/meeting/index.ts +54 -10
- package/src/meeting/util.ts +2 -0
- package/src/meetings/index.ts +4 -3
- package/src/reachability/index.ts +49 -4
- package/src/reconnection-manager/index.ts +1 -1
- package/src/rtcMetrics/index.ts +25 -5
- package/test/integration/spec/converged-space-meetings.js +1 -1
- package/test/unit/spec/breakouts/index.ts +1 -0
- package/test/unit/spec/interceptors/locusRetry.ts +11 -10
- package/test/unit/spec/media/MediaConnectionAwaiter.ts +1 -0
- package/test/unit/spec/media/index.ts +34 -7
- package/test/unit/spec/media/properties.ts +1 -1
- package/test/unit/spec/meeting/connectionStateHandler.ts +1 -0
- package/test/unit/spec/meeting/index.js +77 -6
- package/test/unit/spec/meeting/locusMediaRequest.ts +3 -2
- package/test/unit/spec/meeting/request.js +1 -0
- package/test/unit/spec/meeting/utils.js +4 -0
- package/test/unit/spec/meeting-info/meetinginfov2.js +10 -11
- package/test/unit/spec/meeting-info/request.js +1 -1
- package/test/unit/spec/meetings/index.js +30 -3
- package/test/unit/spec/members/request.js +2 -1
- package/test/unit/spec/multistream/mediaRequestManager.ts +1 -0
- package/test/unit/spec/multistream/receiveSlot.ts +1 -0
- package/test/unit/spec/multistream/receiveSlotManager.ts +1 -0
- package/test/unit/spec/multistream/remoteMedia.ts +1 -0
- package/test/unit/spec/multistream/remoteMediaGroup.ts +1 -0
- package/test/unit/spec/multistream/remoteMediaManager.ts +1 -0
- package/test/unit/spec/multistream/sendSlotManager.ts +1 -0
- package/test/unit/spec/personal-meeting-room/personal-meeting-room.js +0 -1
- package/test/unit/spec/reachability/index.ts +211 -13
- package/test/unit/spec/reachability/request.js +1 -0
- package/test/unit/spec/roap/request.ts +1 -0
- package/test/unit/spec/rtcMetrics/index.ts +31 -0
- package/src/networkQualityMonitor/index.ts +0 -211
- package/test/unit/spec/networkQualityMonitor/index.js +0 -99
package/src/rtcMetrics/index.ts
CHANGED
|
@@ -34,6 +34,8 @@ export default class RtcMetrics {
|
|
|
34
34
|
|
|
35
35
|
connectionId: string;
|
|
36
36
|
|
|
37
|
+
shouldSendMetricsOnNextStatsReport: boolean;
|
|
38
|
+
|
|
37
39
|
/**
|
|
38
40
|
* Initialize the interval.
|
|
39
41
|
*
|
|
@@ -47,9 +49,7 @@ export default class RtcMetrics {
|
|
|
47
49
|
this.meetingId = meetingId;
|
|
48
50
|
this.webex = webex;
|
|
49
51
|
this.correlationId = correlationId;
|
|
50
|
-
this.
|
|
51
|
-
// Send the first set of metrics at 5 seconds in the case of a user leaving the call shortly after joining.
|
|
52
|
-
setTimeout(this.sendMetricsInQueue.bind(this), 5 * 1000);
|
|
52
|
+
this.resetConnection();
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
/**
|
|
@@ -64,6 +64,18 @@ export default class RtcMetrics {
|
|
|
64
64
|
}
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
+
/**
|
|
68
|
+
* Forces sending metrics when we get the next stats-report
|
|
69
|
+
*
|
|
70
|
+
* This is useful for cases when something important happens that affects the media connection,
|
|
71
|
+
* for example when we move from lobby into the meeting.
|
|
72
|
+
*
|
|
73
|
+
* @returns {void}
|
|
74
|
+
*/
|
|
75
|
+
public sendNextMetrics() {
|
|
76
|
+
this.shouldSendMetricsOnNextStatsReport = true;
|
|
77
|
+
}
|
|
78
|
+
|
|
67
79
|
/**
|
|
68
80
|
* Add metrics items to the metrics queue.
|
|
69
81
|
*
|
|
@@ -79,6 +91,13 @@ export default class RtcMetrics {
|
|
|
79
91
|
|
|
80
92
|
this.metricsQueue.push(data);
|
|
81
93
|
|
|
94
|
+
if (this.shouldSendMetricsOnNextStatsReport && data.name === 'stats-report') {
|
|
95
|
+
// this is the first useful set of data (WCME gives it to us after 5s), send it out immediately
|
|
96
|
+
// in case the user is unhappy and closes the browser early
|
|
97
|
+
this.sendMetricsInQueue();
|
|
98
|
+
this.shouldSendMetricsOnNextStatsReport = false;
|
|
99
|
+
}
|
|
100
|
+
|
|
82
101
|
try {
|
|
83
102
|
// If a connection fails, send the rest of the metrics in queue and get a new connection id.
|
|
84
103
|
const parsedPayload = parseJsonPayload(data.payload);
|
|
@@ -88,7 +107,7 @@ export default class RtcMetrics {
|
|
|
88
107
|
parsedPayload.value === 'failed'
|
|
89
108
|
) {
|
|
90
109
|
this.sendMetricsInQueue();
|
|
91
|
-
this.
|
|
110
|
+
this.resetConnection();
|
|
92
111
|
}
|
|
93
112
|
} catch (e) {
|
|
94
113
|
console.error(e);
|
|
@@ -130,8 +149,9 @@ export default class RtcMetrics {
|
|
|
130
149
|
*
|
|
131
150
|
* @returns {void}
|
|
132
151
|
*/
|
|
133
|
-
private
|
|
152
|
+
private resetConnection() {
|
|
134
153
|
this.connectionId = uuid.v4();
|
|
154
|
+
this.shouldSendMetricsOnNextStatsReport = true;
|
|
135
155
|
}
|
|
136
156
|
|
|
137
157
|
/**
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { config } from 'dotenv';
|
|
2
1
|
import 'jsdom-global/register';
|
|
2
|
+
import {config} from 'dotenv';
|
|
3
3
|
import {assert} from '@webex/test-helper-chai';
|
|
4
4
|
import {skipInNode} from '@webex/test-helper-mocha';
|
|
5
5
|
import BrowserDetection from '@webex/plugin-meetings/dist/common/browser-detection';
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
/* eslint-disable camelcase */
|
|
6
|
+
import 'jsdom-global/register';
|
|
6
7
|
import {assert} from '@webex/test-helper-chai';
|
|
7
8
|
import { expect } from "@webex/test-helper-chai";
|
|
8
9
|
import MockWebex from '@webex/test-helper-mock-webex';
|
|
@@ -13,7 +14,7 @@ import sinon from 'sinon';
|
|
|
13
14
|
|
|
14
15
|
describe('plugin-meetings', () => {
|
|
15
16
|
describe('Interceptors', () => {
|
|
16
|
-
describe('LocusRetryStatusInterceptor', () => {
|
|
17
|
+
describe('LocusRetryStatusInterceptor', () => {
|
|
17
18
|
let interceptor, webex;
|
|
18
19
|
beforeEach(() => {
|
|
19
20
|
webex = new MockWebex({
|
|
@@ -24,7 +25,7 @@ describe('plugin-meetings', () => {
|
|
|
24
25
|
interceptor = Reflect.apply(LocusRetryStatusInterceptor.create, {
|
|
25
26
|
sessionId: 'mock-webex_uuid',
|
|
26
27
|
}, []);
|
|
27
|
-
});
|
|
28
|
+
});
|
|
28
29
|
describe('#onResponseError', () => {
|
|
29
30
|
const options = {
|
|
30
31
|
method: 'POST',
|
|
@@ -41,7 +42,7 @@ describe('plugin-meetings', () => {
|
|
|
41
42
|
headers: {
|
|
42
43
|
trackingid: 'test',
|
|
43
44
|
'retry-after': 1000,
|
|
44
|
-
},
|
|
45
|
+
},
|
|
45
46
|
uri: `https://locus-test.webex.com/locus/api/v1/loci/call`,
|
|
46
47
|
},
|
|
47
48
|
body: {
|
|
@@ -54,7 +55,7 @@ describe('plugin-meetings', () => {
|
|
|
54
55
|
headers: {
|
|
55
56
|
trackingid: 'test',
|
|
56
57
|
'retry-after': 1000,
|
|
57
|
-
},
|
|
58
|
+
},
|
|
58
59
|
uri: `https://locus-test.webex.com/locus/api/v1/loci/call`,
|
|
59
60
|
},
|
|
60
61
|
body: {
|
|
@@ -73,7 +74,7 @@ describe('plugin-meetings', () => {
|
|
|
73
74
|
|
|
74
75
|
return interceptor.onResponseError(options, reason2).then(() => {
|
|
75
76
|
expect(handleRetryStub.calledWith(options, 1000)).to.be.true;
|
|
76
|
-
|
|
77
|
+
|
|
77
78
|
});
|
|
78
79
|
});
|
|
79
80
|
});
|
|
@@ -92,7 +93,7 @@ describe('plugin-meetings', () => {
|
|
|
92
93
|
it('returns the correct resolved value when the request is successful', () => {
|
|
93
94
|
const mockResponse = 'mock response'
|
|
94
95
|
interceptor.webex.request = sinon.stub().returns(Promise.resolve(mockResponse));
|
|
95
|
-
|
|
96
|
+
|
|
96
97
|
return interceptor.handleRetryRequestLocusServiceError(options, retryAfterTime)
|
|
97
98
|
.then((response) => {
|
|
98
99
|
expect(response).to.equal(mockResponse);
|
|
@@ -101,9 +102,9 @@ describe('plugin-meetings', () => {
|
|
|
101
102
|
|
|
102
103
|
it('rejects the promise when the request is unsuccessful', () => {
|
|
103
104
|
const rejectionReason = 'Service Unavaialble after retry';
|
|
104
|
-
|
|
105
|
+
|
|
105
106
|
interceptor.webex.request = sinon.stub().returns(Promise.reject(rejectionReason));
|
|
106
|
-
|
|
107
|
+
|
|
107
108
|
return interceptor.handleRetryRequestLocusServiceError(options, retryAfterTime)
|
|
108
109
|
.catch((error) => {
|
|
109
110
|
expect(error).to.equal(rejectionReason);
|
|
@@ -114,10 +115,10 @@ describe('plugin-meetings', () => {
|
|
|
114
115
|
let clock;
|
|
115
116
|
clock = sinon.useFakeTimers();
|
|
116
117
|
const mockResponse = 'mock response'
|
|
117
|
-
|
|
118
|
+
|
|
118
119
|
interceptor.webex.request = sinon.stub().returns(Promise.resolve(mockResponse));
|
|
119
120
|
const promise = interceptor.handleRetryRequestLocusServiceError(options, retryAfterTime);
|
|
120
|
-
|
|
121
|
+
|
|
121
122
|
clock.tick(retryAfterTime);
|
|
122
123
|
|
|
123
124
|
return promise.then(() => {
|
|
@@ -1,16 +1,15 @@
|
|
|
1
|
+
import 'jsdom-global/register';
|
|
1
2
|
import * as InternalMediaCoreModule from '@webex/internal-media-core';
|
|
2
3
|
import Media from '@webex/plugin-meetings/src/media/index';
|
|
3
4
|
import {assert} from '@webex/test-helper-chai';
|
|
4
5
|
import sinon from 'sinon';
|
|
5
6
|
import StaticConfig from '@webex/plugin-meetings/src/common/config';
|
|
6
|
-
import MockWebex from '@webex/test-helper-mock-webex';
|
|
7
7
|
|
|
8
8
|
describe('createMediaConnection', () => {
|
|
9
9
|
let clock;
|
|
10
10
|
beforeEach(() => {
|
|
11
11
|
clock = sinon.useFakeTimers();
|
|
12
12
|
});
|
|
13
|
-
const webex = MockWebex();
|
|
14
13
|
|
|
15
14
|
const fakeRoapMediaConnection = {
|
|
16
15
|
id: 'roap media connection',
|
|
@@ -61,7 +60,7 @@ describe('createMediaConnection', () => {
|
|
|
61
60
|
const ENABLE_EXTMAP = false;
|
|
62
61
|
const ENABLE_RTX = true;
|
|
63
62
|
|
|
64
|
-
Media.createMediaConnection(false, 'some debug id',
|
|
63
|
+
Media.createMediaConnection(false, 'some debug id', 'meetingId', {
|
|
65
64
|
mediaProperties: {
|
|
66
65
|
mediaDirection: {
|
|
67
66
|
sendAudio: false,
|
|
@@ -139,7 +138,13 @@ describe('createMediaConnection', () => {
|
|
|
139
138
|
.stub(InternalMediaCoreModule, 'MultistreamRoapMediaConnection')
|
|
140
139
|
.returns(fakeRoapMediaConnection);
|
|
141
140
|
|
|
142
|
-
|
|
141
|
+
const rtcMetrics = {
|
|
142
|
+
addMetrics: sinon.stub(),
|
|
143
|
+
closeMetrics: sinon.stub(),
|
|
144
|
+
sendMetricsInQueue: sinon.stub(),
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
Media.createMediaConnection(true, 'some debug id', 'meeting id', {
|
|
143
148
|
mediaProperties: {
|
|
144
149
|
mediaDirection: {
|
|
145
150
|
sendAudio: true,
|
|
@@ -150,6 +155,7 @@ describe('createMediaConnection', () => {
|
|
|
150
155
|
receiveShare: true,
|
|
151
156
|
},
|
|
152
157
|
},
|
|
158
|
+
rtcMetrics,
|
|
153
159
|
turnServerInfo: {
|
|
154
160
|
url: 'turns:turn-server-url:443?transport=tcp',
|
|
155
161
|
username: 'turn username',
|
|
@@ -177,6 +183,27 @@ describe('createMediaConnection', () => {
|
|
|
177
183
|
},
|
|
178
184
|
'meeting id'
|
|
179
185
|
);
|
|
186
|
+
|
|
187
|
+
// check if rtcMetrics callbacks are configured correctly
|
|
188
|
+
const addMetricsCallback = multistreamRoapMediaConnectionConstructorStub.getCalls()[0].args[2];
|
|
189
|
+
const closeMetricsCallback = multistreamRoapMediaConnectionConstructorStub.getCalls()[0].args[3];
|
|
190
|
+
const sendMetricsInQueueCallback = multistreamRoapMediaConnectionConstructorStub.getCalls()[0].args[4];
|
|
191
|
+
|
|
192
|
+
assert.isFunction(addMetricsCallback);
|
|
193
|
+
assert.isFunction(closeMetricsCallback);
|
|
194
|
+
assert.isFunction(sendMetricsInQueueCallback);
|
|
195
|
+
|
|
196
|
+
const fakeMetricsData = {id: 'metrics data'};
|
|
197
|
+
|
|
198
|
+
addMetricsCallback(fakeMetricsData);
|
|
199
|
+
assert.calledOnceWithExactly(rtcMetrics.addMetrics, fakeMetricsData);
|
|
200
|
+
|
|
201
|
+
closeMetricsCallback();
|
|
202
|
+
assert.calledOnce(rtcMetrics.closeMetrics);
|
|
203
|
+
|
|
204
|
+
sendMetricsInQueueCallback();
|
|
205
|
+
assert.calledOnce(rtcMetrics.sendMetricsInQueue);
|
|
206
|
+
|
|
180
207
|
});
|
|
181
208
|
|
|
182
209
|
[
|
|
@@ -191,7 +218,7 @@ describe('createMediaConnection', () => {
|
|
|
191
218
|
.stub(InternalMediaCoreModule, 'MultistreamRoapMediaConnection')
|
|
192
219
|
.returns(fakeRoapMediaConnection);
|
|
193
220
|
|
|
194
|
-
Media.createMediaConnection(true, 'debug string',
|
|
221
|
+
Media.createMediaConnection(true, 'debug string', 'meeting id', {
|
|
195
222
|
mediaProperties: {
|
|
196
223
|
mediaDirection: {
|
|
197
224
|
sendAudio: true,
|
|
@@ -220,7 +247,7 @@ describe('createMediaConnection', () => {
|
|
|
220
247
|
.stub(InternalMediaCoreModule, 'MultistreamRoapMediaConnection')
|
|
221
248
|
.returns(fakeRoapMediaConnection);
|
|
222
249
|
|
|
223
|
-
Media.createMediaConnection(true, 'debug string',
|
|
250
|
+
Media.createMediaConnection(true, 'debug string', 'meeting id', {
|
|
224
251
|
mediaProperties: {
|
|
225
252
|
mediaDirection: {
|
|
226
253
|
sendAudio: true,
|
|
@@ -260,7 +287,7 @@ describe('createMediaConnection', () => {
|
|
|
260
287
|
const ENABLE_EXTMAP = false;
|
|
261
288
|
const ENABLE_RTX = true;
|
|
262
289
|
|
|
263
|
-
Media.createMediaConnection(false, 'some debug id',
|
|
290
|
+
Media.createMediaConnection(false, 'some debug id', 'meeting id', {
|
|
264
291
|
mediaProperties: {
|
|
265
292
|
mediaDirection: {
|
|
266
293
|
sendAudio: true,
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
+
import 'jsdom-global/register';
|
|
1
2
|
import {assert} from '@webex/test-helper-chai';
|
|
2
3
|
import sinon from 'sinon';
|
|
3
4
|
import {ConnectionState} from '@webex/internal-media-core';
|
|
4
5
|
import MediaProperties from '@webex/plugin-meetings/src/media/properties';
|
|
5
|
-
import testUtils from '../../../utils/testUtils';
|
|
6
6
|
import {Defer} from '@webex/common';
|
|
7
7
|
import MediaConnectionAwaiter from '../../../../src/media/MediaConnectionAwaiter';
|
|
8
8
|
|
|
@@ -5,6 +5,8 @@ import 'jsdom-global/register';
|
|
|
5
5
|
import {cloneDeep, forEach, isEqual, isUndefined} from 'lodash';
|
|
6
6
|
import sinon from 'sinon';
|
|
7
7
|
import * as InternalMediaCoreModule from '@webex/internal-media-core';
|
|
8
|
+
import * as RtcMetricsModule from '@webex/plugin-meetings/src/rtcMetrics';
|
|
9
|
+
import * as RemoteMediaManagerModule from '@webex/plugin-meetings/src/multistream/remoteMediaManager';
|
|
8
10
|
import StateMachine from 'javascript-state-machine';
|
|
9
11
|
import uuid from 'uuid';
|
|
10
12
|
import {assert, expect} from '@webex/test-helper-chai';
|
|
@@ -329,6 +331,7 @@ describe('plugin-meetings', () => {
|
|
|
329
331
|
assert.isNull(meeting.partner);
|
|
330
332
|
assert.isNull(meeting.type);
|
|
331
333
|
assert.isNull(meeting.owner);
|
|
334
|
+
assert.isUndefined(meeting.isoLocalClientMeetingJoinTime);
|
|
332
335
|
assert.isNull(meeting.hostId);
|
|
333
336
|
assert.isNull(meeting.policy);
|
|
334
337
|
assert.instanceOf(meeting.meetingRequest, MeetingRequest);
|
|
@@ -1585,6 +1588,10 @@ describe('plugin-meetings', () => {
|
|
|
1585
1588
|
sandbox.stub(MeetingUtil, 'joinMeeting').returns(Promise.resolve(joinMeetingResult));
|
|
1586
1589
|
});
|
|
1587
1590
|
|
|
1591
|
+
afterEach(() => {
|
|
1592
|
+
assert.exists(meeting.isoLocalClientMeetingJoinTime);
|
|
1593
|
+
});
|
|
1594
|
+
|
|
1588
1595
|
it('should join the meeting and return promise', async () => {
|
|
1589
1596
|
const join = meeting.join({pstnAudioType: 'dial-in'});
|
|
1590
1597
|
meeting.config.enableAutomaticLLM = true;
|
|
@@ -1603,6 +1610,7 @@ describe('plugin-meetings', () => {
|
|
|
1603
1610
|
const result = await join;
|
|
1604
1611
|
|
|
1605
1612
|
assert.calledOnce(MeetingUtil.joinMeeting);
|
|
1613
|
+
assert.calledOnce(webex.internal.device.meetingStarted);
|
|
1606
1614
|
assert.calledOnce(meeting.setLocus);
|
|
1607
1615
|
assert.equal(result, joinMeetingResult);
|
|
1608
1616
|
assert.calledWith(webex.internal.llm.on, 'online', meeting.handleLLMOnline);
|
|
@@ -2405,9 +2413,7 @@ describe('plugin-meetings', () => {
|
|
|
2405
2413
|
Media.createMediaConnection,
|
|
2406
2414
|
false,
|
|
2407
2415
|
meeting.getMediaConnectionDebugId(),
|
|
2408
|
-
webex,
|
|
2409
2416
|
meeting.id,
|
|
2410
|
-
meeting.correlationId,
|
|
2411
2417
|
sinon.match({turnServerInfo: undefined})
|
|
2412
2418
|
);
|
|
2413
2419
|
assert.calledOnce(meeting.setMercuryListener);
|
|
@@ -2449,6 +2455,44 @@ describe('plugin-meetings', () => {
|
|
|
2449
2455
|
checkWorking({allowMediaInLobby: true});
|
|
2450
2456
|
});
|
|
2451
2457
|
|
|
2458
|
+
it('should create rtcMetrics and pass them to Media.createMediaConnection()', async () => {
|
|
2459
|
+
const fakeRtcMetrics = {id: 'fake rtc metrics object'};
|
|
2460
|
+
const rtcMetricsCtor = sinon.stub(RtcMetricsModule, 'default').returns(fakeRtcMetrics);
|
|
2461
|
+
|
|
2462
|
+
// setup the minimum mocks required for multistream connection
|
|
2463
|
+
fakeMediaConnection.createSendSlot = sinon.stub().returns({
|
|
2464
|
+
publishStream: sinon.stub(),
|
|
2465
|
+
unpublishStream: sinon.stub(),
|
|
2466
|
+
setNamedMediaGroups: sinon.stub(),
|
|
2467
|
+
});
|
|
2468
|
+
sinon.stub(RemoteMediaManagerModule, 'RemoteMediaManager').returns({
|
|
2469
|
+
start: sinon.stub().resolves(),
|
|
2470
|
+
on: sinon.stub(),
|
|
2471
|
+
logAllReceiveSlots: sinon.stub(),
|
|
2472
|
+
});
|
|
2473
|
+
|
|
2474
|
+
meeting.meetingState = 'ACTIVE';
|
|
2475
|
+
meeting.isMultistream = true;
|
|
2476
|
+
|
|
2477
|
+
await meeting.addMedia({
|
|
2478
|
+
mediaSettings: {},
|
|
2479
|
+
});
|
|
2480
|
+
|
|
2481
|
+
assert.calledOnceWithExactly(rtcMetricsCtor, webex, meeting.id, meeting.correlationId);
|
|
2482
|
+
|
|
2483
|
+
// check that rtcMetrics was passed to Media.createMediaConnection
|
|
2484
|
+
assert.calledOnce(Media.createMediaConnection);
|
|
2485
|
+
assert.calledWith(
|
|
2486
|
+
Media.createMediaConnection,
|
|
2487
|
+
true,
|
|
2488
|
+
meeting.getMediaConnectionDebugId(),
|
|
2489
|
+
meeting.id,
|
|
2490
|
+
sinon.match({
|
|
2491
|
+
rtcMetrics: fakeRtcMetrics,
|
|
2492
|
+
})
|
|
2493
|
+
);
|
|
2494
|
+
});
|
|
2495
|
+
|
|
2452
2496
|
it('should pass the turn server info to the peer connection', async () => {
|
|
2453
2497
|
const FAKE_TURN_URL = 'turns:webex.com:3478';
|
|
2454
2498
|
const FAKE_TURN_USER = 'some-turn-username';
|
|
@@ -2478,9 +2522,7 @@ describe('plugin-meetings', () => {
|
|
|
2478
2522
|
Media.createMediaConnection,
|
|
2479
2523
|
false,
|
|
2480
2524
|
meeting.getMediaConnectionDebugId(),
|
|
2481
|
-
webex,
|
|
2482
2525
|
meeting.id,
|
|
2483
|
-
meeting.correlationId,
|
|
2484
2526
|
sinon.match({
|
|
2485
2527
|
turnServerInfo: {
|
|
2486
2528
|
url: FAKE_TURN_URL,
|
|
@@ -3023,6 +3065,8 @@ describe('plugin-meetings', () => {
|
|
|
3023
3065
|
}),
|
|
3024
3066
|
};
|
|
3025
3067
|
meeting.iceCandidatesCount = 3;
|
|
3068
|
+
meeting.iceCandidateErrors.set('701_error', 3);
|
|
3069
|
+
meeting.iceCandidateErrors.set('701_turn_host_lookup_received_error', 1);
|
|
3026
3070
|
|
|
3027
3071
|
await meeting.addMedia({
|
|
3028
3072
|
mediaSettings: {},
|
|
@@ -3044,6 +3088,8 @@ describe('plugin-meetings', () => {
|
|
|
3044
3088
|
someReachabilityMetric1: 'some value1',
|
|
3045
3089
|
someReachabilityMetric2: 'some value2',
|
|
3046
3090
|
iceCandidatesCount: 3,
|
|
3091
|
+
'701_error': 3,
|
|
3092
|
+
'701_turn_host_lookup_received_error': 1,
|
|
3047
3093
|
}
|
|
3048
3094
|
);
|
|
3049
3095
|
|
|
@@ -3397,9 +3443,7 @@ describe('plugin-meetings', () => {
|
|
|
3397
3443
|
Media.createMediaConnection,
|
|
3398
3444
|
false,
|
|
3399
3445
|
meeting.getMediaConnectionDebugId(),
|
|
3400
|
-
webex,
|
|
3401
3446
|
meeting.id,
|
|
3402
|
-
meeting.correlationId,
|
|
3403
3447
|
sinon.match({
|
|
3404
3448
|
turnServerInfo: {
|
|
3405
3449
|
url: FAKE_TURN_URL,
|
|
@@ -4240,6 +4284,20 @@ describe('plugin-meetings', () => {
|
|
|
4240
4284
|
assert.calledTwice(locusMediaRequestStub);
|
|
4241
4285
|
});
|
|
4242
4286
|
|
|
4287
|
+
it('addMedia() works correctly when media is disabled with no streams to publish', async () => {
|
|
4288
|
+
const handleDeviceLoggingSpy = sinon.spy(Meeting, 'handleDeviceLogging');
|
|
4289
|
+
await meeting.addMedia({audioEnabled: false});
|
|
4290
|
+
//calling handleDeviceLogging with audioEnaled as true adn videoEnabled as false
|
|
4291
|
+
assert.calledWith(handleDeviceLoggingSpy,false,true);
|
|
4292
|
+
});
|
|
4293
|
+
|
|
4294
|
+
it('addMedia() works correctly when video is disabled with no streams to publish', async () => {
|
|
4295
|
+
const handleDeviceLoggingSpy = sinon.spy(Meeting, 'handleDeviceLogging');
|
|
4296
|
+
await meeting.addMedia({videoEnabled: false});
|
|
4297
|
+
//calling handleDeviceLogging audioEnabled as true videoEnabled as false
|
|
4298
|
+
assert.calledWith(handleDeviceLoggingSpy,true,false);
|
|
4299
|
+
});
|
|
4300
|
+
|
|
4243
4301
|
it('addMedia() works correctly when video is disabled with no streams to publish', async () => {
|
|
4244
4302
|
await meeting.addMedia({videoEnabled: false});
|
|
4245
4303
|
await simulateRoapOffer();
|
|
@@ -4306,6 +4364,14 @@ describe('plugin-meetings', () => {
|
|
|
4306
4364
|
assert.calledTwice(locusMediaRequestStub);
|
|
4307
4365
|
});
|
|
4308
4366
|
|
|
4367
|
+
|
|
4368
|
+
it('addMedia() works correctly when both shareAudio and shareVideo is disabled with no streams publish', async () => {
|
|
4369
|
+
const handleDeviceLoggingSpy = sinon.spy(Meeting, 'handleDeviceLogging');
|
|
4370
|
+
await meeting.addMedia({shareAudioEnabled: false, shareVideoEnabled: false});
|
|
4371
|
+
//calling handleDeviceLogging with audioEnabled true and videoEnabled as true
|
|
4372
|
+
assert.calledWith(handleDeviceLoggingSpy,true,true);
|
|
4373
|
+
});
|
|
4374
|
+
|
|
4309
4375
|
describe('publishStreams()/unpublishStreams() calls', () => {
|
|
4310
4376
|
[
|
|
4311
4377
|
{mediaEnabled: true, expected: {direction: 'sendrecv', localMuteSentValue: false}},
|
|
@@ -8450,6 +8516,9 @@ describe('plugin-meetings', () => {
|
|
|
8450
8516
|
it('listens to the self admitted guest event', (done) => {
|
|
8451
8517
|
meeting.stopKeepAlive = sinon.stub();
|
|
8452
8518
|
meeting.updateLLMConnection = sinon.stub();
|
|
8519
|
+
meeting.rtcMetrics = {
|
|
8520
|
+
sendNextMetrics: sinon.stub(),
|
|
8521
|
+
};
|
|
8453
8522
|
meeting.locusInfo.emit({function: 'test', file: 'test'}, 'SELF_ADMITTED_GUEST', test1);
|
|
8454
8523
|
assert.calledOnceWithExactly(meeting.stopKeepAlive);
|
|
8455
8524
|
assert.calledThrice(TriggerProxy.trigger);
|
|
@@ -8461,6 +8530,8 @@ describe('plugin-meetings', () => {
|
|
|
8461
8530
|
{payload: test1}
|
|
8462
8531
|
);
|
|
8463
8532
|
assert.calledOnce(meeting.updateLLMConnection);
|
|
8533
|
+
assert.calledOnceWithExactly(meeting.rtcMetrics.sendNextMetrics);
|
|
8534
|
+
|
|
8464
8535
|
done();
|
|
8465
8536
|
});
|
|
8466
8537
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import 'jsdom-global/register';
|
|
1
2
|
import sinon from 'sinon';
|
|
2
3
|
import {assert} from '@webex/test-helper-chai';
|
|
3
|
-
import { cloneDeep
|
|
4
|
+
import { cloneDeep } from 'lodash';
|
|
4
5
|
|
|
5
6
|
import MockWebex from '@webex/test-helper-mock-webex';
|
|
6
7
|
import Meetings from '@webex/plugin-meetings';
|
|
@@ -495,4 +496,4 @@ describe('LocusMediaRequest.send()', () => {
|
|
|
495
496
|
});
|
|
496
497
|
|
|
497
498
|
});
|
|
498
|
-
})
|
|
499
|
+
})
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import 'jsdom-global/register';
|
|
1
2
|
import sinon from 'sinon';
|
|
2
3
|
import {assert} from '@webex/test-helper-chai';
|
|
3
4
|
import Meetings from '@webex/plugin-meetings';
|
|
@@ -71,6 +72,7 @@ describe('plugin-meetings', () => {
|
|
|
71
72
|
assert.calledOnce(meeting.updateLLMConnection);
|
|
72
73
|
assert.calledOnce(meeting.breakouts.cleanUp);
|
|
73
74
|
assert.calledOnce(meeting.simultaneousInterpretation.cleanUp);
|
|
75
|
+
assert.calledOnce(webex.internal.device.meetingEnded);
|
|
74
76
|
});
|
|
75
77
|
|
|
76
78
|
it('do clean up on meeting object with LLM disabled', async () => {
|
|
@@ -87,6 +89,7 @@ describe('plugin-meetings', () => {
|
|
|
87
89
|
assert.notCalled(meeting.updateLLMConnection);
|
|
88
90
|
assert.calledOnce(meeting.breakouts.cleanUp);
|
|
89
91
|
assert.calledOnce(meeting.simultaneousInterpretation.cleanUp);
|
|
92
|
+
assert.calledOnce(webex.internal.device.meetingEnded);
|
|
90
93
|
});
|
|
91
94
|
|
|
92
95
|
it('do clean up on meeting object with no config', async () => {
|
|
@@ -102,6 +105,7 @@ describe('plugin-meetings', () => {
|
|
|
102
105
|
assert.notCalled(meeting.updateLLMConnection);
|
|
103
106
|
assert.calledOnce(meeting.breakouts.cleanUp);
|
|
104
107
|
assert.calledOnce(meeting.simultaneousInterpretation.cleanUp);
|
|
108
|
+
assert.calledOnce(webex.internal.device.meetingEnded);
|
|
105
109
|
});
|
|
106
110
|
});
|
|
107
111
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/*!
|
|
2
2
|
* Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
|
|
3
3
|
*/
|
|
4
|
-
|
|
4
|
+
import 'jsdom-global/register';
|
|
5
5
|
import {assert} from '@webex/test-helper-chai';
|
|
6
6
|
import sinon from 'sinon';
|
|
7
7
|
import MockWebex from '@webex/test-helper-mock-webex';
|
|
@@ -23,7 +23,6 @@ import MeetingInfoUtil from '@webex/plugin-meetings/src/meeting-info/utilv2';
|
|
|
23
23
|
import Metrics from '@webex/plugin-meetings/src/metrics';
|
|
24
24
|
import BEHAVIORAL_METRICS from '@webex/plugin-meetings/src/metrics/constants';
|
|
25
25
|
import {forEach} from 'lodash';
|
|
26
|
-
import { request } from 'express';
|
|
27
26
|
|
|
28
27
|
describe('plugin-meetings', () => {
|
|
29
28
|
const conversation = {
|
|
@@ -433,7 +432,7 @@ describe('plugin-meetings', () => {
|
|
|
433
432
|
assert.deepEqual(submitInternalEventCalls[1].args[0], {
|
|
434
433
|
name: 'internal.client.meetinginfo.response',
|
|
435
434
|
});
|
|
436
|
-
|
|
435
|
+
|
|
437
436
|
assert.deepEqual(submitClientEventCalls[1].args[0], {
|
|
438
437
|
name: 'client.meetinginfo.response',
|
|
439
438
|
payload: {
|
|
@@ -484,9 +483,9 @@ describe('plugin-meetings', () => {
|
|
|
484
483
|
requestResponse.body.confIdStr = confIdStr;
|
|
485
484
|
}
|
|
486
485
|
const extraParams = {mtid: 'm9fe0afd8c435e892afcce9ea25b97046', joinTXId: 'TSmrX61wNF'}
|
|
487
|
-
|
|
486
|
+
|
|
488
487
|
webex.request.resolves(requestResponse);
|
|
489
|
-
|
|
488
|
+
|
|
490
489
|
const result = await meetingInfo.fetchMeetingInfo(
|
|
491
490
|
'1234323',
|
|
492
491
|
DESTINATION_TYPE.MEETING_ID,
|
|
@@ -497,7 +496,7 @@ describe('plugin-meetings', () => {
|
|
|
497
496
|
extraParams,
|
|
498
497
|
{meetingId, sendCAevents}
|
|
499
498
|
);
|
|
500
|
-
|
|
499
|
+
|
|
501
500
|
assert.calledWith(webex.request, {
|
|
502
501
|
method: 'POST',
|
|
503
502
|
service: WBXAPPAPI_SERVICE,
|
|
@@ -515,7 +514,7 @@ describe('plugin-meetings', () => {
|
|
|
515
514
|
Metrics.sendBehavioralMetric,
|
|
516
515
|
BEHAVIORAL_METRICS.FETCH_MEETING_INFO_V1_SUCCESS
|
|
517
516
|
);
|
|
518
|
-
|
|
517
|
+
|
|
519
518
|
const submitInternalEventCalls = webex.internal.newMetrics.submitInternalEvent.getCalls();
|
|
520
519
|
const submitClientEventCalls = webex.internal.newMetrics.submitClientEvent.getCalls();
|
|
521
520
|
|
|
@@ -529,7 +528,7 @@ describe('plugin-meetings', () => {
|
|
|
529
528
|
meetingId,
|
|
530
529
|
}
|
|
531
530
|
});
|
|
532
|
-
|
|
531
|
+
|
|
533
532
|
assert.deepEqual(submitInternalEventCalls[1].args[0], {
|
|
534
533
|
name: 'internal.client.meetinginfo.response',
|
|
535
534
|
});
|
|
@@ -591,7 +590,7 @@ describe('plugin-meetings', () => {
|
|
|
591
590
|
|
|
592
591
|
const submitInternalEventCalls = webex.internal.newMetrics.submitInternalEvent.getCalls();
|
|
593
592
|
const submitClientEventCalls = webex.internal.newMetrics.submitClientEvent.getCalls();
|
|
594
|
-
|
|
593
|
+
|
|
595
594
|
assert.deepEqual(submitInternalEventCalls[0].args[0], {
|
|
596
595
|
name: 'internal.client.meetinginfo.request',
|
|
597
596
|
});
|
|
@@ -601,7 +600,7 @@ describe('plugin-meetings', () => {
|
|
|
601
600
|
meetingId: 'meetingId',
|
|
602
601
|
}
|
|
603
602
|
});
|
|
604
|
-
|
|
603
|
+
|
|
605
604
|
assert.deepEqual(submitInternalEventCalls[1].args[0], {
|
|
606
605
|
name: 'internal.client.meetinginfo.response',
|
|
607
606
|
});
|
|
@@ -629,7 +628,7 @@ describe('plugin-meetings', () => {
|
|
|
629
628
|
it(`should not send CA metric if meetingId is not provided disregarding if sendCAevents is ${sendCAevents}`, async () => {
|
|
630
629
|
const message = 'a message';
|
|
631
630
|
const meetingInfoData = 'meeting info';
|
|
632
|
-
|
|
631
|
+
|
|
633
632
|
webex.request = sinon.stub().rejects({
|
|
634
633
|
statusCode: 403,
|
|
635
634
|
body: {message, code: 403102, data: {meetingInfo: meetingInfoData}},
|