@webex/plugin-meetings 3.8.0 → 3.8.1-next.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/breakouts/breakout.js +1 -1
- package/dist/breakouts/index.js +70 -6
- package/dist/breakouts/index.js.map +1 -1
- package/dist/common/errors/webex-errors.js +12 -2
- package/dist/common/errors/webex-errors.js.map +1 -1
- package/dist/config.js +5 -1
- package/dist/config.js.map +1 -1
- package/dist/constants.js +23 -123
- package/dist/constants.js.map +1 -1
- package/dist/controls-options-manager/enums.js +2 -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 +52 -0
- package/dist/controls-options-manager/util.js.map +1 -1
- package/dist/interpretation/index.js +4 -4
- package/dist/interpretation/index.js.map +1 -1
- package/dist/interpretation/siLanguage.js +1 -1
- package/dist/locus-info/controlsUtils.js +31 -11
- package/dist/locus-info/controlsUtils.js.map +1 -1
- package/dist/locus-info/index.js +83 -12
- package/dist/locus-info/index.js.map +1 -1
- package/dist/locus-info/selfUtils.js +432 -418
- package/dist/locus-info/selfUtils.js.map +1 -1
- package/dist/media/index.js +17 -17
- package/dist/media/index.js.map +1 -1
- package/dist/media/properties.js +94 -6
- package/dist/media/properties.js.map +1 -1
- package/dist/meeting/brbState.js +9 -2
- package/dist/meeting/brbState.js.map +1 -1
- package/dist/meeting/in-meeting-actions.js +17 -1
- package/dist/meeting/in-meeting-actions.js.map +1 -1
- package/dist/meeting/index.js +661 -334
- package/dist/meeting/index.js.map +1 -1
- package/dist/meeting/locusMediaRequest.js +21 -22
- package/dist/meeting/locusMediaRequest.js.map +1 -1
- package/dist/meeting/muteState.js +4 -4
- package/dist/meeting/muteState.js.map +1 -1
- package/dist/meeting/request.js +30 -0
- package/dist/meeting/request.js.map +1 -1
- package/dist/meeting/request.type.js.map +1 -1
- package/dist/meeting/util.js +13 -2
- package/dist/meeting/util.js.map +1 -1
- package/dist/meeting-info/meeting-info-v2.js +373 -68
- package/dist/meeting-info/meeting-info-v2.js.map +1 -1
- package/dist/meeting-info/utilv2.js +5 -1
- package/dist/meeting-info/utilv2.js.map +1 -1
- package/dist/meetings/index.js +136 -1
- package/dist/meetings/index.js.map +1 -1
- package/dist/meetings/util.js +14 -0
- package/dist/meetings/util.js.map +1 -1
- package/dist/member/index.js +55 -9
- package/dist/member/index.js.map +1 -1
- package/dist/member/types.js +3 -0
- package/dist/member/types.js.map +1 -1
- package/dist/member/util.js +335 -353
- package/dist/member/util.js.map +1 -1
- package/dist/members/collection.js.map +1 -1
- package/dist/members/index.js +137 -29
- package/dist/members/index.js.map +1 -1
- package/dist/members/request.js +38 -0
- package/dist/members/request.js.map +1 -1
- package/dist/members/util.js +36 -1
- package/dist/members/util.js.map +1 -1
- package/dist/metrics/constants.js +10 -0
- package/dist/metrics/constants.js.map +1 -1
- package/dist/multistream/remoteMediaManager.js +40 -8
- package/dist/multistream/remoteMediaManager.js.map +1 -1
- package/dist/reachability/clusterReachability.js +63 -27
- package/dist/reachability/clusterReachability.js.map +1 -1
- package/dist/reachability/index.js +112 -47
- package/dist/reachability/index.js.map +1 -1
- package/dist/reachability/reachability.types.js +14 -0
- package/dist/reachability/reachability.types.js.map +1 -1
- package/dist/reachability/request.js +19 -3
- package/dist/reachability/request.js.map +1 -1
- package/dist/reconnection-manager/index.js +2 -2
- package/dist/reconnection-manager/index.js.map +1 -1
- package/dist/recording-controller/util.js +5 -5
- package/dist/recording-controller/util.js.map +1 -1
- package/dist/roap/index.js.map +1 -1
- package/dist/roap/turnDiscovery.js +45 -27
- package/dist/roap/turnDiscovery.js.map +1 -1
- package/dist/roap/types.js +17 -0
- package/dist/roap/types.js.map +1 -0
- package/dist/types/common/errors/webex-errors.d.ts +7 -1
- package/dist/types/config.d.ts +3 -0
- package/dist/types/constants.d.ts +16 -85
- package/dist/types/controls-options-manager/enums.d.ts +3 -1
- package/dist/types/controls-options-manager/types.d.ts +7 -1
- package/dist/types/locus-info/index.d.ts +3 -3
- package/dist/types/locus-info/selfUtils.d.ts +216 -1
- package/dist/types/media/properties.d.ts +15 -0
- package/dist/types/meeting/in-meeting-actions.d.ts +16 -0
- package/dist/types/meeting/index.d.ts +65 -1
- package/dist/types/meeting/muteState.d.ts +0 -1
- package/dist/types/meeting/request.d.ts +12 -1
- package/dist/types/meeting/request.type.d.ts +6 -0
- package/dist/types/meeting/util.d.ts +3 -1
- package/dist/types/meeting-info/meeting-info-v2.d.ts +82 -1
- package/dist/types/meetings/index.d.ts +57 -0
- package/dist/types/member/index.d.ts +21 -6
- package/dist/types/member/types.d.ts +73 -14
- package/dist/types/member/util.d.ts +156 -1
- package/dist/types/members/collection.d.ts +6 -5
- package/dist/types/members/index.d.ts +32 -43
- package/dist/types/members/request.d.ts +26 -0
- package/dist/types/members/util.d.ts +27 -0
- package/dist/types/metrics/constants.d.ts +10 -0
- package/dist/types/multistream/remoteMediaManager.d.ts +10 -1
- package/dist/types/reachability/clusterReachability.d.ts +15 -7
- package/dist/types/reachability/index.d.ts +10 -1
- package/dist/types/reachability/reachability.types.d.ts +5 -0
- package/dist/types/roap/index.d.ts +3 -2
- package/dist/types/roap/turnDiscovery.d.ts +5 -17
- package/dist/types/roap/types.d.ts +16 -0
- package/dist/webinar/index.js +2 -2
- package/dist/webinar/index.js.map +1 -1
- package/package.json +24 -23
- package/src/breakouts/index.ts +69 -0
- package/src/common/errors/webex-errors.ts +8 -1
- package/src/config.ts +3 -0
- package/src/constants.ts +24 -90
- package/src/controls-options-manager/enums.ts +2 -0
- package/src/controls-options-manager/types.ts +11 -1
- package/src/controls-options-manager/util.ts +62 -0
- package/src/interpretation/index.ts +3 -3
- package/src/locus-info/controlsUtils.ts +50 -14
- package/src/locus-info/index.ts +88 -13
- package/src/locus-info/selfUtils.ts +496 -442
- package/src/media/index.ts +23 -21
- package/src/media/properties.ts +96 -0
- package/src/meeting/brbState.ts +11 -2
- package/src/meeting/in-meeting-actions.ts +32 -0
- package/src/meeting/index.ts +449 -95
- package/src/meeting/locusMediaRequest.ts +27 -22
- package/src/meeting/muteState.ts +4 -4
- package/src/meeting/request.ts +36 -1
- package/src/meeting/request.type.ts +7 -0
- package/src/meeting/util.ts +11 -2
- package/src/meeting-info/meeting-info-v2.ts +254 -8
- package/src/meeting-info/utilv2.ts +5 -0
- package/src/meetings/index.ts +148 -1
- package/src/meetings/util.ts +18 -0
- package/src/member/index.ts +68 -22
- package/src/member/types.ts +82 -16
- package/src/member/util.ts +357 -350
- package/src/members/collection.ts +4 -3
- package/src/members/index.ts +137 -18
- package/src/members/request.ts +44 -0
- package/src/members/util.ts +43 -1
- package/src/metrics/constants.ts +10 -0
- package/src/multistream/remoteMediaManager.ts +32 -10
- package/src/reachability/clusterReachability.ts +73 -26
- package/src/reachability/index.ts +70 -1
- package/src/reachability/reachability.types.ts +6 -0
- package/src/reachability/request.ts +7 -0
- package/src/reconnection-manager/index.ts +2 -2
- package/src/recording-controller/util.ts +17 -13
- package/src/roap/index.ts +3 -7
- package/src/roap/turnDiscovery.ts +34 -39
- package/src/roap/types.ts +23 -0
- package/src/webinar/index.ts +1 -1
- package/test/unit/spec/breakouts/index.ts +167 -95
- package/test/unit/spec/controls-options-manager/util.js +120 -0
- package/test/unit/spec/interpretation/index.ts +39 -1
- package/test/unit/spec/locus-info/controlsUtils.js +139 -9
- package/test/unit/spec/locus-info/index.js +195 -73
- package/test/unit/spec/locus-info/selfUtils.js +98 -24
- package/test/unit/spec/media/index.ts +150 -18
- package/test/unit/spec/media/properties.ts +130 -0
- package/test/unit/spec/meeting/brbState.ts +40 -2
- package/test/unit/spec/meeting/in-meeting-actions.ts +19 -4
- package/test/unit/spec/meeting/index.js +754 -139
- package/test/unit/spec/meeting/locusMediaRequest.ts +95 -87
- package/test/unit/spec/meeting/muteState.js +73 -2
- package/test/unit/spec/meeting/request.js +32 -1
- package/test/unit/spec/meeting/utils.js +119 -18
- package/test/unit/spec/meeting-info/meetinginfov2.js +484 -114
- package/test/unit/spec/meeting-info/utilv2.js +19 -0
- package/test/unit/spec/meetings/index.js +146 -2
- package/test/unit/spec/member/index.js +7 -0
- package/test/unit/spec/member/util.js +24 -0
- package/test/unit/spec/members/index.js +304 -78
- package/test/unit/spec/members/request.js +68 -22
- package/test/unit/spec/members/utils.js +75 -0
- package/test/unit/spec/multistream/remoteMediaManager.ts +397 -118
- package/test/unit/spec/reachability/clusterReachability.ts +88 -56
- package/test/unit/spec/reachability/index.ts +101 -0
- package/test/unit/spec/reachability/request.js +47 -2
- package/test/unit/spec/reconnection-manager/index.js +4 -4
- package/test/unit/spec/roap/turnDiscovery.ts +110 -28
- package/test/unit/spec/webinar/index.ts +5 -0
- 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.js +0 -149
- 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 -33
- 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 -93
- 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 -36
- package/dist/common/queue.d.ts +0 -34
- package/dist/config.d.ts +0 -72
- package/dist/constants.d.ts +0 -1088
- package/dist/controls-options-manager/constants.d.ts +0 -4
- package/dist/controls-options-manager/enums.d.ts +0 -15
- package/dist/controls-options-manager/index.d.ts +0 -136
- package/dist/controls-options-manager/types.d.ts +0 -43
- package/dist/controls-options-manager/util.d.ts +0 -1
- package/dist/index.d.ts +0 -7
- 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 -322
- 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 -272
- package/dist/locus-info/selfUtils.d.ts +0 -2
- package/dist/media/index.d.ts +0 -34
- package/dist/media/properties.d.ts +0 -93
- package/dist/media/util.d.ts +0 -2
- package/dist/mediaQualityMetrics/config.d.ts +0 -241
- package/dist/mediaQualityMetrics/config.js +0 -502
- package/dist/mediaQualityMetrics/config.js.map +0 -1
- package/dist/meeting/effectsState.js +0 -260
- package/dist/meeting/effectsState.js.map +0 -1
- package/dist/meeting/in-meeting-actions.d.ts +0 -167
- package/dist/meeting/index.d.ts +0 -1825
- package/dist/meeting/locusMediaRequest.d.ts +0 -74
- package/dist/meeting/muteState.d.ts +0 -178
- package/dist/meeting/request.d.ts +0 -295
- package/dist/meeting/request.type.d.ts +0 -11
- package/dist/meeting/state.d.ts +0 -9
- package/dist/meeting/util.d.ts +0 -119
- 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 -69
- package/dist/meeting-info/meeting-info-v2.d.ts +0 -123
- 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 -40
- package/dist/meetings/index.d.ts +0 -390
- 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 -160
- package/dist/member/member.types.js +0 -17
- 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 -29
- package/dist/members/index.d.ts +0 -353
- package/dist/members/request.d.ts +0 -114
- package/dist/members/types.d.ts +0 -25
- package/dist/members/util.d.ts +0 -215
- package/dist/metrics/config.js +0 -276
- package/dist/metrics/config.js.map +0 -1
- package/dist/metrics/constants.d.ts +0 -70
- package/dist/metrics/index.d.ts +0 -45
- 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 -221
- package/dist/networkQualityMonitor/index.js.map +0 -1
- 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.js +0 -109
- 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 -105
- package/dist/reachability/request.d.ts +0 -39
- 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 -52
- package/dist/reconnection-manager/index.d.ts +0 -136
- package/dist/recording-controller/enums.d.ts +0 -7
- package/dist/recording-controller/index.d.ts +0 -207
- package/dist/recording-controller/util.d.ts +0 -14
- package/dist/roap/collection.js +0 -62
- package/dist/roap/collection.js.map +0 -1
- package/dist/roap/handler.js +0 -275
- package/dist/roap/handler.js.map +0 -1
- package/dist/roap/index.d.ts +0 -86
- package/dist/roap/request.d.ts +0 -39
- package/dist/roap/state.js +0 -126
- package/dist/roap/state.js.map +0 -1
- package/dist/roap/turnDiscovery.d.ts +0 -155
- package/dist/roap/util.js +0 -75
- package/dist/roap/util.js.map +0 -1
- package/dist/rtcMetrics/constants.d.ts +0 -4
- package/dist/rtcMetrics/constants.js +0 -11
- 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 -36
- package/dist/statsAnalyzer/global.js +0 -126
- package/dist/statsAnalyzer/global.js.map +0 -1
- package/dist/statsAnalyzer/index.d.ts +0 -217
- package/dist/statsAnalyzer/index.js +0 -1013
- package/dist/statsAnalyzer/index.js.map +0 -1
- package/dist/statsAnalyzer/mqaUtil.d.ts +0 -48
- package/dist/statsAnalyzer/mqaUtil.js +0 -179
- 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
@@ -1,6 +1,7 @@
|
|
1
1
|
/*!
|
2
2
|
* Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
|
3
3
|
*/
|
4
|
+
import {v4 as uuidv4} from 'uuid';
|
4
5
|
import 'jsdom-global/register';
|
5
6
|
import {cloneDeep, forEach, isEqual, isUndefined} from 'lodash';
|
6
7
|
import sinon from 'sinon';
|
@@ -93,13 +94,14 @@ import CaptchaError from '../../../../src/common/errors/captcha-error';
|
|
93
94
|
import PermissionError from '../../../../src/common/errors/permission';
|
94
95
|
import JoinWebinarError from '../../../../src/common/errors/join-webinar-error';
|
95
96
|
import IntentToJoinError from '../../../../src/common/errors/intent-to-join';
|
96
|
-
import MultistreamNotSupportedError from '../../../../src/common/errors/multistream-not-supported-error'
|
97
|
+
import MultistreamNotSupportedError from '../../../../src/common/errors/multistream-not-supported-error';
|
97
98
|
import testUtils from '../../../utils/testUtils';
|
98
99
|
import {
|
99
100
|
MeetingInfoV2CaptchaError,
|
100
101
|
MeetingInfoV2PasswordError,
|
101
102
|
MeetingInfoV2PolicyError,
|
102
|
-
MeetingInfoV2JoinWebinarError,
|
103
|
+
MeetingInfoV2JoinWebinarError,
|
104
|
+
MeetingInfoV2JoinForbiddenError,
|
103
105
|
} from '../../../../src/meeting-info/meeting-info-v2';
|
104
106
|
import {
|
105
107
|
DTLS_HANDSHAKE_FAILED_CLIENT_CODE,
|
@@ -114,8 +116,9 @@ import {ERROR_DESCRIPTIONS} from '@webex/internal-plugin-metrics/src/call-diagno
|
|
114
116
|
import MeetingCollection from '@webex/plugin-meetings/src/meetings/collection';
|
115
117
|
|
116
118
|
import {EVENT_TRIGGERS as VOICEAEVENTS} from '@webex/internal-plugin-voicea';
|
117
|
-
import {
|
118
|
-
import JoinForbiddenError
|
119
|
+
import {createBrbState} from '@webex/plugin-meetings/src/meeting/brbState';
|
120
|
+
import JoinForbiddenError from '../../../../src/common/errors/join-forbidden-error';
|
121
|
+
import {EventEmitter} from 'stream';
|
119
122
|
|
120
123
|
describe('plugin-meetings', () => {
|
121
124
|
const logger = {
|
@@ -208,6 +211,8 @@ describe('plugin-meetings', () => {
|
|
208
211
|
let membersSpy;
|
209
212
|
let meetingRequestSpy;
|
210
213
|
let correlationId;
|
214
|
+
let isoLocalClientMeetingJoinTime;
|
215
|
+
let uploadEvent;
|
211
216
|
|
212
217
|
beforeEach(() => {
|
213
218
|
webex = new MockWebex({
|
@@ -238,6 +243,7 @@ describe('plugin-meetings', () => {
|
|
238
243
|
},
|
239
244
|
});
|
240
245
|
|
246
|
+
webex.internal.newMetrics.callDiagnosticMetrics.clearErrorCache = sinon.stub();
|
241
247
|
webex.internal.support.submitLogs = sinon.stub().returns(Promise.resolve());
|
242
248
|
webex.internal.services = {get: sinon.stub().returns('locus-url')};
|
243
249
|
webex.credentials.getOrgId = sinon.stub().returns('fake-org-id');
|
@@ -248,6 +254,7 @@ describe('plugin-meetings', () => {
|
|
248
254
|
getReachabilityResults: sinon.stub().resolves(undefined),
|
249
255
|
getReachabilityMetrics: sinon.stub().resolves({}),
|
250
256
|
stopReachability: sinon.stub(),
|
257
|
+
isSubnetReachable: sinon.stub().returns(true),
|
251
258
|
};
|
252
259
|
webex.internal.llm.on = sinon.stub();
|
253
260
|
webex.internal.newMetrics.callDiagnosticLatencies = new CallDiagnosticLatencies(
|
@@ -277,6 +284,8 @@ describe('plugin-meetings', () => {
|
|
277
284
|
test4 = `test4-${uuid.v4()}`;
|
278
285
|
testDestination = `testDestination-${uuid.v4()}`;
|
279
286
|
correlationId = uuid.v4();
|
287
|
+
uploadEvent = new EventEmitter();
|
288
|
+
uploadEvent.addListener('progress', () => {});
|
280
289
|
|
281
290
|
meeting = new Meeting(
|
282
291
|
{
|
@@ -605,6 +614,22 @@ describe('plugin-meetings', () => {
|
|
605
614
|
assert.calledWith(meeting.members.cancelPhoneInvite, uuid1);
|
606
615
|
});
|
607
616
|
});
|
617
|
+
describe('#cancelSIPInvite', () => {
|
618
|
+
it('should have #cancelSIPInvite', () => {
|
619
|
+
assert.exists(meeting.cancelSIPInvite);
|
620
|
+
});
|
621
|
+
beforeEach(() => {
|
622
|
+
meeting.members.cancelSIPInvite = sinon.stub().returns(Promise.resolve(test1));
|
623
|
+
});
|
624
|
+
it('should proxy members #cancelSIPInvite and return a promise', async () => {
|
625
|
+
const cancel = meeting.cancelSIPInvite({memberId: uuid1});
|
626
|
+
|
627
|
+
assert.exists(cancel.then);
|
628
|
+
await cancel;
|
629
|
+
assert.calledOnce(meeting.members.cancelSIPInvite);
|
630
|
+
assert.calledWith(meeting.members.cancelSIPInvite, {memberId: uuid1});
|
631
|
+
});
|
632
|
+
});
|
608
633
|
describe('#admit', () => {
|
609
634
|
it('should have #admit', () => {
|
610
635
|
assert.exists(meeting.admit);
|
@@ -667,7 +692,7 @@ describe('plugin-meetings', () => {
|
|
667
692
|
beforeEach(() => {
|
668
693
|
meeting.join = sinon.stub().callsFake((joinOptions) => {
|
669
694
|
meeting.isMultistream = joinOptions.enableMultistream;
|
670
|
-
return Promise.resolve(fakeJoinResult)
|
695
|
+
return Promise.resolve(fakeJoinResult);
|
671
696
|
});
|
672
697
|
addMediaInternalStub = sinon
|
673
698
|
.stub(meeting, 'addMediaInternal')
|
@@ -1070,7 +1095,11 @@ describe('plugin-meetings', () => {
|
|
1070
1095
|
mediaOptions,
|
1071
1096
|
});
|
1072
1097
|
|
1073
|
-
assert.deepEqual(result, {
|
1098
|
+
assert.deepEqual(result, {
|
1099
|
+
join: fakeJoinResult,
|
1100
|
+
media: undefined,
|
1101
|
+
multistreamEnabled: false,
|
1102
|
+
});
|
1074
1103
|
|
1075
1104
|
assert.calledOnce(meeting.join);
|
1076
1105
|
|
@@ -1174,7 +1203,10 @@ describe('plugin-meetings', () => {
|
|
1174
1203
|
type: addMediaError.name,
|
1175
1204
|
}
|
1176
1205
|
);
|
1177
|
-
assert.calledOnceWithExactly(meeting.leave, {
|
1206
|
+
assert.calledOnceWithExactly(meeting.leave, {
|
1207
|
+
resourceId: undefined,
|
1208
|
+
reason: 'joinWithMedia failure',
|
1209
|
+
});
|
1178
1210
|
});
|
1179
1211
|
});
|
1180
1212
|
|
@@ -1191,6 +1223,46 @@ describe('plugin-meetings', () => {
|
|
1191
1223
|
});
|
1192
1224
|
});
|
1193
1225
|
|
1226
|
+
describe('#update spoken language', () => {
|
1227
|
+
beforeEach(() => {
|
1228
|
+
webex.internal.voicea.onSpokenLanguageUpdate = sinon.stub();
|
1229
|
+
meeting.transcription = {languageOptions: {currentSpokenLanguage: 'en'}};
|
1230
|
+
});
|
1231
|
+
afterEach(() => {
|
1232
|
+
// Restore the original methods after each test
|
1233
|
+
sinon.restore();
|
1234
|
+
});
|
1235
|
+
it('should call voicea.onSpokenLanguageUpdate when joined', async () => {
|
1236
|
+
|
1237
|
+
meeting.joinedWith = {state: 'JOINED'};
|
1238
|
+
await meeting.locusInfo.emitScoped(
|
1239
|
+
{function: 'test', file: 'test'},
|
1240
|
+
LOCUSINFO.EVENTS.CONTROLS_MEETING_TRANSCRIPTION_SPOKEN_LANGUAGE_UPDATED,
|
1241
|
+
{spokenLanguage: 'fr'},
|
1242
|
+
);
|
1243
|
+
assert.calledWith(webex.internal.voicea.onSpokenLanguageUpdate, 'fr');
|
1244
|
+
assert.equal(meeting.transcription.languageOptions.currentSpokenLanguage, 'fr');
|
1245
|
+
assert.calledWith(
|
1246
|
+
TriggerProxy.trigger,
|
1247
|
+
meeting,
|
1248
|
+
{file: 'meeting/index', function: 'setupLocusControlsListener'},
|
1249
|
+
EVENT_TRIGGERS.MEETING_TRANSCRIPTION_SPOKEN_LANGUAGE_UPDATED
|
1250
|
+
);
|
1251
|
+
});
|
1252
|
+
|
1253
|
+
it('should also call voicea.onSpokenLanguageUpdate when not joined', async () => {
|
1254
|
+
|
1255
|
+
meeting.joinedWith = {state: 'NOT_JOINED'};
|
1256
|
+
await meeting.locusInfo.emitScoped(
|
1257
|
+
{function: 'test', file: 'test'},
|
1258
|
+
LOCUSINFO.EVENTS.CONTROLS_MEETING_TRANSCRIPTION_SPOKEN_LANGUAGE_UPDATED,
|
1259
|
+
{spokenLanguage: 'de'},
|
1260
|
+
);
|
1261
|
+
assert.calledWith(webex.internal.voicea.onSpokenLanguageUpdate, 'de');
|
1262
|
+
assert.equal(meeting.transcription.languageOptions.currentSpokenLanguage, 'de');
|
1263
|
+
});
|
1264
|
+
});
|
1265
|
+
|
1194
1266
|
describe('#startTranscription', () => {
|
1195
1267
|
beforeEach(() => {
|
1196
1268
|
webex.internal.voicea.on = sinon.stub();
|
@@ -1680,10 +1752,6 @@ describe('plugin-meetings', () => {
|
|
1680
1752
|
sandbox.stub(MeetingUtil, 'joinMeeting').returns(Promise.resolve(joinMeetingResult));
|
1681
1753
|
});
|
1682
1754
|
|
1683
|
-
afterEach(() => {
|
1684
|
-
assert.exists(meeting.isoLocalClientMeetingJoinTime);
|
1685
|
-
});
|
1686
|
-
|
1687
1755
|
it('should join the meeting and return promise', async () => {
|
1688
1756
|
const join = meeting.join({pstnAudioType: 'dial-in'});
|
1689
1757
|
meeting.config.enableAutomaticLLM = true;
|
@@ -2035,7 +2103,12 @@ describe('plugin-meetings', () => {
|
|
2035
2103
|
meeting.mediaProperties.waitForMediaConnectionConnected = sinon.stub().resolves();
|
2036
2104
|
meeting.mediaProperties.getCurrentConnectionInfo = sinon
|
2037
2105
|
.stub()
|
2038
|
-
.resolves({
|
2106
|
+
.resolves({
|
2107
|
+
connectionType: 'udp',
|
2108
|
+
selectedCandidatePairChanges: 2,
|
2109
|
+
numTransports: 1,
|
2110
|
+
ipVersion: 'IPv6',
|
2111
|
+
});
|
2039
2112
|
meeting.audio = muteStateStub;
|
2040
2113
|
meeting.video = muteStateStub;
|
2041
2114
|
sinon.stub(Media, 'createMediaConnection').returns(fakeMediaConnection);
|
@@ -2098,6 +2171,7 @@ describe('plugin-meetings', () => {
|
|
2098
2171
|
someReachabilityMetric2: 'some value2',
|
2099
2172
|
}),
|
2100
2173
|
stopReachability: sinon.stub(),
|
2174
|
+
isSubnetReachable: sinon.stub().returns(false),
|
2101
2175
|
};
|
2102
2176
|
|
2103
2177
|
const forceRtcMetricsSend = sinon.stub().resolves();
|
@@ -2153,6 +2227,8 @@ describe('plugin-meetings', () => {
|
|
2153
2227
|
someReachabilityMetric1: 'some value1',
|
2154
2228
|
someReachabilityMetric2: 'some value2',
|
2155
2229
|
selectedCandidatePairChanges: 2,
|
2230
|
+
isSubnetReachable: null,
|
2231
|
+
selectedCluster: null,
|
2156
2232
|
numTransports: 1,
|
2157
2233
|
iceCandidatesCount: 0,
|
2158
2234
|
}
|
@@ -2199,6 +2275,8 @@ describe('plugin-meetings', () => {
|
|
2199
2275
|
signalingState: 'unknown',
|
2200
2276
|
connectionState: 'unknown',
|
2201
2277
|
iceConnectionState: 'unknown',
|
2278
|
+
isSubnetReachable: null,
|
2279
|
+
selectedCluster: null,
|
2202
2280
|
})
|
2203
2281
|
);
|
2204
2282
|
|
@@ -2213,6 +2291,7 @@ describe('plugin-meetings', () => {
|
|
2213
2291
|
someReachabilityMetric1: 'some value1',
|
2214
2292
|
someReachabilityMetric2: 'some value2',
|
2215
2293
|
}),
|
2294
|
+
isSubnetReachable: sinon.stub().returns(true),
|
2216
2295
|
};
|
2217
2296
|
|
2218
2297
|
meeting.waitForRemoteSDPAnswer = sinon.stub().rejects();
|
@@ -2263,6 +2342,8 @@ describe('plugin-meetings', () => {
|
|
2263
2342
|
selectedCandidatePairChanges: 2,
|
2264
2343
|
numTransports: 1,
|
2265
2344
|
iceCandidatesCount: 0,
|
2345
|
+
isSubnetReachable: null,
|
2346
|
+
selectedCluster: null,
|
2266
2347
|
}
|
2267
2348
|
);
|
2268
2349
|
});
|
@@ -2320,6 +2401,8 @@ describe('plugin-meetings', () => {
|
|
2320
2401
|
signalingState: 'have-local-offer',
|
2321
2402
|
connectionState: 'connecting',
|
2322
2403
|
iceConnectionState: 'checking',
|
2404
|
+
isSubnetReachable: null,
|
2405
|
+
selectedCluster: null,
|
2323
2406
|
})
|
2324
2407
|
);
|
2325
2408
|
|
@@ -2377,6 +2460,8 @@ describe('plugin-meetings', () => {
|
|
2377
2460
|
signalingState: 'have-local-offer',
|
2378
2461
|
connectionState: 'connecting',
|
2379
2462
|
iceConnectionState: 'checking',
|
2463
|
+
isSubnetReachable: null,
|
2464
|
+
selectedCluster: null,
|
2380
2465
|
})
|
2381
2466
|
);
|
2382
2467
|
|
@@ -2655,7 +2740,7 @@ describe('plugin-meetings', () => {
|
|
2655
2740
|
|
2656
2741
|
meeting.roap.doTurnDiscovery = sinon.stub().resolves({
|
2657
2742
|
turnServerInfo: {
|
2658
|
-
|
2743
|
+
urls: [FAKE_TURN_URL],
|
2659
2744
|
username: FAKE_TURN_USER,
|
2660
2745
|
password: FAKE_TURN_PASSWORD,
|
2661
2746
|
},
|
@@ -2677,7 +2762,7 @@ describe('plugin-meetings', () => {
|
|
2677
2762
|
meeting.id,
|
2678
2763
|
sinon.match({
|
2679
2764
|
turnServerInfo: {
|
2680
|
-
|
2765
|
+
urls: [FAKE_TURN_URL],
|
2681
2766
|
username: FAKE_TURN_USER,
|
2682
2767
|
password: FAKE_TURN_PASSWORD,
|
2683
2768
|
},
|
@@ -2712,8 +2797,9 @@ describe('plugin-meetings', () => {
|
|
2712
2797
|
sinon.stub().returns(FAKE_ERROR));
|
2713
2798
|
webex.meetings.reachability = {
|
2714
2799
|
isWebexMediaBackendUnreachable: sinon.stub().resolves(false),
|
2715
|
-
getReachabilityMetrics: sinon.stub().resolves(),
|
2800
|
+
getReachabilityMetrics: sinon.stub().resolves({}),
|
2716
2801
|
stopReachability: sinon.stub(),
|
2802
|
+
isSubnetReachable: sinon.stub().returns(true),
|
2717
2803
|
};
|
2718
2804
|
const MOCK_CLIENT_ERROR_CODE = 2004;
|
2719
2805
|
const generateClientErrorCodeForIceFailureStub = sinon
|
@@ -2735,14 +2821,15 @@ describe('plugin-meetings', () => {
|
|
2735
2821
|
.onSecondCall()
|
2736
2822
|
.returns({
|
2737
2823
|
turnServerInfo: {
|
2738
|
-
|
2824
|
+
urls: [FAKE_TURN_URL],
|
2739
2825
|
username: FAKE_TURN_USER,
|
2740
2826
|
password: FAKE_TURN_PASSWORD,
|
2741
2827
|
},
|
2742
2828
|
turnDiscoverySkippedReason: undefined,
|
2743
2829
|
});
|
2744
2830
|
meeting.meetingState = 'ACTIVE';
|
2745
|
-
|
2831
|
+
const error = {iceConnected: false};
|
2832
|
+
meeting.mediaProperties.waitForMediaConnectionConnected.rejects(error);
|
2746
2833
|
|
2747
2834
|
const forceRtcMetricsSend = sinon.stub().resolves();
|
2748
2835
|
const closeMediaConnectionStub = sinon.stub();
|
@@ -2760,6 +2847,7 @@ describe('plugin-meetings', () => {
|
|
2760
2847
|
})
|
2761
2848
|
.catch((err) => {
|
2762
2849
|
errorThrown = err;
|
2850
|
+
assert.instanceOf(err.cause, Error);
|
2763
2851
|
assert.instanceOf(err, AddMediaFailed);
|
2764
2852
|
});
|
2765
2853
|
|
@@ -2816,6 +2904,7 @@ describe('plugin-meetings', () => {
|
|
2816
2904
|
},
|
2817
2905
|
options: {
|
2818
2906
|
meetingId: meeting.id,
|
2907
|
+
rawError: error,
|
2819
2908
|
},
|
2820
2909
|
});
|
2821
2910
|
assert.calledWith(webex.internal.newMetrics.submitClientEvent.thirdCall, {
|
@@ -2827,6 +2916,7 @@ describe('plugin-meetings', () => {
|
|
2827
2916
|
},
|
2828
2917
|
options: {
|
2829
2918
|
meetingId: meeting.id,
|
2919
|
+
rawError: error,
|
2830
2920
|
},
|
2831
2921
|
});
|
2832
2922
|
|
@@ -2893,6 +2983,8 @@ describe('plugin-meetings', () => {
|
|
2893
2983
|
selectedCandidatePairChanges: 2,
|
2894
2984
|
numTransports: 1,
|
2895
2985
|
iceCandidatesCount: 0,
|
2986
|
+
isSubnetReachable: null,
|
2987
|
+
selectedCluster: null,
|
2896
2988
|
},
|
2897
2989
|
]);
|
2898
2990
|
|
@@ -2923,6 +3015,7 @@ describe('plugin-meetings', () => {
|
|
2923
3015
|
.resolves(false),
|
2924
3016
|
getReachabilityMetrics: sinon.stub().resolves({}),
|
2925
3017
|
stopReachability: sinon.stub(),
|
3018
|
+
isSubnetReachable: sinon.stub().returns(true),
|
2926
3019
|
};
|
2927
3020
|
const getErrorPayloadForClientErrorCodeStub =
|
2928
3021
|
(webex.internal.newMetrics.callDiagnosticMetrics.getErrorPayloadForClientErrorCode =
|
@@ -2947,16 +3040,19 @@ describe('plugin-meetings', () => {
|
|
2947
3040
|
.onSecondCall()
|
2948
3041
|
.returns({
|
2949
3042
|
turnServerInfo: {
|
2950
|
-
|
3043
|
+
urls: [FAKE_TURN_URL],
|
2951
3044
|
username: FAKE_TURN_USER,
|
2952
3045
|
password: FAKE_TURN_PASSWORD,
|
2953
3046
|
},
|
2954
3047
|
turnDiscoverySkippedReason: undefined,
|
2955
3048
|
});
|
3049
|
+
|
3050
|
+
const mediaConnectionError = new Error('fake error');
|
3051
|
+
|
2956
3052
|
meeting.mediaProperties.waitForMediaConnectionConnected = sinon
|
2957
3053
|
.stub()
|
2958
3054
|
.onFirstCall()
|
2959
|
-
.rejects()
|
3055
|
+
.rejects(mediaConnectionError)
|
2960
3056
|
.onSecondCall()
|
2961
3057
|
.resolves();
|
2962
3058
|
|
@@ -3025,10 +3121,14 @@ describe('plugin-meetings', () => {
|
|
3025
3121
|
},
|
3026
3122
|
options: {
|
3027
3123
|
meetingId: meeting.id,
|
3124
|
+
rawError: mediaConnectionError,
|
3028
3125
|
},
|
3029
3126
|
});
|
3030
3127
|
assert.calledWith(webex.internal.newMetrics.submitClientEvent.thirdCall, {
|
3031
3128
|
name: 'client.media-engine.ready',
|
3129
|
+
payload: {
|
3130
|
+
ipVersion: 'IPv6',
|
3131
|
+
},
|
3032
3132
|
options: {
|
3033
3133
|
meetingId: meeting.id,
|
3034
3134
|
},
|
@@ -3085,11 +3185,14 @@ describe('plugin-meetings', () => {
|
|
3085
3185
|
locus_id: meeting.locusUrl.split('/').pop(),
|
3086
3186
|
connectionType: 'udp',
|
3087
3187
|
selectedCandidatePairChanges: 2,
|
3188
|
+
ipVersion: 'IPv6',
|
3088
3189
|
numTransports: 1,
|
3089
3190
|
isMultistream: false,
|
3090
3191
|
retriedWithTurnServer: true,
|
3091
3192
|
isJoinWithMediaRetry: false,
|
3092
3193
|
iceCandidatesCount: 0,
|
3194
|
+
isSubnetReachable: null,
|
3195
|
+
selectedCluster: null,
|
3093
3196
|
},
|
3094
3197
|
]);
|
3095
3198
|
meeting.roap.doTurnDiscovery;
|
@@ -3124,7 +3227,7 @@ describe('plugin-meetings', () => {
|
|
3124
3227
|
.onSecondCall()
|
3125
3228
|
.returns({
|
3126
3229
|
turnServerInfo: {
|
3127
|
-
|
3230
|
+
urls: [FAKE_TURN_URL],
|
3128
3231
|
username: FAKE_TURN_USER,
|
3129
3232
|
password: FAKE_TURN_PASSWORD,
|
3130
3233
|
},
|
@@ -3176,7 +3279,7 @@ describe('plugin-meetings', () => {
|
|
3176
3279
|
.onSecondCall()
|
3177
3280
|
.returns({
|
3178
3281
|
turnServerInfo: {
|
3179
|
-
|
3282
|
+
urls: [FAKE_TURN_URL],
|
3180
3283
|
username: FAKE_TURN_USER,
|
3181
3284
|
password: FAKE_TURN_PASSWORD,
|
3182
3285
|
},
|
@@ -3218,7 +3321,13 @@ describe('plugin-meetings', () => {
|
|
3218
3321
|
someReachabilityMetric2: 'some value2',
|
3219
3322
|
}),
|
3220
3323
|
stopReachability: sinon.stub(),
|
3324
|
+
isSubnetReachable: sinon.stub().returns(true),
|
3221
3325
|
};
|
3326
|
+
meeting.mediaConnections = [
|
3327
|
+
{
|
3328
|
+
mediaAgentCluster: 'some.cluster',
|
3329
|
+
}
|
3330
|
+
]
|
3222
3331
|
meeting.iceCandidatesCount = 3;
|
3223
3332
|
meeting.iceCandidateErrors.set('701_error', 3);
|
3224
3333
|
meeting.iceCandidateErrors.set('701_turn_host_lookup_received_error', 1);
|
@@ -3236,6 +3345,7 @@ describe('plugin-meetings', () => {
|
|
3236
3345
|
locus_id: meeting.locusUrl.split('/').pop(),
|
3237
3346
|
connectionType: 'udp',
|
3238
3347
|
selectedCandidatePairChanges: 2,
|
3348
|
+
ipVersion: 'IPv6',
|
3239
3349
|
numTransports: 1,
|
3240
3350
|
isMultistream: false,
|
3241
3351
|
retriedWithTurnServer: false,
|
@@ -3245,6 +3355,8 @@ describe('plugin-meetings', () => {
|
|
3245
3355
|
iceCandidatesCount: 3,
|
3246
3356
|
'701_error': 3,
|
3247
3357
|
'701_turn_host_lookup_received_error': 1,
|
3358
|
+
isSubnetReachable: null,
|
3359
|
+
selectedCluster: 'some.cluster',
|
3248
3360
|
}
|
3249
3361
|
);
|
3250
3362
|
|
@@ -3307,6 +3419,8 @@ describe('plugin-meetings', () => {
|
|
3307
3419
|
iceConnectionState: 'unknown',
|
3308
3420
|
selectedCandidatePairChanges: 2,
|
3309
3421
|
numTransports: 1,
|
3422
|
+
isSubnetReachable: null,
|
3423
|
+
selectedCluster: null,
|
3310
3424
|
iceCandidatesCount: 0,
|
3311
3425
|
}
|
3312
3426
|
);
|
@@ -3368,6 +3482,120 @@ describe('plugin-meetings', () => {
|
|
3368
3482
|
numTransports: 1,
|
3369
3483
|
'701_error': 2,
|
3370
3484
|
'701_turn_host_lookup_received_error': 1,
|
3485
|
+
isSubnetReachable: null,
|
3486
|
+
selectedCluster: null,
|
3487
|
+
iceCandidatesCount: 0,
|
3488
|
+
}
|
3489
|
+
);
|
3490
|
+
|
3491
|
+
assert.isOk(errorThrown);
|
3492
|
+
});
|
3493
|
+
|
3494
|
+
it('should send valid isSubnetReachability if media connection success', async () => {
|
3495
|
+
meeting.roap.doTurnDiscovery = sinon.stub().returns({
|
3496
|
+
turnServerInfo: undefined,
|
3497
|
+
turnDiscoverySkippedReason: undefined,
|
3498
|
+
});
|
3499
|
+
meeting.meetingState = 'ACTIVE';
|
3500
|
+
meeting.mediaProperties.waitForMediaConnectionConnected.resolves();
|
3501
|
+
meeting.webex.meetings.reachability = {
|
3502
|
+
getReachabilityMetrics: sinon.stub().resolves({
|
3503
|
+
reachability_public_udp_success: 5,
|
3504
|
+
}),
|
3505
|
+
stopReachability: sinon.stub(),
|
3506
|
+
isSubnetReachable: sinon.stub().returns(false),
|
3507
|
+
};
|
3508
|
+
|
3509
|
+
const forceRtcMetricsSend = sinon.stub().resolves();
|
3510
|
+
const closeMediaConnectionStub = sinon.stub();
|
3511
|
+
Media.createMediaConnection = sinon.stub().returns({
|
3512
|
+
close: closeMediaConnectionStub,
|
3513
|
+
forceRtcMetricsSend,
|
3514
|
+
getConnectionState: sinon.stub().returns(ConnectionState.Connected),
|
3515
|
+
initiateOffer: sinon.stub().resolves({}),
|
3516
|
+
on: sinon.stub(),
|
3517
|
+
});
|
3518
|
+
|
3519
|
+
await meeting.addMedia({
|
3520
|
+
mediaSettings: {},
|
3521
|
+
});
|
3522
|
+
|
3523
|
+
assert.calledWith(Metrics.sendBehavioralMetric, BEHAVIORAL_METRICS.ADD_MEDIA_SUCCESS, {
|
3524
|
+
correlation_id: meeting.correlationId,
|
3525
|
+
locus_id: meeting.locusUrl.split('/').pop(),
|
3526
|
+
connectionType: 'udp',
|
3527
|
+
ipVersion: 'IPv6',
|
3528
|
+
selectedCandidatePairChanges: 2,
|
3529
|
+
numTransports: 1,
|
3530
|
+
isMultistream: false,
|
3531
|
+
retriedWithTurnServer: false,
|
3532
|
+
isJoinWithMediaRetry: false,
|
3533
|
+
iceCandidatesCount: 0,
|
3534
|
+
reachability_public_udp_success: 5,
|
3535
|
+
isSubnetReachable: false,
|
3536
|
+
selectedCluster: null,
|
3537
|
+
});
|
3538
|
+
});
|
3539
|
+
|
3540
|
+
it('should send valid isSubnetReachability if media connection fails', async () => {
|
3541
|
+
let errorThrown = undefined;
|
3542
|
+
|
3543
|
+
meeting.roap.doTurnDiscovery = sinon.stub().returns({
|
3544
|
+
turnServerInfo: undefined,
|
3545
|
+
turnDiscoverySkippedReason: undefined,
|
3546
|
+
});
|
3547
|
+
meeting.meetingState = 'ACTIVE';
|
3548
|
+
meeting.mediaProperties.waitForMediaConnectionConnected.rejects({iceConnected: false});
|
3549
|
+
meeting.webex.meetings.reachability = {
|
3550
|
+
getReachabilityMetrics: sinon.stub().resolves({
|
3551
|
+
reachability_public_udp_success: 5,
|
3552
|
+
}),
|
3553
|
+
stopReachability: sinon.stub(),
|
3554
|
+
isSubnetReachable: sinon.stub().returns(true),
|
3555
|
+
};
|
3556
|
+
|
3557
|
+
const forceRtcMetricsSend = sinon.stub().resolves();
|
3558
|
+
const closeMediaConnectionStub = sinon.stub();
|
3559
|
+
Media.createMediaConnection = sinon.stub().returns({
|
3560
|
+
close: closeMediaConnectionStub,
|
3561
|
+
forceRtcMetricsSend,
|
3562
|
+
getConnectionState: sinon.stub().returns(ConnectionState.Connected),
|
3563
|
+
initiateOffer: sinon.stub().resolves({}),
|
3564
|
+
on: sinon.stub(),
|
3565
|
+
});
|
3566
|
+
|
3567
|
+
await meeting
|
3568
|
+
.addMedia({
|
3569
|
+
mediaSettings: {},
|
3570
|
+
})
|
3571
|
+
.catch((err) => {
|
3572
|
+
errorThrown = err;
|
3573
|
+
assert.instanceOf(err, AddMediaFailed);
|
3574
|
+
});
|
3575
|
+
|
3576
|
+
// Check that the only metric sent is ADD_MEDIA_FAILURE
|
3577
|
+
assert.calledOnceWithExactly(
|
3578
|
+
Metrics.sendBehavioralMetric,
|
3579
|
+
BEHAVIORAL_METRICS.ADD_MEDIA_FAILURE,
|
3580
|
+
{
|
3581
|
+
correlation_id: meeting.correlationId,
|
3582
|
+
locus_id: meeting.locusUrl.split('/').pop(),
|
3583
|
+
reason: errorThrown.message,
|
3584
|
+
stack: errorThrown.stack,
|
3585
|
+
code: errorThrown.code,
|
3586
|
+
turnDiscoverySkippedReason: undefined,
|
3587
|
+
turnServerUsed: true,
|
3588
|
+
retriedWithTurnServer: false,
|
3589
|
+
isMultistream: false,
|
3590
|
+
isJoinWithMediaRetry: false,
|
3591
|
+
signalingState: 'unknown',
|
3592
|
+
connectionState: 'unknown',
|
3593
|
+
iceConnectionState: 'unknown',
|
3594
|
+
selectedCandidatePairChanges: 2,
|
3595
|
+
numTransports: 1,
|
3596
|
+
reachability_public_udp_success: 5,
|
3597
|
+
isSubnetReachable: true,
|
3598
|
+
selectedCluster: null,
|
3371
3599
|
iceCandidatesCount: 0,
|
3372
3600
|
}
|
3373
3601
|
);
|
@@ -3387,6 +3615,8 @@ describe('plugin-meetings', () => {
|
|
3387
3615
|
meeting.config.stats.enableStatsAnalyzer = true;
|
3388
3616
|
|
3389
3617
|
statsAnalyzerStub = new EventsScope();
|
3618
|
+
statsAnalyzerStub.getNetworkType = sinon.stub().returns('wifi');
|
3619
|
+
|
3390
3620
|
// mock the StatsAnalyzer constructor
|
3391
3621
|
sinon.stub(InternalMediaCoreModule, 'StatsAnalyzer').returns(statsAnalyzerStub);
|
3392
3622
|
|
@@ -3427,6 +3657,40 @@ describe('plugin-meetings', () => {
|
|
3427
3657
|
});
|
3428
3658
|
});
|
3429
3659
|
|
3660
|
+
it('LOCAL_MEDIA_STARTED triggers "meeting:media:local:start" event and does not send metric because we already have', async () => {
|
3661
|
+
meeting.shareCAEventSentStatus = {
|
3662
|
+
transmitStart: true,
|
3663
|
+
transmitStop: false,
|
3664
|
+
receiveStart: false,
|
3665
|
+
receiveStop: false,
|
3666
|
+
};
|
3667
|
+
statsAnalyzerStub.emit(
|
3668
|
+
{file: 'test', function: 'test'},
|
3669
|
+
StatsAnalyzerEventNames.LOCAL_MEDIA_STARTED,
|
3670
|
+
{mediaType: 'share'}
|
3671
|
+
);
|
3672
|
+
|
3673
|
+
assert.calledWith(
|
3674
|
+
TriggerProxy.trigger,
|
3675
|
+
sinon.match.instanceOf(Meeting),
|
3676
|
+
{
|
3677
|
+
file: 'meeting/index',
|
3678
|
+
function: 'addMedia',
|
3679
|
+
},
|
3680
|
+
EVENT_TRIGGERS.MEETING_MEDIA_LOCAL_STARTED,
|
3681
|
+
{
|
3682
|
+
mediaType: 'share',
|
3683
|
+
}
|
3684
|
+
);
|
3685
|
+
assert.neverCalledWith(webex.internal.newMetrics.submitClientEvent, {
|
3686
|
+
name: 'client.media.tx.start',
|
3687
|
+
payload: {mediaType: 'share', shareInstanceId: meeting.remoteShareInstanceId},
|
3688
|
+
options: {
|
3689
|
+
meetingId: meeting.id,
|
3690
|
+
},
|
3691
|
+
});
|
3692
|
+
});
|
3693
|
+
|
3430
3694
|
it('LOCAL_MEDIA_STOPPED triggers the right metrics', async () => {
|
3431
3695
|
statsAnalyzerStub.emit(
|
3432
3696
|
{file: 'test', function: 'test'},
|
@@ -3443,6 +3707,28 @@ describe('plugin-meetings', () => {
|
|
3443
3707
|
});
|
3444
3708
|
});
|
3445
3709
|
|
3710
|
+
it('LOCAL_MEDIA_STOPPED does not send metric because we already have', async () => {
|
3711
|
+
meeting.shareCAEventSentStatus = {
|
3712
|
+
transmitStart: false,
|
3713
|
+
transmitStop: true,
|
3714
|
+
receiveStart: false,
|
3715
|
+
receiveStop: false,
|
3716
|
+
};
|
3717
|
+
statsAnalyzerStub.emit(
|
3718
|
+
{file: 'test', function: 'test'},
|
3719
|
+
StatsAnalyzerEventNames.LOCAL_MEDIA_STOPPED,
|
3720
|
+
{mediaType: 'share'}
|
3721
|
+
);
|
3722
|
+
|
3723
|
+
assert.neverCalledWith(webex.internal.newMetrics.submitClientEvent, {
|
3724
|
+
name: 'client.media.tx.stop',
|
3725
|
+
payload: {mediaType: 'share', shareInstanceId: meeting.remoteShareInstanceId},
|
3726
|
+
options: {
|
3727
|
+
meetingId: meeting.id,
|
3728
|
+
},
|
3729
|
+
});
|
3730
|
+
});
|
3731
|
+
|
3446
3732
|
it('REMOTE_MEDIA_STARTED triggers "meeting:media:remote:start" event and sends metrics', async () => {
|
3447
3733
|
statsAnalyzerStub.emit(
|
3448
3734
|
{file: 'test', function: 'test'},
|
@@ -3523,6 +3809,47 @@ describe('plugin-meetings', () => {
|
|
3523
3809
|
});
|
3524
3810
|
});
|
3525
3811
|
|
3812
|
+
it('REMOTE_MEDIA_STARTED triggers "meeting:media:remote:start" event and does not send metric because we already have', async () => {
|
3813
|
+
meeting.shareCAEventSentStatus = {
|
3814
|
+
transmitStart: false,
|
3815
|
+
transmitStop: false,
|
3816
|
+
receiveStart: true,
|
3817
|
+
receiveStop: false,
|
3818
|
+
};
|
3819
|
+
statsAnalyzerStub.emit(
|
3820
|
+
{file: 'test', function: 'test'},
|
3821
|
+
StatsAnalyzerEventNames.REMOTE_MEDIA_STARTED,
|
3822
|
+
{mediaType: 'share'}
|
3823
|
+
);
|
3824
|
+
|
3825
|
+
assert.calledWith(
|
3826
|
+
TriggerProxy.trigger,
|
3827
|
+
sinon.match.instanceOf(Meeting),
|
3828
|
+
{
|
3829
|
+
file: 'meeting/index',
|
3830
|
+
function: 'addMedia',
|
3831
|
+
},
|
3832
|
+
EVENT_TRIGGERS.MEETING_MEDIA_REMOTE_STARTED,
|
3833
|
+
{
|
3834
|
+
mediaType: 'share',
|
3835
|
+
}
|
3836
|
+
);
|
3837
|
+
assert.neverCalledWith(webex.internal.newMetrics.submitClientEvent, {
|
3838
|
+
name: 'client.media.render.start',
|
3839
|
+
payload: {mediaType: 'share', shareInstanceId: meeting.remoteShareInstanceId},
|
3840
|
+
options: {
|
3841
|
+
meetingId: meeting.id,
|
3842
|
+
},
|
3843
|
+
});
|
3844
|
+
assert.neverCalledWith(webex.internal.newMetrics.submitClientEvent, {
|
3845
|
+
name: 'client.media.rx.start',
|
3846
|
+
payload: {mediaType: 'share', shareInstanceId: meeting.remoteShareInstanceId},
|
3847
|
+
options: {
|
3848
|
+
meetingId: meeting.id,
|
3849
|
+
},
|
3850
|
+
});
|
3851
|
+
});
|
3852
|
+
|
3526
3853
|
it('REMOTE_MEDIA_STOPPED triggers the right metrics for share', async () => {
|
3527
3854
|
statsAnalyzerStub.emit(
|
3528
3855
|
{file: 'test', function: 'test'},
|
@@ -3547,21 +3874,49 @@ describe('plugin-meetings', () => {
|
|
3547
3874
|
});
|
3548
3875
|
});
|
3549
3876
|
|
3877
|
+
it('REMOTE_MEDIA_STOPPED does not send metric because we already have', async () => {
|
3878
|
+
meeting.shareCAEventSentStatus = {
|
3879
|
+
transmitStart: false,
|
3880
|
+
transmitStop: false,
|
3881
|
+
receiveStart: true,
|
3882
|
+
receiveStop: true,
|
3883
|
+
};
|
3884
|
+
statsAnalyzerStub.emit(
|
3885
|
+
{file: 'test', function: 'test'},
|
3886
|
+
StatsAnalyzerEventNames.REMOTE_MEDIA_STOPPED,
|
3887
|
+
{mediaType: 'share'}
|
3888
|
+
);
|
3889
|
+
assert.neverCalledWith(webex.internal.newMetrics.submitClientEvent, {
|
3890
|
+
name: 'client.media.render.stop',
|
3891
|
+
payload: {mediaType: 'share', shareInstanceId: meeting.remoteShareInstanceId},
|
3892
|
+
options: {
|
3893
|
+
meetingId: meeting.id,
|
3894
|
+
},
|
3895
|
+
});
|
3896
|
+
assert.neverCalledWith(webex.internal.newMetrics.submitClientEvent, {
|
3897
|
+
name: 'client.media.rx.stop',
|
3898
|
+
payload: {mediaType: 'share', shareInstanceId: meeting.remoteShareInstanceId},
|
3899
|
+
options: {
|
3900
|
+
meetingId: meeting.id,
|
3901
|
+
},
|
3902
|
+
});
|
3903
|
+
});
|
3904
|
+
|
3550
3905
|
it('counts the number of members that are in the meeting for MEDIA_QUALITY event', async () => {
|
3551
3906
|
let fakeMembersCollection = {
|
3552
3907
|
members: {
|
3553
|
-
member1: {
|
3554
|
-
member2: {
|
3555
|
-
member3: {
|
3908
|
+
member1: {isInMeeting: true},
|
3909
|
+
member2: {isInMeeting: true},
|
3910
|
+
member3: {isInMeeting: false},
|
3556
3911
|
},
|
3557
3912
|
};
|
3558
|
-
sinon.stub(meeting, 'getMembers').returns({
|
3559
|
-
const fakeData = {
|
3913
|
+
sinon.stub(meeting, 'getMembers').returns({membersCollection: fakeMembersCollection});
|
3914
|
+
const fakeData = {intervalMetadata: {}};
|
3560
3915
|
|
3561
3916
|
statsAnalyzerStub.emit(
|
3562
|
-
{
|
3917
|
+
{file: 'test', function: 'test'},
|
3563
3918
|
StatsAnalyzerEventNames.MEDIA_QUALITY,
|
3564
|
-
{
|
3919
|
+
{data: fakeData}
|
3565
3920
|
);
|
3566
3921
|
|
3567
3922
|
assert.calledWithMatch(webex.internal.newMetrics.submitMQE, {
|
@@ -3570,15 +3925,17 @@ describe('plugin-meetings', () => {
|
|
3570
3925
|
meetingId: meeting.id,
|
3571
3926
|
},
|
3572
3927
|
payload: {
|
3573
|
-
intervals: [
|
3928
|
+
intervals: [
|
3929
|
+
sinon.match.has('intervalMetadata', sinon.match.has('meetingUserCount', 2)),
|
3930
|
+
],
|
3574
3931
|
},
|
3575
3932
|
});
|
3576
3933
|
fakeMembersCollection.members.member2.isInMeeting = false;
|
3577
3934
|
|
3578
3935
|
statsAnalyzerStub.emit(
|
3579
|
-
{
|
3936
|
+
{file: 'test', function: 'test'},
|
3580
3937
|
StatsAnalyzerEventNames.MEDIA_QUALITY,
|
3581
|
-
{
|
3938
|
+
{data: fakeData}
|
3582
3939
|
);
|
3583
3940
|
|
3584
3941
|
assert.calledWithMatch(webex.internal.newMetrics.submitMQE, {
|
@@ -3587,13 +3944,15 @@ describe('plugin-meetings', () => {
|
|
3587
3944
|
meetingId: meeting.id,
|
3588
3945
|
},
|
3589
3946
|
payload: {
|
3590
|
-
intervals: [
|
3947
|
+
intervals: [
|
3948
|
+
sinon.match.has('intervalMetadata', sinon.match.has('meetingUserCount', 1)),
|
3949
|
+
],
|
3591
3950
|
},
|
3592
3951
|
});
|
3593
3952
|
});
|
3594
3953
|
|
3595
3954
|
it('calls submitMQE correctly', async () => {
|
3596
|
-
const fakeData = {intervalMetadata: {bla: 'bla'}
|
3955
|
+
const fakeData = {intervalMetadata: {bla: 'bla'}};
|
3597
3956
|
|
3598
3957
|
statsAnalyzerStub.emit(
|
3599
3958
|
{file: 'test', function: 'test'},
|
@@ -3624,7 +3983,7 @@ describe('plugin-meetings', () => {
|
|
3624
3983
|
|
3625
3984
|
meeting.roap.doTurnDiscovery = sinon.stub().resolves({
|
3626
3985
|
turnServerInfo: {
|
3627
|
-
|
3986
|
+
urls: [FAKE_TURN_URL],
|
3628
3987
|
username: FAKE_TURN_USER,
|
3629
3988
|
password: FAKE_TURN_PASSWORD,
|
3630
3989
|
},
|
@@ -3650,7 +4009,7 @@ describe('plugin-meetings', () => {
|
|
3650
4009
|
meeting.id,
|
3651
4010
|
sinon.match({
|
3652
4011
|
turnServerInfo: {
|
3653
|
-
|
4012
|
+
urls: [FAKE_TURN_URL],
|
3654
4013
|
username: FAKE_TURN_USER,
|
3655
4014
|
password: FAKE_TURN_PASSWORD,
|
3656
4015
|
},
|
@@ -3801,6 +4160,9 @@ describe('plugin-meetings', () => {
|
|
3801
4160
|
},
|
3802
4161
|
options: {
|
3803
4162
|
meetingId: meeting.id,
|
4163
|
+
rawError: {
|
4164
|
+
iceConnected: false,
|
4165
|
+
},
|
3804
4166
|
},
|
3805
4167
|
},
|
3806
4168
|
]);
|
@@ -3830,7 +4192,7 @@ describe('plugin-meetings', () => {
|
|
3830
4192
|
meeting.deviceUrl = 'device url';
|
3831
4193
|
meeting.selfId = 'self id';
|
3832
4194
|
meeting.brbState = createBrbState(meeting, false);
|
3833
|
-
meeting.brbState
|
4195
|
+
sinon.stub(meeting.brbState, 'enable').resolves();
|
3834
4196
|
});
|
3835
4197
|
|
3836
4198
|
afterEach(() => {
|
@@ -3842,7 +4204,6 @@ describe('plugin-meetings', () => {
|
|
3842
4204
|
});
|
3843
4205
|
|
3844
4206
|
describe('when in a multistream meeting', () => {
|
3845
|
-
|
3846
4207
|
beforeEach(() => {
|
3847
4208
|
meeting.isMultistream = true;
|
3848
4209
|
});
|
@@ -3853,7 +4214,7 @@ describe('plugin-meetings', () => {
|
|
3853
4214
|
await brbResult;
|
3854
4215
|
assert.exists(brbResult.then);
|
3855
4216
|
assert.calledOnce(meeting.brbState.enable);
|
3856
|
-
})
|
4217
|
+
});
|
3857
4218
|
|
3858
4219
|
it('should disable #beRightBack and return a promise', async () => {
|
3859
4220
|
const brbResult = meeting.beRightBack(false);
|
@@ -3861,7 +4222,7 @@ describe('plugin-meetings', () => {
|
|
3861
4222
|
await brbResult;
|
3862
4223
|
assert.exists(brbResult.then);
|
3863
4224
|
assert.calledOnce(meeting.brbState.enable);
|
3864
|
-
})
|
4225
|
+
});
|
3865
4226
|
|
3866
4227
|
it('should throw an error and reject the promise if setBrb fails', async () => {
|
3867
4228
|
const error = new Error('setBrb failed');
|
@@ -3872,9 +4233,42 @@ describe('plugin-meetings', () => {
|
|
3872
4233
|
} catch (err) {
|
3873
4234
|
assert.instanceOf(err, Error);
|
3874
4235
|
assert.equal(err.message, 'setBrb failed');
|
3875
|
-
assert.isRejected(
|
4236
|
+
assert.isRejected(Promise.reject());
|
3876
4237
|
}
|
3877
|
-
})
|
4238
|
+
});
|
4239
|
+
|
4240
|
+
it('updates remote mute state when brb is enabled', async () => {
|
4241
|
+
meeting.audio = {handleServerRemoteMuteUpdate: sinon.stub()};
|
4242
|
+
|
4243
|
+
await meeting.beRightBack(true);
|
4244
|
+
|
4245
|
+
sinon.assert.calledOnceWithExactly(
|
4246
|
+
meeting.audio.handleServerRemoteMuteUpdate,
|
4247
|
+
meeting,
|
4248
|
+
true
|
4249
|
+
);
|
4250
|
+
});
|
4251
|
+
|
4252
|
+
it('does not update remote mute state when brb is disabled', async () => {
|
4253
|
+
meeting.audio = {handleServerRemoteMuteUpdate: sinon.stub()};
|
4254
|
+
|
4255
|
+
await meeting.beRightBack(false);
|
4256
|
+
|
4257
|
+
assert.notCalled(meeting.audio.handleServerRemoteMuteUpdate);
|
4258
|
+
});
|
4259
|
+
|
4260
|
+
it('should reject when brb enable fails', async () => {
|
4261
|
+
meeting.brbState.enable.restore();
|
4262
|
+
|
4263
|
+
const error = new Error();
|
4264
|
+
meeting.meetingRequest.setBrb = sinon.stub().rejects(error);
|
4265
|
+
|
4266
|
+
await expect(
|
4267
|
+
meeting.beRightBack(true)
|
4268
|
+
).to.be.rejectedWith(error);
|
4269
|
+
|
4270
|
+
assert.isFalse(meeting.brbState.state.syncToServerInProgress);
|
4271
|
+
});
|
3878
4272
|
});
|
3879
4273
|
});
|
3880
4274
|
|
@@ -3928,7 +4322,10 @@ describe('plugin-meetings', () => {
|
|
3928
4322
|
.resolves({id: 'fake clientMediaPreferences'});
|
3929
4323
|
meeting.roap.doTurnDiscovery = sinon.stub().resolves({
|
3930
4324
|
turnServerInfo: {
|
3931
|
-
|
4325
|
+
urls: [
|
4326
|
+
'turns:turn-server-url1:443?transport=tcp',
|
4327
|
+
'turns:turn-server-url2:443?transport=tcp',
|
4328
|
+
],
|
3932
4329
|
username: 'turn user',
|
3933
4330
|
password: 'turn password',
|
3934
4331
|
},
|
@@ -3946,12 +4343,10 @@ describe('plugin-meetings', () => {
|
|
3946
4343
|
expectedMediaConnectionConfig = {
|
3947
4344
|
iceServers: [
|
3948
4345
|
{
|
3949
|
-
urls:
|
3950
|
-
|
3951
|
-
|
3952
|
-
|
3953
|
-
{
|
3954
|
-
urls: 'turns:turn-server-url:443?transport=tcp',
|
4346
|
+
urls: [
|
4347
|
+
'turns:turn-server-url1:443?transport=tcp',
|
4348
|
+
'turns:turn-server-url2:443?transport=tcp',
|
4349
|
+
],
|
3955
4350
|
username: 'turn user',
|
3956
4351
|
credential: 'turn password',
|
3957
4352
|
},
|
@@ -4006,7 +4401,7 @@ describe('plugin-meetings', () => {
|
|
4006
4401
|
initiateOffer: sinon.stub().resolves({}),
|
4007
4402
|
update: sinon.stub().resolves({}),
|
4008
4403
|
on: sinon.stub(),
|
4009
|
-
roapMessageReceived: sinon.stub()
|
4404
|
+
roapMessageReceived: sinon.stub(),
|
4010
4405
|
};
|
4011
4406
|
|
4012
4407
|
fakeMultistreamRoapMediaConnection = {
|
@@ -4033,9 +4428,11 @@ describe('plugin-meetings', () => {
|
|
4033
4428
|
.stub(InternalMediaCoreModule, 'MultistreamRoapMediaConnection')
|
4034
4429
|
.returns(fakeMultistreamRoapMediaConnection);
|
4035
4430
|
|
4036
|
-
locusMediaRequestStub = sinon
|
4037
|
-
|
4038
|
-
.
|
4431
|
+
locusMediaRequestStub = sinon.stub(WebexPlugin.prototype, 'request').resolves({
|
4432
|
+
body: {locus: {fullState: {}}},
|
4433
|
+
upload: sinon.match.instanceOf(EventEmitter),
|
4434
|
+
download: sinon.match.instanceOf(EventEmitter),
|
4435
|
+
});
|
4039
4436
|
|
4040
4437
|
// setup some things and mocks so that the call to join() works
|
4041
4438
|
// (we need to call join() because it creates the LocusMediaRequest instance
|
@@ -4144,6 +4541,8 @@ describe('plugin-meetings', () => {
|
|
4144
4541
|
id: 'fake clientMediaPreferences',
|
4145
4542
|
},
|
4146
4543
|
},
|
4544
|
+
upload: sinon.match.instanceOf(EventEmitter),
|
4545
|
+
download: sinon.match.instanceOf(EventEmitter),
|
4147
4546
|
});
|
4148
4547
|
};
|
4149
4548
|
|
@@ -4171,6 +4570,8 @@ describe('plugin-meetings', () => {
|
|
4171
4570
|
},
|
4172
4571
|
],
|
4173
4572
|
},
|
4573
|
+
upload: sinon.match.instanceOf(EventEmitter),
|
4574
|
+
download: sinon.match.instanceOf(EventEmitter),
|
4174
4575
|
});
|
4175
4576
|
};
|
4176
4577
|
|
@@ -4195,6 +4596,8 @@ describe('plugin-meetings', () => {
|
|
4195
4596
|
respOnlySdp: true,
|
4196
4597
|
usingResource: null,
|
4197
4598
|
},
|
4599
|
+
upload: sinon.match.instanceOf(EventEmitter),
|
4600
|
+
download: sinon.match.instanceOf(EventEmitter),
|
4198
4601
|
});
|
4199
4602
|
};
|
4200
4603
|
|
@@ -5213,7 +5616,10 @@ describe('plugin-meetings', () => {
|
|
5213
5616
|
// and check that when we fallback to transcoded we still do another TURN discovery
|
5214
5617
|
await runCheck(
|
5215
5618
|
{
|
5216
|
-
|
5619
|
+
urls: [
|
5620
|
+
'turns:turn-server-url1:443?transport=tcp',
|
5621
|
+
'turns:turn-server-url2:443?transport=tcp',
|
5622
|
+
],
|
5217
5623
|
username: 'turn user',
|
5218
5624
|
password: 'turn password',
|
5219
5625
|
},
|
@@ -5227,7 +5633,10 @@ describe('plugin-meetings', () => {
|
|
5227
5633
|
// but doing it just for completeness
|
5228
5634
|
await runCheck(
|
5229
5635
|
{
|
5230
|
-
|
5636
|
+
urls: [
|
5637
|
+
'turns:turn-server-url1:443?transport=tcp',
|
5638
|
+
'turns:turn-server-url2:443?transport=tcp',
|
5639
|
+
],
|
5231
5640
|
username: 'turn user',
|
5232
5641
|
password: 'turn password',
|
5233
5642
|
},
|
@@ -6337,7 +6746,10 @@ describe('plugin-meetings', () => {
|
|
6337
6746
|
.throws(new MeetingInfoV2JoinForbiddenError(403003, FAKE_MEETING_INFO)),
|
6338
6747
|
};
|
6339
6748
|
|
6340
|
-
await assert.isRejected(
|
6749
|
+
await assert.isRejected(
|
6750
|
+
meeting.fetchMeetingInfo({sendCAevents: true}),
|
6751
|
+
JoinForbiddenError
|
6752
|
+
);
|
6341
6753
|
|
6342
6754
|
assert.calledWith(
|
6343
6755
|
meeting.attrs.meetingInfoProvider.fetchMeetingInfo,
|
@@ -6353,10 +6765,7 @@ describe('plugin-meetings', () => {
|
|
6353
6765
|
|
6354
6766
|
assert.deepEqual(meeting.meetingInfo, FAKE_MEETING_INFO);
|
6355
6767
|
assert.equal(meeting.meetingInfoFailureCode, 403003);
|
6356
|
-
assert.equal(
|
6357
|
-
meeting.meetingInfoFailureReason,
|
6358
|
-
MEETING_INFO_FAILURE_REASON.NOT_REACH_JBH
|
6359
|
-
);
|
6768
|
+
assert.equal(meeting.meetingInfoFailureReason, MEETING_INFO_FAILURE_REASON.NOT_REACH_JBH);
|
6360
6769
|
assert.equal(meeting.requiredCaptcha, null);
|
6361
6770
|
});
|
6362
6771
|
|
@@ -6733,15 +7142,10 @@ describe('plugin-meetings', () => {
|
|
6733
7142
|
meeting.attrs.meetingInfoProvider = {
|
6734
7143
|
fetchMeetingInfo: sinon
|
6735
7144
|
.stub()
|
6736
|
-
.throws(
|
6737
|
-
new MeetingInfoV2JoinWebinarError(403021, FAKE_MEETING_INFO, 'a message')
|
6738
|
-
),
|
7145
|
+
.throws(new MeetingInfoV2JoinWebinarError(403021, FAKE_MEETING_INFO, 'a message')),
|
6739
7146
|
};
|
6740
7147
|
|
6741
|
-
await assert.isRejected(
|
6742
|
-
meeting.fetchMeetingInfo({sendCAevents: true}),
|
6743
|
-
JoinWebinarError
|
6744
|
-
);
|
7148
|
+
await assert.isRejected(meeting.fetchMeetingInfo({sendCAevents: true}), JoinWebinarError);
|
6745
7149
|
|
6746
7150
|
assert.deepEqual(meeting.meetingInfo, FAKE_MEETING_INFO);
|
6747
7151
|
assert.equal(
|
@@ -6756,15 +7160,10 @@ describe('plugin-meetings', () => {
|
|
6756
7160
|
meeting.attrs.meetingInfoProvider = {
|
6757
7161
|
fetchMeetingInfo: sinon
|
6758
7162
|
.stub()
|
6759
|
-
.throws(
|
6760
|
-
new MeetingInfoV2JoinWebinarError(403026, FAKE_MEETING_INFO, 'a message')
|
6761
|
-
),
|
7163
|
+
.throws(new MeetingInfoV2JoinWebinarError(403026, FAKE_MEETING_INFO, 'a message')),
|
6762
7164
|
};
|
6763
7165
|
|
6764
|
-
await assert.isRejected(
|
6765
|
-
meeting.fetchMeetingInfo({sendCAevents: true}),
|
6766
|
-
JoinWebinarError
|
6767
|
-
);
|
7166
|
+
await assert.isRejected(meeting.fetchMeetingInfo({sendCAevents: true}), JoinWebinarError);
|
6768
7167
|
|
6769
7168
|
assert.deepEqual(meeting.meetingInfo, FAKE_MEETING_INFO);
|
6770
7169
|
assert.equal(
|
@@ -6779,15 +7178,10 @@ describe('plugin-meetings', () => {
|
|
6779
7178
|
meeting.attrs.meetingInfoProvider = {
|
6780
7179
|
fetchMeetingInfo: sinon
|
6781
7180
|
.stub()
|
6782
|
-
.throws(
|
6783
|
-
new MeetingInfoV2JoinWebinarError(403037, FAKE_MEETING_INFO, 'a message')
|
6784
|
-
),
|
7181
|
+
.throws(new MeetingInfoV2JoinWebinarError(403037, FAKE_MEETING_INFO, 'a message')),
|
6785
7182
|
};
|
6786
7183
|
|
6787
|
-
await assert.isRejected(
|
6788
|
-
meeting.fetchMeetingInfo({sendCAevents: true}),
|
6789
|
-
JoinWebinarError
|
6790
|
-
);
|
7184
|
+
await assert.isRejected(meeting.fetchMeetingInfo({sendCAevents: true}), JoinWebinarError);
|
6791
7185
|
|
6792
7186
|
assert.deepEqual(meeting.meetingInfo, FAKE_MEETING_INFO);
|
6793
7187
|
assert.equal(
|
@@ -7524,6 +7918,27 @@ describe('plugin-meetings', () => {
|
|
7524
7918
|
});
|
7525
7919
|
});
|
7526
7920
|
|
7921
|
+
describe('#setIsoLocalClientMeetingJoinTime', () => {
|
7922
|
+
it('should fallback to system clock ISO string when given an undefined value', () => {
|
7923
|
+
const currentSystemTime = new Date().toISOString();
|
7924
|
+
meeting.isoLocalClientMeetingJoinTime = undefined;
|
7925
|
+
assert.equal(meeting.isoLocalClientMeetingJoinTime, currentSystemTime);
|
7926
|
+
});
|
7927
|
+
|
7928
|
+
it('should fallback to system clock ISO string when given an invalid value', () => {
|
7929
|
+
const currentSystemTime = new Date().toISOString();
|
7930
|
+
meeting.isoLocalClientMeetingJoinTime = 'invalid-date';
|
7931
|
+
assert.equal(meeting.isoLocalClientMeetingJoinTime, currentSystemTime);
|
7932
|
+
});
|
7933
|
+
|
7934
|
+
it('should set the isoLocalClientMeetingJoinTime correctly for a valid date string', () => {
|
7935
|
+
const validDateString = 'Tue, 01 Apr 2025 13:00:36 GMT';
|
7936
|
+
const expectedISOString = new Date(validDateString).toISOString();
|
7937
|
+
meeting.isoLocalClientMeetingJoinTime = validDateString;
|
7938
|
+
assert.equal(meeting.isoLocalClientMeetingJoinTime, expectedISOString);
|
7939
|
+
});
|
7940
|
+
});
|
7941
|
+
|
7527
7942
|
describe('#updateCallStateForMetrics', () => {
|
7528
7943
|
it('should update the callState, overriding existing values', () => {
|
7529
7944
|
assert.deepEqual(meeting.callStateForMetrics, {correlationId, sessionCorrelationId: ''});
|
@@ -7605,6 +8020,12 @@ describe('plugin-meetings', () => {
|
|
7605
8020
|
meeting.audio = {handleLocalStreamChange: sinon.stub()};
|
7606
8021
|
meeting.video = {handleLocalStreamChange: sinon.stub()};
|
7607
8022
|
meeting.statsAnalyzer = {updateMediaStatus: sinon.stub()};
|
8023
|
+
meeting.shareCAEventSentStatus = {
|
8024
|
+
transmitStart: false,
|
8025
|
+
transmitStop: false,
|
8026
|
+
receiveStart: false,
|
8027
|
+
receiveStop: false,
|
8028
|
+
};
|
7608
8029
|
fakeMultistreamRoapMediaConnection = {
|
7609
8030
|
createSendSlot: () => {
|
7610
8031
|
return {
|
@@ -7672,6 +8093,9 @@ describe('plugin-meetings', () => {
|
|
7672
8093
|
});
|
7673
8094
|
assert.equal(meeting.mediaProperties.mediaDirection.sendShare, true);
|
7674
8095
|
|
8096
|
+
assert.equal(meeting.shareCAEventSentStatus.transmitStart, false);
|
8097
|
+
assert.equal(meeting.shareCAEventSentStatus.transmitStop, false);
|
8098
|
+
|
7675
8099
|
assert.calledWith(meeting.statsAnalyzer.updateMediaStatus, {
|
7676
8100
|
expected: {sendShare: true},
|
7677
8101
|
});
|
@@ -7692,18 +8116,23 @@ describe('plugin-meetings', () => {
|
|
7692
8116
|
assert.equal(meeting.mediaProperties.shareAudioStream, stream);
|
7693
8117
|
assert.equal(meeting.mediaProperties.mediaDirection.sendShare, true);
|
7694
8118
|
|
8119
|
+
assert.equal(meeting.shareCAEventSentStatus.transmitStart, false);
|
8120
|
+
assert.equal(meeting.shareCAEventSentStatus.transmitStop, false);
|
8121
|
+
|
7695
8122
|
assert.calledWith(meeting.statsAnalyzer.updateMediaStatus, {
|
7696
8123
|
expected: {sendShare: true},
|
7697
8124
|
});
|
7698
8125
|
};
|
7699
8126
|
|
7700
8127
|
it('requests screen share floor and publishes the screen share video stream', async () => {
|
8128
|
+
meeting.shareCAEventSentStatus.transmitStart = true;
|
7701
8129
|
await meeting.publishStreams({screenShare: {video: videoShareStream}});
|
7702
8130
|
|
7703
8131
|
checkScreenShareVideoPublished(videoShareStream);
|
7704
8132
|
});
|
7705
8133
|
|
7706
8134
|
it('requests screen share floor and publishes the screen share audio stream', async () => {
|
8135
|
+
meeting.shareCAEventSentStatus.transmitStart = true;
|
7707
8136
|
await meeting.publishStreams({screenShare: {audio: audioShareStream}});
|
7708
8137
|
|
7709
8138
|
checkScreenShareAudioPublished(audioShareStream);
|
@@ -8590,13 +9019,19 @@ describe('plugin-meetings', () => {
|
|
8590
9019
|
const fakeErrorMessage = 'test error';
|
8591
9020
|
const fakeRootCauseName = 'root cause name';
|
8592
9021
|
const fakeErrorName = 'test error name';
|
9022
|
+
let clock;
|
8593
9023
|
|
8594
9024
|
beforeEach(() => {
|
9025
|
+
clock = sinon.useFakeTimers();
|
8595
9026
|
meeting.setupMediaConnectionListeners();
|
8596
9027
|
webex.internal.newMetrics.submitClientEvent.resetHistory();
|
8597
9028
|
Metrics.sendBehavioralMetric.resetHistory();
|
8598
9029
|
});
|
8599
9030
|
|
9031
|
+
afterEach(() => {
|
9032
|
+
clock.restore();
|
9033
|
+
});
|
9034
|
+
|
8600
9035
|
const checkMetricSent = (event, error) => {
|
8601
9036
|
assert.calledOnce(webex.internal.newMetrics.submitClientEvent);
|
8602
9037
|
assert.calledWithMatch(webex.internal.newMetrics.submitClientEvent, {
|
@@ -8665,6 +9100,13 @@ describe('plugin-meetings', () => {
|
|
8665
9100
|
});
|
8666
9101
|
|
8667
9102
|
it('should send metrics for SdpAnswerHandlingError error', () => {
|
9103
|
+
meeting.sdpResponseTimer = '1234';
|
9104
|
+
meeting.deferSDPAnswer = {
|
9105
|
+
reject: sinon.stub(),
|
9106
|
+
};
|
9107
|
+
|
9108
|
+
const clearTimeoutSpy = sinon.spy(clock, 'clearTimeout');
|
9109
|
+
|
8668
9110
|
const fakeError = new Errors.SdpAnswerHandlingError(fakeErrorMessage, {
|
8669
9111
|
name: fakeErrorName,
|
8670
9112
|
cause: {name: fakeRootCauseName},
|
@@ -8679,6 +9121,8 @@ describe('plugin-meetings', () => {
|
|
8679
9121
|
fakeErrorMessage,
|
8680
9122
|
fakeRootCauseName
|
8681
9123
|
);
|
9124
|
+
assert.calledOnce(meeting.deferSDPAnswer.reject);
|
9125
|
+
assert.calledOnce(clearTimeoutSpy);
|
8682
9126
|
});
|
8683
9127
|
|
8684
9128
|
it('should send metrics for SdpError error', () => {
|
@@ -9223,22 +9667,22 @@ describe('plugin-meetings', () => {
|
|
9223
9667
|
const assertBrb = (enabled) => {
|
9224
9668
|
meeting.brbState = createBrbState(meeting, false);
|
9225
9669
|
meeting.locusInfo.emit(
|
9226
|
-
{
|
9670
|
+
{function: 'test', file: 'test'},
|
9227
9671
|
LOCUSINFO.EVENTS.SELF_MEETING_BRB_CHANGED,
|
9228
|
-
{
|
9229
|
-
)
|
9672
|
+
{brb: {enabled}}
|
9673
|
+
);
|
9230
9674
|
assert.calledWithExactly(
|
9231
9675
|
TriggerProxy.trigger,
|
9232
9676
|
meeting,
|
9233
9677
|
{file: 'meeting/index', function: 'setUpLocusInfoSelfListener'},
|
9234
9678
|
EVENT_TRIGGERS.MEETING_SELF_BRB_UPDATE,
|
9235
|
-
{
|
9679
|
+
{payload: {brb: {enabled}}}
|
9236
9680
|
);
|
9237
|
-
}
|
9681
|
+
};
|
9238
9682
|
|
9239
9683
|
assertBrb(true);
|
9240
9684
|
assertBrb(false);
|
9241
|
-
})
|
9685
|
+
});
|
9242
9686
|
|
9243
9687
|
it('listens to the interpretation changed event', () => {
|
9244
9688
|
meeting.simultaneousInterpretation.updateSelfInterpretation = sinon.stub();
|
@@ -9584,6 +10028,42 @@ describe('plugin-meetings', () => {
|
|
9584
10028
|
);
|
9585
10029
|
});
|
9586
10030
|
|
10031
|
+
it('listens to CONTROLS_ANNOTATION_CHANGED', async () => {
|
10032
|
+
const state = {example: 'value'};
|
10033
|
+
|
10034
|
+
await meeting.locusInfo.emitScoped(
|
10035
|
+
{function: 'test', file: 'test'},
|
10036
|
+
LOCUSINFO.EVENTS.CONTROLS_ANNOTATION_CHANGED,
|
10037
|
+
{state}
|
10038
|
+
);
|
10039
|
+
|
10040
|
+
assert.calledWith(
|
10041
|
+
TriggerProxy.trigger,
|
10042
|
+
meeting,
|
10043
|
+
{file: 'meeting/index', function: 'setupLocusControlsListener'},
|
10044
|
+
EVENT_TRIGGERS.MEETING_CONTROLS_ANNOTATION_UPDATED,
|
10045
|
+
{state}
|
10046
|
+
);
|
10047
|
+
});
|
10048
|
+
|
10049
|
+
it('listens to CONTROLS_REMOTE_DESKTOP_CONTROL_CHANGED', async () => {
|
10050
|
+
const state = {example: 'value'};
|
10051
|
+
|
10052
|
+
await meeting.locusInfo.emitScoped(
|
10053
|
+
{function: 'test', file: 'test'},
|
10054
|
+
LOCUSINFO.EVENTS.CONTROLS_REMOTE_DESKTOP_CONTROL_CHANGED,
|
10055
|
+
{state}
|
10056
|
+
);
|
10057
|
+
|
10058
|
+
assert.calledWith(
|
10059
|
+
TriggerProxy.trigger,
|
10060
|
+
meeting,
|
10061
|
+
{file: 'meeting/index', function: 'setupLocusControlsListener'},
|
10062
|
+
EVENT_TRIGGERS.MEETING_CONTROLS_REMOTE_DESKTOP_CONTROL_UPDATED,
|
10063
|
+
{state}
|
10064
|
+
);
|
10065
|
+
});
|
10066
|
+
|
9587
10067
|
it('listens to the locus interpretation update event', () => {
|
9588
10068
|
const interpretation = {
|
9589
10069
|
siLanguages: [{languageCode: 20, languageName: 'en'}],
|
@@ -9922,6 +10402,22 @@ describe('plugin-meetings', () => {
|
|
9922
10402
|
});
|
9923
10403
|
});
|
9924
10404
|
|
10405
|
+
describe('#emailInput', () => {
|
10406
|
+
it('should set the email input', () => {
|
10407
|
+
assert.notOk(meeting.emailInput);
|
10408
|
+
meeting.emailInput = 'current';
|
10409
|
+
assert.equal(meeting.emailInput, 'current');
|
10410
|
+
});
|
10411
|
+
});
|
10412
|
+
|
10413
|
+
describe('#userNameInput', () => {
|
10414
|
+
it('should set the user name input', () => {
|
10415
|
+
assert.notOk(meeting.userNameInput);
|
10416
|
+
meeting.userNameInput = 'current';
|
10417
|
+
assert.equal(meeting.userNameInput, 'current');
|
10418
|
+
});
|
10419
|
+
});
|
10420
|
+
|
9925
10421
|
describe('#setPermissionTokenPayload', () => {
|
9926
10422
|
let now;
|
9927
10423
|
let clock;
|
@@ -10463,9 +10959,11 @@ describe('plugin-meetings', () => {
|
|
10463
10959
|
let canUserLowerSomeoneElsesHandSpy;
|
10464
10960
|
let waitingForOthersToJoinSpy;
|
10465
10961
|
let canSendReactionsSpy;
|
10962
|
+
let requiresPostMeetingDataConsentPromptSpy;
|
10466
10963
|
let canUserRenameSelfAndObservedSpy;
|
10467
10964
|
let canUserRenameOthersSpy;
|
10468
10965
|
let canShareWhiteBoardSpy;
|
10966
|
+
let canMoveToLobbySpy;
|
10469
10967
|
// Due to import tree issues, hasHints must be stubed within the scope of the `it`.
|
10470
10968
|
|
10471
10969
|
beforeEach(() => {
|
@@ -10490,8 +10988,13 @@ describe('plugin-meetings', () => {
|
|
10490
10988
|
waitingForOthersToJoinSpy = sinon.spy(MeetingUtil, 'waitingForOthersToJoin');
|
10491
10989
|
canSendReactionsSpy = sinon.spy(MeetingUtil, 'canSendReactions');
|
10492
10990
|
canUserRenameSelfAndObservedSpy = sinon.spy(MeetingUtil, 'canUserRenameSelfAndObserved');
|
10991
|
+
requiresPostMeetingDataConsentPromptSpy = sinon.spy(
|
10992
|
+
MeetingUtil,
|
10993
|
+
'requiresPostMeetingDataConsentPrompt'
|
10994
|
+
);
|
10493
10995
|
canUserRenameOthersSpy = sinon.spy(MeetingUtil, 'canUserRenameOthers');
|
10494
10996
|
canShareWhiteBoardSpy = sinon.spy(MeetingUtil, 'canShareWhiteBoard');
|
10997
|
+
canMoveToLobbySpy = sinon.spy(MeetingUtil, 'canMoveToLobby');
|
10495
10998
|
});
|
10496
10999
|
|
10497
11000
|
afterEach(() => {
|
@@ -10589,6 +11092,16 @@ describe('plugin-meetings', () => {
|
|
10589
11092
|
requiredDisplayHints: [],
|
10590
11093
|
requiredPolicies: [SELF_POLICY.SUPPORT_FILE_TRANSFER],
|
10591
11094
|
},
|
11095
|
+
{
|
11096
|
+
actionName: 'canRealtimeCloseCaption',
|
11097
|
+
requiredDisplayHints: [],
|
11098
|
+
requiredPolicies: [SELF_POLICY.SUPPORT_REALTIME_CLOSE_CAPTION],
|
11099
|
+
},
|
11100
|
+
{
|
11101
|
+
actionName: 'canRealtimeCloseCaptionManual',
|
11102
|
+
requiredDisplayHints: [],
|
11103
|
+
requiredPolicies: [SELF_POLICY.SUPPORT_REALTIME_CLOSE_CAPTION_MANUAL],
|
11104
|
+
},
|
10592
11105
|
{
|
10593
11106
|
actionName: 'canChat',
|
10594
11107
|
requiredDisplayHints: [],
|
@@ -10618,6 +11131,11 @@ describe('plugin-meetings', () => {
|
|
10618
11131
|
requiredDisplayHints: [],
|
10619
11132
|
requiredPolicies: [SELF_POLICY.SUPPORT_POLLING_AND_QA],
|
10620
11133
|
},
|
11134
|
+
{
|
11135
|
+
actionName: 'canShareWhiteBoard',
|
11136
|
+
requiredDisplayHints: [DISPLAY_HINTS.SHARE_WHITEBOARD],
|
11137
|
+
requiredPolicies: [SELF_POLICY.SUPPORT_WHITEBOARD],
|
11138
|
+
},
|
10621
11139
|
],
|
10622
11140
|
({
|
10623
11141
|
actionName,
|
@@ -11025,8 +11543,10 @@ describe('plugin-meetings', () => {
|
|
11025
11543
|
assert.calledWith(waitingForOthersToJoinSpy, userDisplayHints);
|
11026
11544
|
assert.calledWith(canSendReactionsSpy, null, userDisplayHints);
|
11027
11545
|
assert.calledWith(canUserRenameSelfAndObservedSpy, userDisplayHints);
|
11546
|
+
assert.calledWith(requiresPostMeetingDataConsentPromptSpy, userDisplayHints);
|
11028
11547
|
assert.calledWith(canUserRenameOthersSpy, userDisplayHints);
|
11029
|
-
assert.calledWith(canShareWhiteBoardSpy, userDisplayHints);
|
11548
|
+
assert.calledWith(canShareWhiteBoardSpy, userDisplayHints, selfUserPolicies);
|
11549
|
+
assert.calledWith(canMoveToLobbySpy, userDisplayHints);
|
11030
11550
|
|
11031
11551
|
assert.calledWith(ControlsOptionsUtil.hasHints, {
|
11032
11552
|
requiredHints: [DISPLAY_HINTS.MUTE_ALL],
|
@@ -11120,6 +11640,22 @@ describe('plugin-meetings', () => {
|
|
11120
11640
|
requiredPolicies: [SELF_POLICY.SUPPORT_VOIP],
|
11121
11641
|
policies: selfUserPolicies,
|
11122
11642
|
});
|
11643
|
+
assert.calledWith(ControlsOptionsUtil.hasHints, {
|
11644
|
+
requiredHints: [DISPLAY_HINTS.ENABLE_ANNOTATION_MEETING_OPTION],
|
11645
|
+
displayHints: userDisplayHints,
|
11646
|
+
});
|
11647
|
+
assert.calledWith(ControlsOptionsUtil.hasHints, {
|
11648
|
+
requiredHints: [DISPLAY_HINTS.DISABLE_ANNOTATION_MEETING_OPTION],
|
11649
|
+
displayHints: userDisplayHints,
|
11650
|
+
});
|
11651
|
+
assert.calledWith(ControlsOptionsUtil.hasHints, {
|
11652
|
+
requiredHints: [DISPLAY_HINTS.ENABLE_RDC_MEETING_OPTION],
|
11653
|
+
displayHints: userDisplayHints,
|
11654
|
+
});
|
11655
|
+
assert.calledWith(ControlsOptionsUtil.hasHints, {
|
11656
|
+
requiredHints: [DISPLAY_HINTS.DISABLE_RDC_MEETING_OPTION],
|
11657
|
+
displayHints: userDisplayHints,
|
11658
|
+
});
|
11123
11659
|
|
11124
11660
|
assert.calledWith(
|
11125
11661
|
TriggerProxy.trigger,
|
@@ -11251,7 +11787,10 @@ describe('plugin-meetings', () => {
|
|
11251
11787
|
|
11252
11788
|
const result = await meeting.updateLLMConnection();
|
11253
11789
|
|
11254
|
-
assert.calledWith(webex.internal.llm.disconnectLLM
|
11790
|
+
assert.calledWith(webex.internal.llm.disconnectLLM, {
|
11791
|
+
code: 3050,
|
11792
|
+
reason: 'done (permanent)',
|
11793
|
+
});
|
11255
11794
|
assert.calledWith(
|
11256
11795
|
webex.internal.llm.registerAndConnect,
|
11257
11796
|
'a different url',
|
@@ -11281,7 +11820,10 @@ describe('plugin-meetings', () => {
|
|
11281
11820
|
|
11282
11821
|
const result = await meeting.updateLLMConnection();
|
11283
11822
|
|
11284
|
-
assert.calledWith(webex.internal.llm.disconnectLLM
|
11823
|
+
assert.calledWith(webex.internal.llm.disconnectLLM, {
|
11824
|
+
code: 3050,
|
11825
|
+
reason: 'done (permanent)',
|
11826
|
+
});
|
11285
11827
|
assert.calledWith(
|
11286
11828
|
webex.internal.llm.registerAndConnect,
|
11287
11829
|
'a url',
|
@@ -11310,7 +11852,7 @@ describe('plugin-meetings', () => {
|
|
11310
11852
|
|
11311
11853
|
const result = await meeting.updateLLMConnection();
|
11312
11854
|
|
11313
|
-
assert.calledWith(webex.internal.llm.disconnectLLM);
|
11855
|
+
assert.calledWith(webex.internal.llm.disconnectLLM, undefined);
|
11314
11856
|
assert.notCalled(webex.internal.llm.registerAndConnect);
|
11315
11857
|
assert.equal(result, undefined);
|
11316
11858
|
assert.calledOnceWithExactly(
|
@@ -11320,18 +11862,21 @@ describe('plugin-meetings', () => {
|
|
11320
11862
|
);
|
11321
11863
|
});
|
11322
11864
|
|
11323
|
-
|
11324
11865
|
it('connect ps data channel if ps started in webinar', async () => {
|
11325
11866
|
meeting.joinedWith = {state: 'JOINED'};
|
11326
|
-
meeting.locusInfo = {
|
11867
|
+
meeting.locusInfo = {
|
11868
|
+
url: 'a url',
|
11869
|
+
info: {
|
11870
|
+
datachannelUrl: 'a datachannel url',
|
11871
|
+
practiceSessionDatachannelUrl: 'a ps datachannel url',
|
11872
|
+
},
|
11873
|
+
};
|
11327
11874
|
meeting.webinar.isJoinPracticeSessionDataChannel = sinon.stub().returns(true);
|
11328
11875
|
await meeting.updateLLMConnection();
|
11329
11876
|
|
11330
11877
|
assert.notCalled(webex.internal.llm.disconnectLLM);
|
11331
11878
|
assert.calledWith(webex.internal.llm.registerAndConnect, 'a url', 'a ps datachannel url');
|
11332
|
-
|
11333
11879
|
});
|
11334
|
-
|
11335
11880
|
});
|
11336
11881
|
|
11337
11882
|
describe('#setLocus', () => {
|
@@ -11749,24 +12294,29 @@ describe('plugin-meetings', () => {
|
|
11749
12294
|
|
11750
12295
|
activeSharingId.whiteboard = beneficiaryId;
|
11751
12296
|
|
11752
|
-
eventTrigger.share.push(
|
11753
|
-
|
11754
|
-
|
11755
|
-
|
11756
|
-
|
11757
|
-
|
11758
|
-
|
11759
|
-
|
11760
|
-
|
11761
|
-
|
11762
|
-
|
11763
|
-
|
11764
|
-
|
11765
|
-
|
11766
|
-
|
11767
|
-
|
11768
|
-
|
12297
|
+
eventTrigger.share.push(
|
12298
|
+
meeting.webinar.selfIsAttendee
|
12299
|
+
? {
|
12300
|
+
eventName: EVENT_TRIGGERS.MEETING_STARTED_SHARING_REMOTE,
|
12301
|
+
functionName: 'remoteShare',
|
12302
|
+
eventPayload: {
|
12303
|
+
memberId: null,
|
12304
|
+
url,
|
12305
|
+
shareInstanceId,
|
12306
|
+
annotationInfo: undefined,
|
12307
|
+
resourceType: undefined,
|
12308
|
+
},
|
12309
|
+
}
|
12310
|
+
: {
|
12311
|
+
eventName: EVENT_TRIGGERS.MEETING_STARTED_SHARING_WHITEBOARD,
|
12312
|
+
functionName: 'startWhiteboardShare',
|
12313
|
+
eventPayload: {resourceUrl, memberId: beneficiaryId},
|
12314
|
+
}
|
12315
|
+
);
|
11769
12316
|
|
12317
|
+
shareStatus = meeting.webinar.selfIsAttendee
|
12318
|
+
? SHARE_STATUS.REMOTE_SHARE_ACTIVE
|
12319
|
+
: SHARE_STATUS.WHITEBOARD_SHARE_ACTIVE;
|
11770
12320
|
}
|
11771
12321
|
|
11772
12322
|
if (eventTrigger.member) {
|
@@ -11798,24 +12348,29 @@ describe('plugin-meetings', () => {
|
|
11798
12348
|
newPayload.current.content.disposition = FLOOR_ACTION.ACCEPTED;
|
11799
12349
|
newPayload.current.content.beneficiaryId = otherBeneficiaryId;
|
11800
12350
|
|
11801
|
-
eventTrigger.share.push(
|
11802
|
-
|
11803
|
-
|
11804
|
-
|
11805
|
-
|
11806
|
-
|
11807
|
-
|
11808
|
-
|
11809
|
-
|
11810
|
-
|
11811
|
-
|
11812
|
-
|
11813
|
-
|
11814
|
-
|
11815
|
-
|
11816
|
-
|
11817
|
-
|
12351
|
+
eventTrigger.share.push(
|
12352
|
+
meeting.webinar.selfIsAttendee
|
12353
|
+
? {
|
12354
|
+
eventName: EVENT_TRIGGERS.MEETING_STARTED_SHARING_REMOTE,
|
12355
|
+
functionName: 'remoteShare',
|
12356
|
+
eventPayload: {
|
12357
|
+
memberId: null,
|
12358
|
+
url,
|
12359
|
+
shareInstanceId,
|
12360
|
+
annotationInfo: undefined,
|
12361
|
+
resourceType: undefined,
|
12362
|
+
},
|
12363
|
+
}
|
12364
|
+
: {
|
12365
|
+
eventName: EVENT_TRIGGERS.MEETING_STARTED_SHARING_WHITEBOARD,
|
12366
|
+
functionName: 'startWhiteboardShare',
|
12367
|
+
eventPayload: {resourceUrl, memberId: beneficiaryId},
|
12368
|
+
}
|
12369
|
+
);
|
11818
12370
|
|
12371
|
+
shareStatus = meeting.webinar.selfIsAttendee
|
12372
|
+
? SHARE_STATUS.REMOTE_SHARE_ACTIVE
|
12373
|
+
: SHARE_STATUS.WHITEBOARD_SHARE_ACTIVE;
|
11819
12374
|
} else {
|
11820
12375
|
eventTrigger.share.push({
|
11821
12376
|
eventName: EVENT_TRIGGERS.MEETING_STOPPED_SHARING_WHITEBOARD,
|
@@ -11945,24 +12500,26 @@ describe('plugin-meetings', () => {
|
|
11945
12500
|
describe('Whiteboard Share - Webinar Attendee', () => {
|
11946
12501
|
it('Scenario #1: Whiteboard sharing as a webinar attendee', () => {
|
11947
12502
|
// Set the webinar attendee flag
|
11948
|
-
meeting.webinar = {
|
12503
|
+
meeting.webinar = {selfIsAttendee: true};
|
11949
12504
|
meeting.locusInfo.info.isWebinar = true;
|
12505
|
+
meeting.shareCAEventSentStatus.receiveStart = true;
|
12506
|
+
meeting.shareCAEventSentStatus.receiveStop = true;
|
11950
12507
|
|
11951
12508
|
// Step 1: Start sharing whiteboard A
|
11952
12509
|
const data1 = generateData(
|
11953
|
-
blankPayload,
|
11954
|
-
true,
|
11955
|
-
false,
|
11956
|
-
USER_IDS.REMOTE_A,
|
12510
|
+
blankPayload, // Initial payload
|
12511
|
+
true, // isGranting: Granting share
|
12512
|
+
false, // isContent: Whiteboard (not content)
|
12513
|
+
USER_IDS.REMOTE_A, // Beneficiary ID: Remote user A
|
11957
12514
|
RESOURCE_URLS.WHITEBOARD_A // Resource URL: Whiteboard A
|
11958
12515
|
);
|
11959
12516
|
|
11960
12517
|
// Step 2: Stop sharing whiteboard A
|
11961
12518
|
const data2 = generateData(
|
11962
|
-
data1.payload,
|
11963
|
-
false,
|
11964
|
-
false,
|
11965
|
-
USER_IDS.REMOTE_A
|
12519
|
+
data1.payload, // Updated payload from Step 1
|
12520
|
+
false, // isGranting: Stopping share
|
12521
|
+
false, // isContent: Whiteboard
|
12522
|
+
USER_IDS.REMOTE_A // Beneficiary ID: Remote user A
|
11966
12523
|
);
|
11967
12524
|
|
11968
12525
|
// Validate the payload changes and status updates
|
@@ -11970,10 +12527,11 @@ describe('plugin-meetings', () => {
|
|
11970
12527
|
|
11971
12528
|
// Specific assertions for webinar attendee status
|
11972
12529
|
assert.equal(meeting.shareStatus, SHARE_STATUS.REMOTE_SHARE_ACTIVE);
|
12530
|
+
assert.equal(meeting.shareCAEventSentStatus.receiveStart, false);
|
12531
|
+
assert.equal(meeting.shareCAEventSentStatus.receiveStop, false);
|
11973
12532
|
});
|
11974
12533
|
});
|
11975
12534
|
|
11976
|
-
|
11977
12535
|
describe('Whiteboard A --> Whiteboard B', () => {
|
11978
12536
|
it('Scenario #1: you share both whiteboards', () => {
|
11979
12537
|
const data1 = generateData(
|
@@ -12626,6 +13184,31 @@ describe('plugin-meetings', () => {
|
|
12626
13184
|
});
|
12627
13185
|
});
|
12628
13186
|
});
|
13187
|
+
|
13188
|
+
describe('handleShareVideoStreamMuteStateChange', () => {
|
13189
|
+
it('should emit MEETING_SHARE_VIDEO_MUTE_STATE_CHANGE event with correct fields', () => {
|
13190
|
+
meeting.isMultistream = true;
|
13191
|
+
meeting.statsAnalyzer = {shareVideoEncoderImplementation: 'OpenH264'};
|
13192
|
+
meeting.mediaProperties.shareVideoStream = {
|
13193
|
+
getSettings: sinon.stub().returns({displaySurface: 'monitor', frameRate: 30}),
|
13194
|
+
};
|
13195
|
+
|
13196
|
+
meeting.handleShareVideoStreamMuteStateChange(true);
|
13197
|
+
|
13198
|
+
assert.calledOnceWithExactly(
|
13199
|
+
Metrics.sendBehavioralMetric,
|
13200
|
+
BEHAVIORAL_METRICS.MEETING_SHARE_VIDEO_MUTE_STATE_CHANGE,
|
13201
|
+
{
|
13202
|
+
correlationId: meeting.correlationId,
|
13203
|
+
muted: true,
|
13204
|
+
encoderImplementation: 'OpenH264',
|
13205
|
+
displaySurface: 'monitor',
|
13206
|
+
isMultistream: true,
|
13207
|
+
frameRate: 30,
|
13208
|
+
}
|
13209
|
+
);
|
13210
|
+
});
|
13211
|
+
});
|
12629
13212
|
});
|
12630
13213
|
|
12631
13214
|
describe('#startKeepAlive', () => {
|
@@ -12793,6 +13376,38 @@ describe('plugin-meetings', () => {
|
|
12793
13376
|
});
|
12794
13377
|
});
|
12795
13378
|
|
13379
|
+
describe('#setPostMeetingDataConsent', () => {
|
13380
|
+
it('should have #setPostMeetingDataConsent', () => {
|
13381
|
+
assert.exists(meeting.setPostMeetingDataConsent);
|
13382
|
+
});
|
13383
|
+
|
13384
|
+
beforeEach(() => {
|
13385
|
+
meeting.meetingRequest.setPostMeetingDataConsent = sinon
|
13386
|
+
.stub()
|
13387
|
+
.returns(Promise.resolve());
|
13388
|
+
});
|
13389
|
+
|
13390
|
+
[true, false].forEach((accept) => {
|
13391
|
+
it(`should send consent with ${accept}`, async () => {
|
13392
|
+
const id = uuidv4();
|
13393
|
+
meeting.locusUrl = `https://locus-test.wbx2.com/locus/api/v1/loci/${accept}`;
|
13394
|
+
meeting.deviceUrl = `https://wdm-test.wbx2.com/wdm/api/v1/devices/${accept}`;
|
13395
|
+
meeting.members.selfId = id;
|
13396
|
+
|
13397
|
+
const consentPromise = meeting.setPostMeetingDataConsent(accept);
|
13398
|
+
|
13399
|
+
assert.exists(consentPromise.then);
|
13400
|
+
await consentPromise;
|
13401
|
+
assert.calledOnceWithExactly(meeting.meetingRequest.setPostMeetingDataConsent, {
|
13402
|
+
locusUrl: `https://locus-test.wbx2.com/locus/api/v1/loci/${accept}`,
|
13403
|
+
postMeetingDataConsent: accept,
|
13404
|
+
selfId: id,
|
13405
|
+
deviceUrl: `https://wdm-test.wbx2.com/wdm/api/v1/devices/${accept}`,
|
13406
|
+
});
|
13407
|
+
});
|
13408
|
+
});
|
13409
|
+
});
|
13410
|
+
|
12796
13411
|
describe('#sendReaction', () => {
|
12797
13412
|
it('should have #sendReaction', () => {
|
12798
13413
|
assert.exists(meeting.sendReaction);
|
@@ -13284,7 +13899,7 @@ describe('plugin-meetings', () => {
|
|
13284
13899
|
await meeting.roapMessageReceived(fakeMessage);
|
13285
13900
|
|
13286
13901
|
assert.fail('Expected MultistreamNotSupportedError to be thrown');
|
13287
|
-
} catch(e) {
|
13902
|
+
} catch (e) {
|
13288
13903
|
assert.isTrue(e instanceof MultistreamNotSupportedError);
|
13289
13904
|
}
|
13290
13905
|
|