@webex/plugin-meetings 3.9.0-next.19 → 3.9.0-next.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/breakouts/breakout.js +1 -1
- package/dist/breakouts/index.js +1 -1
- package/dist/constants.js +1 -0
- package/dist/constants.js.map +1 -1
- package/dist/interpretation/index.js +1 -1
- package/dist/interpretation/siLanguage.js +1 -1
- package/dist/media/properties.js +53 -5
- package/dist/media/properties.js.map +1 -1
- package/dist/meeting/index.js +109 -73
- package/dist/meeting/index.js.map +1 -1
- package/dist/metrics/constants.js +2 -1
- package/dist/metrics/constants.js.map +1 -1
- package/dist/types/constants.d.ts +1 -0
- package/dist/types/media/properties.d.ts +21 -0
- package/dist/types/meeting/index.d.ts +2 -1
- package/dist/types/metrics/constants.d.ts +1 -0
- package/dist/webinar/index.js +1 -1
- package/package.json +3 -3
- package/src/constants.ts +1 -0
- package/src/media/properties.ts +43 -0
- package/src/meeting/index.ts +47 -0
- package/src/metrics/constants.ts +1 -0
- package/test/unit/spec/media/properties.ts +137 -0
- package/test/unit/spec/meeting/index.js +175 -4
@@ -39,6 +39,7 @@ import {
|
|
39
39
|
ConnectionState,
|
40
40
|
MediaConnectionEventNames,
|
41
41
|
StatsAnalyzerEventNames,
|
42
|
+
StatsMonitorEventNames,
|
42
43
|
Errors,
|
43
44
|
ErrorType,
|
44
45
|
RemoteTrackType,
|
@@ -2288,13 +2289,24 @@ describe('plugin-meetings', () => {
|
|
2288
2289
|
close: sinon.stub(),
|
2289
2290
|
forceRtcMetricsSend,
|
2290
2291
|
});
|
2291
|
-
|
2292
|
+
|
2293
|
+
const mockStatsMonitor = {removeAllListeners: sinon.stub()};
|
2294
|
+
const mockNetworkQualityMonitor = {removeAllListeners: sinon.stub()};
|
2295
|
+
|
2296
|
+
// set a statsAnalyzer and statsMonitor on the meeting so that we can check that they get reset to null
|
2292
2297
|
meeting.statsAnalyzer = {stopAnalyzer: sinon.stub().resolves()};
|
2298
|
+
meeting.statsMonitor = mockStatsMonitor;
|
2299
|
+
meeting.networkQualityMonitor = mockNetworkQualityMonitor;
|
2293
2300
|
const error = await assert.isRejected(meeting.addMedia());
|
2294
2301
|
|
2295
2302
|
assert.calledOnce(forceRtcMetricsSend);
|
2303
|
+
assert.calledOnce(mockStatsMonitor.removeAllListeners);
|
2304
|
+
assert.calledOnce(mockNetworkQualityMonitor.removeAllListeners);
|
2296
2305
|
|
2297
2306
|
assert.isNull(meeting.statsAnalyzer);
|
2307
|
+
assert.isNull(meeting.statsMonitor);
|
2308
|
+
assert.isNull(meeting.networkQualityMonitor);
|
2309
|
+
|
2298
2310
|
assert(webex.internal.newMetrics.submitInternalEvent.calledTwice);
|
2299
2311
|
assert.calledWith(webex.internal.newMetrics.submitInternalEvent.firstCall, {
|
2300
2312
|
name: 'internal.client.add-media.turn-discovery.start',
|
@@ -2406,12 +2418,23 @@ describe('plugin-meetings', () => {
|
|
2406
2418
|
|
2407
2419
|
meeting.waitForRemoteSDPAnswer = sinon.stub().rejects();
|
2408
2420
|
|
2409
|
-
|
2421
|
+
const mockStatsMonitor = {removeAllListeners: sinon.stub()};
|
2422
|
+
const mockNetworkQualityMonitor = {removeAllListeners: sinon.stub()};
|
2423
|
+
|
2424
|
+
// set a statsAnalyzer and statsMonitor on the meeting so that we can check that they get reset to null
|
2410
2425
|
meeting.statsAnalyzer = {stopAnalyzer: sinon.stub().resolves()};
|
2426
|
+
meeting.statsMonitor = mockStatsMonitor;
|
2427
|
+
meeting.networkQualityMonitor = mockNetworkQualityMonitor;
|
2411
2428
|
|
2412
2429
|
const error = await assert.isRejected(meeting.addMedia());
|
2413
2430
|
|
2414
2431
|
assert.isNull(meeting.statsAnalyzer);
|
2432
|
+
assert.isNull(meeting.statsMonitor);
|
2433
|
+
assert.isNull(meeting.networkQualityMonitor);
|
2434
|
+
|
2435
|
+
assert.calledOnce(mockStatsMonitor.removeAllListeners);
|
2436
|
+
assert.calledOnce(mockNetworkQualityMonitor.removeAllListeners);
|
2437
|
+
|
2415
2438
|
assert(webex.internal.newMetrics.submitInternalEvent.calledTwice);
|
2416
2439
|
assert.calledWith(webex.internal.newMetrics.submitInternalEvent.firstCall, {
|
2417
2440
|
name: 'internal.client.add-media.turn-discovery.start',
|
@@ -2476,8 +2499,9 @@ describe('plugin-meetings', () => {
|
|
2476
2499
|
},
|
2477
2500
|
},
|
2478
2501
|
});
|
2479
|
-
// set a statsAnalyzer on the meeting so that we can check that
|
2502
|
+
// set a statsAnalyzer and statsMonitor on the meeting so that we can check that they get reset to null
|
2480
2503
|
meeting.statsAnalyzer = {stopAnalyzer: sinon.stub().resolves()};
|
2504
|
+
meeting.statsMonitor = {removeAllListeners: sinon.stub()};
|
2481
2505
|
const error = await assert.isRejected(meeting.addMedia());
|
2482
2506
|
|
2483
2507
|
assert(webex.internal.newMetrics.submitInternalEvent.calledTwice);
|
@@ -2521,6 +2545,7 @@ describe('plugin-meetings', () => {
|
|
2521
2545
|
);
|
2522
2546
|
|
2523
2547
|
assert.isNull(meeting.statsAnalyzer);
|
2548
|
+
assert.isNull(meeting.statsMonitor);
|
2524
2549
|
});
|
2525
2550
|
|
2526
2551
|
it('should include the peer connection properties correctly for transcoded', async () => {
|
@@ -2537,8 +2562,14 @@ describe('plugin-meetings', () => {
|
|
2537
2562
|
},
|
2538
2563
|
},
|
2539
2564
|
});
|
2540
|
-
|
2565
|
+
|
2566
|
+
const mockStatsMonitor = {removeAllListeners: sinon.stub()};
|
2567
|
+
const mockNetworkQualityMonitor = {removeAllListeners: sinon.stub()};
|
2568
|
+
|
2569
|
+
// set a statsAnalyzer and statsMonitor on the meeting so that we can check that they get reset to null
|
2541
2570
|
meeting.statsAnalyzer = {stopAnalyzer: sinon.stub().resolves()};
|
2571
|
+
meeting.statsMonitor = mockStatsMonitor;
|
2572
|
+
meeting.networkQualityMonitor = mockNetworkQualityMonitor;
|
2542
2573
|
const error = await assert.isRejected(meeting.addMedia());
|
2543
2574
|
|
2544
2575
|
assert(webex.internal.newMetrics.submitInternalEvent.calledTwice);
|
@@ -2582,6 +2613,10 @@ describe('plugin-meetings', () => {
|
|
2582
2613
|
);
|
2583
2614
|
|
2584
2615
|
assert.isNull(meeting.statsAnalyzer);
|
2616
|
+
assert.isNull(meeting.statsMonitor);
|
2617
|
+
assert.isNull(meeting.networkQualityMonitor);
|
2618
|
+
assert.calledOnce(mockStatsMonitor.removeAllListeners);
|
2619
|
+
assert.calledOnce(mockNetworkQualityMonitor.removeAllListeners);
|
2585
2620
|
});
|
2586
2621
|
|
2587
2622
|
it('should work the second time addMedia is called in case the first time fails', async () => {
|
@@ -4117,6 +4152,132 @@ describe('plugin-meetings', () => {
|
|
4117
4152
|
});
|
4118
4153
|
});
|
4119
4154
|
|
4155
|
+
describe('handles StatsMonitor events', () => {
|
4156
|
+
let statsMonitorStub;
|
4157
|
+
let prevConfigValue;
|
4158
|
+
let listeners;
|
4159
|
+
|
4160
|
+
beforeEach(async () => {
|
4161
|
+
meeting.meetingState = 'ACTIVE';
|
4162
|
+
prevConfigValue = meeting.config.stats.enableStatsAnalyzer;
|
4163
|
+
|
4164
|
+
meeting.config.stats.enableStatsAnalyzer = true;
|
4165
|
+
|
4166
|
+
listeners = {};
|
4167
|
+
|
4168
|
+
statsMonitorStub = {
|
4169
|
+
on: sinon.stub().callsFake((event, callback) => {
|
4170
|
+
listeners[event] = callback;
|
4171
|
+
}),
|
4172
|
+
removeAllListeners: sinon.stub(),
|
4173
|
+
};
|
4174
|
+
|
4175
|
+
sinon.stub(meeting.mediaProperties, 'sendMediaIssueMetric');
|
4176
|
+
|
4177
|
+
// mock the StatsMonitor constructor
|
4178
|
+
sinon.stub(InternalMediaCoreModule, 'StatsMonitor').returns(statsMonitorStub);
|
4179
|
+
|
4180
|
+
await meeting.addMedia({
|
4181
|
+
mediaSettings: {},
|
4182
|
+
});
|
4183
|
+
});
|
4184
|
+
|
4185
|
+
afterEach(() => {
|
4186
|
+
meeting.config.stats.enableStatsAnalyzer = prevConfigValue;
|
4187
|
+
sinon.restore();
|
4188
|
+
});
|
4189
|
+
|
4190
|
+
describe('INBOUND_AUDIO_ISSUE event', () => {
|
4191
|
+
it('should not trigger event when no unmuted members exist', () => {
|
4192
|
+
const fakeEventData = {issueSubType: 'DECODE_RESULTS_IN_ZERO_AUDIO_LEVEL'};
|
4193
|
+
|
4194
|
+
// Setup members that are either self or muted
|
4195
|
+
const mutedMember = {
|
4196
|
+
isSelf: false,
|
4197
|
+
isPairedWithSelf: false,
|
4198
|
+
isAudioMuted: true,
|
4199
|
+
};
|
4200
|
+
const selfMember = {
|
4201
|
+
isSelf: true,
|
4202
|
+
isPairedWithSelf: false,
|
4203
|
+
isAudioMuted: false,
|
4204
|
+
};
|
4205
|
+
const pairedMember = {
|
4206
|
+
isSelf: false,
|
4207
|
+
isPairedWithSelf: true,
|
4208
|
+
isAudioMuted: false,
|
4209
|
+
};
|
4210
|
+
meeting.members.membersCollection.getAll = sinon.stub().returns({
|
4211
|
+
member1: mutedMember,
|
4212
|
+
member2: selfMember,
|
4213
|
+
member3: pairedMember,
|
4214
|
+
});
|
4215
|
+
|
4216
|
+
// Reset the stub to clear any previous calls
|
4217
|
+
TriggerProxy.trigger.resetHistory();
|
4218
|
+
|
4219
|
+
// Emit the event from statsMonitor
|
4220
|
+
listeners[StatsMonitorEventNames.INBOUND_AUDIO_ISSUE](fakeEventData);
|
4221
|
+
|
4222
|
+
assert.neverCalledWith(
|
4223
|
+
TriggerProxy.trigger,
|
4224
|
+
meeting,
|
4225
|
+
sinon.match.object,
|
4226
|
+
EVENT_TRIGGERS.MEDIA_INBOUND_AUDIO_ISSUE_DETECTED,
|
4227
|
+
fakeEventData
|
4228
|
+
);
|
4229
|
+
assert.notCalled(meeting.mediaProperties.sendMediaIssueMetric);
|
4230
|
+
});
|
4231
|
+
|
4232
|
+
it('should trigger event and metric when there are multiple members and at least one is unmuted', () => {
|
4233
|
+
const fakeEventData = {issueSubType: 'DECODE_RESULTS_IN_ZERO_AUDIO_LEVEL'};
|
4234
|
+
|
4235
|
+
// Setup mixed members - some muted, one unmuted
|
4236
|
+
const mutedMember = {
|
4237
|
+
isSelf: false,
|
4238
|
+
isPairedWithSelf: false,
|
4239
|
+
isAudioMuted: true,
|
4240
|
+
};
|
4241
|
+
const unmutedMember = {
|
4242
|
+
isSelf: false,
|
4243
|
+
isPairedWithSelf: false,
|
4244
|
+
isAudioMuted: false,
|
4245
|
+
};
|
4246
|
+
const selfMember = {
|
4247
|
+
isSelf: true,
|
4248
|
+
isPairedWithSelf: false,
|
4249
|
+
isAudioMuted: false,
|
4250
|
+
};
|
4251
|
+
meeting.members.membersCollection.getAll = sinon.stub().returns({
|
4252
|
+
member1: mutedMember,
|
4253
|
+
member2: unmutedMember,
|
4254
|
+
member3: selfMember,
|
4255
|
+
});
|
4256
|
+
|
4257
|
+
// Reset the stub to clear any previous calls
|
4258
|
+
TriggerProxy.trigger.resetHistory();
|
4259
|
+
|
4260
|
+
// Emit the event from statsMonitor
|
4261
|
+
listeners[StatsMonitorEventNames.INBOUND_AUDIO_ISSUE](fakeEventData);
|
4262
|
+
|
4263
|
+
assert.calledWith(
|
4264
|
+
TriggerProxy.trigger,
|
4265
|
+
meeting,
|
4266
|
+
sinon.match.object,
|
4267
|
+
EVENT_TRIGGERS.MEDIA_INBOUND_AUDIO_ISSUE_DETECTED,
|
4268
|
+
fakeEventData
|
4269
|
+
);
|
4270
|
+
|
4271
|
+
assert.calledOnceWithExactly(
|
4272
|
+
meeting.mediaProperties.sendMediaIssueMetric,
|
4273
|
+
'inbound_audio',
|
4274
|
+
fakeEventData.issueSubType,
|
4275
|
+
meeting.correlationId
|
4276
|
+
);
|
4277
|
+
});
|
4278
|
+
});
|
4279
|
+
});
|
4280
|
+
|
4120
4281
|
describe('bundlePolicy', () => {
|
4121
4282
|
const FAKE_TURN_URL = 'turns:webex.com:3478';
|
4122
4283
|
const FAKE_TURN_USER = 'some-turn-username';
|
@@ -5583,6 +5744,7 @@ describe('plugin-meetings', () => {
|
|
5583
5744
|
let multistreamEventListeners;
|
5584
5745
|
let transcodedEventListeners;
|
5585
5746
|
let mockStatsAnalyzerCtor;
|
5747
|
+
let statsMonitorStub;
|
5586
5748
|
|
5587
5749
|
const setupFakeRoapMediaConnection = (fakeRoapMediaConnection, eventListeners) => {
|
5588
5750
|
fakeRoapMediaConnection.on.callsFake((eventName, cb) => {
|
@@ -5614,6 +5776,14 @@ describe('plugin-meetings', () => {
|
|
5614
5776
|
return {on: sinon.stub(), stopAnalyzer: sinon.stub()};
|
5615
5777
|
});
|
5616
5778
|
|
5779
|
+
statsMonitorStub = {
|
5780
|
+
on: sinon.stub(),
|
5781
|
+
removeAllListeners: sinon.stub(),
|
5782
|
+
};
|
5783
|
+
|
5784
|
+
// mock the StatsMonitor constructor
|
5785
|
+
sinon.stub(InternalMediaCoreModule, 'StatsMonitor').returns(statsMonitorStub);
|
5786
|
+
|
5617
5787
|
webex.internal.newMetrics.callDiagnosticMetrics.getErrorPayloadForClientErrorCode =
|
5618
5788
|
sinon.stub();
|
5619
5789
|
|
@@ -5676,6 +5846,7 @@ describe('plugin-meetings', () => {
|
|
5676
5846
|
mockStatsAnalyzerCtor,
|
5677
5847
|
sinon.match({
|
5678
5848
|
isMultistream: true,
|
5849
|
+
statsMonitor: statsMonitorStub,
|
5679
5850
|
})
|
5680
5851
|
);
|
5681
5852
|
const initialStatsAnalyzer = mockStatsAnalyzerCtor.returnValues[0];
|