@webex/plugin-meetings 3.10.0 → 3.11.0-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/dist/annotation/annotation.types.js.map +1 -1
- package/dist/annotation/constants.js.map +1 -1
- package/dist/annotation/index.js +19 -22
- package/dist/annotation/index.js.map +1 -1
- package/dist/breakouts/breakout.js +6 -6
- package/dist/breakouts/breakout.js.map +1 -1
- package/dist/breakouts/collection.js.map +1 -1
- package/dist/breakouts/edit-lock-error.js +9 -11
- package/dist/breakouts/edit-lock-error.js.map +1 -1
- package/dist/breakouts/events.js.map +1 -1
- package/dist/breakouts/index.js +126 -127
- package/dist/breakouts/index.js.map +1 -1
- package/dist/breakouts/request.js +6 -8
- package/dist/breakouts/request.js.map +1 -1
- package/dist/breakouts/utils.js.map +1 -1
- package/dist/common/browser-detection.js.map +1 -1
- package/dist/common/collection.js +1 -2
- package/dist/common/collection.js.map +1 -1
- package/dist/common/config.js.map +1 -1
- package/dist/common/errors/captcha-error.js +9 -11
- package/dist/common/errors/captcha-error.js.map +1 -1
- package/dist/common/errors/intent-to-join.js +10 -12
- package/dist/common/errors/intent-to-join.js.map +1 -1
- package/dist/common/errors/join-forbidden-error.js +10 -12
- package/dist/common/errors/join-forbidden-error.js.map +1 -1
- package/dist/common/errors/join-meeting.js +10 -12
- package/dist/common/errors/join-meeting.js.map +1 -1
- package/dist/common/errors/join-webinar-error.js +9 -11
- package/dist/common/errors/join-webinar-error.js.map +1 -1
- package/dist/common/errors/media.js +9 -11
- package/dist/common/errors/media.js.map +1 -1
- package/dist/common/errors/multistream-not-supported-error.js +9 -11
- package/dist/common/errors/multistream-not-supported-error.js.map +1 -1
- package/dist/common/errors/no-meeting-info.js +9 -11
- package/dist/common/errors/no-meeting-info.js.map +1 -1
- package/dist/common/errors/parameter.js +11 -14
- package/dist/common/errors/parameter.js.map +1 -1
- package/dist/common/errors/password-error.js +9 -11
- package/dist/common/errors/password-error.js.map +1 -1
- package/dist/common/errors/permission.js +9 -11
- package/dist/common/errors/permission.js.map +1 -1
- package/dist/common/errors/reclaim-host-role-errors.js +32 -38
- package/dist/common/errors/reclaim-host-role-errors.js.map +1 -1
- package/dist/common/errors/reconnection-not-started.js +5 -6
- package/dist/common/errors/reconnection-not-started.js.map +1 -1
- package/dist/common/errors/reconnection.js +9 -11
- package/dist/common/errors/reconnection.js.map +1 -1
- package/dist/common/errors/stats.js +9 -11
- package/dist/common/errors/stats.js.map +1 -1
- package/dist/common/errors/webex-errors.js +38 -27
- package/dist/common/errors/webex-errors.js.map +1 -1
- package/dist/common/errors/webex-meetings-error.js +9 -12
- package/dist/common/errors/webex-meetings-error.js.map +1 -1
- package/dist/common/events/events-scope.js +9 -10
- package/dist/common/events/events-scope.js.map +1 -1
- package/dist/common/events/events.js +9 -10
- package/dist/common/events/events.js.map +1 -1
- package/dist/common/events/trigger-proxy.js.map +1 -1
- package/dist/common/events/util.js.map +1 -1
- package/dist/common/logs/logger-config.js.map +1 -1
- package/dist/common/logs/logger-proxy.js.map +1 -1
- package/dist/common/logs/request.js +17 -17
- package/dist/common/logs/request.js.map +1 -1
- package/dist/common/queue.js +1 -2
- package/dist/common/queue.js.map +1 -1
- package/dist/config.js +2 -2
- package/dist/config.js.map +1 -1
- package/dist/constants.js +14 -8
- package/dist/constants.js.map +1 -1
- package/dist/controls-options-manager/constants.js.map +1 -1
- package/dist/controls-options-manager/enums.js.map +1 -1
- package/dist/controls-options-manager/index.js +1 -2
- package/dist/controls-options-manager/index.js.map +1 -1
- package/dist/controls-options-manager/types.js.map +1 -1
- package/dist/controls-options-manager/util.js +1 -2
- package/dist/controls-options-manager/util.js.map +1 -1
- package/dist/hashTree/constants.js +20 -0
- package/dist/hashTree/constants.js.map +1 -0
- package/dist/hashTree/hashTree.js +515 -0
- package/dist/hashTree/hashTree.js.map +1 -0
- package/dist/hashTree/hashTreeParser.js +1250 -0
- package/dist/hashTree/hashTreeParser.js.map +1 -0
- package/dist/hashTree/types.js +23 -0
- package/dist/hashTree/types.js.map +1 -0
- package/dist/hashTree/utils.js +59 -0
- package/dist/hashTree/utils.js.map +1 -0
- package/dist/index.js +8 -2
- package/dist/index.js.map +1 -1
- package/dist/interceptors/index.js.map +1 -1
- package/dist/interceptors/locusRetry.js +6 -8
- package/dist/interceptors/locusRetry.js.map +1 -1
- package/dist/interceptors/locusRouteToken.js +33 -13
- package/dist/interceptors/locusRouteToken.js.map +1 -1
- package/dist/interpretation/collection.js.map +1 -1
- package/dist/interpretation/index.js +1 -2
- package/dist/interpretation/index.js.map +1 -1
- package/dist/interpretation/siLanguage.js +1 -1
- package/dist/interpretation/siLanguage.js.map +1 -1
- package/dist/locus-info/controlsUtils.js +5 -3
- package/dist/locus-info/controlsUtils.js.map +1 -1
- package/dist/locus-info/embeddedAppsUtils.js.map +1 -1
- package/dist/locus-info/fullState.js.map +1 -1
- package/dist/locus-info/hostUtils.js.map +1 -1
- package/dist/locus-info/index.js +619 -177
- package/dist/locus-info/index.js.map +1 -1
- package/dist/locus-info/infoUtils.js.map +1 -1
- package/dist/locus-info/mediaSharesUtils.js.map +1 -1
- package/dist/locus-info/parser.js +3 -4
- package/dist/locus-info/parser.js.map +1 -1
- package/dist/locus-info/selfUtils.js.map +1 -1
- package/dist/locus-info/types.js +7 -0
- package/dist/locus-info/types.js.map +1 -0
- package/dist/media/MediaConnectionAwaiter.js +58 -3
- package/dist/media/MediaConnectionAwaiter.js.map +1 -1
- package/dist/media/index.js +5 -2
- package/dist/media/index.js.map +1 -1
- package/dist/media/properties.js +19 -19
- package/dist/media/properties.js.map +1 -1
- package/dist/media/util.js.map +1 -1
- package/dist/meeting/brbState.js +8 -9
- package/dist/meeting/brbState.js.map +1 -1
- package/dist/meeting/connectionStateHandler.js +10 -13
- package/dist/meeting/connectionStateHandler.js.map +1 -1
- package/dist/meeting/in-meeting-actions.js.map +1 -1
- package/dist/meeting/index.js +1672 -1553
- package/dist/meeting/index.js.map +1 -1
- package/dist/meeting/locusMediaRequest.js +13 -17
- package/dist/meeting/locusMediaRequest.js.map +1 -1
- package/dist/meeting/muteState.js +11 -12
- package/dist/meeting/muteState.js.map +1 -1
- package/dist/meeting/request.js +101 -104
- package/dist/meeting/request.js.map +1 -1
- package/dist/meeting/request.type.js.map +1 -1
- package/dist/meeting/state.js.map +1 -1
- package/dist/meeting/type.js.map +1 -1
- package/dist/meeting/util.js +118 -25
- package/dist/meeting/util.js.map +1 -1
- package/dist/meeting/voicea-meeting.js +3 -3
- package/dist/meeting/voicea-meeting.js.map +1 -1
- package/dist/meeting-info/collection.js +7 -10
- package/dist/meeting-info/collection.js.map +1 -1
- package/dist/meeting-info/index.js +1 -2
- package/dist/meeting-info/index.js.map +1 -1
- package/dist/meeting-info/meeting-info-v2.js +135 -146
- package/dist/meeting-info/meeting-info-v2.js.map +1 -1
- package/dist/meeting-info/request.js +1 -2
- package/dist/meeting-info/request.js.map +1 -1
- package/dist/meeting-info/util.js +36 -37
- package/dist/meeting-info/util.js.map +1 -1
- package/dist/meeting-info/utilv2.js +30 -31
- package/dist/meeting-info/utilv2.js.map +1 -1
- package/dist/meetings/collection.js +6 -8
- package/dist/meetings/collection.js.map +1 -1
- package/dist/meetings/index.js +276 -174
- package/dist/meetings/index.js.map +1 -1
- package/dist/meetings/meetings.types.js.map +1 -1
- package/dist/meetings/request.js +6 -8
- package/dist/meetings/request.js.map +1 -1
- package/dist/meetings/util.js +36 -30
- package/dist/meetings/util.js.map +1 -1
- package/dist/member/index.js +1 -2
- package/dist/member/index.js.map +1 -1
- package/dist/member/types.js +6 -3
- package/dist/member/types.js.map +1 -1
- package/dist/member/util.js.map +1 -1
- package/dist/members/collection.js +1 -2
- package/dist/members/collection.js.map +1 -1
- package/dist/members/index.js +18 -21
- package/dist/members/index.js.map +1 -1
- package/dist/members/request.js +8 -11
- package/dist/members/request.js.map +1 -1
- package/dist/members/types.js.map +1 -1
- package/dist/members/util.js.map +1 -1
- package/dist/metrics/constants.js +5 -1
- package/dist/metrics/constants.js.map +1 -1
- package/dist/metrics/index.js +3 -4
- package/dist/metrics/index.js.map +1 -1
- package/dist/multistream/mediaRequestManager.js +1 -2
- package/dist/multistream/mediaRequestManager.js.map +1 -1
- package/dist/multistream/receiveSlot.js +34 -45
- package/dist/multistream/receiveSlot.js.map +1 -1
- package/dist/multistream/receiveSlotManager.js +8 -9
- package/dist/multistream/receiveSlotManager.js.map +1 -1
- package/dist/multistream/remoteMedia.js +12 -15
- package/dist/multistream/remoteMedia.js.map +1 -1
- package/dist/multistream/remoteMediaGroup.js +1 -2
- package/dist/multistream/remoteMediaGroup.js.map +1 -1
- package/dist/multistream/remoteMediaManager.js +122 -123
- package/dist/multistream/remoteMediaManager.js.map +1 -1
- package/dist/multistream/sendSlotManager.js +29 -30
- package/dist/multistream/sendSlotManager.js.map +1 -1
- package/dist/personal-meeting-room/index.js +16 -19
- package/dist/personal-meeting-room/index.js.map +1 -1
- package/dist/personal-meeting-room/request.js +7 -10
- package/dist/personal-meeting-room/request.js.map +1 -1
- package/dist/personal-meeting-room/util.js.map +1 -1
- package/dist/reachability/clusterReachability.js +188 -352
- package/dist/reachability/clusterReachability.js.map +1 -1
- package/dist/reachability/index.js +212 -204
- package/dist/reachability/index.js.map +1 -1
- package/dist/reachability/reachability.types.js +14 -1
- package/dist/reachability/reachability.types.js.map +1 -1
- package/dist/reachability/reachabilityPeerConnection.js +445 -0
- package/dist/reachability/reachabilityPeerConnection.js.map +1 -0
- package/dist/reachability/request.js.map +1 -1
- package/dist/reachability/util.js.map +1 -1
- package/dist/reactions/constants.js.map +1 -1
- package/dist/reactions/reactions.js.map +1 -1
- package/dist/reactions/reactions.type.js.map +1 -1
- package/dist/reconnection-manager/index.js +178 -176
- package/dist/reconnection-manager/index.js.map +1 -1
- package/dist/recording-controller/enums.js.map +1 -1
- package/dist/recording-controller/index.js +1 -2
- package/dist/recording-controller/index.js.map +1 -1
- package/dist/recording-controller/util.js.map +1 -1
- package/dist/roap/index.js +12 -15
- package/dist/roap/index.js.map +1 -1
- package/dist/roap/request.js +24 -26
- package/dist/roap/request.js.map +1 -1
- package/dist/roap/turnDiscovery.js +75 -76
- package/dist/roap/turnDiscovery.js.map +1 -1
- package/dist/roap/types.js.map +1 -1
- package/dist/transcription/index.js +4 -5
- package/dist/transcription/index.js.map +1 -1
- package/dist/types/common/errors/webex-errors.d.ts +12 -0
- package/dist/types/config.d.ts +1 -0
- package/dist/types/constants.d.ts +28 -21
- package/dist/types/hashTree/constants.d.ts +8 -0
- package/dist/types/hashTree/hashTree.d.ts +129 -0
- package/dist/types/hashTree/hashTreeParser.d.ts +250 -0
- package/dist/types/hashTree/types.d.ts +33 -0
- package/dist/types/hashTree/utils.d.ts +16 -0
- package/dist/types/index.d.ts +2 -1
- package/dist/types/interceptors/locusRouteToken.d.ts +2 -0
- package/dist/types/locus-info/index.d.ts +98 -80
- package/dist/types/locus-info/types.d.ts +54 -0
- package/dist/types/media/MediaConnectionAwaiter.d.ts +10 -1
- package/dist/types/media/properties.d.ts +2 -1
- package/dist/types/meeting/index.d.ts +40 -12
- package/dist/types/meeting/util.d.ts +25 -0
- package/dist/types/meetings/index.d.ts +12 -3
- package/dist/types/metrics/constants.d.ts +4 -0
- package/dist/types/reachability/clusterReachability.d.ts +33 -84
- package/dist/types/reachability/reachability.types.d.ts +12 -1
- package/dist/types/reachability/reachabilityPeerConnection.d.ts +111 -0
- package/dist/types/reactions/reactions.type.d.ts +1 -0
- package/dist/types/webinar/utils.d.ts +6 -0
- package/dist/webinar/collection.js +1 -2
- package/dist/webinar/collection.js.map +1 -1
- package/dist/webinar/index.js +206 -158
- package/dist/webinar/index.js.map +1 -1
- package/dist/webinar/utils.js +25 -0
- package/dist/webinar/utils.js.map +1 -0
- package/package.json +24 -23
- package/src/common/errors/webex-errors.ts +19 -0
- package/src/config.ts +1 -0
- package/src/constants.ts +17 -2
- package/src/hashTree/constants.ts +9 -0
- package/src/hashTree/hashTree.ts +463 -0
- package/src/hashTree/hashTreeParser.ts +1143 -0
- package/src/hashTree/types.ts +39 -0
- package/src/hashTree/utils.ts +53 -0
- package/src/index.ts +2 -0
- package/src/interceptors/locusRouteToken.ts +22 -5
- package/src/locus-info/controlsUtils.ts +6 -0
- package/src/locus-info/index.ts +641 -164
- package/src/locus-info/types.ts +53 -0
- package/src/media/MediaConnectionAwaiter.ts +41 -1
- package/src/media/index.ts +6 -0
- package/src/media/properties.ts +3 -1
- package/src/meeting/index.ts +173 -37
- package/src/meeting/util.ts +119 -1
- package/src/meetings/index.ts +212 -67
- package/src/meetings/util.ts +10 -9
- package/src/metrics/constants.ts +4 -0
- package/src/reachability/clusterReachability.ts +159 -330
- package/src/reachability/index.ts +15 -1
- package/src/reachability/reachability.types.ts +15 -1
- package/src/reachability/reachabilityPeerConnection.ts +418 -0
- package/src/reactions/reactions.type.ts +1 -0
- package/src/webinar/index.ts +44 -1
- package/src/webinar/utils.ts +16 -0
- package/test/unit/spec/hashTree/hashTree.ts +655 -0
- package/test/unit/spec/hashTree/hashTreeParser.ts +1524 -0
- package/test/unit/spec/hashTree/utils.ts +140 -0
- package/test/unit/spec/interceptors/locusRouteToken.ts +44 -0
- package/test/unit/spec/locus-info/controlsUtils.js +27 -1
- package/test/unit/spec/locus-info/index.js +879 -16
- package/test/unit/spec/media/MediaConnectionAwaiter.ts +41 -1
- package/test/unit/spec/media/index.ts +140 -9
- package/test/unit/spec/media/properties.ts +12 -3
- package/test/unit/spec/meeting/index.js +514 -130
- package/test/unit/spec/meeting/utils.js +341 -15
- package/test/unit/spec/meetings/index.js +822 -32
- package/test/unit/spec/meetings/utils.js +51 -1
- package/test/unit/spec/reachability/clusterReachability.ts +404 -137
- package/test/unit/spec/reachability/index.ts +26 -3
- package/test/unit/spec/webinar/index.ts +106 -0
- package/test/unit/spec/webinar/utils.ts +39 -0
|
@@ -46,6 +46,7 @@ import {
|
|
|
46
46
|
MediaType,
|
|
47
47
|
} from '@webex/internal-media-core';
|
|
48
48
|
import {LocalStreamEventNames} from '@webex/media-helpers';
|
|
49
|
+
import {CapabilityState, WebCapabilities} from '@webex/web-capabilities';
|
|
49
50
|
import EventsScope from '@webex/plugin-meetings/src/common/events/events-scope';
|
|
50
51
|
import Meetings, {CONSTANTS} from '@webex/plugin-meetings';
|
|
51
52
|
import Meeting from '@webex/plugin-meetings/src/meeting';
|
|
@@ -97,6 +98,7 @@ import PermissionError from '../../../../src/common/errors/permission';
|
|
|
97
98
|
import JoinWebinarError from '../../../../src/common/errors/join-webinar-error';
|
|
98
99
|
import IntentToJoinError from '../../../../src/common/errors/intent-to-join';
|
|
99
100
|
import MultistreamNotSupportedError from '../../../../src/common/errors/multistream-not-supported-error';
|
|
101
|
+
import {SdpResponseTimeoutError} from '@webex/plugin-meetings/src/common/errors/webex-errors';
|
|
100
102
|
import testUtils from '../../../utils/testUtils';
|
|
101
103
|
import {
|
|
102
104
|
MeetingInfoV2CaptchaError,
|
|
@@ -132,11 +134,15 @@ describe('plugin-meetings', () => {
|
|
|
132
134
|
debug: () => {},
|
|
133
135
|
};
|
|
134
136
|
|
|
137
|
+
let fakeClock;
|
|
138
|
+
|
|
135
139
|
beforeEach(() => {
|
|
136
140
|
sinon.stub(Metrics, 'sendBehavioralMetric');
|
|
141
|
+
fakeClock = sinon.useFakeTimers();
|
|
137
142
|
});
|
|
138
143
|
afterEach(() => {
|
|
139
144
|
sinon.restore();
|
|
145
|
+
fakeClock.restore();
|
|
140
146
|
});
|
|
141
147
|
|
|
142
148
|
before(() => {
|
|
@@ -729,8 +735,11 @@ describe('plugin-meetings', () => {
|
|
|
729
735
|
let handleTurnDiscoveryHttpResponseStub;
|
|
730
736
|
let abortTurnDiscoveryStub;
|
|
731
737
|
let addMediaInternalStub;
|
|
738
|
+
let supportsRTCPeerConnectionStub;
|
|
732
739
|
|
|
733
740
|
beforeEach(() => {
|
|
741
|
+
supportsRTCPeerConnectionStub = sinon.stub(WebCapabilities, 'supportsRTCPeerConnection').returns(CapabilityState.CAPABLE);
|
|
742
|
+
|
|
734
743
|
meeting.join = sinon.stub().callsFake((joinOptions) => {
|
|
735
744
|
meeting.isMultistream = joinOptions.enableMultistream;
|
|
736
745
|
return Promise.resolve(fakeJoinResult);
|
|
@@ -1002,6 +1011,35 @@ describe('plugin-meetings', () => {
|
|
|
1002
1011
|
);
|
|
1003
1012
|
});
|
|
1004
1013
|
|
|
1014
|
+
it('should call leave() if addMediaInternal() fails ', async () => {
|
|
1015
|
+
const addMediaError = new Error('fake addMedia error');
|
|
1016
|
+
addMediaError.name = 'TypeError';
|
|
1017
|
+
|
|
1018
|
+
const rejectError = {
|
|
1019
|
+
error: {
|
|
1020
|
+
body: {
|
|
1021
|
+
errorCode: 2729,
|
|
1022
|
+
message: 'fake addMedia error',
|
|
1023
|
+
name: 'TypeError'
|
|
1024
|
+
}
|
|
1025
|
+
}
|
|
1026
|
+
};
|
|
1027
|
+
meeting.addMediaInternal.rejects(addMediaError);
|
|
1028
|
+
sinon.stub(meeting, 'leave').resolves();
|
|
1029
|
+
|
|
1030
|
+
await assert.isRejected(
|
|
1031
|
+
meeting.joinWithMedia({
|
|
1032
|
+
joinOptions,
|
|
1033
|
+
mediaOptions,
|
|
1034
|
+
}),
|
|
1035
|
+
rejectError
|
|
1036
|
+
);
|
|
1037
|
+
|
|
1038
|
+
assert.calledOnce(meeting.join);
|
|
1039
|
+
assert.calledOnce(meeting.addMediaInternal);
|
|
1040
|
+
assert.calledOnce(Metrics.sendBehavioralMetric);
|
|
1041
|
+
});
|
|
1042
|
+
|
|
1005
1043
|
it('should not call leave() if addMediaInternal() fails the first time and succeeds the second time and should only call join() once', async () => {
|
|
1006
1044
|
const addMediaError = new Error('fake addMedia error');
|
|
1007
1045
|
const leaveStub = sinon.stub(meeting, 'leave');
|
|
@@ -1210,44 +1248,49 @@ describe('plugin-meetings', () => {
|
|
|
1210
1248
|
await assert.isRejected(result);
|
|
1211
1249
|
});
|
|
1212
1250
|
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1251
|
+
[
|
|
1252
|
+
{errorName: 'SdpOfferCreationError', description: 'if we fail to create the offer on first attempt'},
|
|
1253
|
+
{errorName: 'WebrtcApiNotAvailableError', description: 'if RTCPeerConnection is not available'},
|
|
1254
|
+
].forEach(({errorName, description}) => {
|
|
1255
|
+
it(`should not attempt a retry ${description}`, async () => {
|
|
1256
|
+
const addMediaError = new Error('fake addMedia error');
|
|
1257
|
+
addMediaError.name = errorName;
|
|
1216
1258
|
|
|
1217
|
-
|
|
1218
|
-
|
|
1259
|
+
meeting.addMediaInternal.rejects(addMediaError);
|
|
1260
|
+
sinon.stub(meeting, 'leave').resolves();
|
|
1219
1261
|
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1262
|
+
await assert.isRejected(
|
|
1263
|
+
meeting.joinWithMedia({
|
|
1264
|
+
joinOptions,
|
|
1265
|
+
mediaOptions,
|
|
1266
|
+
}),
|
|
1267
|
+
addMediaError
|
|
1268
|
+
);
|
|
1227
1269
|
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1270
|
+
// check that only 1 attempt was done
|
|
1271
|
+
assert.calledOnce(meeting.join);
|
|
1272
|
+
assert.calledOnce(meeting.addMediaInternal);
|
|
1273
|
+
assert.calledOnce(Metrics.sendBehavioralMetric);
|
|
1274
|
+
assert.calledWith(
|
|
1275
|
+
Metrics.sendBehavioralMetric.firstCall,
|
|
1276
|
+
BEHAVIORAL_METRICS.JOIN_WITH_MEDIA_FAILURE,
|
|
1277
|
+
{
|
|
1278
|
+
correlation_id: meeting.correlationId,
|
|
1279
|
+
locus_id: meeting.locusUrl.split('/').pop(),
|
|
1280
|
+
reason: addMediaError.message,
|
|
1281
|
+
stack: addMediaError.stack,
|
|
1282
|
+
leaveErrorReason: undefined,
|
|
1283
|
+
isRetry: false,
|
|
1284
|
+
},
|
|
1285
|
+
{
|
|
1286
|
+
type: addMediaError.name,
|
|
1287
|
+
}
|
|
1288
|
+
);
|
|
1289
|
+
assert.calledOnceWithExactly(meeting.leave, {
|
|
1290
|
+
resourceId: undefined,
|
|
1291
|
+
reason: 'joinWithMedia failure',
|
|
1292
|
+
});
|
|
1293
|
+
})
|
|
1251
1294
|
});
|
|
1252
1295
|
|
|
1253
1296
|
it('should ignore sendVideo/receiveVideo when videoEnabled is false', async () => {
|
|
@@ -1315,6 +1358,21 @@ describe('plugin-meetings', () => {
|
|
|
1315
1358
|
})
|
|
1316
1359
|
);
|
|
1317
1360
|
});
|
|
1361
|
+
|
|
1362
|
+
it('should throw immediately if RTCPeerConnection is not available', async () => {
|
|
1363
|
+
supportsRTCPeerConnectionStub.returns(CapabilityState.NOT_CAPABLE);
|
|
1364
|
+
|
|
1365
|
+
await assert.isRejected(
|
|
1366
|
+
meeting.joinWithMedia({
|
|
1367
|
+
joinOptions,
|
|
1368
|
+
mediaOptions,
|
|
1369
|
+
}),
|
|
1370
|
+
Errors.WebrtcApiNotAvailableError
|
|
1371
|
+
);
|
|
1372
|
+
|
|
1373
|
+
assert.notCalled(meeting.join);
|
|
1374
|
+
assert.notCalled(meeting.addMediaInternal);
|
|
1375
|
+
});
|
|
1318
1376
|
});
|
|
1319
1377
|
describe('#isTranscriptionSupported', () => {
|
|
1320
1378
|
it('should return false if the feature is not supported for the meeting', () => {
|
|
@@ -1329,6 +1387,25 @@ describe('plugin-meetings', () => {
|
|
|
1329
1387
|
});
|
|
1330
1388
|
});
|
|
1331
1389
|
|
|
1390
|
+
describe('#update hesiod llm id', () => {
|
|
1391
|
+
beforeEach(() => {
|
|
1392
|
+
webex.internal.voicea.onCaptionServiceIdUpdate = sinon.stub();
|
|
1393
|
+
});
|
|
1394
|
+
afterEach(() => {
|
|
1395
|
+
// Restore the original methods after each test
|
|
1396
|
+
sinon.restore();
|
|
1397
|
+
});
|
|
1398
|
+
it('should call voicea.onCaptionServiceIdUpdate when joined', async () => {
|
|
1399
|
+
meeting.joinedWith = {state: 'JOINED'};
|
|
1400
|
+
await meeting.locusInfo.emitScoped(
|
|
1401
|
+
{function: 'test', file: 'test'},
|
|
1402
|
+
LOCUSINFO.EVENTS.CONTROLS_MEETING_HESIOD_LLM_ID_UPDATED,
|
|
1403
|
+
{hesiodLlmId: '123a-456b-789c'}
|
|
1404
|
+
);
|
|
1405
|
+
assert.calledWith(webex.internal.voicea.onCaptionServiceIdUpdate, '123a-456b-789c');
|
|
1406
|
+
});
|
|
1407
|
+
});
|
|
1408
|
+
|
|
1332
1409
|
describe('#update spoken language', () => {
|
|
1333
1410
|
beforeEach(() => {
|
|
1334
1411
|
webex.internal.voicea.onSpokenLanguageUpdate = sinon.stub();
|
|
@@ -1805,6 +1882,53 @@ describe('plugin-meetings', () => {
|
|
|
1805
1882
|
fakeProcessedReaction
|
|
1806
1883
|
);
|
|
1807
1884
|
});
|
|
1885
|
+
|
|
1886
|
+
it('should process if participantId does not exist in membersCollection but has displayName in Webinar', () => {
|
|
1887
|
+
LoggerProxy.logger.warn = sinon.stub();
|
|
1888
|
+
meeting.isReactionsSupported = sinon.stub().returns(true);
|
|
1889
|
+
meeting.config.receiveReactions = true;
|
|
1890
|
+
meeting.locusInfo.info = {isWebinar: true};
|
|
1891
|
+
const fakeSendersName = 'Fake reactors name';
|
|
1892
|
+
const fakeReactionPayload = {
|
|
1893
|
+
type: 'fake_type',
|
|
1894
|
+
codepoints: 'fake_codepoints',
|
|
1895
|
+
shortcodes: 'fake_shortcodes',
|
|
1896
|
+
tone: {
|
|
1897
|
+
type: 'fake_tone_type',
|
|
1898
|
+
codepoints: 'fake_tone_codepoints',
|
|
1899
|
+
shortcodes: 'fake_tone_shortcodes',
|
|
1900
|
+
},
|
|
1901
|
+
};
|
|
1902
|
+
const fakeSenderPayload = {
|
|
1903
|
+
displayName: 'Fake reactors name',
|
|
1904
|
+
participantId: 'fake_participant_id',
|
|
1905
|
+
};
|
|
1906
|
+
const fakeProcessedReaction = {
|
|
1907
|
+
reaction: fakeReactionPayload,
|
|
1908
|
+
sender: {
|
|
1909
|
+
id: fakeSenderPayload.participantId,
|
|
1910
|
+
name: fakeSendersName,
|
|
1911
|
+
},
|
|
1912
|
+
};
|
|
1913
|
+
const fakeRelayEvent = {
|
|
1914
|
+
data: {
|
|
1915
|
+
relayType: REACTION_RELAY_TYPES.REACTION,
|
|
1916
|
+
reaction: fakeReactionPayload,
|
|
1917
|
+
sender: fakeSenderPayload,
|
|
1918
|
+
},
|
|
1919
|
+
};
|
|
1920
|
+
meeting.processRelayEvent(fakeRelayEvent);
|
|
1921
|
+
assert.calledWith(
|
|
1922
|
+
TriggerProxy.trigger,
|
|
1923
|
+
sinon.match.instanceOf(Meeting),
|
|
1924
|
+
{
|
|
1925
|
+
file: 'meeting/index',
|
|
1926
|
+
function: 'join',
|
|
1927
|
+
},
|
|
1928
|
+
EVENT_TRIGGERS.MEETING_RECEIVE_REACTIONS,
|
|
1929
|
+
fakeProcessedReaction
|
|
1930
|
+
);
|
|
1931
|
+
});
|
|
1808
1932
|
});
|
|
1809
1933
|
|
|
1810
1934
|
describe('#handleLLMOnline', () => {
|
|
@@ -1848,7 +1972,7 @@ describe('plugin-meetings', () => {
|
|
|
1848
1972
|
setCorrelationIdSpy = sinon.spy(meeting, 'setCorrelationId');
|
|
1849
1973
|
meeting.setLocus = sinon.stub().returns(true);
|
|
1850
1974
|
webex.meetings.registered = true;
|
|
1851
|
-
|
|
1975
|
+
sinon.stub(meeting, 'updateLLMConnection').returns(Promise.resolve());
|
|
1852
1976
|
});
|
|
1853
1977
|
|
|
1854
1978
|
describe('successful', () => {
|
|
@@ -1999,18 +2123,15 @@ describe('plugin-meetings', () => {
|
|
|
1999
2123
|
|
|
2000
2124
|
// Assert that client.locus.join.response error event is not sent from this function, it is now emitted from MeetingUtil.joinMeeting
|
|
2001
2125
|
assert.calledOnce(webex.internal.newMetrics.submitClientEvent);
|
|
2002
|
-
assert.calledWithMatch(
|
|
2003
|
-
|
|
2004
|
-
{
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
options: {meetingId: meeting.id},
|
|
2012
|
-
}
|
|
2013
|
-
);
|
|
2126
|
+
assert.calledWithMatch(webex.internal.newMetrics.submitClientEvent, {
|
|
2127
|
+
name: 'client.call.initiated',
|
|
2128
|
+
payload: {
|
|
2129
|
+
trigger: 'user-interaction',
|
|
2130
|
+
isRoapCallEnabled: true,
|
|
2131
|
+
pstnAudioType: undefined,
|
|
2132
|
+
},
|
|
2133
|
+
options: {meetingId: meeting.id},
|
|
2134
|
+
});
|
|
2014
2135
|
});
|
|
2015
2136
|
});
|
|
2016
2137
|
it('should fail if password is required', async () => {
|
|
@@ -2042,7 +2163,7 @@ describe('plugin-meetings', () => {
|
|
|
2042
2163
|
const defer = new Defer();
|
|
2043
2164
|
|
|
2044
2165
|
meeting.config.enableAutomaticLLM = true;
|
|
2045
|
-
meeting.updateLLMConnection
|
|
2166
|
+
meeting.updateLLMConnection.returns(defer.promise);
|
|
2046
2167
|
|
|
2047
2168
|
const result = await meeting.join();
|
|
2048
2169
|
|
|
@@ -2053,7 +2174,7 @@ describe('plugin-meetings', () => {
|
|
|
2053
2174
|
|
|
2054
2175
|
it('should call updateLLMConnection as part of joining if config value is set', async () => {
|
|
2055
2176
|
meeting.config.enableAutomaticLLM = true;
|
|
2056
|
-
meeting.updateLLMConnection
|
|
2177
|
+
meeting.updateLLMConnection.resolves();
|
|
2057
2178
|
|
|
2058
2179
|
await meeting.join();
|
|
2059
2180
|
|
|
@@ -2061,7 +2182,7 @@ describe('plugin-meetings', () => {
|
|
|
2061
2182
|
});
|
|
2062
2183
|
|
|
2063
2184
|
it('should not call updateLLMConnection as part of joining if config value is not set', async () => {
|
|
2064
|
-
meeting.updateLLMConnection
|
|
2185
|
+
meeting.updateLLMConnection.resolves();
|
|
2065
2186
|
await meeting.join();
|
|
2066
2187
|
|
|
2067
2188
|
assert.notCalled(meeting.updateLLMConnection);
|
|
@@ -2071,7 +2192,7 @@ describe('plugin-meetings', () => {
|
|
|
2071
2192
|
const defer = new Defer();
|
|
2072
2193
|
|
|
2073
2194
|
meeting.config.enableAutomaticLLM = true;
|
|
2074
|
-
meeting.updateLLMConnection
|
|
2195
|
+
meeting.updateLLMConnection.returns(defer.promise);
|
|
2075
2196
|
|
|
2076
2197
|
const result = await meeting.join();
|
|
2077
2198
|
|
|
@@ -2097,6 +2218,111 @@ describe('plugin-meetings', () => {
|
|
|
2097
2218
|
]);
|
|
2098
2219
|
}
|
|
2099
2220
|
});
|
|
2221
|
+
|
|
2222
|
+
it('handles Locus LLM events', async () => {
|
|
2223
|
+
const locusInfoParseStub = sinon.stub(meeting.locusInfo, 'parse');
|
|
2224
|
+
sinon.stub(meeting, 'isJoined').returns(true);
|
|
2225
|
+
|
|
2226
|
+
// Set up llm.on stub to capture the registered listener when updateLLMConnection is called
|
|
2227
|
+
let locusLLMEventListener;
|
|
2228
|
+
meeting.webex.internal.llm.on = sinon.stub().callsFake((eventName, callback) => {
|
|
2229
|
+
if (eventName === 'event:locus.state_message') {
|
|
2230
|
+
locusLLMEventListener = callback;
|
|
2231
|
+
}
|
|
2232
|
+
});
|
|
2233
|
+
meeting.webex.internal.llm.off = sinon.stub();
|
|
2234
|
+
|
|
2235
|
+
// we need the real meeting.updateLLMConnection not the mock
|
|
2236
|
+
meeting.updateLLMConnection.restore();
|
|
2237
|
+
|
|
2238
|
+
// Call updateLLMConnection to register the listener
|
|
2239
|
+
await meeting.updateLLMConnection();
|
|
2240
|
+
|
|
2241
|
+
// Verify the listener was registered and we captured it
|
|
2242
|
+
assert.isDefined(locusLLMEventListener, 'LLM event listener should be registered');
|
|
2243
|
+
|
|
2244
|
+
// Now trigger the event
|
|
2245
|
+
const eventData = {
|
|
2246
|
+
eventType: 'locus.state_message',
|
|
2247
|
+
stateElementsMessage: {
|
|
2248
|
+
header: {messageId: 'msg-1'},
|
|
2249
|
+
elements: [],
|
|
2250
|
+
},
|
|
2251
|
+
};
|
|
2252
|
+
|
|
2253
|
+
locusLLMEventListener({data: eventData});
|
|
2254
|
+
|
|
2255
|
+
assert.calledOnceWithExactly(locusInfoParseStub, meeting, eventData);
|
|
2256
|
+
});
|
|
2257
|
+
|
|
2258
|
+
it('UpdateLLMConnection sends a metric if not connected after timeout', async () => {
|
|
2259
|
+
sinon.stub(meeting, 'isJoined').returns(true);
|
|
2260
|
+
sinon.stub(meeting.webex.internal.llm, 'isConnected').returns(false);
|
|
2261
|
+
sinon.stub(meeting.webex.internal.llm, 'hasEverConnected').value(true);
|
|
2262
|
+
sinon.stub(meeting.webex.internal.llm, 'registerAndConnect').resolves({});
|
|
2263
|
+
|
|
2264
|
+
// Restore the real updateLLMConnection
|
|
2265
|
+
meeting.updateLLMConnection.restore();
|
|
2266
|
+
|
|
2267
|
+
// Call updateLLMConnection to start the timer
|
|
2268
|
+
await meeting.updateLLMConnection();
|
|
2269
|
+
|
|
2270
|
+
// Fast forward time by 3 minutes
|
|
2271
|
+
fakeClock.tick(3 * 60 * 1000);
|
|
2272
|
+
|
|
2273
|
+
assert.calledWith(
|
|
2274
|
+
Metrics.sendBehavioralMetric,
|
|
2275
|
+
BEHAVIORAL_METRICS.LLM_HEALTHCHECK_FAILURE,
|
|
2276
|
+
{
|
|
2277
|
+
correlation_id: meeting.correlationId,
|
|
2278
|
+
hasEverConnected: true,
|
|
2279
|
+
}
|
|
2280
|
+
);
|
|
2281
|
+
});
|
|
2282
|
+
|
|
2283
|
+
it('clears the LLM health check timer when disconnecting LLM', async () => {
|
|
2284
|
+
const isJoinedStub = sinon.stub(meeting, 'isJoined');
|
|
2285
|
+
sinon.stub(meeting.webex.internal.llm, 'isConnected');
|
|
2286
|
+
sinon.stub(meeting.webex.internal.llm, 'disconnectLLM').resolves();
|
|
2287
|
+
sinon.stub(meeting.webex.internal.llm, 'registerAndConnect').resolves({});
|
|
2288
|
+
sinon
|
|
2289
|
+
.stub(meeting.webex.internal.llm, 'getLocusUrl')
|
|
2290
|
+
.returns('https://locus1.example.com');
|
|
2291
|
+
sinon
|
|
2292
|
+
.stub(meeting.webex.internal.llm, 'getDatachannelUrl')
|
|
2293
|
+
.returns('https://datachannel1.example.com');
|
|
2294
|
+
|
|
2295
|
+
// Restore the real updateLLMConnection
|
|
2296
|
+
meeting.updateLLMConnection.restore();
|
|
2297
|
+
|
|
2298
|
+
// First, connect LLM and start the timer
|
|
2299
|
+
isJoinedStub.returns(true);
|
|
2300
|
+
meeting.webex.internal.llm.isConnected.returns(false);
|
|
2301
|
+
await meeting.updateLLMConnection();
|
|
2302
|
+
|
|
2303
|
+
// Verify timer was started
|
|
2304
|
+
assert.exists(meeting.llmHealthCheckTimer);
|
|
2305
|
+
|
|
2306
|
+
// Now simulate that we're no longer joined
|
|
2307
|
+
isJoinedStub.returns(false);
|
|
2308
|
+
meeting.webex.internal.llm.isConnected.returns(true);
|
|
2309
|
+
|
|
2310
|
+
await meeting.updateLLMConnection();
|
|
2311
|
+
|
|
2312
|
+
assert.calledOnce(meeting.webex.internal.llm.disconnectLLM);
|
|
2313
|
+
|
|
2314
|
+
// Verify the timer was cleared (should be undefined)
|
|
2315
|
+
assert.isUndefined(meeting.llmHealthCheckTimer);
|
|
2316
|
+
|
|
2317
|
+
// Fast forward time to ensure no metric is sent
|
|
2318
|
+
Metrics.sendBehavioralMetric.resetHistory();
|
|
2319
|
+
fakeClock.tick(3 * 60 * 1000);
|
|
2320
|
+
|
|
2321
|
+
assert.neverCalledWith(
|
|
2322
|
+
Metrics.sendBehavioralMetric,
|
|
2323
|
+
BEHAVIORAL_METRICS.LLM_HEALTHCHECK_FAILURE
|
|
2324
|
+
);
|
|
2325
|
+
});
|
|
2100
2326
|
});
|
|
2101
2327
|
|
|
2102
2328
|
describe('refreshPermissionToken', () => {
|
|
@@ -2679,7 +2905,11 @@ describe('plugin-meetings', () => {
|
|
|
2679
2905
|
// simulate timeout waiting for the SDP answer that never comes
|
|
2680
2906
|
await clock.tickAsync(ROAP_OFFER_ANSWER_EXCHANGE_TIMEOUT);
|
|
2681
2907
|
|
|
2682
|
-
await assert.isRejected(
|
|
2908
|
+
await assert.isRejected(
|
|
2909
|
+
result,
|
|
2910
|
+
SdpResponseTimeoutError,
|
|
2911
|
+
'Timed out waiting for REMOTE SDP ANSWER'
|
|
2912
|
+
);
|
|
2683
2913
|
|
|
2684
2914
|
assert.calledOnceWithExactly(getErrorPayloadForClientErrorCodeStub, {
|
|
2685
2915
|
clientErrorCode: 2007,
|
|
@@ -2845,6 +3075,111 @@ describe('plugin-meetings', () => {
|
|
|
2845
3075
|
checkWorking({allowMediaInLobby: true});
|
|
2846
3076
|
});
|
|
2847
3077
|
|
|
3078
|
+
const setupLobbyTest = () => {
|
|
3079
|
+
meeting.roap.doTurnDiscovery = sinon
|
|
3080
|
+
.stub()
|
|
3081
|
+
.resolves({turnServerInfo: undefined, turnDiscoverySkippedReason: undefined});
|
|
3082
|
+
|
|
3083
|
+
meeting.meetingState = 'ACTIVE';
|
|
3084
|
+
meeting.locusInfo.parsedLocus = {self: {state: 'IDLE'}};
|
|
3085
|
+
meeting.isUserUnadmitted = true;
|
|
3086
|
+
|
|
3087
|
+
// Mock locusMediaRequest
|
|
3088
|
+
meeting.locusMediaRequest = {
|
|
3089
|
+
send: sinon.stub().resolves(),
|
|
3090
|
+
isConfluenceCreated: sinon.stub().returns(false),
|
|
3091
|
+
};
|
|
3092
|
+
|
|
3093
|
+
sinon.stub(RemoteMediaManagerModule, 'RemoteMediaManager').returns({
|
|
3094
|
+
start: sinon.stub().resolves(),
|
|
3095
|
+
on: sinon.stub(),
|
|
3096
|
+
logAllReceiveSlots: sinon.stub(),
|
|
3097
|
+
});
|
|
3098
|
+
|
|
3099
|
+
meeting.isMultistream = true;
|
|
3100
|
+
|
|
3101
|
+
const createFakeStream = (id) => ({
|
|
3102
|
+
on: sinon.stub(),
|
|
3103
|
+
off: sinon.stub(),
|
|
3104
|
+
userMuted: false,
|
|
3105
|
+
systemMuted: false,
|
|
3106
|
+
get muted() {
|
|
3107
|
+
return this.userMuted || this.systemMuted;
|
|
3108
|
+
},
|
|
3109
|
+
setUnmuteAllowed: sinon.stub(),
|
|
3110
|
+
setUserMuted: sinon.stub(),
|
|
3111
|
+
outputStream: {
|
|
3112
|
+
getTracks: () => [{id}],
|
|
3113
|
+
},
|
|
3114
|
+
getSettings: sinon.stub().returns({}),
|
|
3115
|
+
});
|
|
3116
|
+
|
|
3117
|
+
return {
|
|
3118
|
+
fakeMicrophoneStream: createFakeStream('fake mic'),
|
|
3119
|
+
fakeCameraStream: createFakeStream('fake camera'),
|
|
3120
|
+
};
|
|
3121
|
+
};
|
|
3122
|
+
|
|
3123
|
+
it('should not publish any local streams when in the lobby and allowPublishMediaInLobby is false', async () => {
|
|
3124
|
+
const {fakeMicrophoneStream, fakeCameraStream} = setupLobbyTest();
|
|
3125
|
+
|
|
3126
|
+
const publishStreamStub = sinon.stub();
|
|
3127
|
+
fakeMediaConnection.createSendSlot = sinon.stub().returns({
|
|
3128
|
+
publishStream: publishStreamStub,
|
|
3129
|
+
unpublishStream: sinon.stub(),
|
|
3130
|
+
setNamedMediaGroups: sinon.stub(),
|
|
3131
|
+
});
|
|
3132
|
+
|
|
3133
|
+
await meeting.addMedia({
|
|
3134
|
+
allowMediaInLobby: true,
|
|
3135
|
+
allowPublishMediaInLobby: false,
|
|
3136
|
+
audioEnabled: true,
|
|
3137
|
+
videoEnabled: true,
|
|
3138
|
+
localStreams: {
|
|
3139
|
+
microphone: fakeMicrophoneStream,
|
|
3140
|
+
camera: fakeCameraStream,
|
|
3141
|
+
},
|
|
3142
|
+
});
|
|
3143
|
+
|
|
3144
|
+
assert.notCalled(publishStreamStub);
|
|
3145
|
+
});
|
|
3146
|
+
|
|
3147
|
+
it('should publish local streams when in the lobby and allowPublishMediaInLobby is true', async () => {
|
|
3148
|
+
const {fakeMicrophoneStream, fakeCameraStream} = setupLobbyTest();
|
|
3149
|
+
|
|
3150
|
+
const audioSlot = {
|
|
3151
|
+
publishStream: sinon.stub(),
|
|
3152
|
+
unpublishStream: sinon.stub(),
|
|
3153
|
+
setNamedMediaGroups: sinon.stub(),
|
|
3154
|
+
};
|
|
3155
|
+
const videoSlot = {
|
|
3156
|
+
publishStream: sinon.stub(),
|
|
3157
|
+
unpublishStream: sinon.stub(),
|
|
3158
|
+
setNamedMediaGroups: sinon.stub(),
|
|
3159
|
+
};
|
|
3160
|
+
|
|
3161
|
+
fakeMediaConnection.createSendSlot = sinon.stub().callsFake((mediaType) => {
|
|
3162
|
+
if (mediaType === 'AUDIO-MAIN') {
|
|
3163
|
+
return audioSlot;
|
|
3164
|
+
}
|
|
3165
|
+
return videoSlot;
|
|
3166
|
+
});
|
|
3167
|
+
|
|
3168
|
+
await meeting.addMedia({
|
|
3169
|
+
allowMediaInLobby: true,
|
|
3170
|
+
allowPublishMediaInLobby: true,
|
|
3171
|
+
audioEnabled: true,
|
|
3172
|
+
videoEnabled: true,
|
|
3173
|
+
localStreams: {
|
|
3174
|
+
microphone: fakeMicrophoneStream,
|
|
3175
|
+
camera: fakeCameraStream,
|
|
3176
|
+
},
|
|
3177
|
+
});
|
|
3178
|
+
|
|
3179
|
+
assert.calledOnceWithExactly(audioSlot.publishStream, fakeMicrophoneStream);
|
|
3180
|
+
assert.calledOnceWithExactly(videoSlot.publishStream, fakeCameraStream);
|
|
3181
|
+
});
|
|
3182
|
+
|
|
2848
3183
|
it('should create rtcMetrics and pass them to Media.createMediaConnection()', async () => {
|
|
2849
3184
|
const setIntervalOriginal = window.setInterval;
|
|
2850
3185
|
window.setInterval = sinon.stub().returns(1);
|
|
@@ -4087,7 +4422,7 @@ describe('plugin-meetings', () => {
|
|
|
4087
4422
|
member2: {isInMeeting: false, isInLobby: true},
|
|
4088
4423
|
member3: {isInMeeting: false, isInLobby: false},
|
|
4089
4424
|
member4: {isInMeeting: true, isInLobby: false},
|
|
4090
|
-
}
|
|
4425
|
+
},
|
|
4091
4426
|
};
|
|
4092
4427
|
sinon.stub(meeting, 'getMembers').returns({membersCollection: fakeMembersCollection});
|
|
4093
4428
|
const fakeData = {intervalMetadata: {}};
|
|
@@ -4747,6 +5082,7 @@ describe('plugin-meetings', () => {
|
|
|
4747
5082
|
id: 'fake locus from mocked join request',
|
|
4748
5083
|
locusUrl: 'fake locus url',
|
|
4749
5084
|
mediaId: 'fake media id',
|
|
5085
|
+
locus: {fullState: {}},
|
|
4750
5086
|
});
|
|
4751
5087
|
sinon.stub(meeting.meetingRequest, 'joinMeeting').resolves({
|
|
4752
5088
|
headers: {
|
|
@@ -6739,7 +7075,7 @@ describe('plugin-meetings', () => {
|
|
|
6739
7075
|
// Verify pstnCorrelationId was set
|
|
6740
7076
|
assert.exists(meeting.pstnCorrelationId);
|
|
6741
7077
|
assert.notEqual(meeting.pstnCorrelationId, meeting.correlationId);
|
|
6742
|
-
const firstPstnCorrelationId = meeting.pstnCorrelationId
|
|
7078
|
+
const firstPstnCorrelationId = meeting.pstnCorrelationId;
|
|
6743
7079
|
|
|
6744
7080
|
meeting.meetingRequest.dialIn.resetHistory();
|
|
6745
7081
|
|
|
@@ -6814,15 +7150,19 @@ describe('plugin-meetings', () => {
|
|
|
6814
7150
|
assert.equal(e, error);
|
|
6815
7151
|
|
|
6816
7152
|
// Verify behavioral metric was sent with dial_in_correlation_id
|
|
6817
|
-
assert.calledWith(
|
|
6818
|
-
|
|
6819
|
-
|
|
6820
|
-
|
|
6821
|
-
|
|
6822
|
-
|
|
6823
|
-
|
|
6824
|
-
|
|
6825
|
-
|
|
7153
|
+
assert.calledWith(
|
|
7154
|
+
Metrics.sendBehavioralMetric,
|
|
7155
|
+
BEHAVIORAL_METRICS.ADD_DIAL_IN_FAILURE,
|
|
7156
|
+
{
|
|
7157
|
+
correlation_id: meeting.correlationId,
|
|
7158
|
+
dial_in_url: meeting.dialInUrl,
|
|
7159
|
+
dial_in_correlation_id: sinon.match.string,
|
|
7160
|
+
locus_id: meeting.locusUrl.split('/').pop(),
|
|
7161
|
+
client_url: meeting.deviceUrl,
|
|
7162
|
+
reason: error.error.message,
|
|
7163
|
+
stack: error.stack,
|
|
7164
|
+
}
|
|
7165
|
+
);
|
|
6826
7166
|
|
|
6827
7167
|
// Verify pstnCorrelationId was cleared after error
|
|
6828
7168
|
assert.equal(meeting.pstnCorrelationId, undefined);
|
|
@@ -6841,15 +7181,19 @@ describe('plugin-meetings', () => {
|
|
|
6841
7181
|
assert.equal(e, error);
|
|
6842
7182
|
|
|
6843
7183
|
// Verify behavioral metric was sent with dial_out_correlation_id
|
|
6844
|
-
assert.calledWith(
|
|
6845
|
-
|
|
6846
|
-
|
|
6847
|
-
|
|
6848
|
-
|
|
6849
|
-
|
|
6850
|
-
|
|
6851
|
-
|
|
6852
|
-
|
|
7184
|
+
assert.calledWith(
|
|
7185
|
+
Metrics.sendBehavioralMetric,
|
|
7186
|
+
BEHAVIORAL_METRICS.ADD_DIAL_OUT_FAILURE,
|
|
7187
|
+
{
|
|
7188
|
+
correlation_id: meeting.correlationId,
|
|
7189
|
+
dial_out_url: meeting.dialOutUrl,
|
|
7190
|
+
dial_out_correlation_id: sinon.match.string,
|
|
7191
|
+
locus_id: meeting.locusUrl.split('/').pop(),
|
|
7192
|
+
client_url: meeting.deviceUrl,
|
|
7193
|
+
reason: error.error.message,
|
|
7194
|
+
stack: error.stack,
|
|
7195
|
+
}
|
|
7196
|
+
);
|
|
6853
7197
|
|
|
6854
7198
|
// Verify pstnCorrelationId was cleared after error
|
|
6855
7199
|
assert.equal(meeting.pstnCorrelationId, undefined);
|
|
@@ -6894,7 +7238,7 @@ describe('plugin-meetings', () => {
|
|
|
6894
7238
|
|
|
6895
7239
|
// Verify that pstnCorrelationId is still cleared even when no phone connection is active
|
|
6896
7240
|
assert.equal(meeting.pstnCorrelationId, undefined);
|
|
6897
|
-
|
|
7241
|
+
// And verify no disconnect was attempted
|
|
6898
7242
|
assert.notCalled(MeetingUtil.disconnectPhoneAudio);
|
|
6899
7243
|
});
|
|
6900
7244
|
});
|
|
@@ -8957,7 +9301,10 @@ describe('plugin-meetings', () => {
|
|
|
8957
9301
|
|
|
8958
9302
|
// check that the right things were called by the callback
|
|
8959
9303
|
assert.calledOnceWithExactly(meeting.waitForRemoteSDPAnswer);
|
|
8960
|
-
assert.calledOnceWithExactly(
|
|
9304
|
+
assert.calledOnceWithExactly(
|
|
9305
|
+
meeting.mediaProperties.waitForMediaConnectionConnected,
|
|
9306
|
+
meeting.correlationId
|
|
9307
|
+
);
|
|
8961
9308
|
});
|
|
8962
9309
|
});
|
|
8963
9310
|
|
|
@@ -10568,7 +10915,7 @@ describe('plugin-meetings', () => {
|
|
|
10568
10915
|
describe('#setUpLocusUrlListener', () => {
|
|
10569
10916
|
it('listens to the locus url update event', (done) => {
|
|
10570
10917
|
const newLocusUrl = 'newLocusUrl/12345';
|
|
10571
|
-
const payload = {url: newLocusUrl}
|
|
10918
|
+
const payload = {url: newLocusUrl};
|
|
10572
10919
|
|
|
10573
10920
|
meeting.members = {locusUrlUpdate: sinon.stub().returns(Promise.resolve(test1))};
|
|
10574
10921
|
meeting.recordingController = {setLocusUrl: sinon.stub().returns(undefined)};
|
|
@@ -10611,7 +10958,7 @@ describe('plugin-meetings', () => {
|
|
|
10611
10958
|
});
|
|
10612
10959
|
it('update mainLocusUrl for controlsOptionManager if payload.isMainLocus as true', (done) => {
|
|
10613
10960
|
const newLocusUrl = 'newLocusUrl/12345';
|
|
10614
|
-
const payload = {url: newLocusUrl, isMainLocus: true}
|
|
10961
|
+
const payload = {url: newLocusUrl, isMainLocus: true};
|
|
10615
10962
|
|
|
10616
10963
|
meeting.controlsOptionsManager = {setLocusUrl: sinon.stub().returns(undefined)};
|
|
10617
10964
|
|
|
@@ -10843,7 +11190,9 @@ describe('plugin-meetings', () => {
|
|
|
10843
11190
|
meeting.meetingRequest.changeMeetingFloor = sinon.stub().returns(Promise.resolve());
|
|
10844
11191
|
(meeting.deviceUrl = 'deviceUrl.com'), (meeting.localShareInstanceId = '1234-5678');
|
|
10845
11192
|
webex.internal.newMetrics.callDiagnosticLatencies.saveTimestamp = sinon.stub();
|
|
10846
|
-
webex.internal.newMetrics.callDiagnosticLatencies.getShareDuration = sinon
|
|
11193
|
+
webex.internal.newMetrics.callDiagnosticLatencies.getShareDuration = sinon
|
|
11194
|
+
.stub()
|
|
11195
|
+
.returns(1000);
|
|
10847
11196
|
});
|
|
10848
11197
|
it('should call changeMeetingFloor()', async () => {
|
|
10849
11198
|
meeting.screenShareFloorState = 'GRANTED';
|
|
@@ -11494,8 +11843,10 @@ describe('plugin-meetings', () => {
|
|
|
11494
11843
|
canShareWhiteBoardSpy = sinon.spy(MeetingUtil, 'canShareWhiteBoard');
|
|
11495
11844
|
canMoveToLobbySpy = sinon.spy(MeetingUtil, 'canMoveToLobby');
|
|
11496
11845
|
showAutoEndMeetingWarningSpy = sinon.spy(MeetingUtil, 'showAutoEndMeetingWarning');
|
|
11497
|
-
isSpokenLanguageAutoDetectionEnabledSpy = sinon.spy(
|
|
11498
|
-
|
|
11846
|
+
isSpokenLanguageAutoDetectionEnabledSpy = sinon.spy(
|
|
11847
|
+
MeetingUtil,
|
|
11848
|
+
'isSpokenLanguageAutoDetectionEnabled'
|
|
11849
|
+
);
|
|
11499
11850
|
});
|
|
11500
11851
|
|
|
11501
11852
|
afterEach(() => {
|
|
@@ -12277,16 +12628,26 @@ describe('plugin-meetings', () => {
|
|
|
12277
12628
|
assert.notCalled(webex.internal.llm.disconnectLLM);
|
|
12278
12629
|
assert.calledWith(webex.internal.llm.registerAndConnect, 'a url', 'a datachannel url');
|
|
12279
12630
|
assert.equal(result, 'something');
|
|
12280
|
-
assert.
|
|
12631
|
+
assert.calledWithExactly(
|
|
12281
12632
|
meeting.webex.internal.llm.off,
|
|
12282
12633
|
'event:relay.event',
|
|
12283
12634
|
meeting.processRelayEvent
|
|
12284
12635
|
);
|
|
12285
|
-
assert.
|
|
12636
|
+
assert.calledWithExactly(
|
|
12637
|
+
meeting.webex.internal.llm.off,
|
|
12638
|
+
'event:locus.state_message',
|
|
12639
|
+
meeting.processLocusLLMEvent
|
|
12640
|
+
);
|
|
12641
|
+
assert.calledWithExactly(
|
|
12286
12642
|
meeting.webex.internal.llm.on,
|
|
12287
12643
|
'event:relay.event',
|
|
12288
12644
|
meeting.processRelayEvent
|
|
12289
12645
|
);
|
|
12646
|
+
assert.calledWithExactly(
|
|
12647
|
+
meeting.webex.internal.llm.on,
|
|
12648
|
+
'event:locus.state_message',
|
|
12649
|
+
meeting.processLocusLLMEvent
|
|
12650
|
+
);
|
|
12290
12651
|
});
|
|
12291
12652
|
|
|
12292
12653
|
it('disconnects if first if the locus url has changed', async () => {
|
|
@@ -12314,15 +12675,25 @@ describe('plugin-meetings', () => {
|
|
|
12314
12675
|
'event:relay.event',
|
|
12315
12676
|
meeting.processRelayEvent
|
|
12316
12677
|
);
|
|
12317
|
-
assert.
|
|
12318
|
-
|
|
12678
|
+
assert.calledWithExactly(
|
|
12679
|
+
meeting.webex.internal.llm.off,
|
|
12680
|
+
'event:locus.state_message',
|
|
12681
|
+
meeting.processLocusLLMEvent
|
|
12682
|
+
);
|
|
12683
|
+
assert.callCount(meeting.webex.internal.llm.off, 4);
|
|
12684
|
+
assert.calledWithExactly(
|
|
12319
12685
|
meeting.webex.internal.llm.on,
|
|
12320
12686
|
'event:relay.event',
|
|
12321
12687
|
meeting.processRelayEvent
|
|
12322
12688
|
);
|
|
12689
|
+
assert.calledWithExactly(
|
|
12690
|
+
meeting.webex.internal.llm.on,
|
|
12691
|
+
'event:locus.state_message',
|
|
12692
|
+
meeting.processLocusLLMEvent
|
|
12693
|
+
);
|
|
12323
12694
|
});
|
|
12324
12695
|
|
|
12325
|
-
it('disconnects
|
|
12696
|
+
it('disconnects it first if the data channel url has changed', async () => {
|
|
12326
12697
|
meeting.joinedWith = {state: 'JOINED'};
|
|
12327
12698
|
webex.internal.llm.isConnected.returns(true);
|
|
12328
12699
|
webex.internal.llm.getLocusUrl.returns('a url');
|
|
@@ -12347,12 +12718,21 @@ describe('plugin-meetings', () => {
|
|
|
12347
12718
|
'event:relay.event',
|
|
12348
12719
|
meeting.processRelayEvent
|
|
12349
12720
|
);
|
|
12350
|
-
assert.
|
|
12351
|
-
|
|
12721
|
+
assert.calledWithExactly(
|
|
12722
|
+
meeting.webex.internal.llm.off,
|
|
12723
|
+
'event:locus.state_message',
|
|
12724
|
+
meeting.processLocusLLMEvent
|
|
12725
|
+
);
|
|
12726
|
+
assert.calledWithExactly(
|
|
12352
12727
|
meeting.webex.internal.llm.on,
|
|
12353
12728
|
'event:relay.event',
|
|
12354
12729
|
meeting.processRelayEvent
|
|
12355
12730
|
);
|
|
12731
|
+
assert.calledWithExactly(
|
|
12732
|
+
meeting.webex.internal.llm.on,
|
|
12733
|
+
'event:locus.state_message',
|
|
12734
|
+
meeting.processLocusLLMEvent
|
|
12735
|
+
);
|
|
12356
12736
|
});
|
|
12357
12737
|
|
|
12358
12738
|
it('disconnects when the state is not JOINED', async () => {
|
|
@@ -12367,11 +12747,16 @@ describe('plugin-meetings', () => {
|
|
|
12367
12747
|
assert.calledWith(webex.internal.llm.disconnectLLM, undefined);
|
|
12368
12748
|
assert.notCalled(webex.internal.llm.registerAndConnect);
|
|
12369
12749
|
assert.equal(result, undefined);
|
|
12370
|
-
assert.
|
|
12750
|
+
assert.calledWithExactly(
|
|
12371
12751
|
meeting.webex.internal.llm.off,
|
|
12372
12752
|
'event:relay.event',
|
|
12373
12753
|
meeting.processRelayEvent
|
|
12374
12754
|
);
|
|
12755
|
+
assert.calledWithExactly(
|
|
12756
|
+
meeting.webex.internal.llm.off,
|
|
12757
|
+
'event:locus.state_message',
|
|
12758
|
+
meeting.processLocusLLMEvent
|
|
12759
|
+
);
|
|
12375
12760
|
});
|
|
12376
12761
|
|
|
12377
12762
|
it('connect ps data channel if ps started in webinar', async () => {
|
|
@@ -12397,22 +12782,22 @@ describe('plugin-meetings', () => {
|
|
|
12397
12782
|
});
|
|
12398
12783
|
|
|
12399
12784
|
it('should read the locus object, set on the meeting and return null', () => {
|
|
12785
|
+
const dataSets = {someFakeStuff: 'dataSet'};
|
|
12786
|
+
|
|
12400
12787
|
meeting.setLocus({
|
|
12401
12788
|
mediaConnections: [test1],
|
|
12402
12789
|
locusUrl: url1,
|
|
12403
12790
|
locusId: uuid1,
|
|
12404
12791
|
selfId: uuid2,
|
|
12405
12792
|
mediaId: uuid3,
|
|
12406
|
-
host: {id: uuid4},
|
|
12793
|
+
locus: {host: {id: uuid4}},
|
|
12794
|
+
dataSets,
|
|
12407
12795
|
});
|
|
12408
12796
|
assert.calledOnce(meeting.locusInfo.initialSetup);
|
|
12409
12797
|
assert.calledWith(meeting.locusInfo.initialSetup, {
|
|
12410
|
-
|
|
12411
|
-
|
|
12412
|
-
|
|
12413
|
-
selfId: uuid2,
|
|
12414
|
-
mediaId: uuid3,
|
|
12415
|
-
host: {id: uuid4},
|
|
12798
|
+
trigger: 'join-response',
|
|
12799
|
+
locus: {host: {id: uuid4}},
|
|
12800
|
+
dataSets,
|
|
12416
12801
|
});
|
|
12417
12802
|
assert.equal(meeting.mediaConnections, test1);
|
|
12418
12803
|
assert.equal(meeting.locusUrl, url1);
|
|
@@ -12502,7 +12887,9 @@ describe('plugin-meetings', () => {
|
|
|
12502
12887
|
meeting.meetingRequest.changeMeetingFloor = sinon.stub().returns(Promise.resolve());
|
|
12503
12888
|
meeting.deviceUrl = 'deviceUrl.com';
|
|
12504
12889
|
webex.internal.newMetrics.callDiagnosticLatencies.saveTimestamp = sinon.stub();
|
|
12505
|
-
webex.internal.newMetrics.callDiagnosticLatencies.getShareDuration = sinon
|
|
12890
|
+
webex.internal.newMetrics.callDiagnosticLatencies.getShareDuration = sinon
|
|
12891
|
+
.stub()
|
|
12892
|
+
.returns(1000);
|
|
12506
12893
|
webex.internal.newMetrics.submitClientEvent = sinon.stub();
|
|
12507
12894
|
});
|
|
12508
12895
|
it('should stop the whiteboard share', async () => {
|
|
@@ -12606,7 +12993,9 @@ describe('plugin-meetings', () => {
|
|
|
12606
12993
|
meeting.deviceUrl = 'my-web-url';
|
|
12607
12994
|
meeting.locusInfo.info = {isWebinar: false};
|
|
12608
12995
|
webex.internal.newMetrics.callDiagnosticLatencies.saveTimestamp = sinon.stub();
|
|
12609
|
-
webex.internal.newMetrics.callDiagnosticLatencies.getShareDuration = sinon
|
|
12996
|
+
webex.internal.newMetrics.callDiagnosticLatencies.getShareDuration = sinon
|
|
12997
|
+
.stub()
|
|
12998
|
+
.returns(1500);
|
|
12610
12999
|
webex.internal.newMetrics.submitClientEvent = sinon.stub();
|
|
12611
13000
|
});
|
|
12612
13001
|
|
|
@@ -12855,8 +13244,8 @@ describe('plugin-meetings', () => {
|
|
|
12855
13244
|
|
|
12856
13245
|
shareStatus =
|
|
12857
13246
|
meeting.webinar.selfIsAttendee || meeting.guest
|
|
12858
|
-
|
|
12859
|
-
|
|
13247
|
+
? SHARE_STATUS.REMOTE_SHARE_ACTIVE
|
|
13248
|
+
: SHARE_STATUS.WHITEBOARD_SHARE_ACTIVE;
|
|
12860
13249
|
}
|
|
12861
13250
|
|
|
12862
13251
|
if (eventTrigger.member) {
|
|
@@ -13802,32 +14191,32 @@ describe('plugin-meetings', () => {
|
|
|
13802
14191
|
});
|
|
13803
14192
|
});
|
|
13804
14193
|
|
|
13805
|
-
|
|
13806
|
-
|
|
13807
|
-
|
|
13808
|
-
|
|
13809
|
-
|
|
13810
|
-
|
|
13811
|
-
|
|
14194
|
+
describe('handleShareVideoStreamMuteStateChange', () => {
|
|
14195
|
+
it('should emit MEETING_SHARE_VIDEO_MUTE_STATE_CHANGE event with correct fields', () => {
|
|
14196
|
+
meeting.isMultistream = true;
|
|
14197
|
+
meeting.statsAnalyzer = {shareVideoEncoderImplementation: 'OpenH264'};
|
|
14198
|
+
meeting.mediaProperties.shareVideoStream = {
|
|
14199
|
+
getSettings: sinon.stub().returns({displaySurface: 'monitor', frameRate: 30}),
|
|
14200
|
+
};
|
|
13812
14201
|
|
|
13813
|
-
|
|
14202
|
+
meeting.handleShareVideoStreamMuteStateChange(true);
|
|
13814
14203
|
|
|
13815
|
-
|
|
13816
|
-
|
|
13817
|
-
|
|
13818
|
-
|
|
13819
|
-
|
|
13820
|
-
|
|
13821
|
-
|
|
13822
|
-
|
|
13823
|
-
|
|
13824
|
-
|
|
13825
|
-
|
|
13826
|
-
|
|
14204
|
+
assert.calledOnceWithExactly(
|
|
14205
|
+
Metrics.sendBehavioralMetric,
|
|
14206
|
+
BEHAVIORAL_METRICS.MEETING_SHARE_VIDEO_MUTE_STATE_CHANGE,
|
|
14207
|
+
{
|
|
14208
|
+
correlationId: meeting.correlationId,
|
|
14209
|
+
muted: true,
|
|
14210
|
+
encoderImplementation: 'OpenH264',
|
|
14211
|
+
displaySurface: 'monitor',
|
|
14212
|
+
isMultistream: true,
|
|
14213
|
+
frameRate: 30,
|
|
14214
|
+
}
|
|
14215
|
+
);
|
|
14216
|
+
});
|
|
13827
14217
|
});
|
|
13828
14218
|
});
|
|
13829
14219
|
});
|
|
13830
|
-
});
|
|
13831
14220
|
|
|
13832
14221
|
describe('#startKeepAlive', () => {
|
|
13833
14222
|
let clock;
|
|
@@ -15026,11 +15415,9 @@ describe('plugin-meetings', () => {
|
|
|
15026
15415
|
assert.exists(unsetStagePromise.then);
|
|
15027
15416
|
await unsetStagePromise;
|
|
15028
15417
|
|
|
15029
|
-
assert.calledOnceWithExactly(
|
|
15030
|
-
|
|
15031
|
-
|
|
15032
|
-
{overrideDefault: false}
|
|
15033
|
-
);
|
|
15418
|
+
assert.calledOnceWithExactly(meeting.meetingRequest.synchronizeStage, locusUrl, {
|
|
15419
|
+
overrideDefault: false,
|
|
15420
|
+
});
|
|
15034
15421
|
});
|
|
15035
15422
|
});
|
|
15036
15423
|
|
|
@@ -15055,7 +15442,7 @@ describe('plugin-meetings', () => {
|
|
|
15055
15442
|
meeting.meetingInfo.siteFullUrl,
|
|
15056
15443
|
meeting.locusId,
|
|
15057
15444
|
meetingUuid,
|
|
15058
|
-
displayName
|
|
15445
|
+
displayName
|
|
15059
15446
|
);
|
|
15060
15447
|
});
|
|
15061
15448
|
});
|
|
@@ -15102,10 +15489,7 @@ describe('plugin-meetings', () => {
|
|
|
15102
15489
|
assert.exists(cancelSipCallOutPromise.then);
|
|
15103
15490
|
await cancelSipCallOutPromise;
|
|
15104
15491
|
|
|
15105
|
-
assert.calledOnceWithExactly(
|
|
15106
|
-
meeting.meetingRequest.cancelSipCallOut,
|
|
15107
|
-
participantId
|
|
15108
|
-
);
|
|
15492
|
+
assert.calledOnceWithExactly(meeting.meetingRequest.cancelSipCallOut, participantId);
|
|
15109
15493
|
});
|
|
15110
15494
|
});
|
|
15111
15495
|
});
|