@webex/plugin-meetings 3.9.0 → 3.10.0-next.2
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 +9 -0
- package/dist/constants.js.map +1 -1
- package/dist/controls-options-manager/index.js +22 -5
- package/dist/controls-options-manager/index.js.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/interceptors/index.js +7 -0
- package/dist/interceptors/index.js.map +1 -1
- package/dist/interceptors/locusRouteToken.js +116 -0
- package/dist/interceptors/locusRouteToken.js.map +1 -0
- package/dist/interpretation/index.js +1 -1
- package/dist/interpretation/siLanguage.js +1 -1
- package/dist/locus-info/controlsUtils.js +11 -2
- package/dist/locus-info/controlsUtils.js.map +1 -1
- package/dist/locus-info/index.js +56 -14
- package/dist/locus-info/index.js.map +1 -1
- package/dist/locus-info/parser.js +4 -1
- package/dist/locus-info/parser.js.map +1 -1
- package/dist/media/index.js +5 -0
- package/dist/media/index.js.map +1 -1
- package/dist/media/properties.js +53 -5
- package/dist/media/properties.js.map +1 -1
- package/dist/meeting/in-meeting-actions.js +8 -0
- package/dist/meeting/in-meeting-actions.js.map +1 -1
- package/dist/meeting/index.js +339 -185
- package/dist/meeting/index.js.map +1 -1
- package/dist/meeting/muteState.js +2 -5
- package/dist/meeting/muteState.js.map +1 -1
- package/dist/meeting/request.js +177 -14
- package/dist/meeting/request.js.map +1 -1
- package/dist/meeting/util.js +39 -11
- package/dist/meeting/util.js.map +1 -1
- package/dist/meeting-info/meeting-info-v2.js +29 -21
- package/dist/meeting-info/meeting-info-v2.js.map +1 -1
- package/dist/meetings/index.js +31 -25
- package/dist/meetings/index.js.map +1 -1
- package/dist/member/index.js +9 -0
- package/dist/member/index.js.map +1 -1
- package/dist/member/types.js.map +1 -1
- package/dist/member/util.js +10 -0
- package/dist/member/util.js.map +1 -1
- package/dist/members/collection.js +13 -0
- package/dist/members/collection.js.map +1 -1
- package/dist/members/index.js +42 -20
- package/dist/members/index.js.map +1 -1
- package/dist/members/util.js +7 -2
- package/dist/members/util.js.map +1 -1
- package/dist/metrics/constants.js +2 -1
- package/dist/metrics/constants.js.map +1 -1
- package/dist/reachability/index.js +3 -3
- package/dist/reachability/index.js.map +1 -1
- package/dist/types/constants.d.ts +7 -0
- package/dist/types/controls-options-manager/index.d.ts +9 -1
- package/dist/types/interceptors/index.d.ts +2 -1
- package/dist/types/interceptors/locusRouteToken.d.ts +38 -0
- package/dist/types/locus-info/index.d.ts +56 -2
- package/dist/types/media/properties.d.ts +21 -0
- package/dist/types/meeting/in-meeting-actions.d.ts +8 -0
- package/dist/types/meeting/index.d.ts +41 -1
- package/dist/types/meeting/request.d.ts +42 -0
- package/dist/types/meeting/util.d.ts +13 -3
- package/dist/types/meeting-info/meeting-info-v2.d.ts +6 -3
- package/dist/types/meetings/index.d.ts +3 -1
- package/dist/types/member/index.d.ts +1 -0
- package/dist/types/member/types.d.ts +1 -0
- package/dist/types/member/util.d.ts +5 -0
- package/dist/types/members/collection.d.ts +6 -0
- package/dist/types/members/index.d.ts +12 -2
- package/dist/types/members/util.d.ts +6 -3
- package/dist/types/metrics/constants.d.ts +1 -0
- package/dist/webinar/index.js +1 -1
- package/package.json +24 -24
- package/src/constants.ts +10 -0
- package/src/controls-options-manager/index.ts +26 -5
- package/src/index.ts +2 -1
- package/src/interceptors/index.ts +2 -1
- package/src/interceptors/locusRouteToken.ts +80 -0
- package/src/locus-info/controlsUtils.ts +18 -0
- package/src/locus-info/index.ts +99 -17
- package/src/locus-info/parser.ts +5 -1
- package/src/media/index.ts +6 -0
- package/src/media/properties.ts +43 -0
- package/src/meeting/in-meeting-actions.ts +16 -0
- package/src/meeting/index.ts +205 -24
- package/src/meeting/muteState.ts +2 -6
- package/src/meeting/request.ts +141 -0
- package/src/meeting/util.ts +50 -20
- package/src/meeting-info/meeting-info-v2.ts +24 -5
- package/src/meetings/index.ts +9 -3
- package/src/member/index.ts +10 -0
- package/src/member/types.ts +1 -0
- package/src/member/util.ts +14 -0
- package/src/members/collection.ts +11 -0
- package/src/members/index.ts +38 -5
- package/src/members/util.ts +18 -2
- package/src/metrics/constants.ts +1 -0
- package/src/reachability/index.ts +3 -3
- package/test/unit/spec/common/browser-detection.js +0 -24
- package/test/unit/spec/controls-options-manager/index.js +47 -0
- package/test/unit/spec/fixture/locus.js +1 -0
- package/test/unit/spec/interceptors/locusRouteToken.ts +87 -0
- package/test/unit/spec/locus-info/index.js +91 -15
- package/test/unit/spec/locus-info/parser.js +3 -2
- package/test/unit/spec/media/index.ts +140 -9
- package/test/unit/spec/media/properties.ts +137 -0
- package/test/unit/spec/meeting/in-meeting-actions.ts +8 -0
- package/test/unit/spec/meeting/index.js +398 -30
- package/test/unit/spec/meeting/muteState.js +32 -6
- package/test/unit/spec/meeting/request.js +21 -0
- package/test/unit/spec/meeting/utils.js +48 -16
- package/test/unit/spec/meeting-info/meetinginfov2.js +8 -3
- package/test/unit/spec/meetings/index.js +10 -7
- package/test/unit/spec/member/util.js +24 -0
- package/test/unit/spec/members/collection.js +120 -0
- package/test/unit/spec/members/index.js +72 -3
- package/test/unit/spec/members/request.js +55 -0
- package/test/unit/spec/members/utils.js +116 -14
- package/test/unit/spec/reachability/index.ts +158 -3
- package/test/unit/spec/roap/turnDiscovery.ts +3 -3
|
@@ -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,
|
|
@@ -487,7 +488,7 @@ describe('plugin-meetings', () => {
|
|
|
487
488
|
|
|
488
489
|
it('pstnCorrelationId getter/setter should work correctly', () => {
|
|
489
490
|
const testPstnCorrelationId = uuid.v4();
|
|
490
|
-
|
|
491
|
+
|
|
491
492
|
meeting.pstnCorrelationId = testPstnCorrelationId;
|
|
492
493
|
assert.equal(meeting.pstnCorrelationId, testPstnCorrelationId);
|
|
493
494
|
assert.equal(meeting.callStateForMetrics.pstnCorrelationId, testPstnCorrelationId);
|
|
@@ -1992,10 +1993,10 @@ describe('plugin-meetings', () => {
|
|
|
1992
1993
|
it('should handle join failure', async () => {
|
|
1993
1994
|
MeetingUtil.isPinOrGuest = sinon.stub().returns(false);
|
|
1994
1995
|
webex.internal.newMetrics.submitClientEvent = sinon.stub();
|
|
1995
|
-
|
|
1996
|
+
|
|
1996
1997
|
await meeting.join().catch(() => {
|
|
1997
1998
|
assert.calledOnce(MeetingUtil.joinMeeting);
|
|
1998
|
-
|
|
1999
|
+
|
|
1999
2000
|
// Assert that client.locus.join.response error event is not sent from this function, it is now emitted from MeetingUtil.joinMeeting
|
|
2000
2001
|
assert.calledOnce(webex.internal.newMetrics.submitClientEvent);
|
|
2001
2002
|
assert.calledWithMatch(
|
|
@@ -2216,6 +2217,7 @@ describe('plugin-meetings', () => {
|
|
|
2216
2217
|
});
|
|
2217
2218
|
meeting.audio = muteStateStub;
|
|
2218
2219
|
meeting.video = muteStateStub;
|
|
2220
|
+
sinon.stub(MeetingUtil, 'getIpVersion').returns(IP_VERSION.ipv4_and_ipv6);
|
|
2219
2221
|
sinon.stub(Media, 'createMediaConnection').returns(fakeMediaConnection);
|
|
2220
2222
|
sinon.stub(meeting, 'setupMediaConnectionListeners');
|
|
2221
2223
|
sinon.stub(meeting, 'setMercuryListener');
|
|
@@ -2287,13 +2289,24 @@ describe('plugin-meetings', () => {
|
|
|
2287
2289
|
close: sinon.stub(),
|
|
2288
2290
|
forceRtcMetricsSend,
|
|
2289
2291
|
});
|
|
2290
|
-
|
|
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
|
|
2291
2297
|
meeting.statsAnalyzer = {stopAnalyzer: sinon.stub().resolves()};
|
|
2298
|
+
meeting.statsMonitor = mockStatsMonitor;
|
|
2299
|
+
meeting.networkQualityMonitor = mockNetworkQualityMonitor;
|
|
2292
2300
|
const error = await assert.isRejected(meeting.addMedia());
|
|
2293
2301
|
|
|
2294
2302
|
assert.calledOnce(forceRtcMetricsSend);
|
|
2303
|
+
assert.calledOnce(mockStatsMonitor.removeAllListeners);
|
|
2304
|
+
assert.calledOnce(mockNetworkQualityMonitor.removeAllListeners);
|
|
2295
2305
|
|
|
2296
2306
|
assert.isNull(meeting.statsAnalyzer);
|
|
2307
|
+
assert.isNull(meeting.statsMonitor);
|
|
2308
|
+
assert.isNull(meeting.networkQualityMonitor);
|
|
2309
|
+
|
|
2297
2310
|
assert(webex.internal.newMetrics.submitInternalEvent.calledTwice);
|
|
2298
2311
|
assert.calledWith(webex.internal.newMetrics.submitInternalEvent.firstCall, {
|
|
2299
2312
|
name: 'internal.client.add-media.turn-discovery.start',
|
|
@@ -2337,6 +2350,7 @@ describe('plugin-meetings', () => {
|
|
|
2337
2350
|
selected_subnet: null,
|
|
2338
2351
|
numTransports: 1,
|
|
2339
2352
|
iceCandidatesCount: 0,
|
|
2353
|
+
ipver: 1,
|
|
2340
2354
|
}
|
|
2341
2355
|
);
|
|
2342
2356
|
});
|
|
@@ -2384,6 +2398,7 @@ describe('plugin-meetings', () => {
|
|
|
2384
2398
|
subnet_reachable: null,
|
|
2385
2399
|
selected_cluster: null,
|
|
2386
2400
|
selected_subnet: null,
|
|
2401
|
+
ipver: 1,
|
|
2387
2402
|
})
|
|
2388
2403
|
);
|
|
2389
2404
|
|
|
@@ -2403,12 +2418,23 @@ describe('plugin-meetings', () => {
|
|
|
2403
2418
|
|
|
2404
2419
|
meeting.waitForRemoteSDPAnswer = sinon.stub().rejects();
|
|
2405
2420
|
|
|
2406
|
-
|
|
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
|
|
2407
2425
|
meeting.statsAnalyzer = {stopAnalyzer: sinon.stub().resolves()};
|
|
2426
|
+
meeting.statsMonitor = mockStatsMonitor;
|
|
2427
|
+
meeting.networkQualityMonitor = mockNetworkQualityMonitor;
|
|
2408
2428
|
|
|
2409
2429
|
const error = await assert.isRejected(meeting.addMedia());
|
|
2410
2430
|
|
|
2411
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
|
+
|
|
2412
2438
|
assert(webex.internal.newMetrics.submitInternalEvent.calledTwice);
|
|
2413
2439
|
assert.calledWith(webex.internal.newMetrics.submitInternalEvent.firstCall, {
|
|
2414
2440
|
name: 'internal.client.add-media.turn-discovery.start',
|
|
@@ -2452,6 +2478,7 @@ describe('plugin-meetings', () => {
|
|
|
2452
2478
|
subnet_reachable: null,
|
|
2453
2479
|
selected_cluster: null,
|
|
2454
2480
|
selected_subnet: null,
|
|
2481
|
+
ipver: 1,
|
|
2455
2482
|
}
|
|
2456
2483
|
);
|
|
2457
2484
|
});
|
|
@@ -2472,8 +2499,9 @@ describe('plugin-meetings', () => {
|
|
|
2472
2499
|
},
|
|
2473
2500
|
},
|
|
2474
2501
|
});
|
|
2475
|
-
// 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
|
|
2476
2503
|
meeting.statsAnalyzer = {stopAnalyzer: sinon.stub().resolves()};
|
|
2504
|
+
meeting.statsMonitor = {removeAllListeners: sinon.stub()};
|
|
2477
2505
|
const error = await assert.isRejected(meeting.addMedia());
|
|
2478
2506
|
|
|
2479
2507
|
assert(webex.internal.newMetrics.submitInternalEvent.calledTwice);
|
|
@@ -2512,10 +2540,12 @@ describe('plugin-meetings', () => {
|
|
|
2512
2540
|
subnet_reachable: null,
|
|
2513
2541
|
selected_cluster: null,
|
|
2514
2542
|
selected_subnet: null,
|
|
2543
|
+
ipver: 1,
|
|
2515
2544
|
})
|
|
2516
2545
|
);
|
|
2517
2546
|
|
|
2518
2547
|
assert.isNull(meeting.statsAnalyzer);
|
|
2548
|
+
assert.isNull(meeting.statsMonitor);
|
|
2519
2549
|
});
|
|
2520
2550
|
|
|
2521
2551
|
it('should include the peer connection properties correctly for transcoded', async () => {
|
|
@@ -2532,8 +2562,14 @@ describe('plugin-meetings', () => {
|
|
|
2532
2562
|
},
|
|
2533
2563
|
},
|
|
2534
2564
|
});
|
|
2535
|
-
|
|
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
|
|
2536
2570
|
meeting.statsAnalyzer = {stopAnalyzer: sinon.stub().resolves()};
|
|
2571
|
+
meeting.statsMonitor = mockStatsMonitor;
|
|
2572
|
+
meeting.networkQualityMonitor = mockNetworkQualityMonitor;
|
|
2537
2573
|
const error = await assert.isRejected(meeting.addMedia());
|
|
2538
2574
|
|
|
2539
2575
|
assert(webex.internal.newMetrics.submitInternalEvent.calledTwice);
|
|
@@ -2572,10 +2608,15 @@ describe('plugin-meetings', () => {
|
|
|
2572
2608
|
subnet_reachable: null,
|
|
2573
2609
|
selected_cluster: null,
|
|
2574
2610
|
selected_subnet: null,
|
|
2611
|
+
ipver: 1,
|
|
2575
2612
|
})
|
|
2576
2613
|
);
|
|
2577
2614
|
|
|
2578
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);
|
|
2579
2620
|
});
|
|
2580
2621
|
|
|
2581
2622
|
it('should work the second time addMedia is called in case the first time fails', async () => {
|
|
@@ -3096,6 +3137,7 @@ describe('plugin-meetings', () => {
|
|
|
3096
3137
|
subnet_reachable: null,
|
|
3097
3138
|
selected_cluster: null,
|
|
3098
3139
|
selected_subnet: null,
|
|
3140
|
+
ipver: 1,
|
|
3099
3141
|
},
|
|
3100
3142
|
]);
|
|
3101
3143
|
|
|
@@ -3297,6 +3339,7 @@ describe('plugin-meetings', () => {
|
|
|
3297
3339
|
connectionType: 'udp',
|
|
3298
3340
|
selectedCandidatePairChanges: 2,
|
|
3299
3341
|
ipVersion: 'IPv6',
|
|
3342
|
+
ipver: 1,
|
|
3300
3343
|
numTransports: 1,
|
|
3301
3344
|
isMultistream: false,
|
|
3302
3345
|
retriedWithTurnServer: true,
|
|
@@ -3443,6 +3486,7 @@ describe('plugin-meetings', () => {
|
|
|
3443
3486
|
meeting.iceCandidatesCount = 3;
|
|
3444
3487
|
meeting.iceCandidateErrors.set('701_error', 3);
|
|
3445
3488
|
meeting.iceCandidateErrors.set('701_turn_host_lookup_received_error', 1);
|
|
3489
|
+
MeetingUtil.getIpVersion.returns(IP_VERSION.only_ipv6);
|
|
3446
3490
|
|
|
3447
3491
|
await meeting.addMedia({
|
|
3448
3492
|
mediaSettings: {},
|
|
@@ -3458,6 +3502,7 @@ describe('plugin-meetings', () => {
|
|
|
3458
3502
|
connectionType: 'udp',
|
|
3459
3503
|
selectedCandidatePairChanges: 2,
|
|
3460
3504
|
ipVersion: 'IPv6',
|
|
3505
|
+
ipver: 6,
|
|
3461
3506
|
numTransports: 1,
|
|
3462
3507
|
isMultistream: false,
|
|
3463
3508
|
retriedWithTurnServer: false,
|
|
@@ -3536,6 +3581,7 @@ describe('plugin-meetings', () => {
|
|
|
3536
3581
|
selected_cluster: null,
|
|
3537
3582
|
selected_subnet: null,
|
|
3538
3583
|
iceCandidatesCount: 0,
|
|
3584
|
+
ipver: 1,
|
|
3539
3585
|
}
|
|
3540
3586
|
);
|
|
3541
3587
|
|
|
@@ -3600,6 +3646,7 @@ describe('plugin-meetings', () => {
|
|
|
3600
3646
|
selected_cluster: null,
|
|
3601
3647
|
selected_subnet: null,
|
|
3602
3648
|
iceCandidatesCount: 0,
|
|
3649
|
+
ipver: 1,
|
|
3603
3650
|
}
|
|
3604
3651
|
);
|
|
3605
3652
|
|
|
@@ -3646,6 +3693,7 @@ describe('plugin-meetings', () => {
|
|
|
3646
3693
|
locus_id: meeting.locusUrl.split('/').pop(),
|
|
3647
3694
|
connectionType: 'udp',
|
|
3648
3695
|
ipVersion: 'IPv6',
|
|
3696
|
+
ipver: 1,
|
|
3649
3697
|
selectedCandidatePairChanges: 2,
|
|
3650
3698
|
numTransports: 1,
|
|
3651
3699
|
isMultistream: false,
|
|
@@ -3726,6 +3774,7 @@ describe('plugin-meetings', () => {
|
|
|
3726
3774
|
selected_cluster: 'some.cluster',
|
|
3727
3775
|
selected_subnet: '1.X.X.X',
|
|
3728
3776
|
iceCandidatesCount: 0,
|
|
3777
|
+
ipver: 1,
|
|
3729
3778
|
}
|
|
3730
3779
|
);
|
|
3731
3780
|
|
|
@@ -4031,13 +4080,14 @@ describe('plugin-meetings', () => {
|
|
|
4031
4080
|
});
|
|
4032
4081
|
});
|
|
4033
4082
|
|
|
4034
|
-
it('counts the number of members that are in the meeting for MEDIA_QUALITY event', async () => {
|
|
4083
|
+
it('counts the number of members that are in the meeting or lobby for MEDIA_QUALITY event', async () => {
|
|
4035
4084
|
let fakeMembersCollection = {
|
|
4036
4085
|
members: {
|
|
4037
|
-
member1: {isInMeeting: true},
|
|
4038
|
-
member2: {isInMeeting: true},
|
|
4039
|
-
member3: {isInMeeting: false},
|
|
4040
|
-
|
|
4086
|
+
member1: {isInMeeting: true, isInLobby: false},
|
|
4087
|
+
member2: {isInMeeting: false, isInLobby: true},
|
|
4088
|
+
member3: {isInMeeting: false, isInLobby: false},
|
|
4089
|
+
member4: {isInMeeting: true, isInLobby: false},
|
|
4090
|
+
}
|
|
4041
4091
|
};
|
|
4042
4092
|
sinon.stub(meeting, 'getMembers').returns({membersCollection: fakeMembersCollection});
|
|
4043
4093
|
const fakeData = {intervalMetadata: {}};
|
|
@@ -4055,11 +4105,12 @@ describe('plugin-meetings', () => {
|
|
|
4055
4105
|
},
|
|
4056
4106
|
payload: {
|
|
4057
4107
|
intervals: [
|
|
4058
|
-
sinon.match.has('intervalMetadata', sinon.match.has('meetingUserCount',
|
|
4108
|
+
sinon.match.has('intervalMetadata', sinon.match.has('meetingUserCount', 3)),
|
|
4059
4109
|
],
|
|
4060
4110
|
},
|
|
4061
4111
|
});
|
|
4062
|
-
|
|
4112
|
+
// Move member2 from lobby to neither in meeting nor lobby
|
|
4113
|
+
fakeMembersCollection.members.member2.isInLobby = false;
|
|
4063
4114
|
|
|
4064
4115
|
statsAnalyzerStub.emit(
|
|
4065
4116
|
{file: 'test', function: 'test'},
|
|
@@ -4074,7 +4125,7 @@ describe('plugin-meetings', () => {
|
|
|
4074
4125
|
},
|
|
4075
4126
|
payload: {
|
|
4076
4127
|
intervals: [
|
|
4077
|
-
sinon.match.has('intervalMetadata', sinon.match.has('meetingUserCount',
|
|
4128
|
+
sinon.match.has('intervalMetadata', sinon.match.has('meetingUserCount', 2)),
|
|
4078
4129
|
],
|
|
4079
4130
|
},
|
|
4080
4131
|
});
|
|
@@ -4101,6 +4152,132 @@ describe('plugin-meetings', () => {
|
|
|
4101
4152
|
});
|
|
4102
4153
|
});
|
|
4103
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
|
+
|
|
4104
4281
|
describe('bundlePolicy', () => {
|
|
4105
4282
|
const FAKE_TURN_URL = 'turns:webex.com:3478';
|
|
4106
4283
|
const FAKE_TURN_USER = 'some-turn-username';
|
|
@@ -5567,6 +5744,7 @@ describe('plugin-meetings', () => {
|
|
|
5567
5744
|
let multistreamEventListeners;
|
|
5568
5745
|
let transcodedEventListeners;
|
|
5569
5746
|
let mockStatsAnalyzerCtor;
|
|
5747
|
+
let statsMonitorStub;
|
|
5570
5748
|
|
|
5571
5749
|
const setupFakeRoapMediaConnection = (fakeRoapMediaConnection, eventListeners) => {
|
|
5572
5750
|
fakeRoapMediaConnection.on.callsFake((eventName, cb) => {
|
|
@@ -5598,6 +5776,14 @@ describe('plugin-meetings', () => {
|
|
|
5598
5776
|
return {on: sinon.stub(), stopAnalyzer: sinon.stub()};
|
|
5599
5777
|
});
|
|
5600
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
|
+
|
|
5601
5787
|
webex.internal.newMetrics.callDiagnosticMetrics.getErrorPayloadForClientErrorCode =
|
|
5602
5788
|
sinon.stub();
|
|
5603
5789
|
|
|
@@ -5660,6 +5846,7 @@ describe('plugin-meetings', () => {
|
|
|
5660
5846
|
mockStatsAnalyzerCtor,
|
|
5661
5847
|
sinon.match({
|
|
5662
5848
|
isMultistream: true,
|
|
5849
|
+
statsMonitor: statsMonitorStub,
|
|
5663
5850
|
})
|
|
5664
5851
|
);
|
|
5665
5852
|
const initialStatsAnalyzer = mockStatsAnalyzerCtor.returnValues[0];
|
|
@@ -6548,7 +6735,7 @@ describe('plugin-meetings', () => {
|
|
|
6548
6735
|
clientUrl: meeting.deviceUrl,
|
|
6549
6736
|
});
|
|
6550
6737
|
assert.notCalled(meeting.meetingRequest.dialOut);
|
|
6551
|
-
|
|
6738
|
+
|
|
6552
6739
|
// Verify pstnCorrelationId was set
|
|
6553
6740
|
assert.exists(meeting.pstnCorrelationId);
|
|
6554
6741
|
assert.notEqual(meeting.pstnCorrelationId, meeting.correlationId);
|
|
@@ -6625,7 +6812,7 @@ describe('plugin-meetings', () => {
|
|
|
6625
6812
|
throw new Error('Promise resolved when it should have rejected');
|
|
6626
6813
|
} catch (e) {
|
|
6627
6814
|
assert.equal(e, error);
|
|
6628
|
-
|
|
6815
|
+
|
|
6629
6816
|
// Verify behavioral metric was sent with dial_in_correlation_id
|
|
6630
6817
|
assert.calledWith(Metrics.sendBehavioralMetric, BEHAVIORAL_METRICS.ADD_DIAL_IN_FAILURE, {
|
|
6631
6818
|
correlation_id: meeting.correlationId,
|
|
@@ -6636,7 +6823,7 @@ describe('plugin-meetings', () => {
|
|
|
6636
6823
|
reason: error.error.message,
|
|
6637
6824
|
stack: error.stack,
|
|
6638
6825
|
});
|
|
6639
|
-
|
|
6826
|
+
|
|
6640
6827
|
// Verify pstnCorrelationId was cleared after error
|
|
6641
6828
|
assert.equal(meeting.pstnCorrelationId, undefined);
|
|
6642
6829
|
}
|
|
@@ -6652,7 +6839,7 @@ describe('plugin-meetings', () => {
|
|
|
6652
6839
|
throw new Error('Promise resolved when it should have rejected');
|
|
6653
6840
|
} catch (e) {
|
|
6654
6841
|
assert.equal(e, error);
|
|
6655
|
-
|
|
6842
|
+
|
|
6656
6843
|
// Verify behavioral metric was sent with dial_out_correlation_id
|
|
6657
6844
|
assert.calledWith(Metrics.sendBehavioralMetric, BEHAVIORAL_METRICS.ADD_DIAL_OUT_FAILURE, {
|
|
6658
6845
|
correlation_id: meeting.correlationId,
|
|
@@ -6663,7 +6850,7 @@ describe('plugin-meetings', () => {
|
|
|
6663
6850
|
reason: error.error.message,
|
|
6664
6851
|
stack: error.stack,
|
|
6665
6852
|
});
|
|
6666
|
-
|
|
6853
|
+
|
|
6667
6854
|
// Verify pstnCorrelationId was cleared after error
|
|
6668
6855
|
assert.equal(meeting.pstnCorrelationId, undefined);
|
|
6669
6856
|
}
|
|
@@ -6686,12 +6873,12 @@ describe('plugin-meetings', () => {
|
|
|
6686
6873
|
|
|
6687
6874
|
it('should disconnect phone audio and clear pstnCorrelationId', async () => {
|
|
6688
6875
|
meeting.pstnCorrelationId = 'test-pstn-correlation-id';
|
|
6689
|
-
|
|
6876
|
+
|
|
6690
6877
|
await meeting.disconnectPhoneAudio();
|
|
6691
|
-
|
|
6878
|
+
|
|
6692
6879
|
// Verify that pstnCorrelationId is cleared
|
|
6693
6880
|
assert.equal(meeting.pstnCorrelationId, undefined);
|
|
6694
|
-
|
|
6881
|
+
|
|
6695
6882
|
// Verify that MeetingUtil.disconnectPhoneAudio was called for both dial-in and dial-out
|
|
6696
6883
|
assert.calledTwice(MeetingUtil.disconnectPhoneAudio);
|
|
6697
6884
|
assert.calledWith(MeetingUtil.disconnectPhoneAudio, meeting, meeting.dialInUrl);
|
|
@@ -6702,9 +6889,9 @@ describe('plugin-meetings', () => {
|
|
|
6702
6889
|
meeting.dialInDeviceStatus = 'IDLE';
|
|
6703
6890
|
meeting.dialOutDeviceStatus = 'IDLE';
|
|
6704
6891
|
meeting.pstnCorrelationId = 'test-pstn-correlation-id';
|
|
6705
|
-
|
|
6892
|
+
|
|
6706
6893
|
await meeting.disconnectPhoneAudio();
|
|
6707
|
-
|
|
6894
|
+
|
|
6708
6895
|
// Verify that pstnCorrelationId is still cleared even when no phone connection is active
|
|
6709
6896
|
assert.equal(meeting.pstnCorrelationId, undefined);
|
|
6710
6897
|
// And verify no disconnect was attempted
|
|
@@ -7462,6 +7649,8 @@ describe('plugin-meetings', () => {
|
|
|
7462
7649
|
'locus-id',
|
|
7463
7650
|
{extraParam1: 'value1', permissionToken: FAKE_PERMISSION_TOKEN},
|
|
7464
7651
|
{meetingId: meeting.id, sendCAevents: true},
|
|
7652
|
+
null,
|
|
7653
|
+
null,
|
|
7465
7654
|
null
|
|
7466
7655
|
);
|
|
7467
7656
|
assert.deepEqual(meeting.meetingInfo, {
|
|
@@ -7508,6 +7697,8 @@ describe('plugin-meetings', () => {
|
|
|
7508
7697
|
'locus-id',
|
|
7509
7698
|
{extraParam1: 'value1', permissionToken: FAKE_PERMISSION_TOKEN},
|
|
7510
7699
|
{meetingId: meeting.id, sendCAevents: true},
|
|
7700
|
+
null,
|
|
7701
|
+
null,
|
|
7511
7702
|
null
|
|
7512
7703
|
);
|
|
7513
7704
|
assert.deepEqual(meeting.meetingInfo, {
|
|
@@ -7563,6 +7754,8 @@ describe('plugin-meetings', () => {
|
|
|
7563
7754
|
permissionToken: FAKE_PERMISSION_TOKEN,
|
|
7564
7755
|
},
|
|
7565
7756
|
{meetingId: meeting.id, sendCAevents: true},
|
|
7757
|
+
null,
|
|
7758
|
+
null,
|
|
7566
7759
|
null
|
|
7567
7760
|
);
|
|
7568
7761
|
assert.deepEqual(meeting.meetingInfo, {
|
|
@@ -9004,11 +9197,16 @@ describe('plugin-meetings', () => {
|
|
|
9004
9197
|
meeting.hasMediaConnectionConnectedAtLeastOnce = false;
|
|
9005
9198
|
meeting.setupMediaConnectionListeners();
|
|
9006
9199
|
|
|
9200
|
+
sinon.stub(MeetingUtil, 'getCaEventLabelsForIpVersion').returns(['fake labels']);
|
|
9201
|
+
|
|
9007
9202
|
simulateConnectionStateChange(ConnectionState.Connecting);
|
|
9008
9203
|
|
|
9009
9204
|
assert.calledOnce(webex.internal.newMetrics.submitClientEvent);
|
|
9010
9205
|
assert.calledWithMatch(webex.internal.newMetrics.submitClientEvent, {
|
|
9011
9206
|
name: 'client.ice.start',
|
|
9207
|
+
payload: {
|
|
9208
|
+
labels: ['fake labels'],
|
|
9209
|
+
},
|
|
9012
9210
|
options: {
|
|
9013
9211
|
meetingId: meeting.id,
|
|
9014
9212
|
},
|
|
@@ -10273,6 +10471,24 @@ describe('plugin-meetings', () => {
|
|
|
10273
10471
|
);
|
|
10274
10472
|
});
|
|
10275
10473
|
|
|
10474
|
+
it('listens to CONTROLS_AUTO_END_MEETING_WARNING_CHANGED', async () => {
|
|
10475
|
+
const state = {example: 'value'};
|
|
10476
|
+
|
|
10477
|
+
await meeting.locusInfo.emitScoped(
|
|
10478
|
+
{function: 'test', file: 'test'},
|
|
10479
|
+
LOCUSINFO.EVENTS.CONTROLS_AUTO_END_MEETING_WARNING_CHANGED,
|
|
10480
|
+
{state}
|
|
10481
|
+
);
|
|
10482
|
+
|
|
10483
|
+
assert.calledWith(
|
|
10484
|
+
TriggerProxy.trigger,
|
|
10485
|
+
meeting,
|
|
10486
|
+
{file: 'meeting/index', function: 'setupLocusControlsListener'},
|
|
10487
|
+
EVENT_TRIGGERS.MEETING_CONTROLS_AUTO_END_MEETING_WARNING_UPDATED,
|
|
10488
|
+
{state}
|
|
10489
|
+
);
|
|
10490
|
+
});
|
|
10491
|
+
|
|
10276
10492
|
it('listens to CONTROLS_REMOTE_DESKTOP_CONTROL_CHANGED', async () => {
|
|
10277
10493
|
const state = {example: 'value'};
|
|
10278
10494
|
|
|
@@ -10352,6 +10568,7 @@ describe('plugin-meetings', () => {
|
|
|
10352
10568
|
describe('#setUpLocusUrlListener', () => {
|
|
10353
10569
|
it('listens to the locus url update event', (done) => {
|
|
10354
10570
|
const newLocusUrl = 'newLocusUrl/12345';
|
|
10571
|
+
const payload = {url: newLocusUrl}
|
|
10355
10572
|
|
|
10356
10573
|
meeting.members = {locusUrlUpdate: sinon.stub().returns(Promise.resolve(test1))};
|
|
10357
10574
|
meeting.recordingController = {setLocusUrl: sinon.stub().returns(undefined)};
|
|
@@ -10365,14 +10582,14 @@ describe('plugin-meetings', () => {
|
|
|
10365
10582
|
meeting.locusInfo.emit(
|
|
10366
10583
|
{function: 'test', file: 'test'},
|
|
10367
10584
|
'LOCUS_INFO_UPDATE_URL',
|
|
10368
|
-
|
|
10585
|
+
payload
|
|
10369
10586
|
);
|
|
10370
10587
|
assert.calledWith(meeting.members.locusUrlUpdate, newLocusUrl);
|
|
10371
10588
|
assert.calledOnceWithExactly(meeting.breakouts.locusUrlUpdate, newLocusUrl);
|
|
10372
10589
|
assert.calledOnceWithExactly(meeting.annotation.locusUrlUpdate, newLocusUrl);
|
|
10373
10590
|
assert.calledWith(meeting.members.locusUrlUpdate, newLocusUrl);
|
|
10374
10591
|
assert.calledWith(meeting.recordingController.setLocusUrl, newLocusUrl);
|
|
10375
|
-
assert.calledWith(meeting.controlsOptionsManager.setLocusUrl, newLocusUrl);
|
|
10592
|
+
assert.calledWith(meeting.controlsOptionsManager.setLocusUrl, newLocusUrl, false);
|
|
10376
10593
|
assert.calledWith(meeting.simultaneousInterpretation.locusUrlUpdate, newLocusUrl);
|
|
10377
10594
|
assert.calledWith(meeting.webinar.locusUrlUpdate, newLocusUrl);
|
|
10378
10595
|
assert.equal(meeting.locusUrl, newLocusUrl);
|
|
@@ -10390,6 +10607,22 @@ describe('plugin-meetings', () => {
|
|
|
10390
10607
|
{locusUrl: 'newLocusUrl/12345'}
|
|
10391
10608
|
);
|
|
10392
10609
|
|
|
10610
|
+
done();
|
|
10611
|
+
});
|
|
10612
|
+
it('update mainLocusUrl for controlsOptionManager if payload.isMainLocus as true', (done) => {
|
|
10613
|
+
const newLocusUrl = 'newLocusUrl/12345';
|
|
10614
|
+
const payload = {url: newLocusUrl, isMainLocus: true}
|
|
10615
|
+
|
|
10616
|
+
meeting.controlsOptionsManager = {setLocusUrl: sinon.stub().returns(undefined)};
|
|
10617
|
+
|
|
10618
|
+
meeting.locusInfo.emit(
|
|
10619
|
+
{function: 'test', file: 'test'},
|
|
10620
|
+
'LOCUS_INFO_UPDATE_URL',
|
|
10621
|
+
payload
|
|
10622
|
+
);
|
|
10623
|
+
|
|
10624
|
+
assert.calledWith(meeting.controlsOptionsManager.setLocusUrl, newLocusUrl, true);
|
|
10625
|
+
|
|
10393
10626
|
done();
|
|
10394
10627
|
});
|
|
10395
10628
|
});
|
|
@@ -11227,6 +11460,8 @@ describe('plugin-meetings', () => {
|
|
|
11227
11460
|
let canUserRenameOthersSpy;
|
|
11228
11461
|
let canShareWhiteBoardSpy;
|
|
11229
11462
|
let canMoveToLobbySpy;
|
|
11463
|
+
let isSpokenLanguageAutoDetectionEnabledSpy;
|
|
11464
|
+
let showAutoEndMeetingWarningSpy;
|
|
11230
11465
|
// Due to import tree issues, hasHints must be stubed within the scope of the `it`.
|
|
11231
11466
|
|
|
11232
11467
|
beforeEach(() => {
|
|
@@ -11258,11 +11493,15 @@ describe('plugin-meetings', () => {
|
|
|
11258
11493
|
canUserRenameOthersSpy = sinon.spy(MeetingUtil, 'canUserRenameOthers');
|
|
11259
11494
|
canShareWhiteBoardSpy = sinon.spy(MeetingUtil, 'canShareWhiteBoard');
|
|
11260
11495
|
canMoveToLobbySpy = sinon.spy(MeetingUtil, 'canMoveToLobby');
|
|
11496
|
+
showAutoEndMeetingWarningSpy = sinon.spy(MeetingUtil, 'showAutoEndMeetingWarning');
|
|
11497
|
+
isSpokenLanguageAutoDetectionEnabledSpy = sinon.spy(MeetingUtil, 'isSpokenLanguageAutoDetectionEnabled');
|
|
11498
|
+
|
|
11261
11499
|
});
|
|
11262
11500
|
|
|
11263
11501
|
afterEach(() => {
|
|
11264
11502
|
inMeetingActionsSetSpy.restore();
|
|
11265
11503
|
waitingForOthersToJoinSpy.restore();
|
|
11504
|
+
showAutoEndMeetingWarningSpy.restore();
|
|
11266
11505
|
});
|
|
11267
11506
|
|
|
11268
11507
|
forEach(
|
|
@@ -11810,6 +12049,8 @@ describe('plugin-meetings', () => {
|
|
|
11810
12049
|
assert.calledWith(canUserRenameOthersSpy, userDisplayHints);
|
|
11811
12050
|
assert.calledWith(canShareWhiteBoardSpy, userDisplayHints, selfUserPolicies);
|
|
11812
12051
|
assert.calledWith(canMoveToLobbySpy, userDisplayHints);
|
|
12052
|
+
assert.calledWith(showAutoEndMeetingWarningSpy, userDisplayHints);
|
|
12053
|
+
assert.calledWith(isSpokenLanguageAutoDetectionEnabledSpy, userDisplayHints);
|
|
11813
12054
|
|
|
11814
12055
|
assert.calledWith(ControlsOptionsUtil.hasHints, {
|
|
11815
12056
|
requiredHints: [DISPLAY_HINTS.MUTE_ALL],
|
|
@@ -12262,6 +12503,7 @@ describe('plugin-meetings', () => {
|
|
|
12262
12503
|
meeting.deviceUrl = 'deviceUrl.com';
|
|
12263
12504
|
webex.internal.newMetrics.callDiagnosticLatencies.saveTimestamp = sinon.stub();
|
|
12264
12505
|
webex.internal.newMetrics.callDiagnosticLatencies.getShareDuration = sinon.stub().returns(1000);
|
|
12506
|
+
webex.internal.newMetrics.submitClientEvent = sinon.stub();
|
|
12265
12507
|
});
|
|
12266
12508
|
it('should stop the whiteboard share', async () => {
|
|
12267
12509
|
const whiteboardShare = meeting.stopWhiteboardShare();
|
|
@@ -12363,6 +12605,9 @@ describe('plugin-meetings', () => {
|
|
|
12363
12605
|
meeting.selfId = '9528d952-e4de-46cf-8157-fd4823b98377';
|
|
12364
12606
|
meeting.deviceUrl = 'my-web-url';
|
|
12365
12607
|
meeting.locusInfo.info = {isWebinar: false};
|
|
12608
|
+
webex.internal.newMetrics.callDiagnosticLatencies.saveTimestamp = sinon.stub();
|
|
12609
|
+
webex.internal.newMetrics.callDiagnosticLatencies.getShareDuration = sinon.stub().returns(1500);
|
|
12610
|
+
webex.internal.newMetrics.submitClientEvent = sinon.stub();
|
|
12366
12611
|
});
|
|
12367
12612
|
|
|
12368
12613
|
const USER_IDS = {
|
|
@@ -12594,7 +12839,7 @@ describe('plugin-meetings', () => {
|
|
|
12594
12839
|
eventName: EVENT_TRIGGERS.MEETING_STARTED_SHARING_REMOTE,
|
|
12595
12840
|
functionName: 'remoteShare',
|
|
12596
12841
|
eventPayload: {
|
|
12597
|
-
memberId: null,
|
|
12842
|
+
memberId: meeting.webinar.selfIsAttendee ? beneficiaryId : null,
|
|
12598
12843
|
url,
|
|
12599
12844
|
shareInstanceId,
|
|
12600
12845
|
annotationInfo: undefined,
|
|
@@ -12649,7 +12894,7 @@ describe('plugin-meetings', () => {
|
|
|
12649
12894
|
eventName: EVENT_TRIGGERS.MEETING_STARTED_SHARING_REMOTE,
|
|
12650
12895
|
functionName: 'remoteShare',
|
|
12651
12896
|
eventPayload: {
|
|
12652
|
-
memberId:
|
|
12897
|
+
memberId: beneficiaryId,
|
|
12653
12898
|
url,
|
|
12654
12899
|
shareInstanceId,
|
|
12655
12900
|
annotationInfo: undefined,
|
|
@@ -13508,7 +13753,54 @@ describe('plugin-meetings', () => {
|
|
|
13508
13753
|
payloadTestHelper([data1, data2, data3]);
|
|
13509
13754
|
});
|
|
13510
13755
|
});
|
|
13511
|
-
|
|
13756
|
+
|
|
13757
|
+
it('should send share stopped metric when whiteboard sharing stops', () => {
|
|
13758
|
+
// Start whiteboard sharing (this won't trigger metrics)
|
|
13759
|
+
const data1 = generateData(
|
|
13760
|
+
blankPayload,
|
|
13761
|
+
true, // isGranting: true
|
|
13762
|
+
false, // isContent: false (whiteboard)
|
|
13763
|
+
USER_IDS.ME,
|
|
13764
|
+
RESOURCE_URLS.WHITEBOARD_A
|
|
13765
|
+
);
|
|
13766
|
+
|
|
13767
|
+
// Stop whiteboard sharing (this should trigger metrics)
|
|
13768
|
+
const data2 = generateData(
|
|
13769
|
+
data1.payload,
|
|
13770
|
+
false, // isGranting: false (stopping share)
|
|
13771
|
+
false, // isContent: false (whiteboard)
|
|
13772
|
+
USER_IDS.ME
|
|
13773
|
+
);
|
|
13774
|
+
|
|
13775
|
+
// Trigger the events
|
|
13776
|
+
meeting.locusInfo.emit(
|
|
13777
|
+
{function: 'test', file: 'test'},
|
|
13778
|
+
EVENTS.LOCUS_INFO_UPDATE_MEDIA_SHARES,
|
|
13779
|
+
data1.payload
|
|
13780
|
+
);
|
|
13781
|
+
|
|
13782
|
+
meeting.locusInfo.emit(
|
|
13783
|
+
{function: 'test', file: 'test'},
|
|
13784
|
+
EVENTS.LOCUS_INFO_UPDATE_MEDIA_SHARES,
|
|
13785
|
+
data2.payload
|
|
13786
|
+
);
|
|
13787
|
+
|
|
13788
|
+
// Verify metrics were called when whiteboard sharing stopped
|
|
13789
|
+
assert.calledWith(webex.internal.newMetrics.callDiagnosticLatencies.saveTimestamp, {
|
|
13790
|
+
key: 'internal.client.share.stopped',
|
|
13791
|
+
});
|
|
13792
|
+
|
|
13793
|
+
assert.calledWith(webex.internal.newMetrics.submitClientEvent, {
|
|
13794
|
+
name: 'client.share.stopped',
|
|
13795
|
+
payload: {
|
|
13796
|
+
mediaType: 'whiteboard',
|
|
13797
|
+
shareDuration: 1500, // mocked return value
|
|
13798
|
+
},
|
|
13799
|
+
options: {
|
|
13800
|
+
meetingId: meeting.id,
|
|
13801
|
+
},
|
|
13802
|
+
});
|
|
13803
|
+
});
|
|
13512
13804
|
|
|
13513
13805
|
describe('handleShareVideoStreamMuteStateChange', () => {
|
|
13514
13806
|
it('should emit MEETING_SHARE_VIDEO_MUTE_STATE_CHANGE event with correct fields', () => {
|
|
@@ -13535,6 +13827,7 @@ describe('plugin-meetings', () => {
|
|
|
13535
13827
|
});
|
|
13536
13828
|
});
|
|
13537
13829
|
});
|
|
13830
|
+
});
|
|
13538
13831
|
|
|
13539
13832
|
describe('#startKeepAlive', () => {
|
|
13540
13833
|
let clock;
|
|
@@ -14740,4 +15033,79 @@ describe('plugin-meetings', () => {
|
|
|
14740
15033
|
);
|
|
14741
15034
|
});
|
|
14742
15035
|
});
|
|
15036
|
+
|
|
15037
|
+
describe('#notifyHost', () => {
|
|
15038
|
+
beforeEach(() => {
|
|
15039
|
+
meeting.meetingRequest.notifyHost = sinon.stub().returns(Promise.resolve());
|
|
15040
|
+
});
|
|
15041
|
+
|
|
15042
|
+
it('sends the expected request', async () => {
|
|
15043
|
+
meeting.meetingInfo.siteFullUrl = `convergedats.webex.com`;
|
|
15044
|
+
const meetingUuid = 'meeting-uuid';
|
|
15045
|
+
const displayName = ['Test', 'User'];
|
|
15046
|
+
meeting.locusId = 'locusId';
|
|
15047
|
+
|
|
15048
|
+
const notifyHostPromise = meeting.notifyHost(meetingUuid, displayName);
|
|
15049
|
+
|
|
15050
|
+
assert.exists(notifyHostPromise.then);
|
|
15051
|
+
await notifyHostPromise;
|
|
15052
|
+
|
|
15053
|
+
assert.calledOnceWithExactly(
|
|
15054
|
+
meeting.meetingRequest.notifyHost,
|
|
15055
|
+
meeting.meetingInfo.siteFullUrl,
|
|
15056
|
+
meeting.locusId,
|
|
15057
|
+
meetingUuid,
|
|
15058
|
+
displayName,
|
|
15059
|
+
);
|
|
15060
|
+
});
|
|
15061
|
+
});
|
|
15062
|
+
|
|
15063
|
+
describe('#sipCallOut', () => {
|
|
15064
|
+
beforeEach(() => {
|
|
15065
|
+
meeting.meetingRequest.sipCallOut = sinon.stub().returns(Promise.resolve({body: {}}));
|
|
15066
|
+
});
|
|
15067
|
+
|
|
15068
|
+
it('sends the expected request', async () => {
|
|
15069
|
+
const address = 'sip:user@example.com';
|
|
15070
|
+
const displayName = 'John Doe';
|
|
15071
|
+
const meetingId = 'a643beaa47f04eedac08f1310ca12366';
|
|
15072
|
+
|
|
15073
|
+
meeting.meetingInfo = {
|
|
15074
|
+
meetingId,
|
|
15075
|
+
};
|
|
15076
|
+
|
|
15077
|
+
const sipCallOutPromise = meeting.sipCallOut(address, displayName);
|
|
15078
|
+
|
|
15079
|
+
assert.exists(sipCallOutPromise.then);
|
|
15080
|
+
await sipCallOutPromise;
|
|
15081
|
+
|
|
15082
|
+
assert.calledOnceWithExactly(
|
|
15083
|
+
meeting.meetingRequest.sipCallOut,
|
|
15084
|
+
meetingId,
|
|
15085
|
+
meetingId,
|
|
15086
|
+
address,
|
|
15087
|
+
displayName
|
|
15088
|
+
);
|
|
15089
|
+
});
|
|
15090
|
+
});
|
|
15091
|
+
|
|
15092
|
+
describe('#cancelSipCallOut', () => {
|
|
15093
|
+
beforeEach(() => {
|
|
15094
|
+
meeting.meetingRequest.cancelSipCallOut = sinon.stub().returns(Promise.resolve({body: {}}));
|
|
15095
|
+
});
|
|
15096
|
+
|
|
15097
|
+
it('sends the expected request', async () => {
|
|
15098
|
+
const participantId = '12345-abcde';
|
|
15099
|
+
|
|
15100
|
+
const cancelSipCallOutPromise = meeting.cancelSipCallOut(participantId);
|
|
15101
|
+
|
|
15102
|
+
assert.exists(cancelSipCallOutPromise.then);
|
|
15103
|
+
await cancelSipCallOutPromise;
|
|
15104
|
+
|
|
15105
|
+
assert.calledOnceWithExactly(
|
|
15106
|
+
meeting.meetingRequest.cancelSipCallOut,
|
|
15107
|
+
participantId
|
|
15108
|
+
);
|
|
15109
|
+
});
|
|
15110
|
+
});
|
|
14743
15111
|
});
|