@webex/plugin-meetings 3.8.0 → 3.8.1-next.10
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 +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 +28 -123
- package/dist/constants.js.map +1 -1
- package/dist/controls-options-manager/enums.js +3 -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 +78 -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 +37 -11
- package/dist/locus-info/controlsUtils.js.map +1 -1
- package/dist/locus-info/index.js +92 -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 +21 -1
- package/dist/meeting/in-meeting-actions.js.map +1 -1
- package/dist/meeting/index.js +678 -344
- 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 +107 -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 +20 -85
- package/dist/types/controls-options-manager/enums.d.ts +4 -1
- package/dist/types/controls-options-manager/types.d.ts +10 -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 +20 -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 +30 -90
- package/src/controls-options-manager/enums.ts +3 -0
- package/src/controls-options-manager/types.ts +16 -1
- package/src/controls-options-manager/util.ts +93 -0
- package/src/interpretation/index.ts +3 -3
- package/src/locus-info/controlsUtils.ts +59 -14
- package/src/locus-info/index.ts +97 -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 +40 -0
- package/src/meeting/index.ts +470 -105
- 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 +62 -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 +178 -0
- package/test/unit/spec/interpretation/index.ts +39 -1
- package/test/unit/spec/locus-info/controlsUtils.js +155 -9
- package/test/unit/spec/locus-info/index.js +209 -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 +23 -4
- package/test/unit/spec/meeting/index.js +804 -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 +97 -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,9 @@ describe('plugin-meetings', () => {
|
|
2153
2227
|
someReachabilityMetric1: 'some value1',
|
2154
2228
|
someReachabilityMetric2: 'some value2',
|
2155
2229
|
selectedCandidatePairChanges: 2,
|
2230
|
+
subnet_reachable: null,
|
2231
|
+
selected_cluster: null,
|
2232
|
+
selected_subnet: null,
|
2156
2233
|
numTransports: 1,
|
2157
2234
|
iceCandidatesCount: 0,
|
2158
2235
|
}
|
@@ -2199,6 +2276,9 @@ describe('plugin-meetings', () => {
|
|
2199
2276
|
signalingState: 'unknown',
|
2200
2277
|
connectionState: 'unknown',
|
2201
2278
|
iceConnectionState: 'unknown',
|
2279
|
+
subnet_reachable: null,
|
2280
|
+
selected_cluster: null,
|
2281
|
+
selected_subnet: null,
|
2202
2282
|
})
|
2203
2283
|
);
|
2204
2284
|
|
@@ -2213,6 +2293,7 @@ describe('plugin-meetings', () => {
|
|
2213
2293
|
someReachabilityMetric1: 'some value1',
|
2214
2294
|
someReachabilityMetric2: 'some value2',
|
2215
2295
|
}),
|
2296
|
+
isSubnetReachable: sinon.stub().returns(true),
|
2216
2297
|
};
|
2217
2298
|
|
2218
2299
|
meeting.waitForRemoteSDPAnswer = sinon.stub().rejects();
|
@@ -2263,6 +2344,9 @@ describe('plugin-meetings', () => {
|
|
2263
2344
|
selectedCandidatePairChanges: 2,
|
2264
2345
|
numTransports: 1,
|
2265
2346
|
iceCandidatesCount: 0,
|
2347
|
+
subnet_reachable: null,
|
2348
|
+
selected_cluster: null,
|
2349
|
+
selected_subnet: null,
|
2266
2350
|
}
|
2267
2351
|
);
|
2268
2352
|
});
|
@@ -2320,6 +2404,9 @@ describe('plugin-meetings', () => {
|
|
2320
2404
|
signalingState: 'have-local-offer',
|
2321
2405
|
connectionState: 'connecting',
|
2322
2406
|
iceConnectionState: 'checking',
|
2407
|
+
subnet_reachable: null,
|
2408
|
+
selected_cluster: null,
|
2409
|
+
selected_subnet: null,
|
2323
2410
|
})
|
2324
2411
|
);
|
2325
2412
|
|
@@ -2377,6 +2464,9 @@ describe('plugin-meetings', () => {
|
|
2377
2464
|
signalingState: 'have-local-offer',
|
2378
2465
|
connectionState: 'connecting',
|
2379
2466
|
iceConnectionState: 'checking',
|
2467
|
+
subnet_reachable: null,
|
2468
|
+
selected_cluster: null,
|
2469
|
+
selected_subnet: null,
|
2380
2470
|
})
|
2381
2471
|
);
|
2382
2472
|
|
@@ -2655,7 +2745,7 @@ describe('plugin-meetings', () => {
|
|
2655
2745
|
|
2656
2746
|
meeting.roap.doTurnDiscovery = sinon.stub().resolves({
|
2657
2747
|
turnServerInfo: {
|
2658
|
-
|
2748
|
+
urls: [FAKE_TURN_URL],
|
2659
2749
|
username: FAKE_TURN_USER,
|
2660
2750
|
password: FAKE_TURN_PASSWORD,
|
2661
2751
|
},
|
@@ -2677,7 +2767,7 @@ describe('plugin-meetings', () => {
|
|
2677
2767
|
meeting.id,
|
2678
2768
|
sinon.match({
|
2679
2769
|
turnServerInfo: {
|
2680
|
-
|
2770
|
+
urls: [FAKE_TURN_URL],
|
2681
2771
|
username: FAKE_TURN_USER,
|
2682
2772
|
password: FAKE_TURN_PASSWORD,
|
2683
2773
|
},
|
@@ -2712,8 +2802,9 @@ describe('plugin-meetings', () => {
|
|
2712
2802
|
sinon.stub().returns(FAKE_ERROR));
|
2713
2803
|
webex.meetings.reachability = {
|
2714
2804
|
isWebexMediaBackendUnreachable: sinon.stub().resolves(false),
|
2715
|
-
getReachabilityMetrics: sinon.stub().resolves(),
|
2805
|
+
getReachabilityMetrics: sinon.stub().resolves({}),
|
2716
2806
|
stopReachability: sinon.stub(),
|
2807
|
+
isSubnetReachable: sinon.stub().returns(true),
|
2717
2808
|
};
|
2718
2809
|
const MOCK_CLIENT_ERROR_CODE = 2004;
|
2719
2810
|
const generateClientErrorCodeForIceFailureStub = sinon
|
@@ -2735,14 +2826,15 @@ describe('plugin-meetings', () => {
|
|
2735
2826
|
.onSecondCall()
|
2736
2827
|
.returns({
|
2737
2828
|
turnServerInfo: {
|
2738
|
-
|
2829
|
+
urls: [FAKE_TURN_URL],
|
2739
2830
|
username: FAKE_TURN_USER,
|
2740
2831
|
password: FAKE_TURN_PASSWORD,
|
2741
2832
|
},
|
2742
2833
|
turnDiscoverySkippedReason: undefined,
|
2743
2834
|
});
|
2744
2835
|
meeting.meetingState = 'ACTIVE';
|
2745
|
-
|
2836
|
+
const error = {iceConnected: false};
|
2837
|
+
meeting.mediaProperties.waitForMediaConnectionConnected.rejects(error);
|
2746
2838
|
|
2747
2839
|
const forceRtcMetricsSend = sinon.stub().resolves();
|
2748
2840
|
const closeMediaConnectionStub = sinon.stub();
|
@@ -2760,6 +2852,7 @@ describe('plugin-meetings', () => {
|
|
2760
2852
|
})
|
2761
2853
|
.catch((err) => {
|
2762
2854
|
errorThrown = err;
|
2855
|
+
assert.instanceOf(err.cause, Error);
|
2763
2856
|
assert.instanceOf(err, AddMediaFailed);
|
2764
2857
|
});
|
2765
2858
|
|
@@ -2816,6 +2909,7 @@ describe('plugin-meetings', () => {
|
|
2816
2909
|
},
|
2817
2910
|
options: {
|
2818
2911
|
meetingId: meeting.id,
|
2912
|
+
rawError: error,
|
2819
2913
|
},
|
2820
2914
|
});
|
2821
2915
|
assert.calledWith(webex.internal.newMetrics.submitClientEvent.thirdCall, {
|
@@ -2827,6 +2921,7 @@ describe('plugin-meetings', () => {
|
|
2827
2921
|
},
|
2828
2922
|
options: {
|
2829
2923
|
meetingId: meeting.id,
|
2924
|
+
rawError: error,
|
2830
2925
|
},
|
2831
2926
|
});
|
2832
2927
|
|
@@ -2893,6 +2988,9 @@ describe('plugin-meetings', () => {
|
|
2893
2988
|
selectedCandidatePairChanges: 2,
|
2894
2989
|
numTransports: 1,
|
2895
2990
|
iceCandidatesCount: 0,
|
2991
|
+
subnet_reachable: null,
|
2992
|
+
selected_cluster: null,
|
2993
|
+
selected_subnet: null,
|
2896
2994
|
},
|
2897
2995
|
]);
|
2898
2996
|
|
@@ -2923,6 +3021,7 @@ describe('plugin-meetings', () => {
|
|
2923
3021
|
.resolves(false),
|
2924
3022
|
getReachabilityMetrics: sinon.stub().resolves({}),
|
2925
3023
|
stopReachability: sinon.stub(),
|
3024
|
+
isSubnetReachable: sinon.stub().returns(true),
|
2926
3025
|
};
|
2927
3026
|
const getErrorPayloadForClientErrorCodeStub =
|
2928
3027
|
(webex.internal.newMetrics.callDiagnosticMetrics.getErrorPayloadForClientErrorCode =
|
@@ -2947,16 +3046,19 @@ describe('plugin-meetings', () => {
|
|
2947
3046
|
.onSecondCall()
|
2948
3047
|
.returns({
|
2949
3048
|
turnServerInfo: {
|
2950
|
-
|
3049
|
+
urls: [FAKE_TURN_URL],
|
2951
3050
|
username: FAKE_TURN_USER,
|
2952
3051
|
password: FAKE_TURN_PASSWORD,
|
2953
3052
|
},
|
2954
3053
|
turnDiscoverySkippedReason: undefined,
|
2955
3054
|
});
|
3055
|
+
|
3056
|
+
const mediaConnectionError = new Error('fake error');
|
3057
|
+
|
2956
3058
|
meeting.mediaProperties.waitForMediaConnectionConnected = sinon
|
2957
3059
|
.stub()
|
2958
3060
|
.onFirstCall()
|
2959
|
-
.rejects()
|
3061
|
+
.rejects(mediaConnectionError)
|
2960
3062
|
.onSecondCall()
|
2961
3063
|
.resolves();
|
2962
3064
|
|
@@ -3025,10 +3127,14 @@ describe('plugin-meetings', () => {
|
|
3025
3127
|
},
|
3026
3128
|
options: {
|
3027
3129
|
meetingId: meeting.id,
|
3130
|
+
rawError: mediaConnectionError,
|
3028
3131
|
},
|
3029
3132
|
});
|
3030
3133
|
assert.calledWith(webex.internal.newMetrics.submitClientEvent.thirdCall, {
|
3031
3134
|
name: 'client.media-engine.ready',
|
3135
|
+
payload: {
|
3136
|
+
ipVersion: 'IPv6',
|
3137
|
+
},
|
3032
3138
|
options: {
|
3033
3139
|
meetingId: meeting.id,
|
3034
3140
|
},
|
@@ -3085,11 +3191,15 @@ describe('plugin-meetings', () => {
|
|
3085
3191
|
locus_id: meeting.locusUrl.split('/').pop(),
|
3086
3192
|
connectionType: 'udp',
|
3087
3193
|
selectedCandidatePairChanges: 2,
|
3194
|
+
ipVersion: 'IPv6',
|
3088
3195
|
numTransports: 1,
|
3089
3196
|
isMultistream: false,
|
3090
3197
|
retriedWithTurnServer: true,
|
3091
3198
|
isJoinWithMediaRetry: false,
|
3092
3199
|
iceCandidatesCount: 0,
|
3200
|
+
subnet_reachable: null,
|
3201
|
+
selected_cluster: null,
|
3202
|
+
selected_subnet: null,
|
3093
3203
|
},
|
3094
3204
|
]);
|
3095
3205
|
meeting.roap.doTurnDiscovery;
|
@@ -3124,7 +3234,7 @@ describe('plugin-meetings', () => {
|
|
3124
3234
|
.onSecondCall()
|
3125
3235
|
.returns({
|
3126
3236
|
turnServerInfo: {
|
3127
|
-
|
3237
|
+
urls: [FAKE_TURN_URL],
|
3128
3238
|
username: FAKE_TURN_USER,
|
3129
3239
|
password: FAKE_TURN_PASSWORD,
|
3130
3240
|
},
|
@@ -3176,7 +3286,7 @@ describe('plugin-meetings', () => {
|
|
3176
3286
|
.onSecondCall()
|
3177
3287
|
.returns({
|
3178
3288
|
turnServerInfo: {
|
3179
|
-
|
3289
|
+
urls: [FAKE_TURN_URL],
|
3180
3290
|
username: FAKE_TURN_USER,
|
3181
3291
|
password: FAKE_TURN_PASSWORD,
|
3182
3292
|
},
|
@@ -3218,7 +3328,13 @@ describe('plugin-meetings', () => {
|
|
3218
3328
|
someReachabilityMetric2: 'some value2',
|
3219
3329
|
}),
|
3220
3330
|
stopReachability: sinon.stub(),
|
3331
|
+
isSubnetReachable: sinon.stub().returns(true),
|
3221
3332
|
};
|
3333
|
+
meeting.mediaConnections = [
|
3334
|
+
{
|
3335
|
+
mediaAgentCluster: 'some.cluster',
|
3336
|
+
}
|
3337
|
+
]
|
3222
3338
|
meeting.iceCandidatesCount = 3;
|
3223
3339
|
meeting.iceCandidateErrors.set('701_error', 3);
|
3224
3340
|
meeting.iceCandidateErrors.set('701_turn_host_lookup_received_error', 1);
|
@@ -3236,6 +3352,7 @@ describe('plugin-meetings', () => {
|
|
3236
3352
|
locus_id: meeting.locusUrl.split('/').pop(),
|
3237
3353
|
connectionType: 'udp',
|
3238
3354
|
selectedCandidatePairChanges: 2,
|
3355
|
+
ipVersion: 'IPv6',
|
3239
3356
|
numTransports: 1,
|
3240
3357
|
isMultistream: false,
|
3241
3358
|
retriedWithTurnServer: false,
|
@@ -3245,6 +3362,9 @@ describe('plugin-meetings', () => {
|
|
3245
3362
|
iceCandidatesCount: 3,
|
3246
3363
|
'701_error': 3,
|
3247
3364
|
'701_turn_host_lookup_received_error': 1,
|
3365
|
+
subnet_reachable: null,
|
3366
|
+
selected_cluster: 'some.cluster',
|
3367
|
+
selected_subnet: null,
|
3248
3368
|
}
|
3249
3369
|
);
|
3250
3370
|
|
@@ -3307,6 +3427,9 @@ describe('plugin-meetings', () => {
|
|
3307
3427
|
iceConnectionState: 'unknown',
|
3308
3428
|
selectedCandidatePairChanges: 2,
|
3309
3429
|
numTransports: 1,
|
3430
|
+
subnet_reachable: null,
|
3431
|
+
selected_cluster: null,
|
3432
|
+
selected_subnet: null,
|
3310
3433
|
iceCandidatesCount: 0,
|
3311
3434
|
}
|
3312
3435
|
);
|
@@ -3368,6 +3491,135 @@ describe('plugin-meetings', () => {
|
|
3368
3491
|
numTransports: 1,
|
3369
3492
|
'701_error': 2,
|
3370
3493
|
'701_turn_host_lookup_received_error': 1,
|
3494
|
+
subnet_reachable: null,
|
3495
|
+
selected_cluster: null,
|
3496
|
+
selected_subnet: null,
|
3497
|
+
iceCandidatesCount: 0,
|
3498
|
+
}
|
3499
|
+
);
|
3500
|
+
|
3501
|
+
assert.isOk(errorThrown);
|
3502
|
+
});
|
3503
|
+
|
3504
|
+
it('should send subnet reachablity metrics if media connection success', async () => {
|
3505
|
+
meeting.roap.doTurnDiscovery = sinon.stub().returns({
|
3506
|
+
turnServerInfo: undefined,
|
3507
|
+
turnDiscoverySkippedReason: undefined,
|
3508
|
+
});
|
3509
|
+
meeting.meetingState = 'ACTIVE';
|
3510
|
+
meeting.mediaProperties.waitForMediaConnectionConnected.resolves();
|
3511
|
+
meeting.webex.meetings.reachability = {
|
3512
|
+
getReachabilityMetrics: sinon.stub().resolves({
|
3513
|
+
reachability_public_udp_success: 5,
|
3514
|
+
}),
|
3515
|
+
stopReachability: sinon.stub(),
|
3516
|
+
isSubnetReachable: sinon.stub().returns(false),
|
3517
|
+
};
|
3518
|
+
meeting.mediaServerIp = '1.2.3.4';
|
3519
|
+
meeting.mediaConnections = [
|
3520
|
+
{
|
3521
|
+
mediaAgentCluster: 'some.cluster',
|
3522
|
+
}
|
3523
|
+
]
|
3524
|
+
|
3525
|
+
const forceRtcMetricsSend = sinon.stub().resolves();
|
3526
|
+
const closeMediaConnectionStub = sinon.stub();
|
3527
|
+
Media.createMediaConnection = sinon.stub().returns({
|
3528
|
+
close: closeMediaConnectionStub,
|
3529
|
+
forceRtcMetricsSend,
|
3530
|
+
getConnectionState: sinon.stub().returns(ConnectionState.Connected),
|
3531
|
+
initiateOffer: sinon.stub().resolves({}),
|
3532
|
+
on: sinon.stub(),
|
3533
|
+
});
|
3534
|
+
|
3535
|
+
await meeting.addMedia({
|
3536
|
+
mediaSettings: {},
|
3537
|
+
});
|
3538
|
+
|
3539
|
+
assert.calledWith(Metrics.sendBehavioralMetric, BEHAVIORAL_METRICS.ADD_MEDIA_SUCCESS, {
|
3540
|
+
correlation_id: meeting.correlationId,
|
3541
|
+
locus_id: meeting.locusUrl.split('/').pop(),
|
3542
|
+
connectionType: 'udp',
|
3543
|
+
ipVersion: 'IPv6',
|
3544
|
+
selectedCandidatePairChanges: 2,
|
3545
|
+
numTransports: 1,
|
3546
|
+
isMultistream: false,
|
3547
|
+
retriedWithTurnServer: false,
|
3548
|
+
isJoinWithMediaRetry: false,
|
3549
|
+
iceCandidatesCount: 0,
|
3550
|
+
reachability_public_udp_success: 5,
|
3551
|
+
subnet_reachable: false,
|
3552
|
+
selected_cluster: 'some.cluster',
|
3553
|
+
selected_subnet: '1.X.X.X',
|
3554
|
+
});
|
3555
|
+
});
|
3556
|
+
|
3557
|
+
it('should send subnet reachablity metrics if media connection fails', async () => {
|
3558
|
+
let errorThrown = undefined;
|
3559
|
+
|
3560
|
+
meeting.roap.doTurnDiscovery = sinon.stub().returns({
|
3561
|
+
turnServerInfo: undefined,
|
3562
|
+
turnDiscoverySkippedReason: undefined,
|
3563
|
+
});
|
3564
|
+
meeting.meetingState = 'ACTIVE';
|
3565
|
+
meeting.mediaProperties.waitForMediaConnectionConnected.rejects({iceConnected: false});
|
3566
|
+
meeting.webex.meetings.reachability = {
|
3567
|
+
getReachabilityMetrics: sinon.stub().resolves({
|
3568
|
+
reachability_public_udp_success: 5,
|
3569
|
+
}),
|
3570
|
+
stopReachability: sinon.stub(),
|
3571
|
+
isSubnetReachable: sinon.stub().returns(true),
|
3572
|
+
};
|
3573
|
+
meeting.mediaServerIp = '1.2.3.4';
|
3574
|
+
meeting.mediaConnections = [
|
3575
|
+
{
|
3576
|
+
mediaAgentCluster: 'some.cluster',
|
3577
|
+
}
|
3578
|
+
]
|
3579
|
+
|
3580
|
+
const forceRtcMetricsSend = sinon.stub().resolves();
|
3581
|
+
const closeMediaConnectionStub = sinon.stub();
|
3582
|
+
Media.createMediaConnection = sinon.stub().returns({
|
3583
|
+
close: closeMediaConnectionStub,
|
3584
|
+
forceRtcMetricsSend,
|
3585
|
+
getConnectionState: sinon.stub().returns(ConnectionState.Connected),
|
3586
|
+
initiateOffer: sinon.stub().resolves({}),
|
3587
|
+
on: sinon.stub(),
|
3588
|
+
});
|
3589
|
+
|
3590
|
+
await meeting
|
3591
|
+
.addMedia({
|
3592
|
+
mediaSettings: {},
|
3593
|
+
})
|
3594
|
+
.catch((err) => {
|
3595
|
+
errorThrown = err;
|
3596
|
+
assert.instanceOf(err, AddMediaFailed);
|
3597
|
+
});
|
3598
|
+
|
3599
|
+
// Check that the only metric sent is ADD_MEDIA_FAILURE
|
3600
|
+
assert.calledOnceWithExactly(
|
3601
|
+
Metrics.sendBehavioralMetric,
|
3602
|
+
BEHAVIORAL_METRICS.ADD_MEDIA_FAILURE,
|
3603
|
+
{
|
3604
|
+
correlation_id: meeting.correlationId,
|
3605
|
+
locus_id: meeting.locusUrl.split('/').pop(),
|
3606
|
+
reason: errorThrown.message,
|
3607
|
+
stack: errorThrown.stack,
|
3608
|
+
code: errorThrown.code,
|
3609
|
+
turnDiscoverySkippedReason: undefined,
|
3610
|
+
turnServerUsed: true,
|
3611
|
+
retriedWithTurnServer: false,
|
3612
|
+
isMultistream: false,
|
3613
|
+
isJoinWithMediaRetry: false,
|
3614
|
+
signalingState: 'unknown',
|
3615
|
+
connectionState: 'unknown',
|
3616
|
+
iceConnectionState: 'unknown',
|
3617
|
+
selectedCandidatePairChanges: 2,
|
3618
|
+
numTransports: 1,
|
3619
|
+
reachability_public_udp_success: 5,
|
3620
|
+
subnet_reachable: true,
|
3621
|
+
selected_cluster: 'some.cluster',
|
3622
|
+
selected_subnet: '1.X.X.X',
|
3371
3623
|
iceCandidatesCount: 0,
|
3372
3624
|
}
|
3373
3625
|
);
|
@@ -3387,6 +3639,8 @@ describe('plugin-meetings', () => {
|
|
3387
3639
|
meeting.config.stats.enableStatsAnalyzer = true;
|
3388
3640
|
|
3389
3641
|
statsAnalyzerStub = new EventsScope();
|
3642
|
+
statsAnalyzerStub.getNetworkType = sinon.stub().returns('wifi');
|
3643
|
+
|
3390
3644
|
// mock the StatsAnalyzer constructor
|
3391
3645
|
sinon.stub(InternalMediaCoreModule, 'StatsAnalyzer').returns(statsAnalyzerStub);
|
3392
3646
|
|
@@ -3427,6 +3681,40 @@ describe('plugin-meetings', () => {
|
|
3427
3681
|
});
|
3428
3682
|
});
|
3429
3683
|
|
3684
|
+
it('LOCAL_MEDIA_STARTED triggers "meeting:media:local:start" event and does not send metric because we already have', async () => {
|
3685
|
+
meeting.shareCAEventSentStatus = {
|
3686
|
+
transmitStart: true,
|
3687
|
+
transmitStop: false,
|
3688
|
+
receiveStart: false,
|
3689
|
+
receiveStop: false,
|
3690
|
+
};
|
3691
|
+
statsAnalyzerStub.emit(
|
3692
|
+
{file: 'test', function: 'test'},
|
3693
|
+
StatsAnalyzerEventNames.LOCAL_MEDIA_STARTED,
|
3694
|
+
{mediaType: 'share'}
|
3695
|
+
);
|
3696
|
+
|
3697
|
+
assert.calledWith(
|
3698
|
+
TriggerProxy.trigger,
|
3699
|
+
sinon.match.instanceOf(Meeting),
|
3700
|
+
{
|
3701
|
+
file: 'meeting/index',
|
3702
|
+
function: 'addMedia',
|
3703
|
+
},
|
3704
|
+
EVENT_TRIGGERS.MEETING_MEDIA_LOCAL_STARTED,
|
3705
|
+
{
|
3706
|
+
mediaType: 'share',
|
3707
|
+
}
|
3708
|
+
);
|
3709
|
+
assert.neverCalledWith(webex.internal.newMetrics.submitClientEvent, {
|
3710
|
+
name: 'client.media.tx.start',
|
3711
|
+
payload: {mediaType: 'share', shareInstanceId: meeting.remoteShareInstanceId},
|
3712
|
+
options: {
|
3713
|
+
meetingId: meeting.id,
|
3714
|
+
},
|
3715
|
+
});
|
3716
|
+
});
|
3717
|
+
|
3430
3718
|
it('LOCAL_MEDIA_STOPPED triggers the right metrics', async () => {
|
3431
3719
|
statsAnalyzerStub.emit(
|
3432
3720
|
{file: 'test', function: 'test'},
|
@@ -3443,6 +3731,28 @@ describe('plugin-meetings', () => {
|
|
3443
3731
|
});
|
3444
3732
|
});
|
3445
3733
|
|
3734
|
+
it('LOCAL_MEDIA_STOPPED does not send metric because we already have', async () => {
|
3735
|
+
meeting.shareCAEventSentStatus = {
|
3736
|
+
transmitStart: false,
|
3737
|
+
transmitStop: true,
|
3738
|
+
receiveStart: false,
|
3739
|
+
receiveStop: false,
|
3740
|
+
};
|
3741
|
+
statsAnalyzerStub.emit(
|
3742
|
+
{file: 'test', function: 'test'},
|
3743
|
+
StatsAnalyzerEventNames.LOCAL_MEDIA_STOPPED,
|
3744
|
+
{mediaType: 'share'}
|
3745
|
+
);
|
3746
|
+
|
3747
|
+
assert.neverCalledWith(webex.internal.newMetrics.submitClientEvent, {
|
3748
|
+
name: 'client.media.tx.stop',
|
3749
|
+
payload: {mediaType: 'share', shareInstanceId: meeting.remoteShareInstanceId},
|
3750
|
+
options: {
|
3751
|
+
meetingId: meeting.id,
|
3752
|
+
},
|
3753
|
+
});
|
3754
|
+
});
|
3755
|
+
|
3446
3756
|
it('REMOTE_MEDIA_STARTED triggers "meeting:media:remote:start" event and sends metrics', async () => {
|
3447
3757
|
statsAnalyzerStub.emit(
|
3448
3758
|
{file: 'test', function: 'test'},
|
@@ -3523,6 +3833,47 @@ describe('plugin-meetings', () => {
|
|
3523
3833
|
});
|
3524
3834
|
});
|
3525
3835
|
|
3836
|
+
it('REMOTE_MEDIA_STARTED triggers "meeting:media:remote:start" event and does not send metric because we already have', async () => {
|
3837
|
+
meeting.shareCAEventSentStatus = {
|
3838
|
+
transmitStart: false,
|
3839
|
+
transmitStop: false,
|
3840
|
+
receiveStart: true,
|
3841
|
+
receiveStop: false,
|
3842
|
+
};
|
3843
|
+
statsAnalyzerStub.emit(
|
3844
|
+
{file: 'test', function: 'test'},
|
3845
|
+
StatsAnalyzerEventNames.REMOTE_MEDIA_STARTED,
|
3846
|
+
{mediaType: 'share'}
|
3847
|
+
);
|
3848
|
+
|
3849
|
+
assert.calledWith(
|
3850
|
+
TriggerProxy.trigger,
|
3851
|
+
sinon.match.instanceOf(Meeting),
|
3852
|
+
{
|
3853
|
+
file: 'meeting/index',
|
3854
|
+
function: 'addMedia',
|
3855
|
+
},
|
3856
|
+
EVENT_TRIGGERS.MEETING_MEDIA_REMOTE_STARTED,
|
3857
|
+
{
|
3858
|
+
mediaType: 'share',
|
3859
|
+
}
|
3860
|
+
);
|
3861
|
+
assert.neverCalledWith(webex.internal.newMetrics.submitClientEvent, {
|
3862
|
+
name: 'client.media.render.start',
|
3863
|
+
payload: {mediaType: 'share', shareInstanceId: meeting.remoteShareInstanceId},
|
3864
|
+
options: {
|
3865
|
+
meetingId: meeting.id,
|
3866
|
+
},
|
3867
|
+
});
|
3868
|
+
assert.neverCalledWith(webex.internal.newMetrics.submitClientEvent, {
|
3869
|
+
name: 'client.media.rx.start',
|
3870
|
+
payload: {mediaType: 'share', shareInstanceId: meeting.remoteShareInstanceId},
|
3871
|
+
options: {
|
3872
|
+
meetingId: meeting.id,
|
3873
|
+
},
|
3874
|
+
});
|
3875
|
+
});
|
3876
|
+
|
3526
3877
|
it('REMOTE_MEDIA_STOPPED triggers the right metrics for share', async () => {
|
3527
3878
|
statsAnalyzerStub.emit(
|
3528
3879
|
{file: 'test', function: 'test'},
|
@@ -3547,21 +3898,49 @@ describe('plugin-meetings', () => {
|
|
3547
3898
|
});
|
3548
3899
|
});
|
3549
3900
|
|
3901
|
+
it('REMOTE_MEDIA_STOPPED does not send metric because we already have', async () => {
|
3902
|
+
meeting.shareCAEventSentStatus = {
|
3903
|
+
transmitStart: false,
|
3904
|
+
transmitStop: false,
|
3905
|
+
receiveStart: true,
|
3906
|
+
receiveStop: true,
|
3907
|
+
};
|
3908
|
+
statsAnalyzerStub.emit(
|
3909
|
+
{file: 'test', function: 'test'},
|
3910
|
+
StatsAnalyzerEventNames.REMOTE_MEDIA_STOPPED,
|
3911
|
+
{mediaType: 'share'}
|
3912
|
+
);
|
3913
|
+
assert.neverCalledWith(webex.internal.newMetrics.submitClientEvent, {
|
3914
|
+
name: 'client.media.render.stop',
|
3915
|
+
payload: {mediaType: 'share', shareInstanceId: meeting.remoteShareInstanceId},
|
3916
|
+
options: {
|
3917
|
+
meetingId: meeting.id,
|
3918
|
+
},
|
3919
|
+
});
|
3920
|
+
assert.neverCalledWith(webex.internal.newMetrics.submitClientEvent, {
|
3921
|
+
name: 'client.media.rx.stop',
|
3922
|
+
payload: {mediaType: 'share', shareInstanceId: meeting.remoteShareInstanceId},
|
3923
|
+
options: {
|
3924
|
+
meetingId: meeting.id,
|
3925
|
+
},
|
3926
|
+
});
|
3927
|
+
});
|
3928
|
+
|
3550
3929
|
it('counts the number of members that are in the meeting for MEDIA_QUALITY event', async () => {
|
3551
3930
|
let fakeMembersCollection = {
|
3552
3931
|
members: {
|
3553
|
-
member1: {
|
3554
|
-
member2: {
|
3555
|
-
member3: {
|
3932
|
+
member1: {isInMeeting: true},
|
3933
|
+
member2: {isInMeeting: true},
|
3934
|
+
member3: {isInMeeting: false},
|
3556
3935
|
},
|
3557
3936
|
};
|
3558
|
-
sinon.stub(meeting, 'getMembers').returns({
|
3559
|
-
const fakeData = {
|
3937
|
+
sinon.stub(meeting, 'getMembers').returns({membersCollection: fakeMembersCollection});
|
3938
|
+
const fakeData = {intervalMetadata: {}};
|
3560
3939
|
|
3561
3940
|
statsAnalyzerStub.emit(
|
3562
|
-
{
|
3941
|
+
{file: 'test', function: 'test'},
|
3563
3942
|
StatsAnalyzerEventNames.MEDIA_QUALITY,
|
3564
|
-
{
|
3943
|
+
{data: fakeData}
|
3565
3944
|
);
|
3566
3945
|
|
3567
3946
|
assert.calledWithMatch(webex.internal.newMetrics.submitMQE, {
|
@@ -3570,15 +3949,17 @@ describe('plugin-meetings', () => {
|
|
3570
3949
|
meetingId: meeting.id,
|
3571
3950
|
},
|
3572
3951
|
payload: {
|
3573
|
-
intervals: [
|
3952
|
+
intervals: [
|
3953
|
+
sinon.match.has('intervalMetadata', sinon.match.has('meetingUserCount', 2)),
|
3954
|
+
],
|
3574
3955
|
},
|
3575
3956
|
});
|
3576
3957
|
fakeMembersCollection.members.member2.isInMeeting = false;
|
3577
3958
|
|
3578
3959
|
statsAnalyzerStub.emit(
|
3579
|
-
{
|
3960
|
+
{file: 'test', function: 'test'},
|
3580
3961
|
StatsAnalyzerEventNames.MEDIA_QUALITY,
|
3581
|
-
{
|
3962
|
+
{data: fakeData}
|
3582
3963
|
);
|
3583
3964
|
|
3584
3965
|
assert.calledWithMatch(webex.internal.newMetrics.submitMQE, {
|
@@ -3587,13 +3968,15 @@ describe('plugin-meetings', () => {
|
|
3587
3968
|
meetingId: meeting.id,
|
3588
3969
|
},
|
3589
3970
|
payload: {
|
3590
|
-
intervals: [
|
3971
|
+
intervals: [
|
3972
|
+
sinon.match.has('intervalMetadata', sinon.match.has('meetingUserCount', 1)),
|
3973
|
+
],
|
3591
3974
|
},
|
3592
3975
|
});
|
3593
3976
|
});
|
3594
3977
|
|
3595
3978
|
it('calls submitMQE correctly', async () => {
|
3596
|
-
const fakeData = {intervalMetadata: {bla: 'bla'}
|
3979
|
+
const fakeData = {intervalMetadata: {bla: 'bla'}};
|
3597
3980
|
|
3598
3981
|
statsAnalyzerStub.emit(
|
3599
3982
|
{file: 'test', function: 'test'},
|
@@ -3624,7 +4007,7 @@ describe('plugin-meetings', () => {
|
|
3624
4007
|
|
3625
4008
|
meeting.roap.doTurnDiscovery = sinon.stub().resolves({
|
3626
4009
|
turnServerInfo: {
|
3627
|
-
|
4010
|
+
urls: [FAKE_TURN_URL],
|
3628
4011
|
username: FAKE_TURN_USER,
|
3629
4012
|
password: FAKE_TURN_PASSWORD,
|
3630
4013
|
},
|
@@ -3650,7 +4033,7 @@ describe('plugin-meetings', () => {
|
|
3650
4033
|
meeting.id,
|
3651
4034
|
sinon.match({
|
3652
4035
|
turnServerInfo: {
|
3653
|
-
|
4036
|
+
urls: [FAKE_TURN_URL],
|
3654
4037
|
username: FAKE_TURN_USER,
|
3655
4038
|
password: FAKE_TURN_PASSWORD,
|
3656
4039
|
},
|
@@ -3801,6 +4184,9 @@ describe('plugin-meetings', () => {
|
|
3801
4184
|
},
|
3802
4185
|
options: {
|
3803
4186
|
meetingId: meeting.id,
|
4187
|
+
rawError: {
|
4188
|
+
iceConnected: false,
|
4189
|
+
},
|
3804
4190
|
},
|
3805
4191
|
},
|
3806
4192
|
]);
|
@@ -3830,7 +4216,7 @@ describe('plugin-meetings', () => {
|
|
3830
4216
|
meeting.deviceUrl = 'device url';
|
3831
4217
|
meeting.selfId = 'self id';
|
3832
4218
|
meeting.brbState = createBrbState(meeting, false);
|
3833
|
-
meeting.brbState
|
4219
|
+
sinon.stub(meeting.brbState, 'enable').resolves();
|
3834
4220
|
});
|
3835
4221
|
|
3836
4222
|
afterEach(() => {
|
@@ -3842,7 +4228,6 @@ describe('plugin-meetings', () => {
|
|
3842
4228
|
});
|
3843
4229
|
|
3844
4230
|
describe('when in a multistream meeting', () => {
|
3845
|
-
|
3846
4231
|
beforeEach(() => {
|
3847
4232
|
meeting.isMultistream = true;
|
3848
4233
|
});
|
@@ -3853,7 +4238,7 @@ describe('plugin-meetings', () => {
|
|
3853
4238
|
await brbResult;
|
3854
4239
|
assert.exists(brbResult.then);
|
3855
4240
|
assert.calledOnce(meeting.brbState.enable);
|
3856
|
-
})
|
4241
|
+
});
|
3857
4242
|
|
3858
4243
|
it('should disable #beRightBack and return a promise', async () => {
|
3859
4244
|
const brbResult = meeting.beRightBack(false);
|
@@ -3861,7 +4246,7 @@ describe('plugin-meetings', () => {
|
|
3861
4246
|
await brbResult;
|
3862
4247
|
assert.exists(brbResult.then);
|
3863
4248
|
assert.calledOnce(meeting.brbState.enable);
|
3864
|
-
})
|
4249
|
+
});
|
3865
4250
|
|
3866
4251
|
it('should throw an error and reject the promise if setBrb fails', async () => {
|
3867
4252
|
const error = new Error('setBrb failed');
|
@@ -3872,9 +4257,42 @@ describe('plugin-meetings', () => {
|
|
3872
4257
|
} catch (err) {
|
3873
4258
|
assert.instanceOf(err, Error);
|
3874
4259
|
assert.equal(err.message, 'setBrb failed');
|
3875
|
-
assert.isRejected(
|
4260
|
+
assert.isRejected(Promise.reject());
|
3876
4261
|
}
|
3877
|
-
})
|
4262
|
+
});
|
4263
|
+
|
4264
|
+
it('updates remote mute state when brb is enabled', async () => {
|
4265
|
+
meeting.audio = {handleServerRemoteMuteUpdate: sinon.stub()};
|
4266
|
+
|
4267
|
+
await meeting.beRightBack(true);
|
4268
|
+
|
4269
|
+
sinon.assert.calledOnceWithExactly(
|
4270
|
+
meeting.audio.handleServerRemoteMuteUpdate,
|
4271
|
+
meeting,
|
4272
|
+
true
|
4273
|
+
);
|
4274
|
+
});
|
4275
|
+
|
4276
|
+
it('does not update remote mute state when brb is disabled', async () => {
|
4277
|
+
meeting.audio = {handleServerRemoteMuteUpdate: sinon.stub()};
|
4278
|
+
|
4279
|
+
await meeting.beRightBack(false);
|
4280
|
+
|
4281
|
+
assert.notCalled(meeting.audio.handleServerRemoteMuteUpdate);
|
4282
|
+
});
|
4283
|
+
|
4284
|
+
it('should reject when brb enable fails', async () => {
|
4285
|
+
meeting.brbState.enable.restore();
|
4286
|
+
|
4287
|
+
const error = new Error();
|
4288
|
+
meeting.meetingRequest.setBrb = sinon.stub().rejects(error);
|
4289
|
+
|
4290
|
+
await expect(
|
4291
|
+
meeting.beRightBack(true)
|
4292
|
+
).to.be.rejectedWith(error);
|
4293
|
+
|
4294
|
+
assert.isFalse(meeting.brbState.state.syncToServerInProgress);
|
4295
|
+
});
|
3878
4296
|
});
|
3879
4297
|
});
|
3880
4298
|
|
@@ -3928,7 +4346,10 @@ describe('plugin-meetings', () => {
|
|
3928
4346
|
.resolves({id: 'fake clientMediaPreferences'});
|
3929
4347
|
meeting.roap.doTurnDiscovery = sinon.stub().resolves({
|
3930
4348
|
turnServerInfo: {
|
3931
|
-
|
4349
|
+
urls: [
|
4350
|
+
'turns:turn-server-url1:443?transport=tcp',
|
4351
|
+
'turns:turn-server-url2:443?transport=tcp',
|
4352
|
+
],
|
3932
4353
|
username: 'turn user',
|
3933
4354
|
password: 'turn password',
|
3934
4355
|
},
|
@@ -3946,12 +4367,10 @@ describe('plugin-meetings', () => {
|
|
3946
4367
|
expectedMediaConnectionConfig = {
|
3947
4368
|
iceServers: [
|
3948
4369
|
{
|
3949
|
-
urls:
|
3950
|
-
|
3951
|
-
|
3952
|
-
|
3953
|
-
{
|
3954
|
-
urls: 'turns:turn-server-url:443?transport=tcp',
|
4370
|
+
urls: [
|
4371
|
+
'turns:turn-server-url1:443?transport=tcp',
|
4372
|
+
'turns:turn-server-url2:443?transport=tcp',
|
4373
|
+
],
|
3955
4374
|
username: 'turn user',
|
3956
4375
|
credential: 'turn password',
|
3957
4376
|
},
|
@@ -4006,7 +4425,7 @@ describe('plugin-meetings', () => {
|
|
4006
4425
|
initiateOffer: sinon.stub().resolves({}),
|
4007
4426
|
update: sinon.stub().resolves({}),
|
4008
4427
|
on: sinon.stub(),
|
4009
|
-
roapMessageReceived: sinon.stub()
|
4428
|
+
roapMessageReceived: sinon.stub(),
|
4010
4429
|
};
|
4011
4430
|
|
4012
4431
|
fakeMultistreamRoapMediaConnection = {
|
@@ -4033,9 +4452,11 @@ describe('plugin-meetings', () => {
|
|
4033
4452
|
.stub(InternalMediaCoreModule, 'MultistreamRoapMediaConnection')
|
4034
4453
|
.returns(fakeMultistreamRoapMediaConnection);
|
4035
4454
|
|
4036
|
-
locusMediaRequestStub = sinon
|
4037
|
-
|
4038
|
-
.
|
4455
|
+
locusMediaRequestStub = sinon.stub(WebexPlugin.prototype, 'request').resolves({
|
4456
|
+
body: {locus: {fullState: {}}},
|
4457
|
+
upload: sinon.match.instanceOf(EventEmitter),
|
4458
|
+
download: sinon.match.instanceOf(EventEmitter),
|
4459
|
+
});
|
4039
4460
|
|
4040
4461
|
// setup some things and mocks so that the call to join() works
|
4041
4462
|
// (we need to call join() because it creates the LocusMediaRequest instance
|
@@ -4144,6 +4565,8 @@ describe('plugin-meetings', () => {
|
|
4144
4565
|
id: 'fake clientMediaPreferences',
|
4145
4566
|
},
|
4146
4567
|
},
|
4568
|
+
upload: sinon.match.instanceOf(EventEmitter),
|
4569
|
+
download: sinon.match.instanceOf(EventEmitter),
|
4147
4570
|
});
|
4148
4571
|
};
|
4149
4572
|
|
@@ -4171,6 +4594,8 @@ describe('plugin-meetings', () => {
|
|
4171
4594
|
},
|
4172
4595
|
],
|
4173
4596
|
},
|
4597
|
+
upload: sinon.match.instanceOf(EventEmitter),
|
4598
|
+
download: sinon.match.instanceOf(EventEmitter),
|
4174
4599
|
});
|
4175
4600
|
};
|
4176
4601
|
|
@@ -4195,6 +4620,8 @@ describe('plugin-meetings', () => {
|
|
4195
4620
|
respOnlySdp: true,
|
4196
4621
|
usingResource: null,
|
4197
4622
|
},
|
4623
|
+
upload: sinon.match.instanceOf(EventEmitter),
|
4624
|
+
download: sinon.match.instanceOf(EventEmitter),
|
4198
4625
|
});
|
4199
4626
|
};
|
4200
4627
|
|
@@ -5213,7 +5640,10 @@ describe('plugin-meetings', () => {
|
|
5213
5640
|
// and check that when we fallback to transcoded we still do another TURN discovery
|
5214
5641
|
await runCheck(
|
5215
5642
|
{
|
5216
|
-
|
5643
|
+
urls: [
|
5644
|
+
'turns:turn-server-url1:443?transport=tcp',
|
5645
|
+
'turns:turn-server-url2:443?transport=tcp',
|
5646
|
+
],
|
5217
5647
|
username: 'turn user',
|
5218
5648
|
password: 'turn password',
|
5219
5649
|
},
|
@@ -5227,7 +5657,10 @@ describe('plugin-meetings', () => {
|
|
5227
5657
|
// but doing it just for completeness
|
5228
5658
|
await runCheck(
|
5229
5659
|
{
|
5230
|
-
|
5660
|
+
urls: [
|
5661
|
+
'turns:turn-server-url1:443?transport=tcp',
|
5662
|
+
'turns:turn-server-url2:443?transport=tcp',
|
5663
|
+
],
|
5231
5664
|
username: 'turn user',
|
5232
5665
|
password: 'turn password',
|
5233
5666
|
},
|
@@ -6337,7 +6770,10 @@ describe('plugin-meetings', () => {
|
|
6337
6770
|
.throws(new MeetingInfoV2JoinForbiddenError(403003, FAKE_MEETING_INFO)),
|
6338
6771
|
};
|
6339
6772
|
|
6340
|
-
await assert.isRejected(
|
6773
|
+
await assert.isRejected(
|
6774
|
+
meeting.fetchMeetingInfo({sendCAevents: true}),
|
6775
|
+
JoinForbiddenError
|
6776
|
+
);
|
6341
6777
|
|
6342
6778
|
assert.calledWith(
|
6343
6779
|
meeting.attrs.meetingInfoProvider.fetchMeetingInfo,
|
@@ -6353,10 +6789,7 @@ describe('plugin-meetings', () => {
|
|
6353
6789
|
|
6354
6790
|
assert.deepEqual(meeting.meetingInfo, FAKE_MEETING_INFO);
|
6355
6791
|
assert.equal(meeting.meetingInfoFailureCode, 403003);
|
6356
|
-
assert.equal(
|
6357
|
-
meeting.meetingInfoFailureReason,
|
6358
|
-
MEETING_INFO_FAILURE_REASON.NOT_REACH_JBH
|
6359
|
-
);
|
6792
|
+
assert.equal(meeting.meetingInfoFailureReason, MEETING_INFO_FAILURE_REASON.NOT_REACH_JBH);
|
6360
6793
|
assert.equal(meeting.requiredCaptcha, null);
|
6361
6794
|
});
|
6362
6795
|
|
@@ -6733,15 +7166,10 @@ describe('plugin-meetings', () => {
|
|
6733
7166
|
meeting.attrs.meetingInfoProvider = {
|
6734
7167
|
fetchMeetingInfo: sinon
|
6735
7168
|
.stub()
|
6736
|
-
.throws(
|
6737
|
-
new MeetingInfoV2JoinWebinarError(403021, FAKE_MEETING_INFO, 'a message')
|
6738
|
-
),
|
7169
|
+
.throws(new MeetingInfoV2JoinWebinarError(403021, FAKE_MEETING_INFO, 'a message')),
|
6739
7170
|
};
|
6740
7171
|
|
6741
|
-
await assert.isRejected(
|
6742
|
-
meeting.fetchMeetingInfo({sendCAevents: true}),
|
6743
|
-
JoinWebinarError
|
6744
|
-
);
|
7172
|
+
await assert.isRejected(meeting.fetchMeetingInfo({sendCAevents: true}), JoinWebinarError);
|
6745
7173
|
|
6746
7174
|
assert.deepEqual(meeting.meetingInfo, FAKE_MEETING_INFO);
|
6747
7175
|
assert.equal(
|
@@ -6756,15 +7184,10 @@ describe('plugin-meetings', () => {
|
|
6756
7184
|
meeting.attrs.meetingInfoProvider = {
|
6757
7185
|
fetchMeetingInfo: sinon
|
6758
7186
|
.stub()
|
6759
|
-
.throws(
|
6760
|
-
new MeetingInfoV2JoinWebinarError(403026, FAKE_MEETING_INFO, 'a message')
|
6761
|
-
),
|
7187
|
+
.throws(new MeetingInfoV2JoinWebinarError(403026, FAKE_MEETING_INFO, 'a message')),
|
6762
7188
|
};
|
6763
7189
|
|
6764
|
-
await assert.isRejected(
|
6765
|
-
meeting.fetchMeetingInfo({sendCAevents: true}),
|
6766
|
-
JoinWebinarError
|
6767
|
-
);
|
7190
|
+
await assert.isRejected(meeting.fetchMeetingInfo({sendCAevents: true}), JoinWebinarError);
|
6768
7191
|
|
6769
7192
|
assert.deepEqual(meeting.meetingInfo, FAKE_MEETING_INFO);
|
6770
7193
|
assert.equal(
|
@@ -6779,15 +7202,10 @@ describe('plugin-meetings', () => {
|
|
6779
7202
|
meeting.attrs.meetingInfoProvider = {
|
6780
7203
|
fetchMeetingInfo: sinon
|
6781
7204
|
.stub()
|
6782
|
-
.throws(
|
6783
|
-
new MeetingInfoV2JoinWebinarError(403037, FAKE_MEETING_INFO, 'a message')
|
6784
|
-
),
|
7205
|
+
.throws(new MeetingInfoV2JoinWebinarError(403037, FAKE_MEETING_INFO, 'a message')),
|
6785
7206
|
};
|
6786
7207
|
|
6787
|
-
await assert.isRejected(
|
6788
|
-
meeting.fetchMeetingInfo({sendCAevents: true}),
|
6789
|
-
JoinWebinarError
|
6790
|
-
);
|
7208
|
+
await assert.isRejected(meeting.fetchMeetingInfo({sendCAevents: true}), JoinWebinarError);
|
6791
7209
|
|
6792
7210
|
assert.deepEqual(meeting.meetingInfo, FAKE_MEETING_INFO);
|
6793
7211
|
assert.equal(
|
@@ -7524,6 +7942,27 @@ describe('plugin-meetings', () => {
|
|
7524
7942
|
});
|
7525
7943
|
});
|
7526
7944
|
|
7945
|
+
describe('#setIsoLocalClientMeetingJoinTime', () => {
|
7946
|
+
it('should fallback to system clock ISO string when given an undefined value', () => {
|
7947
|
+
const currentSystemTime = new Date().toISOString();
|
7948
|
+
meeting.isoLocalClientMeetingJoinTime = undefined;
|
7949
|
+
assert.equal(meeting.isoLocalClientMeetingJoinTime, currentSystemTime);
|
7950
|
+
});
|
7951
|
+
|
7952
|
+
it('should fallback to system clock ISO string when given an invalid value', () => {
|
7953
|
+
const currentSystemTime = new Date().toISOString();
|
7954
|
+
meeting.isoLocalClientMeetingJoinTime = 'invalid-date';
|
7955
|
+
assert.equal(meeting.isoLocalClientMeetingJoinTime, currentSystemTime);
|
7956
|
+
});
|
7957
|
+
|
7958
|
+
it('should set the isoLocalClientMeetingJoinTime correctly for a valid date string', () => {
|
7959
|
+
const validDateString = 'Tue, 01 Apr 2025 13:00:36 GMT';
|
7960
|
+
const expectedISOString = new Date(validDateString).toISOString();
|
7961
|
+
meeting.isoLocalClientMeetingJoinTime = validDateString;
|
7962
|
+
assert.equal(meeting.isoLocalClientMeetingJoinTime, expectedISOString);
|
7963
|
+
});
|
7964
|
+
});
|
7965
|
+
|
7527
7966
|
describe('#updateCallStateForMetrics', () => {
|
7528
7967
|
it('should update the callState, overriding existing values', () => {
|
7529
7968
|
assert.deepEqual(meeting.callStateForMetrics, {correlationId, sessionCorrelationId: ''});
|
@@ -7605,6 +8044,12 @@ describe('plugin-meetings', () => {
|
|
7605
8044
|
meeting.audio = {handleLocalStreamChange: sinon.stub()};
|
7606
8045
|
meeting.video = {handleLocalStreamChange: sinon.stub()};
|
7607
8046
|
meeting.statsAnalyzer = {updateMediaStatus: sinon.stub()};
|
8047
|
+
meeting.shareCAEventSentStatus = {
|
8048
|
+
transmitStart: false,
|
8049
|
+
transmitStop: false,
|
8050
|
+
receiveStart: false,
|
8051
|
+
receiveStop: false,
|
8052
|
+
};
|
7608
8053
|
fakeMultistreamRoapMediaConnection = {
|
7609
8054
|
createSendSlot: () => {
|
7610
8055
|
return {
|
@@ -7672,6 +8117,9 @@ describe('plugin-meetings', () => {
|
|
7672
8117
|
});
|
7673
8118
|
assert.equal(meeting.mediaProperties.mediaDirection.sendShare, true);
|
7674
8119
|
|
8120
|
+
assert.equal(meeting.shareCAEventSentStatus.transmitStart, false);
|
8121
|
+
assert.equal(meeting.shareCAEventSentStatus.transmitStop, false);
|
8122
|
+
|
7675
8123
|
assert.calledWith(meeting.statsAnalyzer.updateMediaStatus, {
|
7676
8124
|
expected: {sendShare: true},
|
7677
8125
|
});
|
@@ -7692,18 +8140,23 @@ describe('plugin-meetings', () => {
|
|
7692
8140
|
assert.equal(meeting.mediaProperties.shareAudioStream, stream);
|
7693
8141
|
assert.equal(meeting.mediaProperties.mediaDirection.sendShare, true);
|
7694
8142
|
|
8143
|
+
assert.equal(meeting.shareCAEventSentStatus.transmitStart, false);
|
8144
|
+
assert.equal(meeting.shareCAEventSentStatus.transmitStop, false);
|
8145
|
+
|
7695
8146
|
assert.calledWith(meeting.statsAnalyzer.updateMediaStatus, {
|
7696
8147
|
expected: {sendShare: true},
|
7697
8148
|
});
|
7698
8149
|
};
|
7699
8150
|
|
7700
8151
|
it('requests screen share floor and publishes the screen share video stream', async () => {
|
8152
|
+
meeting.shareCAEventSentStatus.transmitStart = true;
|
7701
8153
|
await meeting.publishStreams({screenShare: {video: videoShareStream}});
|
7702
8154
|
|
7703
8155
|
checkScreenShareVideoPublished(videoShareStream);
|
7704
8156
|
});
|
7705
8157
|
|
7706
8158
|
it('requests screen share floor and publishes the screen share audio stream', async () => {
|
8159
|
+
meeting.shareCAEventSentStatus.transmitStart = true;
|
7707
8160
|
await meeting.publishStreams({screenShare: {audio: audioShareStream}});
|
7708
8161
|
|
7709
8162
|
checkScreenShareAudioPublished(audioShareStream);
|
@@ -8590,13 +9043,19 @@ describe('plugin-meetings', () => {
|
|
8590
9043
|
const fakeErrorMessage = 'test error';
|
8591
9044
|
const fakeRootCauseName = 'root cause name';
|
8592
9045
|
const fakeErrorName = 'test error name';
|
9046
|
+
let clock;
|
8593
9047
|
|
8594
9048
|
beforeEach(() => {
|
9049
|
+
clock = sinon.useFakeTimers();
|
8595
9050
|
meeting.setupMediaConnectionListeners();
|
8596
9051
|
webex.internal.newMetrics.submitClientEvent.resetHistory();
|
8597
9052
|
Metrics.sendBehavioralMetric.resetHistory();
|
8598
9053
|
});
|
8599
9054
|
|
9055
|
+
afterEach(() => {
|
9056
|
+
clock.restore();
|
9057
|
+
});
|
9058
|
+
|
8600
9059
|
const checkMetricSent = (event, error) => {
|
8601
9060
|
assert.calledOnce(webex.internal.newMetrics.submitClientEvent);
|
8602
9061
|
assert.calledWithMatch(webex.internal.newMetrics.submitClientEvent, {
|
@@ -8665,6 +9124,13 @@ describe('plugin-meetings', () => {
|
|
8665
9124
|
});
|
8666
9125
|
|
8667
9126
|
it('should send metrics for SdpAnswerHandlingError error', () => {
|
9127
|
+
meeting.sdpResponseTimer = '1234';
|
9128
|
+
meeting.deferSDPAnswer = {
|
9129
|
+
reject: sinon.stub(),
|
9130
|
+
};
|
9131
|
+
|
9132
|
+
const clearTimeoutSpy = sinon.spy(clock, 'clearTimeout');
|
9133
|
+
|
8668
9134
|
const fakeError = new Errors.SdpAnswerHandlingError(fakeErrorMessage, {
|
8669
9135
|
name: fakeErrorName,
|
8670
9136
|
cause: {name: fakeRootCauseName},
|
@@ -8679,6 +9145,8 @@ describe('plugin-meetings', () => {
|
|
8679
9145
|
fakeErrorMessage,
|
8680
9146
|
fakeRootCauseName
|
8681
9147
|
);
|
9148
|
+
assert.calledOnce(meeting.deferSDPAnswer.reject);
|
9149
|
+
assert.calledOnce(clearTimeoutSpy);
|
8682
9150
|
});
|
8683
9151
|
|
8684
9152
|
it('should send metrics for SdpError error', () => {
|
@@ -9223,22 +9691,22 @@ describe('plugin-meetings', () => {
|
|
9223
9691
|
const assertBrb = (enabled) => {
|
9224
9692
|
meeting.brbState = createBrbState(meeting, false);
|
9225
9693
|
meeting.locusInfo.emit(
|
9226
|
-
{
|
9694
|
+
{function: 'test', file: 'test'},
|
9227
9695
|
LOCUSINFO.EVENTS.SELF_MEETING_BRB_CHANGED,
|
9228
|
-
{
|
9229
|
-
)
|
9696
|
+
{brb: {enabled}}
|
9697
|
+
);
|
9230
9698
|
assert.calledWithExactly(
|
9231
9699
|
TriggerProxy.trigger,
|
9232
9700
|
meeting,
|
9233
9701
|
{file: 'meeting/index', function: 'setUpLocusInfoSelfListener'},
|
9234
9702
|
EVENT_TRIGGERS.MEETING_SELF_BRB_UPDATE,
|
9235
|
-
{
|
9703
|
+
{payload: {brb: {enabled}}}
|
9236
9704
|
);
|
9237
|
-
}
|
9705
|
+
};
|
9238
9706
|
|
9239
9707
|
assertBrb(true);
|
9240
9708
|
assertBrb(false);
|
9241
|
-
})
|
9709
|
+
});
|
9242
9710
|
|
9243
9711
|
it('listens to the interpretation changed event', () => {
|
9244
9712
|
meeting.simultaneousInterpretation.updateSelfInterpretation = sinon.stub();
|
@@ -9584,6 +10052,60 @@ describe('plugin-meetings', () => {
|
|
9584
10052
|
);
|
9585
10053
|
});
|
9586
10054
|
|
10055
|
+
it('listens to CONTROLS_ANNOTATION_CHANGED', async () => {
|
10056
|
+
const state = {example: 'value'};
|
10057
|
+
|
10058
|
+
await meeting.locusInfo.emitScoped(
|
10059
|
+
{function: 'test', file: 'test'},
|
10060
|
+
LOCUSINFO.EVENTS.CONTROLS_ANNOTATION_CHANGED,
|
10061
|
+
{state}
|
10062
|
+
);
|
10063
|
+
|
10064
|
+
assert.calledWith(
|
10065
|
+
TriggerProxy.trigger,
|
10066
|
+
meeting,
|
10067
|
+
{file: 'meeting/index', function: 'setupLocusControlsListener'},
|
10068
|
+
EVENT_TRIGGERS.MEETING_CONTROLS_ANNOTATION_UPDATED,
|
10069
|
+
{state}
|
10070
|
+
);
|
10071
|
+
});
|
10072
|
+
|
10073
|
+
it('listens to CONTROLS_REMOTE_DESKTOP_CONTROL_CHANGED', async () => {
|
10074
|
+
const state = {example: 'value'};
|
10075
|
+
|
10076
|
+
await meeting.locusInfo.emitScoped(
|
10077
|
+
{function: 'test', file: 'test'},
|
10078
|
+
LOCUSINFO.EVENTS.CONTROLS_REMOTE_DESKTOP_CONTROL_CHANGED,
|
10079
|
+
{state}
|
10080
|
+
);
|
10081
|
+
|
10082
|
+
assert.calledWith(
|
10083
|
+
TriggerProxy.trigger,
|
10084
|
+
meeting,
|
10085
|
+
{file: 'meeting/index', function: 'setupLocusControlsListener'},
|
10086
|
+
EVENT_TRIGGERS.MEETING_CONTROLS_REMOTE_DESKTOP_CONTROL_UPDATED,
|
10087
|
+
{state}
|
10088
|
+
);
|
10089
|
+
});
|
10090
|
+
|
10091
|
+
it('listens to CONTROLS_POLLING_QA_CHANGED', async () => {
|
10092
|
+
const state = {example: 'value'};
|
10093
|
+
|
10094
|
+
await meeting.locusInfo.emitScoped(
|
10095
|
+
{function: 'test', file: 'test'},
|
10096
|
+
LOCUSINFO.EVENTS.CONTROLS_POLLING_QA_CHANGED,
|
10097
|
+
{state}
|
10098
|
+
);
|
10099
|
+
|
10100
|
+
assert.calledWith(
|
10101
|
+
TriggerProxy.trigger,
|
10102
|
+
meeting,
|
10103
|
+
{file: 'meeting/index', function: 'setupLocusControlsListener'},
|
10104
|
+
EVENT_TRIGGERS.MEETING_CONTROLS_POLLING_QA_UPDATED,
|
10105
|
+
{state}
|
10106
|
+
);
|
10107
|
+
});
|
10108
|
+
|
9587
10109
|
it('listens to the locus interpretation update event', () => {
|
9588
10110
|
const interpretation = {
|
9589
10111
|
siLanguages: [{languageCode: 20, languageName: 'en'}],
|
@@ -9922,6 +10444,22 @@ describe('plugin-meetings', () => {
|
|
9922
10444
|
});
|
9923
10445
|
});
|
9924
10446
|
|
10447
|
+
describe('#emailInput', () => {
|
10448
|
+
it('should set the email input', () => {
|
10449
|
+
assert.notOk(meeting.emailInput);
|
10450
|
+
meeting.emailInput = 'current';
|
10451
|
+
assert.equal(meeting.emailInput, 'current');
|
10452
|
+
});
|
10453
|
+
});
|
10454
|
+
|
10455
|
+
describe('#userNameInput', () => {
|
10456
|
+
it('should set the user name input', () => {
|
10457
|
+
assert.notOk(meeting.userNameInput);
|
10458
|
+
meeting.userNameInput = 'current';
|
10459
|
+
assert.equal(meeting.userNameInput, 'current');
|
10460
|
+
});
|
10461
|
+
});
|
10462
|
+
|
9925
10463
|
describe('#setPermissionTokenPayload', () => {
|
9926
10464
|
let now;
|
9927
10465
|
let clock;
|
@@ -10463,9 +11001,11 @@ describe('plugin-meetings', () => {
|
|
10463
11001
|
let canUserLowerSomeoneElsesHandSpy;
|
10464
11002
|
let waitingForOthersToJoinSpy;
|
10465
11003
|
let canSendReactionsSpy;
|
11004
|
+
let requiresPostMeetingDataConsentPromptSpy;
|
10466
11005
|
let canUserRenameSelfAndObservedSpy;
|
10467
11006
|
let canUserRenameOthersSpy;
|
10468
11007
|
let canShareWhiteBoardSpy;
|
11008
|
+
let canMoveToLobbySpy;
|
10469
11009
|
// Due to import tree issues, hasHints must be stubed within the scope of the `it`.
|
10470
11010
|
|
10471
11011
|
beforeEach(() => {
|
@@ -10490,8 +11030,13 @@ describe('plugin-meetings', () => {
|
|
10490
11030
|
waitingForOthersToJoinSpy = sinon.spy(MeetingUtil, 'waitingForOthersToJoin');
|
10491
11031
|
canSendReactionsSpy = sinon.spy(MeetingUtil, 'canSendReactions');
|
10492
11032
|
canUserRenameSelfAndObservedSpy = sinon.spy(MeetingUtil, 'canUserRenameSelfAndObserved');
|
11033
|
+
requiresPostMeetingDataConsentPromptSpy = sinon.spy(
|
11034
|
+
MeetingUtil,
|
11035
|
+
'requiresPostMeetingDataConsentPrompt'
|
11036
|
+
);
|
10493
11037
|
canUserRenameOthersSpy = sinon.spy(MeetingUtil, 'canUserRenameOthers');
|
10494
11038
|
canShareWhiteBoardSpy = sinon.spy(MeetingUtil, 'canShareWhiteBoard');
|
11039
|
+
canMoveToLobbySpy = sinon.spy(MeetingUtil, 'canMoveToLobby');
|
10495
11040
|
});
|
10496
11041
|
|
10497
11042
|
afterEach(() => {
|
@@ -10589,6 +11134,16 @@ describe('plugin-meetings', () => {
|
|
10589
11134
|
requiredDisplayHints: [],
|
10590
11135
|
requiredPolicies: [SELF_POLICY.SUPPORT_FILE_TRANSFER],
|
10591
11136
|
},
|
11137
|
+
{
|
11138
|
+
actionName: 'canRealtimeCloseCaption',
|
11139
|
+
requiredDisplayHints: [],
|
11140
|
+
requiredPolicies: [SELF_POLICY.SUPPORT_REALTIME_CLOSE_CAPTION],
|
11141
|
+
},
|
11142
|
+
{
|
11143
|
+
actionName: 'canRealtimeCloseCaptionManual',
|
11144
|
+
requiredDisplayHints: [],
|
11145
|
+
requiredPolicies: [SELF_POLICY.SUPPORT_REALTIME_CLOSE_CAPTION_MANUAL],
|
11146
|
+
},
|
10592
11147
|
{
|
10593
11148
|
actionName: 'canChat',
|
10594
11149
|
requiredDisplayHints: [],
|
@@ -10618,6 +11173,11 @@ describe('plugin-meetings', () => {
|
|
10618
11173
|
requiredDisplayHints: [],
|
10619
11174
|
requiredPolicies: [SELF_POLICY.SUPPORT_POLLING_AND_QA],
|
10620
11175
|
},
|
11176
|
+
{
|
11177
|
+
actionName: 'canShareWhiteBoard',
|
11178
|
+
requiredDisplayHints: [DISPLAY_HINTS.SHARE_WHITEBOARD],
|
11179
|
+
requiredPolicies: [SELF_POLICY.SUPPORT_WHITEBOARD],
|
11180
|
+
},
|
10621
11181
|
],
|
10622
11182
|
({
|
10623
11183
|
actionName,
|
@@ -11025,8 +11585,10 @@ describe('plugin-meetings', () => {
|
|
11025
11585
|
assert.calledWith(waitingForOthersToJoinSpy, userDisplayHints);
|
11026
11586
|
assert.calledWith(canSendReactionsSpy, null, userDisplayHints);
|
11027
11587
|
assert.calledWith(canUserRenameSelfAndObservedSpy, userDisplayHints);
|
11588
|
+
assert.calledWith(requiresPostMeetingDataConsentPromptSpy, userDisplayHints);
|
11028
11589
|
assert.calledWith(canUserRenameOthersSpy, userDisplayHints);
|
11029
|
-
assert.calledWith(canShareWhiteBoardSpy, userDisplayHints);
|
11590
|
+
assert.calledWith(canShareWhiteBoardSpy, userDisplayHints, selfUserPolicies);
|
11591
|
+
assert.calledWith(canMoveToLobbySpy, userDisplayHints);
|
11030
11592
|
|
11031
11593
|
assert.calledWith(ControlsOptionsUtil.hasHints, {
|
11032
11594
|
requiredHints: [DISPLAY_HINTS.MUTE_ALL],
|
@@ -11120,6 +11682,30 @@ describe('plugin-meetings', () => {
|
|
11120
11682
|
requiredPolicies: [SELF_POLICY.SUPPORT_VOIP],
|
11121
11683
|
policies: selfUserPolicies,
|
11122
11684
|
});
|
11685
|
+
assert.calledWith(ControlsOptionsUtil.hasHints, {
|
11686
|
+
requiredHints: [DISPLAY_HINTS.ENABLE_ANNOTATION_MEETING_OPTION],
|
11687
|
+
displayHints: userDisplayHints,
|
11688
|
+
});
|
11689
|
+
assert.calledWith(ControlsOptionsUtil.hasHints, {
|
11690
|
+
requiredHints: [DISPLAY_HINTS.DISABLE_ANNOTATION_MEETING_OPTION],
|
11691
|
+
displayHints: userDisplayHints,
|
11692
|
+
});
|
11693
|
+
assert.calledWith(ControlsOptionsUtil.hasHints, {
|
11694
|
+
requiredHints: [DISPLAY_HINTS.ENABLE_RDC_MEETING_OPTION],
|
11695
|
+
displayHints: userDisplayHints,
|
11696
|
+
});
|
11697
|
+
assert.calledWith(ControlsOptionsUtil.hasHints, {
|
11698
|
+
requiredHints: [DISPLAY_HINTS.DISABLE_RDC_MEETING_OPTION],
|
11699
|
+
displayHints: userDisplayHints,
|
11700
|
+
});
|
11701
|
+
assert.calledWith(ControlsOptionsUtil.hasHints, {
|
11702
|
+
requiredHints: [DISPLAY_HINTS.ENABLE_ATTENDEE_START_POLLING_QA],
|
11703
|
+
displayHints: userDisplayHints,
|
11704
|
+
});
|
11705
|
+
assert.calledWith(ControlsOptionsUtil.hasHints, {
|
11706
|
+
requiredHints: [DISPLAY_HINTS.DISABLE_ATTENDEE_START_POLLING_QA],
|
11707
|
+
displayHints: userDisplayHints,
|
11708
|
+
});
|
11123
11709
|
|
11124
11710
|
assert.calledWith(
|
11125
11711
|
TriggerProxy.trigger,
|
@@ -11251,7 +11837,10 @@ describe('plugin-meetings', () => {
|
|
11251
11837
|
|
11252
11838
|
const result = await meeting.updateLLMConnection();
|
11253
11839
|
|
11254
|
-
assert.calledWith(webex.internal.llm.disconnectLLM
|
11840
|
+
assert.calledWith(webex.internal.llm.disconnectLLM, {
|
11841
|
+
code: 3050,
|
11842
|
+
reason: 'done (permanent)',
|
11843
|
+
});
|
11255
11844
|
assert.calledWith(
|
11256
11845
|
webex.internal.llm.registerAndConnect,
|
11257
11846
|
'a different url',
|
@@ -11281,7 +11870,10 @@ describe('plugin-meetings', () => {
|
|
11281
11870
|
|
11282
11871
|
const result = await meeting.updateLLMConnection();
|
11283
11872
|
|
11284
|
-
assert.calledWith(webex.internal.llm.disconnectLLM
|
11873
|
+
assert.calledWith(webex.internal.llm.disconnectLLM, {
|
11874
|
+
code: 3050,
|
11875
|
+
reason: 'done (permanent)',
|
11876
|
+
});
|
11285
11877
|
assert.calledWith(
|
11286
11878
|
webex.internal.llm.registerAndConnect,
|
11287
11879
|
'a url',
|
@@ -11310,7 +11902,7 @@ describe('plugin-meetings', () => {
|
|
11310
11902
|
|
11311
11903
|
const result = await meeting.updateLLMConnection();
|
11312
11904
|
|
11313
|
-
assert.calledWith(webex.internal.llm.disconnectLLM);
|
11905
|
+
assert.calledWith(webex.internal.llm.disconnectLLM, undefined);
|
11314
11906
|
assert.notCalled(webex.internal.llm.registerAndConnect);
|
11315
11907
|
assert.equal(result, undefined);
|
11316
11908
|
assert.calledOnceWithExactly(
|
@@ -11320,18 +11912,21 @@ describe('plugin-meetings', () => {
|
|
11320
11912
|
);
|
11321
11913
|
});
|
11322
11914
|
|
11323
|
-
|
11324
11915
|
it('connect ps data channel if ps started in webinar', async () => {
|
11325
11916
|
meeting.joinedWith = {state: 'JOINED'};
|
11326
|
-
meeting.locusInfo = {
|
11917
|
+
meeting.locusInfo = {
|
11918
|
+
url: 'a url',
|
11919
|
+
info: {
|
11920
|
+
datachannelUrl: 'a datachannel url',
|
11921
|
+
practiceSessionDatachannelUrl: 'a ps datachannel url',
|
11922
|
+
},
|
11923
|
+
};
|
11327
11924
|
meeting.webinar.isJoinPracticeSessionDataChannel = sinon.stub().returns(true);
|
11328
11925
|
await meeting.updateLLMConnection();
|
11329
11926
|
|
11330
11927
|
assert.notCalled(webex.internal.llm.disconnectLLM);
|
11331
11928
|
assert.calledWith(webex.internal.llm.registerAndConnect, 'a url', 'a ps datachannel url');
|
11332
|
-
|
11333
11929
|
});
|
11334
|
-
|
11335
11930
|
});
|
11336
11931
|
|
11337
11932
|
describe('#setLocus', () => {
|
@@ -11749,24 +12344,29 @@ describe('plugin-meetings', () => {
|
|
11749
12344
|
|
11750
12345
|
activeSharingId.whiteboard = beneficiaryId;
|
11751
12346
|
|
11752
|
-
eventTrigger.share.push(
|
11753
|
-
|
11754
|
-
|
11755
|
-
|
11756
|
-
|
11757
|
-
|
11758
|
-
|
11759
|
-
|
11760
|
-
|
11761
|
-
|
11762
|
-
|
11763
|
-
|
11764
|
-
|
11765
|
-
|
11766
|
-
|
11767
|
-
|
11768
|
-
|
12347
|
+
eventTrigger.share.push(
|
12348
|
+
meeting.webinar.selfIsAttendee
|
12349
|
+
? {
|
12350
|
+
eventName: EVENT_TRIGGERS.MEETING_STARTED_SHARING_REMOTE,
|
12351
|
+
functionName: 'remoteShare',
|
12352
|
+
eventPayload: {
|
12353
|
+
memberId: null,
|
12354
|
+
url,
|
12355
|
+
shareInstanceId,
|
12356
|
+
annotationInfo: undefined,
|
12357
|
+
resourceType: undefined,
|
12358
|
+
},
|
12359
|
+
}
|
12360
|
+
: {
|
12361
|
+
eventName: EVENT_TRIGGERS.MEETING_STARTED_SHARING_WHITEBOARD,
|
12362
|
+
functionName: 'startWhiteboardShare',
|
12363
|
+
eventPayload: {resourceUrl, memberId: beneficiaryId},
|
12364
|
+
}
|
12365
|
+
);
|
11769
12366
|
|
12367
|
+
shareStatus = meeting.webinar.selfIsAttendee
|
12368
|
+
? SHARE_STATUS.REMOTE_SHARE_ACTIVE
|
12369
|
+
: SHARE_STATUS.WHITEBOARD_SHARE_ACTIVE;
|
11770
12370
|
}
|
11771
12371
|
|
11772
12372
|
if (eventTrigger.member) {
|
@@ -11798,24 +12398,29 @@ describe('plugin-meetings', () => {
|
|
11798
12398
|
newPayload.current.content.disposition = FLOOR_ACTION.ACCEPTED;
|
11799
12399
|
newPayload.current.content.beneficiaryId = otherBeneficiaryId;
|
11800
12400
|
|
11801
|
-
eventTrigger.share.push(
|
11802
|
-
|
11803
|
-
|
11804
|
-
|
11805
|
-
|
11806
|
-
|
11807
|
-
|
11808
|
-
|
11809
|
-
|
11810
|
-
|
11811
|
-
|
11812
|
-
|
11813
|
-
|
11814
|
-
|
11815
|
-
|
11816
|
-
|
11817
|
-
|
12401
|
+
eventTrigger.share.push(
|
12402
|
+
meeting.webinar.selfIsAttendee
|
12403
|
+
? {
|
12404
|
+
eventName: EVENT_TRIGGERS.MEETING_STARTED_SHARING_REMOTE,
|
12405
|
+
functionName: 'remoteShare',
|
12406
|
+
eventPayload: {
|
12407
|
+
memberId: null,
|
12408
|
+
url,
|
12409
|
+
shareInstanceId,
|
12410
|
+
annotationInfo: undefined,
|
12411
|
+
resourceType: undefined,
|
12412
|
+
},
|
12413
|
+
}
|
12414
|
+
: {
|
12415
|
+
eventName: EVENT_TRIGGERS.MEETING_STARTED_SHARING_WHITEBOARD,
|
12416
|
+
functionName: 'startWhiteboardShare',
|
12417
|
+
eventPayload: {resourceUrl, memberId: beneficiaryId},
|
12418
|
+
}
|
12419
|
+
);
|
11818
12420
|
|
12421
|
+
shareStatus = meeting.webinar.selfIsAttendee
|
12422
|
+
? SHARE_STATUS.REMOTE_SHARE_ACTIVE
|
12423
|
+
: SHARE_STATUS.WHITEBOARD_SHARE_ACTIVE;
|
11819
12424
|
} else {
|
11820
12425
|
eventTrigger.share.push({
|
11821
12426
|
eventName: EVENT_TRIGGERS.MEETING_STOPPED_SHARING_WHITEBOARD,
|
@@ -11945,24 +12550,26 @@ describe('plugin-meetings', () => {
|
|
11945
12550
|
describe('Whiteboard Share - Webinar Attendee', () => {
|
11946
12551
|
it('Scenario #1: Whiteboard sharing as a webinar attendee', () => {
|
11947
12552
|
// Set the webinar attendee flag
|
11948
|
-
meeting.webinar = {
|
12553
|
+
meeting.webinar = {selfIsAttendee: true};
|
11949
12554
|
meeting.locusInfo.info.isWebinar = true;
|
12555
|
+
meeting.shareCAEventSentStatus.receiveStart = true;
|
12556
|
+
meeting.shareCAEventSentStatus.receiveStop = true;
|
11950
12557
|
|
11951
12558
|
// Step 1: Start sharing whiteboard A
|
11952
12559
|
const data1 = generateData(
|
11953
|
-
blankPayload,
|
11954
|
-
true,
|
11955
|
-
false,
|
11956
|
-
USER_IDS.REMOTE_A,
|
12560
|
+
blankPayload, // Initial payload
|
12561
|
+
true, // isGranting: Granting share
|
12562
|
+
false, // isContent: Whiteboard (not content)
|
12563
|
+
USER_IDS.REMOTE_A, // Beneficiary ID: Remote user A
|
11957
12564
|
RESOURCE_URLS.WHITEBOARD_A // Resource URL: Whiteboard A
|
11958
12565
|
);
|
11959
12566
|
|
11960
12567
|
// Step 2: Stop sharing whiteboard A
|
11961
12568
|
const data2 = generateData(
|
11962
|
-
data1.payload,
|
11963
|
-
false,
|
11964
|
-
false,
|
11965
|
-
USER_IDS.REMOTE_A
|
12569
|
+
data1.payload, // Updated payload from Step 1
|
12570
|
+
false, // isGranting: Stopping share
|
12571
|
+
false, // isContent: Whiteboard
|
12572
|
+
USER_IDS.REMOTE_A // Beneficiary ID: Remote user A
|
11966
12573
|
);
|
11967
12574
|
|
11968
12575
|
// Validate the payload changes and status updates
|
@@ -11970,10 +12577,11 @@ describe('plugin-meetings', () => {
|
|
11970
12577
|
|
11971
12578
|
// Specific assertions for webinar attendee status
|
11972
12579
|
assert.equal(meeting.shareStatus, SHARE_STATUS.REMOTE_SHARE_ACTIVE);
|
12580
|
+
assert.equal(meeting.shareCAEventSentStatus.receiveStart, false);
|
12581
|
+
assert.equal(meeting.shareCAEventSentStatus.receiveStop, false);
|
11973
12582
|
});
|
11974
12583
|
});
|
11975
12584
|
|
11976
|
-
|
11977
12585
|
describe('Whiteboard A --> Whiteboard B', () => {
|
11978
12586
|
it('Scenario #1: you share both whiteboards', () => {
|
11979
12587
|
const data1 = generateData(
|
@@ -12626,6 +13234,31 @@ describe('plugin-meetings', () => {
|
|
12626
13234
|
});
|
12627
13235
|
});
|
12628
13236
|
});
|
13237
|
+
|
13238
|
+
describe('handleShareVideoStreamMuteStateChange', () => {
|
13239
|
+
it('should emit MEETING_SHARE_VIDEO_MUTE_STATE_CHANGE event with correct fields', () => {
|
13240
|
+
meeting.isMultistream = true;
|
13241
|
+
meeting.statsAnalyzer = {shareVideoEncoderImplementation: 'OpenH264'};
|
13242
|
+
meeting.mediaProperties.shareVideoStream = {
|
13243
|
+
getSettings: sinon.stub().returns({displaySurface: 'monitor', frameRate: 30}),
|
13244
|
+
};
|
13245
|
+
|
13246
|
+
meeting.handleShareVideoStreamMuteStateChange(true);
|
13247
|
+
|
13248
|
+
assert.calledOnceWithExactly(
|
13249
|
+
Metrics.sendBehavioralMetric,
|
13250
|
+
BEHAVIORAL_METRICS.MEETING_SHARE_VIDEO_MUTE_STATE_CHANGE,
|
13251
|
+
{
|
13252
|
+
correlationId: meeting.correlationId,
|
13253
|
+
muted: true,
|
13254
|
+
encoderImplementation: 'OpenH264',
|
13255
|
+
displaySurface: 'monitor',
|
13256
|
+
isMultistream: true,
|
13257
|
+
frameRate: 30,
|
13258
|
+
}
|
13259
|
+
);
|
13260
|
+
});
|
13261
|
+
});
|
12629
13262
|
});
|
12630
13263
|
|
12631
13264
|
describe('#startKeepAlive', () => {
|
@@ -12793,6 +13426,38 @@ describe('plugin-meetings', () => {
|
|
12793
13426
|
});
|
12794
13427
|
});
|
12795
13428
|
|
13429
|
+
describe('#setPostMeetingDataConsent', () => {
|
13430
|
+
it('should have #setPostMeetingDataConsent', () => {
|
13431
|
+
assert.exists(meeting.setPostMeetingDataConsent);
|
13432
|
+
});
|
13433
|
+
|
13434
|
+
beforeEach(() => {
|
13435
|
+
meeting.meetingRequest.setPostMeetingDataConsent = sinon
|
13436
|
+
.stub()
|
13437
|
+
.returns(Promise.resolve());
|
13438
|
+
});
|
13439
|
+
|
13440
|
+
[true, false].forEach((accept) => {
|
13441
|
+
it(`should send consent with ${accept}`, async () => {
|
13442
|
+
const id = uuidv4();
|
13443
|
+
meeting.locusUrl = `https://locus-test.wbx2.com/locus/api/v1/loci/${accept}`;
|
13444
|
+
meeting.deviceUrl = `https://wdm-test.wbx2.com/wdm/api/v1/devices/${accept}`;
|
13445
|
+
meeting.members.selfId = id;
|
13446
|
+
|
13447
|
+
const consentPromise = meeting.setPostMeetingDataConsent(accept);
|
13448
|
+
|
13449
|
+
assert.exists(consentPromise.then);
|
13450
|
+
await consentPromise;
|
13451
|
+
assert.calledOnceWithExactly(meeting.meetingRequest.setPostMeetingDataConsent, {
|
13452
|
+
locusUrl: `https://locus-test.wbx2.com/locus/api/v1/loci/${accept}`,
|
13453
|
+
postMeetingDataConsent: accept,
|
13454
|
+
selfId: id,
|
13455
|
+
deviceUrl: `https://wdm-test.wbx2.com/wdm/api/v1/devices/${accept}`,
|
13456
|
+
});
|
13457
|
+
});
|
13458
|
+
});
|
13459
|
+
});
|
13460
|
+
|
12796
13461
|
describe('#sendReaction', () => {
|
12797
13462
|
it('should have #sendReaction', () => {
|
12798
13463
|
assert.exists(meeting.sendReaction);
|
@@ -13284,7 +13949,7 @@ describe('plugin-meetings', () => {
|
|
13284
13949
|
await meeting.roapMessageReceived(fakeMessage);
|
13285
13950
|
|
13286
13951
|
assert.fail('Expected MultistreamNotSupportedError to be thrown');
|
13287
|
-
} catch(e) {
|
13952
|
+
} catch (e) {
|
13288
13953
|
assert.isTrue(e instanceof MultistreamNotSupportedError);
|
13289
13954
|
}
|
13290
13955
|
|