@webex/plugin-meetings 3.8.1 → 3.9.0-multiple-llm.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/README.md +26 -13
- package/dist/breakouts/breakout.js +1 -1
- package/dist/breakouts/index.js +1 -1
- package/dist/constants.js +34 -3
- package/dist/constants.js.map +1 -1
- package/dist/controls-options-manager/enums.js +1 -0
- package/dist/controls-options-manager/enums.js.map +1 -1
- package/dist/controls-options-manager/types.js.map +1 -1
- package/dist/controls-options-manager/util.js +26 -0
- package/dist/controls-options-manager/util.js.map +1 -1
- package/dist/interpretation/index.js +1 -1
- package/dist/interpretation/siLanguage.js +1 -1
- package/dist/locus-info/controlsUtils.js +11 -3
- package/dist/locus-info/controlsUtils.js.map +1 -1
- package/dist/locus-info/index.js +107 -95
- 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 +2 -2
- 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/brbState.js +17 -14
- package/dist/meeting/brbState.js.map +1 -1
- package/dist/meeting/in-meeting-actions.js +13 -1
- package/dist/meeting/in-meeting-actions.js.map +1 -1
- package/dist/meeting/index.js +555 -296
- 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 +44 -0
- package/dist/meeting/request.js.map +1 -1
- package/dist/meeting/request.type.js.map +1 -1
- package/dist/{rtcMetrics/constants.js → meeting/type.js} +1 -5
- package/dist/meeting/type.js.map +1 -0
- package/dist/meeting/util.js +98 -13
- 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 +18 -10
- package/dist/meetings/index.js.map +1 -1
- package/dist/member/types.js.map +1 -1
- package/dist/members/collection.js +13 -0
- package/dist/members/collection.js.map +1 -1
- package/dist/members/index.js +53 -29
- package/dist/members/index.js.map +1 -1
- package/dist/members/request.js +3 -3
- package/dist/members/request.js.map +1 -1
- package/dist/members/util.js +25 -8
- package/dist/members/util.js.map +1 -1
- package/dist/metrics/constants.js +3 -1
- package/dist/metrics/constants.js.map +1 -1
- package/dist/multistream/mediaRequestManager.js +1 -1
- package/dist/multistream/mediaRequestManager.js.map +1 -1
- package/dist/multistream/remoteMedia.js +34 -5
- package/dist/multistream/remoteMedia.js.map +1 -1
- package/dist/multistream/remoteMediaGroup.js +42 -2
- package/dist/multistream/remoteMediaGroup.js.map +1 -1
- package/dist/multistream/sendSlotManager.js +32 -2
- package/dist/multistream/sendSlotManager.js.map +1 -1
- package/dist/reachability/index.js +8 -13
- package/dist/reachability/index.js.map +1 -1
- package/dist/types/constants.d.ts +30 -0
- package/dist/types/controls-options-manager/enums.d.ts +2 -1
- package/dist/types/controls-options-manager/types.d.ts +4 -1
- package/dist/types/locus-info/index.d.ts +54 -10
- package/dist/types/media/properties.d.ts +21 -0
- package/dist/types/meeting/brbState.d.ts +0 -1
- package/dist/types/meeting/in-meeting-actions.d.ts +12 -0
- package/dist/types/meeting/index.d.ts +58 -20
- package/dist/types/meeting/request.d.ts +18 -1
- package/dist/types/meeting/request.type.d.ts +74 -0
- package/dist/types/meeting/type.d.ts +9 -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/types.d.ts +1 -0
- package/dist/types/members/collection.d.ts +6 -0
- package/dist/types/members/index.d.ts +22 -9
- package/dist/types/members/request.d.ts +1 -1
- package/dist/types/members/util.d.ts +13 -6
- package/dist/types/metrics/constants.d.ts +2 -0
- package/dist/types/multistream/remoteMedia.d.ts +20 -1
- package/dist/types/multistream/remoteMediaGroup.d.ts +11 -0
- package/dist/types/multistream/sendSlotManager.d.ts +16 -0
- package/dist/types/reachability/index.d.ts +2 -2
- package/dist/webinar/index.js +1 -1
- package/package.json +25 -26
- package/src/constants.ts +34 -2
- package/src/controls-options-manager/enums.ts +1 -0
- package/src/controls-options-manager/types.ts +6 -1
- package/src/controls-options-manager/util.ts +31 -0
- package/src/locus-info/controlsUtils.ts +15 -0
- package/src/locus-info/index.ts +174 -96
- package/src/locus-info/parser.ts +5 -1
- package/src/media/index.ts +2 -2
- package/src/media/properties.ts +43 -0
- package/src/meeting/brbState.ts +13 -9
- package/src/meeting/in-meeting-actions.ts +25 -0
- package/src/meeting/index.ts +362 -75
- package/src/meeting/muteState.ts +2 -6
- package/src/meeting/request.ts +39 -0
- package/src/meeting/request.type.ts +64 -0
- package/src/meeting/type.ts +9 -0
- package/src/meeting/util.ts +114 -22
- package/src/meeting-info/meeting-info-v2.ts +24 -5
- package/src/meetings/index.ts +12 -5
- package/src/member/types.ts +1 -0
- package/src/members/collection.ts +11 -0
- package/src/members/index.ts +51 -15
- package/src/members/request.ts +2 -2
- package/src/members/util.ts +34 -6
- package/src/metrics/constants.ts +2 -0
- package/src/multistream/mediaRequestManager.ts +7 -7
- package/src/multistream/remoteMedia.ts +34 -4
- package/src/multistream/remoteMediaGroup.ts +37 -2
- package/src/multistream/sendSlotManager.ts +34 -2
- package/src/reachability/index.ts +8 -16
- package/test/unit/spec/common/browser-detection.js +0 -24
- package/test/unit/spec/controls-options-manager/util.js +58 -0
- package/test/unit/spec/locus-info/controlsUtils.js +52 -0
- package/test/unit/spec/locus-info/index.js +270 -97
- package/test/unit/spec/locus-info/parser.js +3 -2
- package/test/unit/spec/media/index.ts +107 -0
- package/test/unit/spec/media/properties.ts +137 -0
- package/test/unit/spec/meeting/brbState.ts +23 -4
- package/test/unit/spec/meeting/in-meeting-actions.ts +12 -0
- package/test/unit/spec/meeting/index.js +1194 -97
- package/test/unit/spec/meeting/muteState.js +32 -6
- package/test/unit/spec/meeting/request.js +92 -0
- package/test/unit/spec/meeting/utils.js +167 -17
- package/test/unit/spec/meeting-info/meetinginfov2.js +8 -3
- package/test/unit/spec/meetings/index.js +12 -5
- package/test/unit/spec/members/collection.js +120 -0
- package/test/unit/spec/members/index.js +140 -12
- package/test/unit/spec/members/request.js +57 -2
- package/test/unit/spec/members/utils.js +139 -17
- package/test/unit/spec/multistream/mediaRequestManager.ts +19 -6
- package/test/unit/spec/multistream/remoteMedia.ts +66 -2
- package/test/unit/spec/multistream/sendSlotManager.ts +59 -0
- package/test/unit/spec/reachability/index.ts +160 -9
- package/test/unit/spec/roap/turnDiscovery.ts +3 -3
- package/dist/annotation/annotation.types.d.ts +0 -42
- package/dist/annotation/constants.d.ts +0 -31
- package/dist/annotation/index.d.ts +0 -117
- package/dist/breakouts/breakout.d.ts +0 -8
- package/dist/breakouts/collection.d.ts +0 -5
- package/dist/breakouts/edit-lock-error.d.ts +0 -15
- package/dist/breakouts/events.d.ts +0 -8
- package/dist/breakouts/index.d.ts +0 -5
- package/dist/breakouts/request.d.ts +0 -22
- package/dist/breakouts/utils.d.ts +0 -15
- package/dist/common/browser-detection.d.ts +0 -9
- package/dist/common/collection.d.ts +0 -48
- package/dist/common/config.d.ts +0 -2
- package/dist/common/errors/captcha-error.d.ts +0 -15
- package/dist/common/errors/intent-to-join.d.ts +0 -16
- package/dist/common/errors/join-meeting.d.ts +0 -17
- package/dist/common/errors/media.d.ts +0 -15
- package/dist/common/errors/no-meeting-info.d.ts +0 -14
- package/dist/common/errors/parameter.d.ts +0 -15
- package/dist/common/errors/password-error.d.ts +0 -15
- package/dist/common/errors/permission.d.ts +0 -14
- package/dist/common/errors/reclaim-host-role-error.d.ts +0 -60
- package/dist/common/errors/reclaim-host-role-error.js +0 -158
- package/dist/common/errors/reclaim-host-role-error.js.map +0 -1
- package/dist/common/errors/reclaim-host-role-errors.d.ts +0 -60
- package/dist/common/errors/reconnection-in-progress.d.ts +0 -9
- package/dist/common/errors/reconnection-in-progress.js +0 -35
- package/dist/common/errors/reconnection-in-progress.js.map +0 -1
- package/dist/common/errors/reconnection.d.ts +0 -15
- package/dist/common/errors/stats.d.ts +0 -15
- package/dist/common/errors/webex-errors.d.ts +0 -81
- package/dist/common/errors/webex-meetings-error.d.ts +0 -20
- package/dist/common/events/events-scope.d.ts +0 -17
- package/dist/common/events/events.d.ts +0 -12
- package/dist/common/events/trigger-proxy.d.ts +0 -2
- package/dist/common/events/util.d.ts +0 -2
- package/dist/common/logs/logger-config.d.ts +0 -2
- package/dist/common/logs/logger-proxy.d.ts +0 -2
- package/dist/common/logs/request.d.ts +0 -34
- package/dist/common/queue.d.ts +0 -32
- package/dist/config.d.ts +0 -73
- package/dist/constants.d.ts +0 -952
- package/dist/controls-options-manager/constants.d.ts +0 -4
- package/dist/controls-options-manager/enums.d.ts +0 -5
- package/dist/controls-options-manager/index.d.ts +0 -120
- package/dist/controls-options-manager/types.d.ts +0 -43
- package/dist/controls-options-manager/util.d.ts +0 -7
- package/dist/index.d.ts +0 -4
- package/dist/interceptors/index.d.ts +0 -2
- package/dist/interceptors/locusRetry.d.ts +0 -27
- package/dist/interpretation/collection.d.ts +0 -5
- package/dist/interpretation/index.d.ts +0 -5
- package/dist/interpretation/siLanguage.d.ts +0 -5
- package/dist/locus-info/controlsUtils.d.ts +0 -2
- package/dist/locus-info/embeddedAppsUtils.d.ts +0 -2
- package/dist/locus-info/fullState.d.ts +0 -2
- package/dist/locus-info/hostUtils.d.ts +0 -2
- package/dist/locus-info/index.d.ts +0 -269
- package/dist/locus-info/infoUtils.d.ts +0 -2
- package/dist/locus-info/mediaSharesUtils.d.ts +0 -2
- package/dist/locus-info/parser.d.ts +0 -212
- package/dist/locus-info/selfUtils.d.ts +0 -2
- package/dist/media/index.d.ts +0 -32
- package/dist/media/properties.d.ts +0 -108
- package/dist/media/util.d.ts +0 -2
- package/dist/mediaQualityMetrics/config.d.ts +0 -233
- package/dist/mediaQualityMetrics/config.js +0 -513
- package/dist/mediaQualityMetrics/config.js.map +0 -1
- package/dist/meeting/effectsState.d.ts +0 -42
- package/dist/meeting/effectsState.js +0 -260
- package/dist/meeting/effectsState.js.map +0 -1
- package/dist/meeting/in-meeting-actions.d.ts +0 -79
- package/dist/meeting/index.d.ts +0 -1622
- package/dist/meeting/locusMediaRequest.d.ts +0 -74
- package/dist/meeting/muteState.d.ts +0 -116
- package/dist/meeting/request.d.ts +0 -257
- package/dist/meeting/request.type.d.ts +0 -11
- package/dist/meeting/state.d.ts +0 -9
- package/dist/meeting/util.d.ts +0 -2
- package/dist/meeting/voicea-meeting.d.ts +0 -16
- package/dist/meeting-info/collection.d.ts +0 -20
- package/dist/meeting-info/index.d.ts +0 -57
- package/dist/meeting-info/meeting-info-v2.d.ts +0 -93
- package/dist/meeting-info/request.d.ts +0 -22
- package/dist/meeting-info/util.d.ts +0 -2
- package/dist/meeting-info/utilv2.d.ts +0 -2
- package/dist/meetings/collection.d.ts +0 -23
- package/dist/meetings/index.d.ts +0 -296
- package/dist/meetings/meetings.types.d.ts +0 -4
- package/dist/meetings/request.d.ts +0 -27
- package/dist/meetings/util.d.ts +0 -18
- package/dist/member/index.d.ts +0 -148
- package/dist/member/member.types.d.ts +0 -11
- package/dist/member/member.types.js +0 -18
- package/dist/member/member.types.js.map +0 -1
- package/dist/member/types.d.ts +0 -32
- package/dist/member/util.d.ts +0 -2
- package/dist/members/collection.d.ts +0 -24
- package/dist/members/index.d.ts +0 -308
- package/dist/members/request.d.ts +0 -58
- package/dist/members/types.d.ts +0 -25
- package/dist/members/util.d.ts +0 -2
- package/dist/metrics/config.d.ts +0 -169
- package/dist/metrics/config.js +0 -289
- package/dist/metrics/config.js.map +0 -1
- package/dist/metrics/constants.d.ts +0 -59
- package/dist/metrics/index.d.ts +0 -152
- package/dist/multistream/mediaRequestManager.d.ts +0 -119
- package/dist/multistream/receiveSlot.d.ts +0 -68
- package/dist/multistream/receiveSlotManager.d.ts +0 -56
- package/dist/multistream/remoteMedia.d.ts +0 -72
- package/dist/multistream/remoteMediaGroup.d.ts +0 -49
- package/dist/multistream/remoteMediaManager.d.ts +0 -300
- package/dist/multistream/sendSlotManager.d.ts +0 -69
- package/dist/networkQualityMonitor/index.d.ts +0 -70
- package/dist/networkQualityMonitor/index.js +0 -226
- package/dist/networkQualityMonitor/index.js.map +0 -1
- package/dist/peer-connection-manager/index.d.ts +0 -6
- package/dist/peer-connection-manager/index.js +0 -671
- package/dist/peer-connection-manager/index.js.map +0 -1
- package/dist/peer-connection-manager/util.d.ts +0 -6
- package/dist/peer-connection-manager/util.js +0 -110
- package/dist/peer-connection-manager/util.js.map +0 -1
- package/dist/personal-meeting-room/index.d.ts +0 -47
- package/dist/personal-meeting-room/request.d.ts +0 -14
- package/dist/personal-meeting-room/util.d.ts +0 -2
- package/dist/reachability/clusterReachability.d.ts +0 -109
- package/dist/reachability/index.d.ts +0 -139
- package/dist/reachability/request.d.ts +0 -35
- package/dist/reachability/util.d.ts +0 -8
- package/dist/reactions/constants.d.ts +0 -3
- package/dist/reactions/reactions.d.ts +0 -4
- package/dist/reactions/reactions.type.d.ts +0 -32
- package/dist/reconnection-manager/index.d.ts +0 -112
- package/dist/recording-controller/enums.d.ts +0 -7
- package/dist/recording-controller/index.d.ts +0 -193
- package/dist/recording-controller/util.d.ts +0 -13
- package/dist/roap/collection.d.ts +0 -10
- package/dist/roap/collection.js +0 -63
- package/dist/roap/collection.js.map +0 -1
- package/dist/roap/handler.d.ts +0 -47
- package/dist/roap/handler.js +0 -279
- package/dist/roap/handler.js.map +0 -1
- package/dist/roap/index.d.ts +0 -116
- package/dist/roap/request.d.ts +0 -35
- package/dist/roap/state.d.ts +0 -9
- package/dist/roap/state.js +0 -127
- package/dist/roap/state.js.map +0 -1
- package/dist/roap/turnDiscovery.d.ts +0 -81
- package/dist/roap/util.d.ts +0 -2
- package/dist/roap/util.js +0 -76
- package/dist/roap/util.js.map +0 -1
- package/dist/rtcMetrics/constants.d.ts +0 -4
- package/dist/rtcMetrics/constants.js.map +0 -1
- package/dist/rtcMetrics/index.d.ts +0 -61
- package/dist/rtcMetrics/index.js +0 -197
- package/dist/rtcMetrics/index.js.map +0 -1
- package/dist/statsAnalyzer/global.d.ts +0 -118
- package/dist/statsAnalyzer/global.js +0 -127
- package/dist/statsAnalyzer/global.js.map +0 -1
- package/dist/statsAnalyzer/index.d.ts +0 -193
- package/dist/statsAnalyzer/index.js +0 -1019
- package/dist/statsAnalyzer/index.js.map +0 -1
- package/dist/statsAnalyzer/mqaUtil.d.ts +0 -22
- package/dist/statsAnalyzer/mqaUtil.js +0 -181
- package/dist/statsAnalyzer/mqaUtil.js.map +0 -1
- package/dist/transcription/index.d.ts +0 -64
- package/dist/types/common/errors/reconnection-in-progress.d.ts +0 -9
- package/dist/types/mediaQualityMetrics/config.d.ts +0 -241
- package/dist/types/networkQualityMonitor/index.d.ts +0 -70
- package/dist/types/rtcMetrics/constants.d.ts +0 -4
- package/dist/types/rtcMetrics/index.d.ts +0 -71
- package/dist/types/statsAnalyzer/global.d.ts +0 -36
- package/dist/types/statsAnalyzer/index.d.ts +0 -217
- package/dist/types/statsAnalyzer/mqaUtil.d.ts +0 -48
- package/dist/webinar/collection.d.ts +0 -16
- package/dist/webinar/index.d.ts +0 -5
@@ -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,
|
@@ -56,6 +57,7 @@ import * as MeetingRequestImport from '@webex/plugin-meetings/src/meeting/reques
|
|
56
57
|
import LocusInfo from '@webex/plugin-meetings/src/locus-info';
|
57
58
|
import MediaProperties from '@webex/plugin-meetings/src/media/properties';
|
58
59
|
import MeetingUtil from '@webex/plugin-meetings/src/meeting/util';
|
60
|
+
import MembersUtil from '@webex/plugin-meetings/src/members/util';
|
59
61
|
import MeetingsUtil from '@webex/plugin-meetings/src/meetings/util';
|
60
62
|
import Media from '@webex/plugin-meetings/src/media/index';
|
61
63
|
import ReconnectionManager from '@webex/plugin-meetings/src/reconnection-manager';
|
@@ -244,6 +246,7 @@ describe('plugin-meetings', () => {
|
|
244
246
|
});
|
245
247
|
|
246
248
|
webex.internal.newMetrics.callDiagnosticMetrics.clearErrorCache = sinon.stub();
|
249
|
+
webex.internal.newMetrics.callDiagnosticMetrics.clearEventLimitsForCorrelationId = sinon.stub();
|
247
250
|
webex.internal.support.submitLogs = sinon.stub().returns(Promise.resolve());
|
248
251
|
webex.internal.services = {get: sinon.stub().returns('locus-url')};
|
249
252
|
webex.credentials.getOrgId = sinon.stub().returns('fake-org-id');
|
@@ -368,6 +371,35 @@ describe('plugin-meetings', () => {
|
|
368
371
|
assert.instanceOf(meeting.simultaneousInterpretation, SimultaneousInterpretation);
|
369
372
|
assert.instanceOf(meeting.webinar, Webinar);
|
370
373
|
});
|
374
|
+
|
375
|
+
it('should call the callback with the meeting that has id already set', () => {
|
376
|
+
let meetingIdFromCallback;
|
377
|
+
// check that the meeting id is already set correctly at the time when the callback is called
|
378
|
+
const meetingCreationCallback = sinon.stub().callsFake((meeting) => {
|
379
|
+
meetingIdFromCallback = meeting.id;
|
380
|
+
});
|
381
|
+
|
382
|
+
meeting = new Meeting(
|
383
|
+
{
|
384
|
+
userId: uuid1,
|
385
|
+
resource: uuid2,
|
386
|
+
deviceUrl: uuid3,
|
387
|
+
locus: {url: url1},
|
388
|
+
destination: testDestination,
|
389
|
+
destinationType: DESTINATION_TYPE.MEETING_ID,
|
390
|
+
correlationId,
|
391
|
+
selfId: uuid1,
|
392
|
+
},
|
393
|
+
{
|
394
|
+
parent: webex,
|
395
|
+
},
|
396
|
+
meetingCreationCallback
|
397
|
+
);
|
398
|
+
assert.exists(meeting.id);
|
399
|
+
assert.calledOnceWithExactly(meetingCreationCallback, meeting);
|
400
|
+
assert.equal(meeting.id, meetingIdFromCallback);
|
401
|
+
});
|
402
|
+
|
371
403
|
it('creates MediaRequestManager instances', () => {
|
372
404
|
assert.instanceOf(meeting.mediaRequestManagers.audio, MediaRequestManager);
|
373
405
|
assert.instanceOf(meeting.mediaRequestManagers.video, MediaRequestManager);
|
@@ -454,6 +486,18 @@ describe('plugin-meetings', () => {
|
|
454
486
|
});
|
455
487
|
});
|
456
488
|
|
489
|
+
it('pstnCorrelationId getter/setter should work correctly', () => {
|
490
|
+
const testPstnCorrelationId = uuid.v4();
|
491
|
+
|
492
|
+
meeting.pstnCorrelationId = testPstnCorrelationId;
|
493
|
+
assert.equal(meeting.pstnCorrelationId, testPstnCorrelationId);
|
494
|
+
assert.equal(meeting.callStateForMetrics.pstnCorrelationId, testPstnCorrelationId);
|
495
|
+
|
496
|
+
meeting.pstnCorrelationId = undefined;
|
497
|
+
assert.equal(meeting.pstnCorrelationId, undefined);
|
498
|
+
assert.equal(meeting.callStateForMetrics.pstnCorrelationId, undefined);
|
499
|
+
});
|
500
|
+
|
457
501
|
describe('creates ReceiveSlot manager instance', () => {
|
458
502
|
let mockReceiveSlotManagerCtor;
|
459
503
|
let providedCreateSlotCallback;
|
@@ -581,7 +625,6 @@ describe('plugin-meetings', () => {
|
|
581
625
|
assert.isFalse(meeting.isLocusCall());
|
582
626
|
});
|
583
627
|
});
|
584
|
-
|
585
628
|
describe('#invite', () => {
|
586
629
|
it('should have #invite', () => {
|
587
630
|
assert.exists(meeting.invite);
|
@@ -592,8 +635,6 @@ describe('plugin-meetings', () => {
|
|
592
635
|
it('should proxy members #addMember and return a promise', async () => {
|
593
636
|
const invite = meeting.invite(uuid1, false);
|
594
637
|
|
595
|
-
assert.exists(invite.then);
|
596
|
-
await invite;
|
597
638
|
assert.calledOnce(meeting.members.addMember);
|
598
639
|
assert.calledWith(meeting.members.addMember, uuid1, false);
|
599
640
|
});
|
@@ -614,20 +655,20 @@ describe('plugin-meetings', () => {
|
|
614
655
|
assert.calledWith(meeting.members.cancelPhoneInvite, uuid1);
|
615
656
|
});
|
616
657
|
});
|
617
|
-
describe('#
|
618
|
-
it('should have #
|
619
|
-
assert.exists(meeting.
|
658
|
+
describe('#cancelInviteByMemberId', () => {
|
659
|
+
it('should have #cancelInviteByMemberId', () => {
|
660
|
+
assert.exists(meeting.cancelInviteByMemberId);
|
620
661
|
});
|
621
662
|
beforeEach(() => {
|
622
|
-
meeting.members.
|
663
|
+
meeting.members.cancelInviteByMemberId = sinon.stub().returns(Promise.resolve(test1));
|
623
664
|
});
|
624
|
-
it('should proxy members #
|
625
|
-
const cancel = meeting.
|
665
|
+
it('should proxy members #cancelInviteByMemberId and return a promise', async () => {
|
666
|
+
const cancel = meeting.cancelInviteByMemberId({memberId: uuid1});
|
626
667
|
|
627
668
|
assert.exists(cancel.then);
|
628
669
|
await cancel;
|
629
|
-
assert.calledOnce(meeting.members.
|
630
|
-
assert.calledWith(meeting.members.
|
670
|
+
assert.calledOnce(meeting.members.cancelInviteByMemberId);
|
671
|
+
assert.calledWith(meeting.members.cancelInviteByMemberId, {memberId: uuid1});
|
631
672
|
});
|
632
673
|
});
|
633
674
|
describe('#admit', () => {
|
@@ -1208,8 +1249,73 @@ describe('plugin-meetings', () => {
|
|
1208
1249
|
reason: 'joinWithMedia failure',
|
1209
1250
|
});
|
1210
1251
|
});
|
1211
|
-
});
|
1212
1252
|
|
1253
|
+
it('should ignore sendVideo/receiveVideo when videoEnabled is false', async () => {
|
1254
|
+
await meeting.joinWithMedia({
|
1255
|
+
joinOptions,
|
1256
|
+
mediaOptions: {
|
1257
|
+
videoEnabled: false,
|
1258
|
+
sendVideo: true,
|
1259
|
+
receiveVideo: true,
|
1260
|
+
allowMediaInLobby: true,
|
1261
|
+
},
|
1262
|
+
});
|
1263
|
+
|
1264
|
+
assert.calledWithMatch(
|
1265
|
+
meeting.addMediaInternal,
|
1266
|
+
sinon.match.any,
|
1267
|
+
sinon.match.any,
|
1268
|
+
sinon.match.any,
|
1269
|
+
sinon.match.has('videoEnabled', false).and(sinon.match.has('allowMediaInLobby', true))
|
1270
|
+
);
|
1271
|
+
});
|
1272
|
+
|
1273
|
+
it('should ignore sendAudio/receiveAudio when audioEnabled is false', async () => {
|
1274
|
+
await meeting.joinWithMedia({
|
1275
|
+
joinOptions,
|
1276
|
+
mediaOptions: {
|
1277
|
+
audioEnabled: false,
|
1278
|
+
sendAudio: true,
|
1279
|
+
receiveAudio: false,
|
1280
|
+
allowMediaInLobby: true,
|
1281
|
+
},
|
1282
|
+
});
|
1283
|
+
|
1284
|
+
assert.calledWithMatch(
|
1285
|
+
meeting.addMediaInternal,
|
1286
|
+
sinon.match.any,
|
1287
|
+
sinon.match.any,
|
1288
|
+
sinon.match.any,
|
1289
|
+
sinon.match.has('audioEnabled', false).and(sinon.match.has('allowMediaInLobby', true))
|
1290
|
+
);
|
1291
|
+
});
|
1292
|
+
|
1293
|
+
it('should use provided send/receive values when videoEnabled/audioEnabled are true or not set', async () => {
|
1294
|
+
await meeting.joinWithMedia({
|
1295
|
+
joinOptions,
|
1296
|
+
mediaOptions: {
|
1297
|
+
sendVideo: true,
|
1298
|
+
receiveVideo: false,
|
1299
|
+
sendAudio: false,
|
1300
|
+
receiveAudio: true,
|
1301
|
+
allowMediaInLobby: true,
|
1302
|
+
},
|
1303
|
+
});
|
1304
|
+
|
1305
|
+
assert.calledWith(
|
1306
|
+
meeting.addMediaInternal,
|
1307
|
+
sinon.match.any,
|
1308
|
+
sinon.match.any,
|
1309
|
+
sinon.match.any,
|
1310
|
+
sinon.match({
|
1311
|
+
sendVideo: true,
|
1312
|
+
receiveVideo: false,
|
1313
|
+
sendAudio: false,
|
1314
|
+
receiveAudio: true,
|
1315
|
+
})
|
1316
|
+
);
|
1317
|
+
});
|
1318
|
+
});
|
1213
1319
|
describe('#isTranscriptionSupported', () => {
|
1214
1320
|
it('should return false if the feature is not supported for the meeting', () => {
|
1215
1321
|
meeting.locusInfo.controls = {transcribe: {caption: false}};
|
@@ -1223,6 +1329,44 @@ describe('plugin-meetings', () => {
|
|
1223
1329
|
});
|
1224
1330
|
});
|
1225
1331
|
|
1332
|
+
describe('#update spoken language', () => {
|
1333
|
+
beforeEach(() => {
|
1334
|
+
webex.internal.voicea.onSpokenLanguageUpdate = sinon.stub();
|
1335
|
+
meeting.transcription = {languageOptions: {currentSpokenLanguage: 'en'}};
|
1336
|
+
});
|
1337
|
+
afterEach(() => {
|
1338
|
+
// Restore the original methods after each test
|
1339
|
+
sinon.restore();
|
1340
|
+
});
|
1341
|
+
it('should call voicea.onSpokenLanguageUpdate when joined', async () => {
|
1342
|
+
meeting.joinedWith = {state: 'JOINED'};
|
1343
|
+
await meeting.locusInfo.emitScoped(
|
1344
|
+
{function: 'test', file: 'test'},
|
1345
|
+
LOCUSINFO.EVENTS.CONTROLS_MEETING_TRANSCRIPTION_SPOKEN_LANGUAGE_UPDATED,
|
1346
|
+
{spokenLanguage: 'fr'}
|
1347
|
+
);
|
1348
|
+
assert.calledWith(webex.internal.voicea.onSpokenLanguageUpdate, 'fr', meeting.id);
|
1349
|
+
assert.equal(meeting.transcription.languageOptions.currentSpokenLanguage, 'fr');
|
1350
|
+
assert.calledWith(
|
1351
|
+
TriggerProxy.trigger,
|
1352
|
+
meeting,
|
1353
|
+
{file: 'meeting/index', function: 'setupLocusControlsListener'},
|
1354
|
+
EVENT_TRIGGERS.MEETING_TRANSCRIPTION_SPOKEN_LANGUAGE_UPDATED
|
1355
|
+
);
|
1356
|
+
});
|
1357
|
+
|
1358
|
+
it('should also call voicea.onSpokenLanguageUpdate when not joined', async () => {
|
1359
|
+
meeting.joinedWith = {state: 'NOT_JOINED'};
|
1360
|
+
await meeting.locusInfo.emitScoped(
|
1361
|
+
{function: 'test', file: 'test'},
|
1362
|
+
LOCUSINFO.EVENTS.CONTROLS_MEETING_TRANSCRIPTION_SPOKEN_LANGUAGE_UPDATED,
|
1363
|
+
{spokenLanguage: 'de'}
|
1364
|
+
);
|
1365
|
+
assert.calledWith(webex.internal.voicea.onSpokenLanguageUpdate, 'de');
|
1366
|
+
assert.equal(meeting.transcription.languageOptions.currentSpokenLanguage, 'de');
|
1367
|
+
});
|
1368
|
+
});
|
1369
|
+
|
1226
1370
|
describe('#startTranscription', () => {
|
1227
1371
|
beforeEach(() => {
|
1228
1372
|
webex.internal.voicea.on = sinon.stub();
|
@@ -1846,21 +1990,25 @@ describe('plugin-meetings', () => {
|
|
1846
1990
|
});
|
1847
1991
|
});
|
1848
1992
|
|
1849
|
-
it('should
|
1993
|
+
it('should handle join failure', async () => {
|
1850
1994
|
MeetingUtil.isPinOrGuest = sinon.stub().returns(false);
|
1995
|
+
webex.internal.newMetrics.submitClientEvent = sinon.stub();
|
1996
|
+
|
1851
1997
|
await meeting.join().catch(() => {
|
1852
|
-
assert.
|
1853
|
-
|
1854
|
-
|
1855
|
-
);
|
1856
|
-
assert.
|
1857
|
-
webex.internal.newMetrics.submitClientEvent
|
1998
|
+
assert.calledOnce(MeetingUtil.joinMeeting);
|
1999
|
+
|
2000
|
+
// Assert that client.locus.join.response error event is not sent from this function, it is now emitted from MeetingUtil.joinMeeting
|
2001
|
+
assert.calledOnce(webex.internal.newMetrics.submitClientEvent);
|
2002
|
+
assert.calledWithMatch(
|
2003
|
+
webex.internal.newMetrics.submitClientEvent,
|
1858
2004
|
{
|
1859
|
-
|
1860
|
-
|
1861
|
-
|
1862
|
-
|
1863
|
-
|
2005
|
+
name: 'client.call.initiated',
|
2006
|
+
payload: {
|
2007
|
+
trigger: 'user-interaction',
|
2008
|
+
isRoapCallEnabled: true,
|
2009
|
+
pstnAudioType: undefined
|
2010
|
+
},
|
2011
|
+
options: {meetingId: meeting.id},
|
1864
2012
|
}
|
1865
2013
|
);
|
1866
2014
|
});
|
@@ -2061,16 +2209,15 @@ describe('plugin-meetings', () => {
|
|
2061
2209
|
};
|
2062
2210
|
meeting.mediaProperties.setMediaDirection = sinon.stub().returns(true);
|
2063
2211
|
meeting.mediaProperties.waitForMediaConnectionConnected = sinon.stub().resolves();
|
2064
|
-
meeting.mediaProperties.getCurrentConnectionInfo = sinon
|
2065
|
-
|
2066
|
-
|
2067
|
-
|
2068
|
-
|
2069
|
-
|
2070
|
-
ipVersion: 'IPv6',
|
2071
|
-
});
|
2212
|
+
meeting.mediaProperties.getCurrentConnectionInfo = sinon.stub().resolves({
|
2213
|
+
connectionType: 'udp',
|
2214
|
+
selectedCandidatePairChanges: 2,
|
2215
|
+
numTransports: 1,
|
2216
|
+
ipVersion: 'IPv6',
|
2217
|
+
});
|
2072
2218
|
meeting.audio = muteStateStub;
|
2073
2219
|
meeting.video = muteStateStub;
|
2220
|
+
sinon.stub(MeetingUtil, 'getIpVersion').returns(IP_VERSION.ipv4_and_ipv6);
|
2074
2221
|
sinon.stub(Media, 'createMediaConnection').returns(fakeMediaConnection);
|
2075
2222
|
sinon.stub(meeting, 'setupMediaConnectionListeners');
|
2076
2223
|
sinon.stub(meeting, 'setMercuryListener');
|
@@ -2142,13 +2289,24 @@ describe('plugin-meetings', () => {
|
|
2142
2289
|
close: sinon.stub(),
|
2143
2290
|
forceRtcMetricsSend,
|
2144
2291
|
});
|
2145
|
-
|
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
|
2146
2297
|
meeting.statsAnalyzer = {stopAnalyzer: sinon.stub().resolves()};
|
2298
|
+
meeting.statsMonitor = mockStatsMonitor;
|
2299
|
+
meeting.networkQualityMonitor = mockNetworkQualityMonitor;
|
2147
2300
|
const error = await assert.isRejected(meeting.addMedia());
|
2148
2301
|
|
2149
2302
|
assert.calledOnce(forceRtcMetricsSend);
|
2303
|
+
assert.calledOnce(mockStatsMonitor.removeAllListeners);
|
2304
|
+
assert.calledOnce(mockNetworkQualityMonitor.removeAllListeners);
|
2150
2305
|
|
2151
2306
|
assert.isNull(meeting.statsAnalyzer);
|
2307
|
+
assert.isNull(meeting.statsMonitor);
|
2308
|
+
assert.isNull(meeting.networkQualityMonitor);
|
2309
|
+
|
2152
2310
|
assert(webex.internal.newMetrics.submitInternalEvent.calledTwice);
|
2153
2311
|
assert.calledWith(webex.internal.newMetrics.submitInternalEvent.firstCall, {
|
2154
2312
|
name: 'internal.client.add-media.turn-discovery.start',
|
@@ -2187,10 +2345,12 @@ describe('plugin-meetings', () => {
|
|
2187
2345
|
someReachabilityMetric1: 'some value1',
|
2188
2346
|
someReachabilityMetric2: 'some value2',
|
2189
2347
|
selectedCandidatePairChanges: 2,
|
2190
|
-
|
2191
|
-
|
2348
|
+
subnet_reachable: null,
|
2349
|
+
selected_cluster: null,
|
2350
|
+
selected_subnet: null,
|
2192
2351
|
numTransports: 1,
|
2193
2352
|
iceCandidatesCount: 0,
|
2353
|
+
ipver: 1,
|
2194
2354
|
}
|
2195
2355
|
);
|
2196
2356
|
});
|
@@ -2235,8 +2395,10 @@ describe('plugin-meetings', () => {
|
|
2235
2395
|
signalingState: 'unknown',
|
2236
2396
|
connectionState: 'unknown',
|
2237
2397
|
iceConnectionState: 'unknown',
|
2238
|
-
|
2239
|
-
|
2398
|
+
subnet_reachable: null,
|
2399
|
+
selected_cluster: null,
|
2400
|
+
selected_subnet: null,
|
2401
|
+
ipver: 1,
|
2240
2402
|
})
|
2241
2403
|
);
|
2242
2404
|
|
@@ -2256,12 +2418,23 @@ describe('plugin-meetings', () => {
|
|
2256
2418
|
|
2257
2419
|
meeting.waitForRemoteSDPAnswer = sinon.stub().rejects();
|
2258
2420
|
|
2259
|
-
|
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
|
2260
2425
|
meeting.statsAnalyzer = {stopAnalyzer: sinon.stub().resolves()};
|
2426
|
+
meeting.statsMonitor = mockStatsMonitor;
|
2427
|
+
meeting.networkQualityMonitor = mockNetworkQualityMonitor;
|
2261
2428
|
|
2262
2429
|
const error = await assert.isRejected(meeting.addMedia());
|
2263
2430
|
|
2264
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
|
+
|
2265
2438
|
assert(webex.internal.newMetrics.submitInternalEvent.calledTwice);
|
2266
2439
|
assert.calledWith(webex.internal.newMetrics.submitInternalEvent.firstCall, {
|
2267
2440
|
name: 'internal.client.add-media.turn-discovery.start',
|
@@ -2302,8 +2475,10 @@ describe('plugin-meetings', () => {
|
|
2302
2475
|
selectedCandidatePairChanges: 2,
|
2303
2476
|
numTransports: 1,
|
2304
2477
|
iceCandidatesCount: 0,
|
2305
|
-
|
2306
|
-
|
2478
|
+
subnet_reachable: null,
|
2479
|
+
selected_cluster: null,
|
2480
|
+
selected_subnet: null,
|
2481
|
+
ipver: 1,
|
2307
2482
|
}
|
2308
2483
|
);
|
2309
2484
|
});
|
@@ -2324,8 +2499,9 @@ describe('plugin-meetings', () => {
|
|
2324
2499
|
},
|
2325
2500
|
},
|
2326
2501
|
});
|
2327
|
-
// 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
|
2328
2503
|
meeting.statsAnalyzer = {stopAnalyzer: sinon.stub().resolves()};
|
2504
|
+
meeting.statsMonitor = {removeAllListeners: sinon.stub()};
|
2329
2505
|
const error = await assert.isRejected(meeting.addMedia());
|
2330
2506
|
|
2331
2507
|
assert(webex.internal.newMetrics.submitInternalEvent.calledTwice);
|
@@ -2361,12 +2537,15 @@ describe('plugin-meetings', () => {
|
|
2361
2537
|
signalingState: 'have-local-offer',
|
2362
2538
|
connectionState: 'connecting',
|
2363
2539
|
iceConnectionState: 'checking',
|
2364
|
-
|
2365
|
-
|
2540
|
+
subnet_reachable: null,
|
2541
|
+
selected_cluster: null,
|
2542
|
+
selected_subnet: null,
|
2543
|
+
ipver: 1,
|
2366
2544
|
})
|
2367
2545
|
);
|
2368
2546
|
|
2369
2547
|
assert.isNull(meeting.statsAnalyzer);
|
2548
|
+
assert.isNull(meeting.statsMonitor);
|
2370
2549
|
});
|
2371
2550
|
|
2372
2551
|
it('should include the peer connection properties correctly for transcoded', async () => {
|
@@ -2383,8 +2562,14 @@ describe('plugin-meetings', () => {
|
|
2383
2562
|
},
|
2384
2563
|
},
|
2385
2564
|
});
|
2386
|
-
|
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
|
2387
2570
|
meeting.statsAnalyzer = {stopAnalyzer: sinon.stub().resolves()};
|
2571
|
+
meeting.statsMonitor = mockStatsMonitor;
|
2572
|
+
meeting.networkQualityMonitor = mockNetworkQualityMonitor;
|
2388
2573
|
const error = await assert.isRejected(meeting.addMedia());
|
2389
2574
|
|
2390
2575
|
assert(webex.internal.newMetrics.submitInternalEvent.calledTwice);
|
@@ -2420,12 +2605,18 @@ describe('plugin-meetings', () => {
|
|
2420
2605
|
signalingState: 'have-local-offer',
|
2421
2606
|
connectionState: 'connecting',
|
2422
2607
|
iceConnectionState: 'checking',
|
2423
|
-
|
2424
|
-
|
2608
|
+
subnet_reachable: null,
|
2609
|
+
selected_cluster: null,
|
2610
|
+
selected_subnet: null,
|
2611
|
+
ipver: 1,
|
2425
2612
|
})
|
2426
2613
|
);
|
2427
2614
|
|
2428
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);
|
2429
2620
|
});
|
2430
2621
|
|
2431
2622
|
it('should work the second time addMedia is called in case the first time fails', async () => {
|
@@ -2943,8 +3134,10 @@ describe('plugin-meetings', () => {
|
|
2943
3134
|
selectedCandidatePairChanges: 2,
|
2944
3135
|
numTransports: 1,
|
2945
3136
|
iceCandidatesCount: 0,
|
2946
|
-
|
2947
|
-
|
3137
|
+
subnet_reachable: null,
|
3138
|
+
selected_cluster: null,
|
3139
|
+
selected_subnet: null,
|
3140
|
+
ipver: 1,
|
2948
3141
|
},
|
2949
3142
|
]);
|
2950
3143
|
|
@@ -3146,13 +3339,15 @@ describe('plugin-meetings', () => {
|
|
3146
3339
|
connectionType: 'udp',
|
3147
3340
|
selectedCandidatePairChanges: 2,
|
3148
3341
|
ipVersion: 'IPv6',
|
3342
|
+
ipver: 1,
|
3149
3343
|
numTransports: 1,
|
3150
3344
|
isMultistream: false,
|
3151
3345
|
retriedWithTurnServer: true,
|
3152
3346
|
isJoinWithMediaRetry: false,
|
3153
3347
|
iceCandidatesCount: 0,
|
3154
|
-
|
3155
|
-
|
3348
|
+
subnet_reachable: null,
|
3349
|
+
selected_cluster: null,
|
3350
|
+
selected_subnet: null,
|
3156
3351
|
},
|
3157
3352
|
]);
|
3158
3353
|
meeting.roap.doTurnDiscovery;
|
@@ -3286,11 +3481,12 @@ describe('plugin-meetings', () => {
|
|
3286
3481
|
meeting.mediaConnections = [
|
3287
3482
|
{
|
3288
3483
|
mediaAgentCluster: 'some.cluster',
|
3289
|
-
}
|
3290
|
-
]
|
3484
|
+
},
|
3485
|
+
];
|
3291
3486
|
meeting.iceCandidatesCount = 3;
|
3292
3487
|
meeting.iceCandidateErrors.set('701_error', 3);
|
3293
3488
|
meeting.iceCandidateErrors.set('701_turn_host_lookup_received_error', 1);
|
3489
|
+
MeetingUtil.getIpVersion.returns(IP_VERSION.only_ipv6);
|
3294
3490
|
|
3295
3491
|
await meeting.addMedia({
|
3296
3492
|
mediaSettings: {},
|
@@ -3306,6 +3502,7 @@ describe('plugin-meetings', () => {
|
|
3306
3502
|
connectionType: 'udp',
|
3307
3503
|
selectedCandidatePairChanges: 2,
|
3308
3504
|
ipVersion: 'IPv6',
|
3505
|
+
ipver: 6,
|
3309
3506
|
numTransports: 1,
|
3310
3507
|
isMultistream: false,
|
3311
3508
|
retriedWithTurnServer: false,
|
@@ -3315,8 +3512,9 @@ describe('plugin-meetings', () => {
|
|
3315
3512
|
iceCandidatesCount: 3,
|
3316
3513
|
'701_error': 3,
|
3317
3514
|
'701_turn_host_lookup_received_error': 1,
|
3318
|
-
|
3319
|
-
|
3515
|
+
subnet_reachable: null,
|
3516
|
+
selected_cluster: 'some.cluster',
|
3517
|
+
selected_subnet: null,
|
3320
3518
|
}
|
3321
3519
|
);
|
3322
3520
|
|
@@ -3379,9 +3577,11 @@ describe('plugin-meetings', () => {
|
|
3379
3577
|
iceConnectionState: 'unknown',
|
3380
3578
|
selectedCandidatePairChanges: 2,
|
3381
3579
|
numTransports: 1,
|
3382
|
-
|
3383
|
-
|
3580
|
+
subnet_reachable: null,
|
3581
|
+
selected_cluster: null,
|
3582
|
+
selected_subnet: null,
|
3384
3583
|
iceCandidatesCount: 0,
|
3584
|
+
ipver: 1,
|
3385
3585
|
}
|
3386
3586
|
);
|
3387
3587
|
|
@@ -3442,16 +3642,18 @@ describe('plugin-meetings', () => {
|
|
3442
3642
|
numTransports: 1,
|
3443
3643
|
'701_error': 2,
|
3444
3644
|
'701_turn_host_lookup_received_error': 1,
|
3445
|
-
|
3446
|
-
|
3645
|
+
subnet_reachable: null,
|
3646
|
+
selected_cluster: null,
|
3647
|
+
selected_subnet: null,
|
3447
3648
|
iceCandidatesCount: 0,
|
3649
|
+
ipver: 1,
|
3448
3650
|
}
|
3449
3651
|
);
|
3450
3652
|
|
3451
3653
|
assert.isOk(errorThrown);
|
3452
3654
|
});
|
3453
3655
|
|
3454
|
-
it('should send
|
3656
|
+
it('should send subnet reachablity metrics if media connection success', async () => {
|
3455
3657
|
meeting.roap.doTurnDiscovery = sinon.stub().returns({
|
3456
3658
|
turnServerInfo: undefined,
|
3457
3659
|
turnDiscoverySkippedReason: undefined,
|
@@ -3465,6 +3667,12 @@ describe('plugin-meetings', () => {
|
|
3465
3667
|
stopReachability: sinon.stub(),
|
3466
3668
|
isSubnetReachable: sinon.stub().returns(false),
|
3467
3669
|
};
|
3670
|
+
meeting.mediaServerIp = '1.2.3.4';
|
3671
|
+
meeting.mediaConnections = [
|
3672
|
+
{
|
3673
|
+
mediaAgentCluster: 'some.cluster',
|
3674
|
+
},
|
3675
|
+
];
|
3468
3676
|
|
3469
3677
|
const forceRtcMetricsSend = sinon.stub().resolves();
|
3470
3678
|
const closeMediaConnectionStub = sinon.stub();
|
@@ -3485,6 +3693,7 @@ describe('plugin-meetings', () => {
|
|
3485
3693
|
locus_id: meeting.locusUrl.split('/').pop(),
|
3486
3694
|
connectionType: 'udp',
|
3487
3695
|
ipVersion: 'IPv6',
|
3696
|
+
ipver: 1,
|
3488
3697
|
selectedCandidatePairChanges: 2,
|
3489
3698
|
numTransports: 1,
|
3490
3699
|
isMultistream: false,
|
@@ -3492,12 +3701,13 @@ describe('plugin-meetings', () => {
|
|
3492
3701
|
isJoinWithMediaRetry: false,
|
3493
3702
|
iceCandidatesCount: 0,
|
3494
3703
|
reachability_public_udp_success: 5,
|
3495
|
-
|
3496
|
-
|
3704
|
+
subnet_reachable: false,
|
3705
|
+
selected_cluster: 'some.cluster',
|
3706
|
+
selected_subnet: '1.X.X.X',
|
3497
3707
|
});
|
3498
3708
|
});
|
3499
3709
|
|
3500
|
-
it('should send
|
3710
|
+
it('should send subnet reachablity metrics if media connection fails', async () => {
|
3501
3711
|
let errorThrown = undefined;
|
3502
3712
|
|
3503
3713
|
meeting.roap.doTurnDiscovery = sinon.stub().returns({
|
@@ -3513,6 +3723,12 @@ describe('plugin-meetings', () => {
|
|
3513
3723
|
stopReachability: sinon.stub(),
|
3514
3724
|
isSubnetReachable: sinon.stub().returns(true),
|
3515
3725
|
};
|
3726
|
+
meeting.mediaServerIp = '1.2.3.4';
|
3727
|
+
meeting.mediaConnections = [
|
3728
|
+
{
|
3729
|
+
mediaAgentCluster: 'some.cluster',
|
3730
|
+
},
|
3731
|
+
];
|
3516
3732
|
|
3517
3733
|
const forceRtcMetricsSend = sinon.stub().resolves();
|
3518
3734
|
const closeMediaConnectionStub = sinon.stub();
|
@@ -3554,9 +3770,11 @@ describe('plugin-meetings', () => {
|
|
3554
3770
|
selectedCandidatePairChanges: 2,
|
3555
3771
|
numTransports: 1,
|
3556
3772
|
reachability_public_udp_success: 5,
|
3557
|
-
|
3558
|
-
|
3773
|
+
subnet_reachable: true,
|
3774
|
+
selected_cluster: 'some.cluster',
|
3775
|
+
selected_subnet: '1.X.X.X',
|
3559
3776
|
iceCandidatesCount: 0,
|
3777
|
+
ipver: 1,
|
3560
3778
|
}
|
3561
3779
|
);
|
3562
3780
|
|
@@ -3862,13 +4080,14 @@ describe('plugin-meetings', () => {
|
|
3862
4080
|
});
|
3863
4081
|
});
|
3864
4082
|
|
3865
|
-
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 () => {
|
3866
4084
|
let fakeMembersCollection = {
|
3867
4085
|
members: {
|
3868
|
-
member1: {isInMeeting: true},
|
3869
|
-
member2: {isInMeeting: true},
|
3870
|
-
member3: {isInMeeting: false},
|
3871
|
-
|
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
|
+
}
|
3872
4091
|
};
|
3873
4092
|
sinon.stub(meeting, 'getMembers').returns({membersCollection: fakeMembersCollection});
|
3874
4093
|
const fakeData = {intervalMetadata: {}};
|
@@ -3886,11 +4105,12 @@ describe('plugin-meetings', () => {
|
|
3886
4105
|
},
|
3887
4106
|
payload: {
|
3888
4107
|
intervals: [
|
3889
|
-
sinon.match.has('intervalMetadata', sinon.match.has('meetingUserCount',
|
4108
|
+
sinon.match.has('intervalMetadata', sinon.match.has('meetingUserCount', 3)),
|
3890
4109
|
],
|
3891
4110
|
},
|
3892
4111
|
});
|
3893
|
-
|
4112
|
+
// Move member2 from lobby to neither in meeting nor lobby
|
4113
|
+
fakeMembersCollection.members.member2.isInLobby = false;
|
3894
4114
|
|
3895
4115
|
statsAnalyzerStub.emit(
|
3896
4116
|
{file: 'test', function: 'test'},
|
@@ -3905,7 +4125,7 @@ describe('plugin-meetings', () => {
|
|
3905
4125
|
},
|
3906
4126
|
payload: {
|
3907
4127
|
intervals: [
|
3908
|
-
sinon.match.has('intervalMetadata', sinon.match.has('meetingUserCount',
|
4128
|
+
sinon.match.has('intervalMetadata', sinon.match.has('meetingUserCount', 2)),
|
3909
4129
|
],
|
3910
4130
|
},
|
3911
4131
|
});
|
@@ -3932,6 +4152,132 @@ describe('plugin-meetings', () => {
|
|
3932
4152
|
});
|
3933
4153
|
});
|
3934
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
|
+
|
3935
4281
|
describe('bundlePolicy', () => {
|
3936
4282
|
const FAKE_TURN_URL = 'turns:webex.com:3478';
|
3937
4283
|
const FAKE_TURN_USER = 'some-turn-username';
|
@@ -4152,7 +4498,7 @@ describe('plugin-meetings', () => {
|
|
4152
4498
|
meeting.deviceUrl = 'device url';
|
4153
4499
|
meeting.selfId = 'self id';
|
4154
4500
|
meeting.brbState = createBrbState(meeting, false);
|
4155
|
-
meeting.brbState
|
4501
|
+
sinon.stub(meeting.brbState, 'enable').resolves();
|
4156
4502
|
});
|
4157
4503
|
|
4158
4504
|
afterEach(() => {
|
@@ -4216,6 +4562,17 @@ describe('plugin-meetings', () => {
|
|
4216
4562
|
|
4217
4563
|
assert.notCalled(meeting.audio.handleServerRemoteMuteUpdate);
|
4218
4564
|
});
|
4565
|
+
|
4566
|
+
it('should reject when brb enable fails', async () => {
|
4567
|
+
meeting.brbState.enable.restore();
|
4568
|
+
|
4569
|
+
const error = new Error();
|
4570
|
+
meeting.meetingRequest.setBrb = sinon.stub().rejects(error);
|
4571
|
+
|
4572
|
+
await expect(meeting.beRightBack(true)).to.be.rejectedWith(error);
|
4573
|
+
|
4574
|
+
assert.isFalse(meeting.brbState.state.syncToServerInProgress);
|
4575
|
+
});
|
4219
4576
|
});
|
4220
4577
|
});
|
4221
4578
|
|
@@ -5387,6 +5744,7 @@ describe('plugin-meetings', () => {
|
|
5387
5744
|
let multistreamEventListeners;
|
5388
5745
|
let transcodedEventListeners;
|
5389
5746
|
let mockStatsAnalyzerCtor;
|
5747
|
+
let statsMonitorStub;
|
5390
5748
|
|
5391
5749
|
const setupFakeRoapMediaConnection = (fakeRoapMediaConnection, eventListeners) => {
|
5392
5750
|
fakeRoapMediaConnection.on.callsFake((eventName, cb) => {
|
@@ -5418,6 +5776,14 @@ describe('plugin-meetings', () => {
|
|
5418
5776
|
return {on: sinon.stub(), stopAnalyzer: sinon.stub()};
|
5419
5777
|
});
|
5420
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
|
+
|
5421
5787
|
webex.internal.newMetrics.callDiagnosticMetrics.getErrorPayloadForClientErrorCode =
|
5422
5788
|
sinon.stub();
|
5423
5789
|
|
@@ -5480,6 +5846,7 @@ describe('plugin-meetings', () => {
|
|
5480
5846
|
mockStatsAnalyzerCtor,
|
5481
5847
|
sinon.match({
|
5482
5848
|
isMultistream: true,
|
5849
|
+
statsMonitor: statsMonitorStub,
|
5483
5850
|
})
|
5484
5851
|
);
|
5485
5852
|
const initialStatsAnalyzer = mockStatsAnalyzerCtor.returnValues[0];
|
@@ -6362,25 +6729,36 @@ describe('plugin-meetings', () => {
|
|
6362
6729
|
const DIAL_IN_URL = meeting.dialInUrl;
|
6363
6730
|
|
6364
6731
|
assert.calledWith(meeting.meetingRequest.dialIn, {
|
6365
|
-
correlationId: meeting.
|
6732
|
+
correlationId: meeting.pstnCorrelationId,
|
6366
6733
|
dialInUrl: DIAL_IN_URL,
|
6367
6734
|
locusUrl: meeting.locusUrl,
|
6368
6735
|
clientUrl: meeting.deviceUrl,
|
6369
6736
|
});
|
6370
6737
|
assert.notCalled(meeting.meetingRequest.dialOut);
|
6371
6738
|
|
6739
|
+
// Verify pstnCorrelationId was set
|
6740
|
+
assert.exists(meeting.pstnCorrelationId);
|
6741
|
+
assert.notEqual(meeting.pstnCorrelationId, meeting.correlationId);
|
6742
|
+
const firstPstnCorrelationId = meeting.pstnCorrelationId
|
6743
|
+
|
6372
6744
|
meeting.meetingRequest.dialIn.resetHistory();
|
6373
6745
|
|
6374
6746
|
// try again. the dial in urls should match
|
6375
6747
|
await meeting.usePhoneAudio();
|
6376
6748
|
|
6377
6749
|
assert.calledWith(meeting.meetingRequest.dialIn, {
|
6378
|
-
correlationId: meeting.
|
6750
|
+
correlationId: meeting.pstnCorrelationId,
|
6379
6751
|
dialInUrl: DIAL_IN_URL,
|
6380
6752
|
locusUrl: meeting.locusUrl,
|
6381
6753
|
clientUrl: meeting.deviceUrl,
|
6382
6754
|
});
|
6383
6755
|
assert.notCalled(meeting.meetingRequest.dialOut);
|
6756
|
+
// A new PSTN correlationId should be generated for the second attempt
|
6757
|
+
assert.notEqual(
|
6758
|
+
meeting.pstnCorrelationId,
|
6759
|
+
firstPstnCorrelationId,
|
6760
|
+
'pstnCorrelationId should be regenerated on each dial-in attempt'
|
6761
|
+
);
|
6384
6762
|
});
|
6385
6763
|
|
6386
6764
|
it('given a phone number, triggers dial-out, delegating request to meetingRequest correctly', async () => {
|
@@ -6390,7 +6768,7 @@ describe('plugin-meetings', () => {
|
|
6390
6768
|
const DIAL_OUT_URL = meeting.dialOutUrl;
|
6391
6769
|
|
6392
6770
|
assert.calledWith(meeting.meetingRequest.dialOut, {
|
6393
|
-
correlationId: meeting.
|
6771
|
+
correlationId: meeting.pstnCorrelationId,
|
6394
6772
|
dialOutUrl: DIAL_OUT_URL,
|
6395
6773
|
locusUrl: meeting.locusUrl,
|
6396
6774
|
clientUrl: meeting.deviceUrl,
|
@@ -6398,49 +6776,126 @@ describe('plugin-meetings', () => {
|
|
6398
6776
|
});
|
6399
6777
|
assert.notCalled(meeting.meetingRequest.dialIn);
|
6400
6778
|
|
6779
|
+
// Verify pstnCorrelationId was set
|
6780
|
+
assert.exists(meeting.pstnCorrelationId);
|
6781
|
+
assert.notEqual(meeting.pstnCorrelationId, meeting.correlationId);
|
6782
|
+
const firstPstnCorrelationId = meeting.pstnCorrelationId;
|
6783
|
+
|
6401
6784
|
meeting.meetingRequest.dialOut.resetHistory();
|
6402
6785
|
|
6403
6786
|
// try again. the dial out urls should match
|
6404
6787
|
await meeting.usePhoneAudio(phoneNumber);
|
6405
6788
|
|
6406
6789
|
assert.calledWith(meeting.meetingRequest.dialOut, {
|
6407
|
-
correlationId: meeting.
|
6790
|
+
correlationId: meeting.pstnCorrelationId,
|
6408
6791
|
dialOutUrl: DIAL_OUT_URL,
|
6409
6792
|
locusUrl: meeting.locusUrl,
|
6410
6793
|
clientUrl: meeting.deviceUrl,
|
6411
6794
|
phoneNumber,
|
6412
6795
|
});
|
6413
6796
|
assert.notCalled(meeting.meetingRequest.dialIn);
|
6797
|
+
// A new PSTN correlationId should be generated for the second attempt
|
6798
|
+
assert.notEqual(
|
6799
|
+
meeting.pstnCorrelationId,
|
6800
|
+
firstPstnCorrelationId,
|
6801
|
+
'pstnCorrelationId should be regenerated on each dial-out attempt'
|
6802
|
+
);
|
6414
6803
|
});
|
6415
6804
|
|
6416
|
-
it('rejects if the request failed (dial in)', () => {
|
6417
|
-
const error = '
|
6805
|
+
it('rejects if the request failed (dial in)', async () => {
|
6806
|
+
const error = {error: {message: 'dial in failed'}, stack: 'error stack'};
|
6418
6807
|
|
6419
6808
|
meeting.meetingRequest.dialIn = sinon.stub().returns(Promise.reject(error));
|
6420
6809
|
|
6421
|
-
|
6422
|
-
.usePhoneAudio()
|
6423
|
-
|
6424
|
-
|
6425
|
-
|
6810
|
+
try {
|
6811
|
+
await meeting.usePhoneAudio();
|
6812
|
+
throw new Error('Promise resolved when it should have rejected');
|
6813
|
+
} catch (e) {
|
6814
|
+
assert.equal(e, error);
|
6426
6815
|
|
6427
|
-
|
6816
|
+
// Verify behavioral metric was sent with dial_in_correlation_id
|
6817
|
+
assert.calledWith(Metrics.sendBehavioralMetric, BEHAVIORAL_METRICS.ADD_DIAL_IN_FAILURE, {
|
6818
|
+
correlation_id: meeting.correlationId,
|
6819
|
+
dial_in_url: meeting.dialInUrl,
|
6820
|
+
dial_in_correlation_id: sinon.match.string,
|
6821
|
+
locus_id: meeting.locusUrl.split('/').pop(),
|
6822
|
+
client_url: meeting.deviceUrl,
|
6823
|
+
reason: error.error.message,
|
6824
|
+
stack: error.stack,
|
6428
6825
|
});
|
6826
|
+
|
6827
|
+
// Verify pstnCorrelationId was cleared after error
|
6828
|
+
assert.equal(meeting.pstnCorrelationId, undefined);
|
6829
|
+
}
|
6429
6830
|
});
|
6430
6831
|
|
6431
6832
|
it('rejects if the request failed (dial out)', async () => {
|
6432
|
-
const error = '
|
6833
|
+
const error = {error: {message: 'dial out failed'}, stack: 'error stack'};
|
6433
6834
|
|
6434
6835
|
meeting.meetingRequest.dialOut = sinon.stub().returns(Promise.reject(error));
|
6435
6836
|
|
6436
|
-
|
6437
|
-
.usePhoneAudio('+441234567890')
|
6438
|
-
|
6439
|
-
|
6440
|
-
|
6837
|
+
try {
|
6838
|
+
await meeting.usePhoneAudio('+441234567890');
|
6839
|
+
throw new Error('Promise resolved when it should have rejected');
|
6840
|
+
} catch (e) {
|
6841
|
+
assert.equal(e, error);
|
6441
6842
|
|
6442
|
-
|
6843
|
+
// Verify behavioral metric was sent with dial_out_correlation_id
|
6844
|
+
assert.calledWith(Metrics.sendBehavioralMetric, BEHAVIORAL_METRICS.ADD_DIAL_OUT_FAILURE, {
|
6845
|
+
correlation_id: meeting.correlationId,
|
6846
|
+
dial_out_url: meeting.dialOutUrl,
|
6847
|
+
dial_out_correlation_id: sinon.match.string,
|
6848
|
+
locus_id: meeting.locusUrl.split('/').pop(),
|
6849
|
+
client_url: meeting.deviceUrl,
|
6850
|
+
reason: error.error.message,
|
6851
|
+
stack: error.stack,
|
6443
6852
|
});
|
6853
|
+
|
6854
|
+
// Verify pstnCorrelationId was cleared after error
|
6855
|
+
assert.equal(meeting.pstnCorrelationId, undefined);
|
6856
|
+
}
|
6857
|
+
});
|
6858
|
+
});
|
6859
|
+
|
6860
|
+
describe('#disconnectPhoneAudio', () => {
|
6861
|
+
beforeEach(() => {
|
6862
|
+
// Mock the MeetingUtil.disconnectPhoneAudio method
|
6863
|
+
sinon.stub(MeetingUtil, 'disconnectPhoneAudio').resolves();
|
6864
|
+
meeting.dialInUrl = 'dialin:///test-dial-in-url';
|
6865
|
+
meeting.dialOutUrl = 'dialout:///test-dial-out-url';
|
6866
|
+
meeting.dialInDeviceStatus = 'JOINED';
|
6867
|
+
meeting.dialOutDeviceStatus = 'JOINED';
|
6868
|
+
});
|
6869
|
+
|
6870
|
+
afterEach(() => {
|
6871
|
+
MeetingUtil.disconnectPhoneAudio.restore();
|
6872
|
+
});
|
6873
|
+
|
6874
|
+
it('should disconnect phone audio and clear pstnCorrelationId', async () => {
|
6875
|
+
meeting.pstnCorrelationId = 'test-pstn-correlation-id';
|
6876
|
+
|
6877
|
+
await meeting.disconnectPhoneAudio();
|
6878
|
+
|
6879
|
+
// Verify that pstnCorrelationId is cleared
|
6880
|
+
assert.equal(meeting.pstnCorrelationId, undefined);
|
6881
|
+
|
6882
|
+
// Verify that MeetingUtil.disconnectPhoneAudio was called for both dial-in and dial-out
|
6883
|
+
assert.calledTwice(MeetingUtil.disconnectPhoneAudio);
|
6884
|
+
assert.calledWith(MeetingUtil.disconnectPhoneAudio, meeting, meeting.dialInUrl);
|
6885
|
+
assert.calledWith(MeetingUtil.disconnectPhoneAudio, meeting, meeting.dialOutUrl);
|
6886
|
+
});
|
6887
|
+
|
6888
|
+
it('should handle case when no PSTN connection is active', async () => {
|
6889
|
+
meeting.dialInDeviceStatus = 'IDLE';
|
6890
|
+
meeting.dialOutDeviceStatus = 'IDLE';
|
6891
|
+
meeting.pstnCorrelationId = 'test-pstn-correlation-id';
|
6892
|
+
|
6893
|
+
await meeting.disconnectPhoneAudio();
|
6894
|
+
|
6895
|
+
// Verify that pstnCorrelationId is still cleared even when no phone connection is active
|
6896
|
+
assert.equal(meeting.pstnCorrelationId, undefined);
|
6897
|
+
// And verify no disconnect was attempted
|
6898
|
+
assert.notCalled(MeetingUtil.disconnectPhoneAudio);
|
6444
6899
|
});
|
6445
6900
|
});
|
6446
6901
|
|
@@ -7194,6 +7649,8 @@ describe('plugin-meetings', () => {
|
|
7194
7649
|
'locus-id',
|
7195
7650
|
{extraParam1: 'value1', permissionToken: FAKE_PERMISSION_TOKEN},
|
7196
7651
|
{meetingId: meeting.id, sendCAevents: true},
|
7652
|
+
null,
|
7653
|
+
null,
|
7197
7654
|
null
|
7198
7655
|
);
|
7199
7656
|
assert.deepEqual(meeting.meetingInfo, {
|
@@ -7240,6 +7697,8 @@ describe('plugin-meetings', () => {
|
|
7240
7697
|
'locus-id',
|
7241
7698
|
{extraParam1: 'value1', permissionToken: FAKE_PERMISSION_TOKEN},
|
7242
7699
|
{meetingId: meeting.id, sendCAevents: true},
|
7700
|
+
null,
|
7701
|
+
null,
|
7243
7702
|
null
|
7244
7703
|
);
|
7245
7704
|
assert.deepEqual(meeting.meetingInfo, {
|
@@ -7295,6 +7754,8 @@ describe('plugin-meetings', () => {
|
|
7295
7754
|
permissionToken: FAKE_PERMISSION_TOKEN,
|
7296
7755
|
},
|
7297
7756
|
{meetingId: meeting.id, sendCAevents: true},
|
7757
|
+
null,
|
7758
|
+
null,
|
7298
7759
|
null
|
7299
7760
|
);
|
7300
7761
|
assert.deepEqual(meeting.meetingInfo, {
|
@@ -7957,6 +8418,7 @@ describe('plugin-meetings', () => {
|
|
7957
8418
|
|
7958
8419
|
meeting.requestScreenShareFloor = sinon.stub().resolves({});
|
7959
8420
|
meeting.releaseScreenShareFloor = sinon.stub().resolves({});
|
8421
|
+
webex.internal.newMetrics.callDiagnosticLatencies.saveTimestamp = sinon.stub();
|
7960
8422
|
meeting.mediaProperties.mediaDirection = {
|
7961
8423
|
sendAudio: 'fake value', // using non-boolean here so that we can check that these values are untouched in tests
|
7962
8424
|
sendVideo: 'fake value',
|
@@ -8038,6 +8500,12 @@ describe('plugin-meetings', () => {
|
|
8038
8500
|
payload: {mediaType: 'share', shareInstanceId: meeting.localShareInstanceId},
|
8039
8501
|
options: {meetingId: meeting.id},
|
8040
8502
|
});
|
8503
|
+
|
8504
|
+
// ensure the share start timestamp is saved
|
8505
|
+
assert.calledWith(webex.internal.newMetrics.callDiagnosticLatencies.saveTimestamp, {
|
8506
|
+
key: 'internal.client.share.initiated',
|
8507
|
+
});
|
8508
|
+
|
8041
8509
|
assert.equal(meeting.mediaProperties.mediaDirection.sendShare, true);
|
8042
8510
|
|
8043
8511
|
assert.equal(meeting.shareCAEventSentStatus.transmitStart, false);
|
@@ -8056,6 +8524,11 @@ describe('plugin-meetings', () => {
|
|
8056
8524
|
options: {meetingId: meeting.id},
|
8057
8525
|
});
|
8058
8526
|
|
8527
|
+
// ensure the share start timestamp is saved
|
8528
|
+
assert.calledWith(webex.internal.newMetrics.callDiagnosticLatencies.saveTimestamp, {
|
8529
|
+
key: 'internal.client.share.initiated',
|
8530
|
+
});
|
8531
|
+
|
8059
8532
|
assert.calledWith(
|
8060
8533
|
meeting.sendSlotManager.getSlot(MediaType.AudioSlides).publishStream,
|
8061
8534
|
stream
|
@@ -8724,11 +9197,16 @@ describe('plugin-meetings', () => {
|
|
8724
9197
|
meeting.hasMediaConnectionConnectedAtLeastOnce = false;
|
8725
9198
|
meeting.setupMediaConnectionListeners();
|
8726
9199
|
|
9200
|
+
sinon.stub(MeetingUtil, 'getCaEventLabelsForIpVersion').returns(['fake labels']);
|
9201
|
+
|
8727
9202
|
simulateConnectionStateChange(ConnectionState.Connecting);
|
8728
9203
|
|
8729
9204
|
assert.calledOnce(webex.internal.newMetrics.submitClientEvent);
|
8730
9205
|
assert.calledWithMatch(webex.internal.newMetrics.submitClientEvent, {
|
8731
9206
|
name: 'client.ice.start',
|
9207
|
+
payload: {
|
9208
|
+
labels: ['fake labels'],
|
9209
|
+
},
|
8732
9210
|
options: {
|
8733
9211
|
meetingId: meeting.id,
|
8734
9212
|
},
|
@@ -10011,6 +10489,24 @@ describe('plugin-meetings', () => {
|
|
10011
10489
|
);
|
10012
10490
|
});
|
10013
10491
|
|
10492
|
+
it('listens to CONTROLS_POLLING_QA_CHANGED', async () => {
|
10493
|
+
const state = {example: 'value'};
|
10494
|
+
|
10495
|
+
await meeting.locusInfo.emitScoped(
|
10496
|
+
{function: 'test', file: 'test'},
|
10497
|
+
LOCUSINFO.EVENTS.CONTROLS_POLLING_QA_CHANGED,
|
10498
|
+
{state}
|
10499
|
+
);
|
10500
|
+
|
10501
|
+
assert.calledWith(
|
10502
|
+
TriggerProxy.trigger,
|
10503
|
+
meeting,
|
10504
|
+
{file: 'meeting/index', function: 'setupLocusControlsListener'},
|
10505
|
+
EVENT_TRIGGERS.MEETING_CONTROLS_POLLING_QA_UPDATED,
|
10506
|
+
{state}
|
10507
|
+
);
|
10508
|
+
});
|
10509
|
+
|
10014
10510
|
it('listens to the locus interpretation update event', () => {
|
10015
10511
|
const interpretation = {
|
10016
10512
|
siLanguages: [{languageCode: 20, languageName: 'en'}],
|
@@ -10311,6 +10807,8 @@ describe('plugin-meetings', () => {
|
|
10311
10807
|
meeting.mediaProperties = {mediaDirection: {sendShare: true}};
|
10312
10808
|
meeting.meetingRequest.changeMeetingFloor = sinon.stub().returns(Promise.resolve());
|
10313
10809
|
(meeting.deviceUrl = 'deviceUrl.com'), (meeting.localShareInstanceId = '1234-5678');
|
10810
|
+
webex.internal.newMetrics.callDiagnosticLatencies.saveTimestamp = sinon.stub();
|
10811
|
+
webex.internal.newMetrics.callDiagnosticLatencies.getShareDuration = sinon.stub().returns(1000);
|
10314
10812
|
});
|
10315
10813
|
it('should call changeMeetingFloor()', async () => {
|
10316
10814
|
meeting.screenShareFloorState = 'GRANTED';
|
@@ -10328,6 +10826,22 @@ describe('plugin-meetings', () => {
|
|
10328
10826
|
assert.exists(share.then);
|
10329
10827
|
await share;
|
10330
10828
|
assert.calledOnce(meeting.meetingRequest.changeMeetingFloor);
|
10829
|
+
|
10830
|
+
// ensure the share stop timestamp is saved
|
10831
|
+
assert.calledWith(webex.internal.newMetrics.callDiagnosticLatencies.saveTimestamp, {
|
10832
|
+
key: 'internal.client.share.stopped',
|
10833
|
+
});
|
10834
|
+
|
10835
|
+
// ensure the CA share stopped metric is submitted with duration
|
10836
|
+
assert.calledWith(webex.internal.newMetrics.submitClientEvent, {
|
10837
|
+
name: 'client.share.stopped',
|
10838
|
+
payload: {
|
10839
|
+
mediaType: 'share',
|
10840
|
+
shareInstanceId: meeting.localShareInstanceId,
|
10841
|
+
shareDuration: 1000,
|
10842
|
+
},
|
10843
|
+
options: {meetingId: meeting.id},
|
10844
|
+
});
|
10331
10845
|
});
|
10332
10846
|
it('should not call changeMeetingFloor() if someone else already has the floor', async () => {
|
10333
10847
|
// change selfId so that it doesn't match the beneficiary id from meeting.locusInfo.mediaShares
|
@@ -10911,6 +11425,7 @@ describe('plugin-meetings', () => {
|
|
10911
11425
|
let canUserRenameOthersSpy;
|
10912
11426
|
let canShareWhiteBoardSpy;
|
10913
11427
|
let canMoveToLobbySpy;
|
11428
|
+
let isSpokenLanguageAutoDetectionEnabledSpy;
|
10914
11429
|
// Due to import tree issues, hasHints must be stubed within the scope of the `it`.
|
10915
11430
|
|
10916
11431
|
beforeEach(() => {
|
@@ -10942,6 +11457,8 @@ describe('plugin-meetings', () => {
|
|
10942
11457
|
canUserRenameOthersSpy = sinon.spy(MeetingUtil, 'canUserRenameOthers');
|
10943
11458
|
canShareWhiteBoardSpy = sinon.spy(MeetingUtil, 'canShareWhiteBoard');
|
10944
11459
|
canMoveToLobbySpy = sinon.spy(MeetingUtil, 'canMoveToLobby');
|
11460
|
+
isSpokenLanguageAutoDetectionEnabledSpy = sinon.spy(MeetingUtil, 'isSpokenLanguageAutoDetectionEnabled');
|
11461
|
+
|
10945
11462
|
});
|
10946
11463
|
|
10947
11464
|
afterEach(() => {
|
@@ -11494,6 +12011,7 @@ describe('plugin-meetings', () => {
|
|
11494
12011
|
assert.calledWith(canUserRenameOthersSpy, userDisplayHints);
|
11495
12012
|
assert.calledWith(canShareWhiteBoardSpy, userDisplayHints, selfUserPolicies);
|
11496
12013
|
assert.calledWith(canMoveToLobbySpy, userDisplayHints);
|
12014
|
+
assert.calledWith(isSpokenLanguageAutoDetectionEnabledSpy, userDisplayHints);
|
11497
12015
|
|
11498
12016
|
assert.calledWith(ControlsOptionsUtil.hasHints, {
|
11499
12017
|
requiredHints: [DISPLAY_HINTS.MUTE_ALL],
|
@@ -11603,6 +12121,14 @@ describe('plugin-meetings', () => {
|
|
11603
12121
|
requiredHints: [DISPLAY_HINTS.DISABLE_RDC_MEETING_OPTION],
|
11604
12122
|
displayHints: userDisplayHints,
|
11605
12123
|
});
|
12124
|
+
assert.calledWith(ControlsOptionsUtil.hasHints, {
|
12125
|
+
requiredHints: [DISPLAY_HINTS.ENABLE_ATTENDEE_START_POLLING_QA],
|
12126
|
+
displayHints: userDisplayHints,
|
12127
|
+
});
|
12128
|
+
assert.calledWith(ControlsOptionsUtil.hasHints, {
|
12129
|
+
requiredHints: [DISPLAY_HINTS.DISABLE_ATTENDEE_START_POLLING_QA],
|
12130
|
+
displayHints: userDisplayHints,
|
12131
|
+
});
|
11606
12132
|
|
11607
12133
|
assert.calledWith(
|
11608
12134
|
TriggerProxy.trigger,
|
@@ -11892,6 +12418,7 @@ describe('plugin-meetings', () => {
|
|
11892
12418
|
meeting.locusInfo.self = {url: url1};
|
11893
12419
|
meeting.meetingRequest.changeMeetingFloor = sinon.stub().returns(Promise.resolve());
|
11894
12420
|
meeting.deviceUrl = 'deviceUrl.com';
|
12421
|
+
webex.internal.newMetrics.callDiagnosticLatencies.saveTimestamp = sinon.stub();
|
11895
12422
|
});
|
11896
12423
|
it('should have #startWhiteboardShare', () => {
|
11897
12424
|
assert.exists(meeting.startWhiteboardShare);
|
@@ -11919,6 +12446,11 @@ describe('plugin-meetings', () => {
|
|
11919
12446
|
payload: {mediaType: 'whiteboard'},
|
11920
12447
|
options: {meetingId: meeting.id},
|
11921
12448
|
});
|
12449
|
+
|
12450
|
+
// ensure the share start timestamp is saved
|
12451
|
+
assert.calledWith(webex.internal.newMetrics.callDiagnosticLatencies.saveTimestamp, {
|
12452
|
+
key: 'internal.client.share.initiated',
|
12453
|
+
});
|
11922
12454
|
});
|
11923
12455
|
});
|
11924
12456
|
describe('#stopWhiteboardShare', () => {
|
@@ -11930,6 +12462,9 @@ describe('plugin-meetings', () => {
|
|
11930
12462
|
meeting.locusInfo.self = {url: url1};
|
11931
12463
|
meeting.meetingRequest.changeMeetingFloor = sinon.stub().returns(Promise.resolve());
|
11932
12464
|
meeting.deviceUrl = 'deviceUrl.com';
|
12465
|
+
webex.internal.newMetrics.callDiagnosticLatencies.saveTimestamp = sinon.stub();
|
12466
|
+
webex.internal.newMetrics.callDiagnosticLatencies.getShareDuration = sinon.stub().returns(1000);
|
12467
|
+
webex.internal.newMetrics.submitClientEvent = sinon.stub();
|
11933
12468
|
});
|
11934
12469
|
it('should stop the whiteboard share', async () => {
|
11935
12470
|
const whiteboardShare = meeting.stopWhiteboardShare();
|
@@ -11944,6 +12479,21 @@ describe('plugin-meetings', () => {
|
|
11944
12479
|
uri: url1,
|
11945
12480
|
});
|
11946
12481
|
assert.calledOnce(meeting.meetingRequest.changeMeetingFloor);
|
12482
|
+
|
12483
|
+
// ensure the share stop timestamp is saved
|
12484
|
+
assert.calledWith(webex.internal.newMetrics.callDiagnosticLatencies.saveTimestamp, {
|
12485
|
+
key: 'internal.client.share.stopped',
|
12486
|
+
});
|
12487
|
+
|
12488
|
+
// ensure the CA share stopped metric is submitted with duration
|
12489
|
+
assert.calledWith(webex.internal.newMetrics.submitClientEvent, {
|
12490
|
+
name: 'client.share.stopped',
|
12491
|
+
payload: {
|
12492
|
+
mediaType: 'whiteboard',
|
12493
|
+
shareDuration: 1000,
|
12494
|
+
},
|
12495
|
+
options: {meetingId: meeting.id},
|
12496
|
+
});
|
11947
12497
|
});
|
11948
12498
|
});
|
11949
12499
|
});
|
@@ -12016,6 +12566,9 @@ describe('plugin-meetings', () => {
|
|
12016
12566
|
meeting.selfId = '9528d952-e4de-46cf-8157-fd4823b98377';
|
12017
12567
|
meeting.deviceUrl = 'my-web-url';
|
12018
12568
|
meeting.locusInfo.info = {isWebinar: false};
|
12569
|
+
webex.internal.newMetrics.callDiagnosticLatencies.saveTimestamp = sinon.stub();
|
12570
|
+
webex.internal.newMetrics.callDiagnosticLatencies.getShareDuration = sinon.stub().returns(1500);
|
12571
|
+
webex.internal.newMetrics.submitClientEvent = sinon.stub();
|
12019
12572
|
});
|
12020
12573
|
|
12021
12574
|
const USER_IDS = {
|
@@ -12242,12 +12795,12 @@ describe('plugin-meetings', () => {
|
|
12242
12795
|
activeSharingId.whiteboard = beneficiaryId;
|
12243
12796
|
|
12244
12797
|
eventTrigger.share.push(
|
12245
|
-
meeting.webinar.selfIsAttendee
|
12798
|
+
meeting.webinar.selfIsAttendee || meeting.guest
|
12246
12799
|
? {
|
12247
12800
|
eventName: EVENT_TRIGGERS.MEETING_STARTED_SHARING_REMOTE,
|
12248
12801
|
functionName: 'remoteShare',
|
12249
12802
|
eventPayload: {
|
12250
|
-
memberId: null,
|
12803
|
+
memberId: meeting.webinar.selfIsAttendee ? beneficiaryId : null,
|
12251
12804
|
url,
|
12252
12805
|
shareInstanceId,
|
12253
12806
|
annotationInfo: undefined,
|
@@ -12261,7 +12814,8 @@ describe('plugin-meetings', () => {
|
|
12261
12814
|
}
|
12262
12815
|
);
|
12263
12816
|
|
12264
|
-
shareStatus =
|
12817
|
+
shareStatus =
|
12818
|
+
meeting.webinar.selfIsAttendee || meeting.guest
|
12265
12819
|
? SHARE_STATUS.REMOTE_SHARE_ACTIVE
|
12266
12820
|
: SHARE_STATUS.WHITEBOARD_SHARE_ACTIVE;
|
12267
12821
|
}
|
@@ -12301,7 +12855,7 @@ describe('plugin-meetings', () => {
|
|
12301
12855
|
eventName: EVENT_TRIGGERS.MEETING_STARTED_SHARING_REMOTE,
|
12302
12856
|
functionName: 'remoteShare',
|
12303
12857
|
eventPayload: {
|
12304
|
-
memberId:
|
12858
|
+
memberId: beneficiaryId,
|
12305
12859
|
url,
|
12306
12860
|
shareInstanceId,
|
12307
12861
|
annotationInfo: undefined,
|
@@ -12479,6 +13033,36 @@ describe('plugin-meetings', () => {
|
|
12479
13033
|
});
|
12480
13034
|
});
|
12481
13035
|
|
13036
|
+
describe('Whiteboard Share - User is guest', () => {
|
13037
|
+
it('User receives a remote share instead of whiteboard share', () => {
|
13038
|
+
// Set the guest flag
|
13039
|
+
meeting.guest = true;
|
13040
|
+
|
13041
|
+
// Step 1: Start sharing whiteboard A
|
13042
|
+
const data1 = generateData(
|
13043
|
+
blankPayload, // Initial payload
|
13044
|
+
true, // isGranting: Granting share
|
13045
|
+
false, // isContent: Whiteboard (not content)
|
13046
|
+
USER_IDS.REMOTE_A, // Beneficiary ID: Remote user A
|
13047
|
+
RESOURCE_URLS.WHITEBOARD_A // Resource URL: Whiteboard A
|
13048
|
+
);
|
13049
|
+
|
13050
|
+
// Step 2: Stop sharing whiteboard A
|
13051
|
+
const data2 = generateData(
|
13052
|
+
data1.payload, // Updated payload from Step 1
|
13053
|
+
false, // isGranting: Stopping share
|
13054
|
+
false, // isContent: Whiteboard
|
13055
|
+
USER_IDS.REMOTE_A // Beneficiary ID: Remote user A
|
13056
|
+
);
|
13057
|
+
|
13058
|
+
// Validate the payload changes and status updates
|
13059
|
+
payloadTestHelper([data1]);
|
13060
|
+
|
13061
|
+
// Specific assertions for guest
|
13062
|
+
assert.equal(meeting.shareStatus, SHARE_STATUS.REMOTE_SHARE_ACTIVE);
|
13063
|
+
});
|
13064
|
+
});
|
13065
|
+
|
12482
13066
|
describe('Whiteboard A --> Whiteboard B', () => {
|
12483
13067
|
it('Scenario #1: you share both whiteboards', () => {
|
12484
13068
|
const data1 = generateData(
|
@@ -13130,7 +13714,54 @@ describe('plugin-meetings', () => {
|
|
13130
13714
|
payloadTestHelper([data1, data2, data3]);
|
13131
13715
|
});
|
13132
13716
|
});
|
13133
|
-
|
13717
|
+
|
13718
|
+
it('should send share stopped metric when whiteboard sharing stops', () => {
|
13719
|
+
// Start whiteboard sharing (this won't trigger metrics)
|
13720
|
+
const data1 = generateData(
|
13721
|
+
blankPayload,
|
13722
|
+
true, // isGranting: true
|
13723
|
+
false, // isContent: false (whiteboard)
|
13724
|
+
USER_IDS.ME,
|
13725
|
+
RESOURCE_URLS.WHITEBOARD_A
|
13726
|
+
);
|
13727
|
+
|
13728
|
+
// Stop whiteboard sharing (this should trigger metrics)
|
13729
|
+
const data2 = generateData(
|
13730
|
+
data1.payload,
|
13731
|
+
false, // isGranting: false (stopping share)
|
13732
|
+
false, // isContent: false (whiteboard)
|
13733
|
+
USER_IDS.ME
|
13734
|
+
);
|
13735
|
+
|
13736
|
+
// Trigger the events
|
13737
|
+
meeting.locusInfo.emit(
|
13738
|
+
{function: 'test', file: 'test'},
|
13739
|
+
EVENTS.LOCUS_INFO_UPDATE_MEDIA_SHARES,
|
13740
|
+
data1.payload
|
13741
|
+
);
|
13742
|
+
|
13743
|
+
meeting.locusInfo.emit(
|
13744
|
+
{function: 'test', file: 'test'},
|
13745
|
+
EVENTS.LOCUS_INFO_UPDATE_MEDIA_SHARES,
|
13746
|
+
data2.payload
|
13747
|
+
);
|
13748
|
+
|
13749
|
+
// Verify metrics were called when whiteboard sharing stopped
|
13750
|
+
assert.calledWith(webex.internal.newMetrics.callDiagnosticLatencies.saveTimestamp, {
|
13751
|
+
key: 'internal.client.share.stopped',
|
13752
|
+
});
|
13753
|
+
|
13754
|
+
assert.calledWith(webex.internal.newMetrics.submitClientEvent, {
|
13755
|
+
name: 'client.share.stopped',
|
13756
|
+
payload: {
|
13757
|
+
mediaType: 'whiteboard',
|
13758
|
+
shareDuration: 1500, // mocked return value
|
13759
|
+
},
|
13760
|
+
options: {
|
13761
|
+
meetingId: meeting.id,
|
13762
|
+
},
|
13763
|
+
});
|
13764
|
+
});
|
13134
13765
|
|
13135
13766
|
describe('handleShareVideoStreamMuteStateChange', () => {
|
13136
13767
|
it('should emit MEETING_SHARE_VIDEO_MUTE_STATE_CHANGE event with correct fields', () => {
|
@@ -13157,6 +13788,7 @@ describe('plugin-meetings', () => {
|
|
13157
13788
|
});
|
13158
13789
|
});
|
13159
13790
|
});
|
13791
|
+
});
|
13160
13792
|
|
13161
13793
|
describe('#startKeepAlive', () => {
|
13162
13794
|
let clock;
|
@@ -13923,4 +14555,469 @@ describe('plugin-meetings', () => {
|
|
13923
14555
|
assert.equal(result.failureReason, MEETING_INFO_FAILURE_REASON.WRONG_CAPTCHA);
|
13924
14556
|
});
|
13925
14557
|
});
|
14558
|
+
|
14559
|
+
describe('#setStage', () => {
|
14560
|
+
const check = async (options, expectedVideoLayout) => {
|
14561
|
+
const locusUrl = `https://locus-test.wbx2.com/locus/api/v1/loci/${uuidv4()}`;
|
14562
|
+
meeting.locusUrl = locusUrl;
|
14563
|
+
|
14564
|
+
const setStagePromise = meeting.setStage(options);
|
14565
|
+
|
14566
|
+
assert.exists(setStagePromise.then);
|
14567
|
+
await setStagePromise;
|
14568
|
+
|
14569
|
+
assert.calledOnceWithExactly(
|
14570
|
+
meeting.meetingRequest.synchronizeStage,
|
14571
|
+
locusUrl,
|
14572
|
+
expectedVideoLayout
|
14573
|
+
);
|
14574
|
+
};
|
14575
|
+
|
14576
|
+
beforeEach(() => {
|
14577
|
+
meeting.meetingRequest.synchronizeStage = sinon.stub().returns(Promise.resolve());
|
14578
|
+
});
|
14579
|
+
|
14580
|
+
it('sends the expected request when no options are provided', async () => {
|
14581
|
+
await check(undefined, {
|
14582
|
+
overrideDefault: true,
|
14583
|
+
lockAttendeeViewOnStageOnly: false,
|
14584
|
+
stageParameters: {
|
14585
|
+
activeSpeakerProportion: 0.5,
|
14586
|
+
showActiveSpeaker: {show: false, order: 0},
|
14587
|
+
stageManagerType: 0,
|
14588
|
+
},
|
14589
|
+
});
|
14590
|
+
});
|
14591
|
+
|
14592
|
+
it('sends the expected request when empty options are provided', async () => {
|
14593
|
+
await check(
|
14594
|
+
{},
|
14595
|
+
{
|
14596
|
+
overrideDefault: true,
|
14597
|
+
lockAttendeeViewOnStageOnly: false,
|
14598
|
+
stageParameters: {
|
14599
|
+
activeSpeakerProportion: 0.5,
|
14600
|
+
showActiveSpeaker: {show: false, order: 0},
|
14601
|
+
stageManagerType: 0,
|
14602
|
+
},
|
14603
|
+
}
|
14604
|
+
);
|
14605
|
+
});
|
14606
|
+
|
14607
|
+
[0.25, 0.5, 0.75].forEach((activeSpeakerProportion) => {
|
14608
|
+
it(`sends the expected request when only the active speaker proportion option is provided as ${activeSpeakerProportion}`, async () => {
|
14609
|
+
await check(
|
14610
|
+
{activeSpeakerProportion},
|
14611
|
+
{
|
14612
|
+
overrideDefault: true,
|
14613
|
+
lockAttendeeViewOnStageOnly: false,
|
14614
|
+
stageParameters: {
|
14615
|
+
activeSpeakerProportion,
|
14616
|
+
showActiveSpeaker: {show: false, order: 0},
|
14617
|
+
stageManagerType: 0,
|
14618
|
+
},
|
14619
|
+
}
|
14620
|
+
);
|
14621
|
+
});
|
14622
|
+
});
|
14623
|
+
|
14624
|
+
it('sends the expected request when only the custom background option is provided', async () => {
|
14625
|
+
const customBackground = {
|
14626
|
+
url: `https://test.wbx2.com/background/${uuidv4()}.jpg`,
|
14627
|
+
};
|
14628
|
+
|
14629
|
+
await check(
|
14630
|
+
{customBackground},
|
14631
|
+
{
|
14632
|
+
overrideDefault: true,
|
14633
|
+
lockAttendeeViewOnStageOnly: false,
|
14634
|
+
stageParameters: {
|
14635
|
+
activeSpeakerProportion: 0.5,
|
14636
|
+
showActiveSpeaker: {show: false, order: 0},
|
14637
|
+
stageManagerType: 2,
|
14638
|
+
},
|
14639
|
+
customLayouts: {background: customBackground},
|
14640
|
+
}
|
14641
|
+
);
|
14642
|
+
});
|
14643
|
+
|
14644
|
+
it('sends the expected request when only the custom logo option is provided', async () => {
|
14645
|
+
const customLogo = {
|
14646
|
+
url: `https://test.wbx2.com/logo/${uuidv4()}.png`,
|
14647
|
+
position: 'LowerRight',
|
14648
|
+
};
|
14649
|
+
|
14650
|
+
await check(
|
14651
|
+
{customLogo},
|
14652
|
+
{
|
14653
|
+
overrideDefault: true,
|
14654
|
+
lockAttendeeViewOnStageOnly: false,
|
14655
|
+
stageParameters: {
|
14656
|
+
activeSpeakerProportion: 0.5,
|
14657
|
+
showActiveSpeaker: {show: false, order: 0},
|
14658
|
+
stageManagerType: 1,
|
14659
|
+
},
|
14660
|
+
customLayouts: {logo: customLogo},
|
14661
|
+
}
|
14662
|
+
);
|
14663
|
+
});
|
14664
|
+
|
14665
|
+
it('sends the expected request when only the custom name label option is provided', async () => {
|
14666
|
+
const customNameLabel = {
|
14667
|
+
accentColor: '#0A7806',
|
14668
|
+
background: {color: 'rgba(255, 255, 255, 1)'},
|
14669
|
+
border: {color: 'rgba(255, 255, 255, 1)'},
|
14670
|
+
content: {
|
14671
|
+
displayName: {color: 'rgba(0, 0, 0, 0.95)'},
|
14672
|
+
subtitle: {color: 'rgba(0, 0, 0, 0.6)'},
|
14673
|
+
},
|
14674
|
+
decoration: {color: 'rgba(10, 120, 6, 1)'},
|
14675
|
+
fadeOut: {delay: 15},
|
14676
|
+
type: 'Primary',
|
14677
|
+
};
|
14678
|
+
|
14679
|
+
await check(
|
14680
|
+
{customNameLabel},
|
14681
|
+
{
|
14682
|
+
overrideDefault: true,
|
14683
|
+
lockAttendeeViewOnStageOnly: false,
|
14684
|
+
stageParameters: {
|
14685
|
+
activeSpeakerProportion: 0.5,
|
14686
|
+
showActiveSpeaker: {show: false, order: 0},
|
14687
|
+
stageManagerType: 4,
|
14688
|
+
},
|
14689
|
+
nameLabelStyle: customNameLabel,
|
14690
|
+
}
|
14691
|
+
);
|
14692
|
+
});
|
14693
|
+
|
14694
|
+
it('sends the expected request when only the custom background and logo options are provided', async () => {
|
14695
|
+
const customBackground = {
|
14696
|
+
url: `https://test.wbx2.com/background/${uuidv4()}.jpg`,
|
14697
|
+
};
|
14698
|
+
const customLogo = {
|
14699
|
+
url: `https://test.wbx2.com/logo/${uuidv4()}.png`,
|
14700
|
+
position: 'UpperRight',
|
14701
|
+
};
|
14702
|
+
|
14703
|
+
await check(
|
14704
|
+
{customBackground, customLogo},
|
14705
|
+
{
|
14706
|
+
overrideDefault: true,
|
14707
|
+
lockAttendeeViewOnStageOnly: false,
|
14708
|
+
stageParameters: {
|
14709
|
+
activeSpeakerProportion: 0.5,
|
14710
|
+
showActiveSpeaker: {show: false, order: 0},
|
14711
|
+
stageManagerType: 3,
|
14712
|
+
},
|
14713
|
+
customLayouts: {background: customBackground, logo: customLogo},
|
14714
|
+
}
|
14715
|
+
);
|
14716
|
+
});
|
14717
|
+
|
14718
|
+
it('sends the expected request when only the custom background and name label options are provided', async () => {
|
14719
|
+
const customBackground = {
|
14720
|
+
url: `https://test.wbx2.com/background/${uuidv4()}.jpg`,
|
14721
|
+
};
|
14722
|
+
const customNameLabel = {
|
14723
|
+
accentColor: '#00A3FF',
|
14724
|
+
background: {color: 'rgba(0, 163, 255, 1)'},
|
14725
|
+
border: {color: 'rgba(0, 163, 255, 1)'},
|
14726
|
+
content: {
|
14727
|
+
displayName: {color: 'rgba(255, 255, 255, 0.95)'},
|
14728
|
+
subtitle: {color: 'rgba(255, 255, 255, 0.7)'},
|
14729
|
+
},
|
14730
|
+
decoration: {color: 'rgba(255, 255, 255, 0.95)'},
|
14731
|
+
fadeOut: {delay: 15},
|
14732
|
+
type: 'PrimaryInverted',
|
14733
|
+
};
|
14734
|
+
|
14735
|
+
await check(
|
14736
|
+
{customBackground, customNameLabel},
|
14737
|
+
{
|
14738
|
+
overrideDefault: true,
|
14739
|
+
lockAttendeeViewOnStageOnly: false,
|
14740
|
+
stageParameters: {
|
14741
|
+
activeSpeakerProportion: 0.5,
|
14742
|
+
showActiveSpeaker: {show: false, order: 0},
|
14743
|
+
stageManagerType: 6,
|
14744
|
+
},
|
14745
|
+
customLayouts: {background: customBackground},
|
14746
|
+
nameLabelStyle: customNameLabel,
|
14747
|
+
}
|
14748
|
+
);
|
14749
|
+
});
|
14750
|
+
|
14751
|
+
it('sends the expected request when only the custom logo and name label options are provided', async () => {
|
14752
|
+
const customLogo = {
|
14753
|
+
url: `https://test.wbx2.com/logo/${uuidv4()}.png`,
|
14754
|
+
position: 'UpperLeft',
|
14755
|
+
};
|
14756
|
+
const customNameLabel = {
|
14757
|
+
accentColor: '#942B2B',
|
14758
|
+
background: {color: 'rgba(255, 255, 255, 1)'},
|
14759
|
+
border: {color: 'rgba(148, 43, 43, 1)'},
|
14760
|
+
content: {
|
14761
|
+
displayName: {color: 'rgba(0, 0, 0, 0.95)'},
|
14762
|
+
subtitle: {color: 'rgba(0, 0, 0, 0.6)'},
|
14763
|
+
},
|
14764
|
+
decoration: {color: 'rgba(0, 0, 0, 0)'},
|
14765
|
+
fadeOut: {delay: 15},
|
14766
|
+
type: 'Secondary',
|
14767
|
+
};
|
14768
|
+
|
14769
|
+
await check(
|
14770
|
+
{customLogo, customNameLabel},
|
14771
|
+
{
|
14772
|
+
overrideDefault: true,
|
14773
|
+
lockAttendeeViewOnStageOnly: false,
|
14774
|
+
stageParameters: {
|
14775
|
+
activeSpeakerProportion: 0.5,
|
14776
|
+
showActiveSpeaker: {show: false, order: 0},
|
14777
|
+
stageManagerType: 5,
|
14778
|
+
},
|
14779
|
+
customLayouts: {logo: customLogo},
|
14780
|
+
nameLabelStyle: customNameLabel,
|
14781
|
+
}
|
14782
|
+
);
|
14783
|
+
});
|
14784
|
+
|
14785
|
+
it('sends the expected request when only the custom background, logo, name label options are provided', async () => {
|
14786
|
+
const customBackground = {
|
14787
|
+
url: `https://test.wbx2.com/background/${uuidv4()}.jpg`,
|
14788
|
+
};
|
14789
|
+
const customLogo = {
|
14790
|
+
url: `https://test.wbx2.com/logo/${uuidv4()}.png`,
|
14791
|
+
position: 'LowerLeft',
|
14792
|
+
};
|
14793
|
+
const customNameLabel = {
|
14794
|
+
accentColor: '#EBD960',
|
14795
|
+
background: {color: 'rgba(235, 217, 96, 0.55)'},
|
14796
|
+
border: {color: 'rgba(235, 217, 96, 0.55)'},
|
14797
|
+
content: {
|
14798
|
+
displayName: {color: 'rgba(255, 255, 255, 0.95)'},
|
14799
|
+
subtitle: {color: 'rgba(255, 255, 255, 0.7)'},
|
14800
|
+
},
|
14801
|
+
decoration: {color: 'rgba(0, 0, 0, 0)'},
|
14802
|
+
fadeOut: {delay: 15},
|
14803
|
+
type: 'SecondaryInverted',
|
14804
|
+
};
|
14805
|
+
|
14806
|
+
await check(
|
14807
|
+
{customBackground, customLogo, customNameLabel},
|
14808
|
+
{
|
14809
|
+
overrideDefault: true,
|
14810
|
+
lockAttendeeViewOnStageOnly: false,
|
14811
|
+
stageParameters: {
|
14812
|
+
activeSpeakerProportion: 0.5,
|
14813
|
+
showActiveSpeaker: {show: false, order: 0},
|
14814
|
+
stageManagerType: 7,
|
14815
|
+
},
|
14816
|
+
customLayouts: {background: customBackground, logo: customLogo},
|
14817
|
+
nameLabelStyle: customNameLabel,
|
14818
|
+
}
|
14819
|
+
);
|
14820
|
+
});
|
14821
|
+
|
14822
|
+
it('sends the expected request when only the important participants option is provided as empty', async () => {
|
14823
|
+
await check(
|
14824
|
+
{importantParticipants: []},
|
14825
|
+
{
|
14826
|
+
overrideDefault: true,
|
14827
|
+
lockAttendeeViewOnStageOnly: false,
|
14828
|
+
stageParameters: {
|
14829
|
+
activeSpeakerProportion: 0.5,
|
14830
|
+
showActiveSpeaker: {show: false, order: 0},
|
14831
|
+
stageManagerType: 0,
|
14832
|
+
},
|
14833
|
+
}
|
14834
|
+
);
|
14835
|
+
});
|
14836
|
+
|
14837
|
+
it('sends the expected request when only the important participants option is provided as populated', async () => {
|
14838
|
+
const importantParticipants = [
|
14839
|
+
{mainCsi: 11111111, participantId: uuidv4()},
|
14840
|
+
{mainCsi: 22222222, participantId: uuidv4()},
|
14841
|
+
{mainCsi: 33333333, participantId: uuidv4()},
|
14842
|
+
{mainCsi: 44444444, participantId: uuidv4()},
|
14843
|
+
{mainCsi: 55555555, participantId: uuidv4()},
|
14844
|
+
{mainCsi: 66666666, participantId: uuidv4()},
|
14845
|
+
{mainCsi: 77777777, participantId: uuidv4()},
|
14846
|
+
{mainCsi: 88888888, participantId: uuidv4()},
|
14847
|
+
];
|
14848
|
+
|
14849
|
+
await check(
|
14850
|
+
{importantParticipants},
|
14851
|
+
{
|
14852
|
+
overrideDefault: true,
|
14853
|
+
lockAttendeeViewOnStageOnly: false,
|
14854
|
+
stageParameters: {
|
14855
|
+
activeSpeakerProportion: 0.5,
|
14856
|
+
importantParticipants: [
|
14857
|
+
{...importantParticipants[0], order: 1},
|
14858
|
+
{...importantParticipants[1], order: 2},
|
14859
|
+
{...importantParticipants[2], order: 3},
|
14860
|
+
{...importantParticipants[3], order: 4},
|
14861
|
+
{...importantParticipants[4], order: 5},
|
14862
|
+
{...importantParticipants[5], order: 6},
|
14863
|
+
{...importantParticipants[6], order: 7},
|
14864
|
+
{...importantParticipants[7], order: 8},
|
14865
|
+
],
|
14866
|
+
showActiveSpeaker: {show: false, order: 0},
|
14867
|
+
stageManagerType: 0,
|
14868
|
+
},
|
14869
|
+
}
|
14870
|
+
);
|
14871
|
+
});
|
14872
|
+
|
14873
|
+
[false, true].forEach((lockAttendeeViewOnStage) => {
|
14874
|
+
it(`sends the expected request when only the lock attendee view on stage option is provided as ${lockAttendeeViewOnStage}`, async () => {
|
14875
|
+
await check(
|
14876
|
+
{lockAttendeeViewOnStage},
|
14877
|
+
{
|
14878
|
+
overrideDefault: true,
|
14879
|
+
lockAttendeeViewOnStageOnly: lockAttendeeViewOnStage,
|
14880
|
+
stageParameters: {
|
14881
|
+
activeSpeakerProportion: 0.5,
|
14882
|
+
showActiveSpeaker: {show: false, order: 0},
|
14883
|
+
stageManagerType: 0,
|
14884
|
+
},
|
14885
|
+
}
|
14886
|
+
);
|
14887
|
+
});
|
14888
|
+
});
|
14889
|
+
|
14890
|
+
[false, true].forEach((showActiveSpeaker) => {
|
14891
|
+
it(`sends the expected request when only the show active speaker option is provided as ${showActiveSpeaker}`, async () => {
|
14892
|
+
await check(
|
14893
|
+
{showActiveSpeaker},
|
14894
|
+
{
|
14895
|
+
overrideDefault: true,
|
14896
|
+
lockAttendeeViewOnStageOnly: false,
|
14897
|
+
stageParameters: {
|
14898
|
+
activeSpeakerProportion: 0.5,
|
14899
|
+
showActiveSpeaker: {show: showActiveSpeaker, order: 0},
|
14900
|
+
stageManagerType: 0,
|
14901
|
+
},
|
14902
|
+
}
|
14903
|
+
);
|
14904
|
+
});
|
14905
|
+
});
|
14906
|
+
|
14907
|
+
it('sends the expected request when all options are provided', async () => {
|
14908
|
+
const activeSpeakerProportion = 0.6;
|
14909
|
+
const customBackground = {
|
14910
|
+
url: `https://test.wbx2.com/background/${uuidv4()}.jpg`,
|
14911
|
+
};
|
14912
|
+
const customLogo = {
|
14913
|
+
url: `https://test.wbx2.com/logo/${uuidv4()}.png`,
|
14914
|
+
position: 'UpperMiddle',
|
14915
|
+
};
|
14916
|
+
const customNameLabel = {
|
14917
|
+
accentColor: '#0A7806',
|
14918
|
+
background: {color: 'rgba(255, 255, 255, 1)'},
|
14919
|
+
border: {color: 'rgba(255, 255, 255, 1)'},
|
14920
|
+
content: {
|
14921
|
+
displayName: {color: 'rgba(0, 0, 0, 0.95)'},
|
14922
|
+
subtitle: {color: 'rgba(0, 0, 0, 0.6)'},
|
14923
|
+
},
|
14924
|
+
decoration: {color: 'rgba(10, 120, 6, 1)'},
|
14925
|
+
fadeOut: {delay: 15},
|
14926
|
+
type: 'Primary',
|
14927
|
+
};
|
14928
|
+
const importantParticipants = [
|
14929
|
+
{mainCsi: 11111111, participantId: uuidv4()},
|
14930
|
+
{mainCsi: 22222222, participantId: uuidv4()},
|
14931
|
+
{mainCsi: 33333333, participantId: uuidv4()},
|
14932
|
+
{mainCsi: 44444444, participantId: uuidv4()},
|
14933
|
+
{mainCsi: 55555555, participantId: uuidv4()},
|
14934
|
+
{mainCsi: 66666666, participantId: uuidv4()},
|
14935
|
+
{mainCsi: 77777777, participantId: uuidv4()},
|
14936
|
+
{mainCsi: 88888888, participantId: uuidv4()},
|
14937
|
+
];
|
14938
|
+
const lockAttendeeViewOnStage = true;
|
14939
|
+
const showActiveSpeaker = true;
|
14940
|
+
|
14941
|
+
await check(
|
14942
|
+
{
|
14943
|
+
activeSpeakerProportion,
|
14944
|
+
customBackground,
|
14945
|
+
customLogo,
|
14946
|
+
customNameLabel,
|
14947
|
+
importantParticipants,
|
14948
|
+
lockAttendeeViewOnStage,
|
14949
|
+
showActiveSpeaker,
|
14950
|
+
},
|
14951
|
+
{
|
14952
|
+
overrideDefault: true,
|
14953
|
+
lockAttendeeViewOnStageOnly: lockAttendeeViewOnStage,
|
14954
|
+
stageParameters: {
|
14955
|
+
activeSpeakerProportion,
|
14956
|
+
importantParticipants: [
|
14957
|
+
{...importantParticipants[0], order: 1},
|
14958
|
+
{...importantParticipants[1], order: 2},
|
14959
|
+
{...importantParticipants[2], order: 3},
|
14960
|
+
{...importantParticipants[3], order: 4},
|
14961
|
+
{...importantParticipants[4], order: 5},
|
14962
|
+
{...importantParticipants[5], order: 6},
|
14963
|
+
{...importantParticipants[6], order: 7},
|
14964
|
+
{...importantParticipants[7], order: 8},
|
14965
|
+
],
|
14966
|
+
showActiveSpeaker: {show: showActiveSpeaker, order: 0},
|
14967
|
+
stageManagerType: 7,
|
14968
|
+
},
|
14969
|
+
customLayouts: {background: customBackground, logo: customLogo},
|
14970
|
+
nameLabelStyle: customNameLabel,
|
14971
|
+
}
|
14972
|
+
);
|
14973
|
+
});
|
14974
|
+
});
|
14975
|
+
|
14976
|
+
describe('#unsetStage', () => {
|
14977
|
+
beforeEach(() => {
|
14978
|
+
meeting.meetingRequest.synchronizeStage = sinon.stub().returns(Promise.resolve());
|
14979
|
+
});
|
14980
|
+
|
14981
|
+
it('sends the expected request', async () => {
|
14982
|
+
const locusUrl = `https://locus-test.wbx2.com/locus/api/v1/loci/${uuidv4()}`;
|
14983
|
+
meeting.locusUrl = locusUrl;
|
14984
|
+
|
14985
|
+
const unsetStagePromise = meeting.unsetStage();
|
14986
|
+
|
14987
|
+
assert.exists(unsetStagePromise.then);
|
14988
|
+
await unsetStagePromise;
|
14989
|
+
|
14990
|
+
assert.calledOnceWithExactly(
|
14991
|
+
meeting.meetingRequest.synchronizeStage,
|
14992
|
+
locusUrl,
|
14993
|
+
{overrideDefault: false}
|
14994
|
+
);
|
14995
|
+
});
|
14996
|
+
});
|
14997
|
+
|
14998
|
+
describe('#notifyHost', () => {
|
14999
|
+
beforeEach(() => {
|
15000
|
+
meeting.meetingRequest.notifyHost = sinon.stub().returns(Promise.resolve());
|
15001
|
+
});
|
15002
|
+
|
15003
|
+
it('sends the expected request', async () => {
|
15004
|
+
meeting.meetingInfo.siteFullUrl = `convergedats.webex.com`;
|
15005
|
+
const meetingUuid = 'meeting-uuid';
|
15006
|
+
const displayName = ['Test', 'User'];
|
15007
|
+
meeting.locusId = 'locusId';
|
15008
|
+
|
15009
|
+
const notifyHostPromise = meeting.notifyHost(meetingUuid, displayName);
|
15010
|
+
|
15011
|
+
assert.exists(notifyHostPromise.then);
|
15012
|
+
await notifyHostPromise;
|
15013
|
+
|
15014
|
+
assert.calledOnceWithExactly(
|
15015
|
+
meeting.meetingRequest.notifyHost,
|
15016
|
+
meeting.meetingInfo.siteFullUrl,
|
15017
|
+
meeting.locusId,
|
15018
|
+
meetingUuid,
|
15019
|
+
displayName,
|
15020
|
+
);
|
15021
|
+
});
|
15022
|
+
});
|
13926
15023
|
});
|