@webex/plugin-meetings 3.8.1-web-workers-keepalive.1 → 3.9.0-multipleLLM.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/breakouts/breakout.js +1 -1
- package/dist/breakouts/index.js +1 -1
- package/dist/constants.js +26 -2
- package/dist/constants.js.map +1 -1
- package/dist/interpretation/index.js +1 -1
- package/dist/interpretation/siLanguage.js +1 -1
- package/dist/locus-info/index.js +77 -95
- package/dist/locus-info/index.js.map +1 -1
- package/dist/locus-info/parser.js +4 -1
- package/dist/locus-info/parser.js.map +1 -1
- package/dist/media/properties.js +53 -5
- package/dist/media/properties.js.map +1 -1
- package/dist/meeting/brbState.js +14 -12
- package/dist/meeting/brbState.js.map +1 -1
- package/dist/meeting/in-meeting-actions.js +8 -0
- package/dist/meeting/in-meeting-actions.js.map +1 -1
- package/dist/meeting/index.js +443 -225
- package/dist/meeting/index.js.map +1 -1
- package/dist/meeting/muteState.js +2 -5
- package/dist/meeting/muteState.js.map +1 -1
- package/dist/meeting/request.js +44 -0
- package/dist/meeting/request.js.map +1 -1
- package/dist/meeting/request.type.js.map +1 -1
- package/dist/meeting/type.js +7 -0
- package/dist/meeting/type.js.map +1 -0
- package/dist/meeting/util.js +98 -13
- package/dist/meeting/util.js.map +1 -1
- package/dist/meeting-info/meeting-info-v2.js +29 -21
- package/dist/meeting-info/meeting-info-v2.js.map +1 -1
- package/dist/meetings/index.js +18 -10
- package/dist/meetings/index.js.map +1 -1
- package/dist/member/index.js.map +1 -1
- package/dist/member/types.js.map +1 -1
- package/dist/members/collection.js +13 -0
- package/dist/members/collection.js.map +1 -1
- package/dist/members/index.js +53 -29
- package/dist/members/index.js.map +1 -1
- package/dist/members/request.js +3 -3
- package/dist/members/request.js.map +1 -1
- package/dist/members/util.js +25 -8
- package/dist/members/util.js.map +1 -1
- package/dist/metrics/constants.js +2 -1
- package/dist/metrics/constants.js.map +1 -1
- package/dist/multistream/mediaRequestManager.js +1 -1
- package/dist/multistream/mediaRequestManager.js.map +1 -1
- package/dist/multistream/remoteMedia.js +34 -5
- package/dist/multistream/remoteMedia.js.map +1 -1
- package/dist/multistream/remoteMediaGroup.js +42 -2
- package/dist/multistream/remoteMediaGroup.js.map +1 -1
- package/dist/multistream/sendSlotManager.js +32 -2
- package/dist/multistream/sendSlotManager.js.map +1 -1
- package/dist/reachability/index.js +3 -3
- package/dist/reachability/index.js.map +1 -1
- package/dist/types/constants.d.ts +24 -0
- package/dist/types/locus-info/index.d.ts +54 -10
- package/dist/types/media/properties.d.ts +21 -0
- package/dist/types/meeting/brbState.d.ts +0 -1
- package/dist/types/meeting/in-meeting-actions.d.ts +8 -0
- package/dist/types/meeting/index.d.ts +51 -20
- package/dist/types/meeting/request.d.ts +18 -1
- package/dist/types/meeting/request.type.d.ts +74 -0
- package/dist/types/meeting/type.d.ts +9 -0
- package/dist/types/meeting/util.d.ts +13 -3
- package/dist/types/meeting-info/meeting-info-v2.d.ts +6 -3
- package/dist/types/meetings/index.d.ts +3 -1
- package/dist/types/member/types.d.ts +1 -0
- package/dist/types/members/collection.d.ts +6 -0
- package/dist/types/members/index.d.ts +22 -9
- package/dist/types/members/request.d.ts +1 -1
- package/dist/types/members/util.d.ts +13 -6
- package/dist/types/metrics/constants.d.ts +1 -0
- package/dist/types/multistream/remoteMedia.d.ts +20 -1
- package/dist/types/multistream/remoteMediaGroup.d.ts +11 -0
- package/dist/types/multistream/sendSlotManager.d.ts +16 -0
- package/dist/webinar/index.js +1 -1
- package/package.json +23 -24
- package/src/constants.ts +25 -2
- package/src/locus-info/index.ts +133 -96
- package/src/locus-info/parser.ts +5 -1
- package/src/media/properties.ts +43 -0
- package/src/meeting/brbState.ts +9 -7
- package/src/meeting/in-meeting-actions.ts +17 -0
- package/src/meeting/index.ts +273 -42
- package/src/meeting/muteState.ts +2 -6
- package/src/meeting/request.ts +39 -0
- package/src/meeting/request.type.ts +64 -0
- package/src/meeting/type.ts +9 -0
- package/src/meeting/util.ts +114 -22
- package/src/meeting-info/meeting-info-v2.ts +24 -5
- package/src/meetings/index.ts +12 -5
- package/src/member/index.ts +1 -0
- package/src/member/types.ts +1 -0
- package/src/members/collection.ts +11 -0
- package/src/members/index.ts +51 -15
- package/src/members/request.ts +2 -2
- package/src/members/util.ts +34 -6
- package/src/metrics/constants.ts +1 -0
- package/src/multistream/mediaRequestManager.ts +7 -7
- package/src/multistream/remoteMedia.ts +34 -4
- package/src/multistream/remoteMediaGroup.ts +37 -2
- package/src/multistream/sendSlotManager.ts +34 -2
- package/src/reachability/index.ts +3 -3
- package/test/unit/spec/locus-info/index.js +229 -98
- package/test/unit/spec/locus-info/parser.js +3 -2
- package/test/unit/spec/media/properties.ts +137 -0
- package/test/unit/spec/meeting/brbState.ts +9 -9
- package/test/unit/spec/meeting/in-meeting-actions.ts +8 -0
- package/test/unit/spec/meeting/index.js +1022 -93
- package/test/unit/spec/meeting/muteState.js +32 -6
- package/test/unit/spec/meeting/request.js +92 -0
- package/test/unit/spec/meeting/utils.js +167 -17
- package/test/unit/spec/meeting-info/meetinginfov2.js +8 -3
- package/test/unit/spec/meetings/index.js +12 -1
- package/test/unit/spec/members/collection.js +120 -0
- package/test/unit/spec/members/index.js +140 -12
- package/test/unit/spec/members/request.js +57 -2
- package/test/unit/spec/members/utils.js +139 -17
- package/test/unit/spec/multistream/mediaRequestManager.ts +19 -6
- package/test/unit/spec/multistream/remoteMedia.ts +66 -2
- package/test/unit/spec/multistream/sendSlotManager.ts +59 -0
- package/test/unit/spec/reachability/index.ts +158 -1
@@ -1,7 +1,17 @@
|
|
1
1
|
import { SendSlot, MediaType, LocalStream, MultistreamRoapMediaConnection, NamedMediaGroup, StreamState } from '@webex/internal-media-core';
|
2
|
+
/**
|
3
|
+
* This class is used to manage the sendSlots for the given media types.
|
4
|
+
*/
|
2
5
|
export default class SendSlotManager {
|
3
6
|
private readonly slots;
|
4
7
|
private readonly LoggerProxy;
|
8
|
+
private readonly sourceStateOverrides;
|
9
|
+
/**
|
10
|
+
* Constructor for SendSlotManager
|
11
|
+
*
|
12
|
+
* @param {any} LoggerProxy is used to log the messages
|
13
|
+
* @constructor
|
14
|
+
*/
|
5
15
|
constructor(LoggerProxy: any);
|
6
16
|
/**
|
7
17
|
* This method is used to create a sendSlot for the given mediaType and returns the created sendSlot
|
@@ -32,6 +42,12 @@ export default class SendSlotManager {
|
|
32
42
|
* @returns {void}
|
33
43
|
*/
|
34
44
|
setSourceStateOverride(mediaType: MediaType, state: StreamState | null): void;
|
45
|
+
/**
|
46
|
+
* Gets the source state override for the given media type.
|
47
|
+
* @param {MediaType} mediaType - The type of media to get the source state override for.
|
48
|
+
* @returns {StreamState | null} - The current source state override or null if not set.
|
49
|
+
*/
|
50
|
+
private getSourceStateOverride;
|
35
51
|
/**
|
36
52
|
* This method publishes the given stream to the sendSlot for the given mediaType
|
37
53
|
* @param {MediaType} mediaType MediaType of the sendSlot to which a stream needs to be published (AUDIO_MAIN/VIDEO_MAIN/AUDIO_SLIDES/VIDEO_SLIDES)
|
package/dist/webinar/index.js
CHANGED
@@ -458,7 +458,7 @@ var Webinar = _webexCore.WebexPlugin.extend({
|
|
458
458
|
}, _callee7);
|
459
459
|
}))();
|
460
460
|
},
|
461
|
-
version: "3.
|
461
|
+
version: "3.9.0-multipleLLM.1"
|
462
462
|
});
|
463
463
|
var _default = exports.default = Webinar;
|
464
464
|
//# sourceMappingURL=index.js.map
|
package/package.json
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
{
|
2
2
|
"name": "@webex/plugin-meetings",
|
3
3
|
"description": "",
|
4
|
-
"license": "Cisco
|
4
|
+
"license": "Cisco's General Terms (https://www.cisco.com/site/us/en/about/legal/contract-experience/index.html)",
|
5
5
|
"contributors": [
|
6
6
|
"Adam Weeks <adweeks@cisco.com> (https://adamweeks.com/)",
|
7
7
|
"Arun Ganeshan <arungane@cisco.com>",
|
@@ -43,13 +43,12 @@
|
|
43
43
|
"@webex/eslint-config-legacy": "0.0.0",
|
44
44
|
"@webex/jest-config-legacy": "0.0.0",
|
45
45
|
"@webex/legacy-tools": "0.0.0",
|
46
|
-
"@webex/plugin-
|
47
|
-
"@webex/
|
48
|
-
"@webex/test-helper-
|
49
|
-
"@webex/test-helper-
|
50
|
-
"@webex/test-helper-
|
51
|
-
"@webex/test-helper-
|
52
|
-
"@webex/test-helper-test-users": "3.8.1-web-workers-keepalive.1",
|
46
|
+
"@webex/plugin-rooms": "3.9.0-multipleLLM.0",
|
47
|
+
"@webex/test-helper-chai": "3.9.0-multipleLLM.0",
|
48
|
+
"@webex/test-helper-mocha": "3.9.0-multipleLLM.0",
|
49
|
+
"@webex/test-helper-mock-webex": "3.9.0-multipleLLM.0",
|
50
|
+
"@webex/test-helper-retry": "3.9.0-multipleLLM.0",
|
51
|
+
"@webex/test-helper-test-users": "3.9.0-multipleLLM.0",
|
53
52
|
"chai": "^4.3.4",
|
54
53
|
"chai-as-promised": "^7.1.1",
|
55
54
|
"eslint": "^8.24.0",
|
@@ -61,23 +60,23 @@
|
|
61
60
|
"typescript": "^4.7.4"
|
62
61
|
},
|
63
62
|
"dependencies": {
|
64
|
-
"@webex/common": "3.
|
65
|
-
"@webex/event-dictionary-ts": "^1.0.
|
66
|
-
"@webex/internal-media-core": "2.
|
67
|
-
"@webex/internal-plugin-conversation": "3.
|
68
|
-
"@webex/internal-plugin-device": "3.
|
69
|
-
"@webex/internal-plugin-llm": "3.
|
70
|
-
"@webex/internal-plugin-mercury": "3.
|
71
|
-
"@webex/internal-plugin-metrics": "3.
|
72
|
-
"@webex/internal-plugin-support": "3.
|
73
|
-
"@webex/internal-plugin-user": "3.
|
74
|
-
"@webex/internal-plugin-voicea": "3.
|
75
|
-
"@webex/media-helpers": "3.
|
76
|
-
"@webex/plugin-people": "3.
|
77
|
-
"@webex/plugin-rooms": "3.
|
63
|
+
"@webex/common": "3.9.0-multipleLLM.0",
|
64
|
+
"@webex/event-dictionary-ts": "^1.0.1930",
|
65
|
+
"@webex/internal-media-core": "2.19.0",
|
66
|
+
"@webex/internal-plugin-conversation": "3.9.0-multipleLLM.0",
|
67
|
+
"@webex/internal-plugin-device": "3.9.0-multipleLLM.0",
|
68
|
+
"@webex/internal-plugin-llm": "3.9.0-multipleLLM.0",
|
69
|
+
"@webex/internal-plugin-mercury": "3.9.0-multipleLLM.0",
|
70
|
+
"@webex/internal-plugin-metrics": "3.9.0-multipleLLM.0",
|
71
|
+
"@webex/internal-plugin-support": "3.9.0-multipleLLM.0",
|
72
|
+
"@webex/internal-plugin-user": "3.9.0-multipleLLM.0",
|
73
|
+
"@webex/internal-plugin-voicea": "3.9.0-multipleLLM.1",
|
74
|
+
"@webex/media-helpers": "3.9.0-multipleLLM.1",
|
75
|
+
"@webex/plugin-people": "3.9.0-multipleLLM.0",
|
76
|
+
"@webex/plugin-rooms": "3.9.0-multipleLLM.0",
|
78
77
|
"@webex/ts-sdp": "^1.8.1",
|
79
78
|
"@webex/web-capabilities": "^1.6.0",
|
80
|
-
"@webex/webex-core": "3.
|
79
|
+
"@webex/webex-core": "3.9.0-multipleLLM.0",
|
81
80
|
"ampersand-collection": "^2.0.2",
|
82
81
|
"bowser": "^2.11.0",
|
83
82
|
"btoa": "^1.2.1",
|
@@ -93,5 +92,5 @@
|
|
93
92
|
"//": [
|
94
93
|
"TODO: upgrade jwt-decode when moving to node 18"
|
95
94
|
],
|
96
|
-
"version": "3.
|
95
|
+
"version": "3.9.0-multipleLLM.1"
|
97
96
|
}
|
package/src/constants.ts
CHANGED
@@ -217,6 +217,7 @@ export const DIALER_REGEX = {
|
|
217
217
|
PHONE_NUMBER:
|
218
218
|
/^(?:(?:\+?1\s*(?:[.-]\s*)?)?(?:\(\s*([2-9]1[02-9]|[2-9][02-8]1|[2-9][02-8][02-9])\s*\)|([2-9]1[02-9]|[2-9][02-8]1|[2-9][02-8][02-9]))\s*(?:[.-]\s*)?)?([2-9]1[02-9]|[2-9][02-9]1|[2-9][02-9]{2})\s*(?:[.-]\s*)?([0-9]{4})(?:\s*(?:#|x\.?|ext\.?|extension)\s*(\d+))?$/,
|
219
219
|
E164_FORMAT: /^\+[1-9]\d{1,14}$/,
|
220
|
+
INTERNAL_NUMBER: /^\d{1,14}$/,
|
220
221
|
};
|
221
222
|
|
222
223
|
// eslint-disable-next-line max-len
|
@@ -262,7 +263,6 @@ export const RECORDING_STATE = {
|
|
262
263
|
PAUSED: 'paused',
|
263
264
|
RESUMED: 'resumed',
|
264
265
|
};
|
265
|
-
|
266
266
|
export const SHARE_STATUS = {
|
267
267
|
NO_SHARE: 'no_share',
|
268
268
|
REMOTE_SHARE_ACTIVE: 'remote_share_active',
|
@@ -347,6 +347,7 @@ export const EVENT_TRIGGERS = {
|
|
347
347
|
MEETING_SELF_LEFT: 'meeting:self:left',
|
348
348
|
NETWORK_QUALITY: 'network:quality',
|
349
349
|
MEDIA_NEGOTIATED: 'media:negotiated',
|
350
|
+
MEDIA_INBOUND_AUDIO_ISSUE_DETECTED: 'media:inboundAudio:issueDetected',
|
350
351
|
// the following events apply only to multistream media connections
|
351
352
|
ACTIVE_SPEAKER_CHANGED: 'media:activeSpeakerChanged',
|
352
353
|
REMOTE_VIDEO_SOURCE_COUNT_CHANGED: 'media:remoteVideoSourceCountChanged',
|
@@ -948,6 +949,9 @@ export const DISPLAY_HINTS = {
|
|
948
949
|
PREMISE_RECORDING_CONTROL_PAUSE: 'PREMISE_RECORDING_CONTROL_PAUSE',
|
949
950
|
PREMISE_RECORDING_CONTROL_STOP: 'PREMISE_RECORDING_CONTROL_STOP',
|
950
951
|
PREMISE_RECORDING_CONTROL_RESUME: 'PREMISE_RECORDING_CONTROL_RESUME',
|
952
|
+
LOCAL_RECORDING_STATUS_STARTED: 'LOCAL_RECORDING_STATUS_STARTED',
|
953
|
+
LOCAL_RECORDING_STATUS_STOPPED: 'LOCAL_RECORDING_STATUS_STOPPED',
|
954
|
+
LOCAL_RECORDING_STATUS_PAUSED: 'LOCAL_RECORDING_STATUS_PAUSED',
|
951
955
|
LOCK_CONTROL_UNLOCK: 'LOCK_CONTROL_UNLOCK',
|
952
956
|
LOCK_CONTROL_LOCK: 'LOCK_CONTROL_LOCK',
|
953
957
|
LOCK_STATUS_LOCKED: 'LOCK_STATUS_LOCKED',
|
@@ -963,6 +967,7 @@ export const DISPLAY_HINTS = {
|
|
963
967
|
MANUAL_CAPTION_STOP: 'MANUAL_CAPTION_STOP',
|
964
968
|
MANUAL_CAPTION_STATUS_ACTIVE: 'MANUAL_CAPTION_STATUS_ACTIVE',
|
965
969
|
DISPLAY_REAL_TIME_TRANSLATION: 'DISPLAY_REAL_TIME_TRANSLATION',
|
970
|
+
SPOKEN_LANGUAGE_AUTO_DETECTION_ENABLED: 'SPOKEN_LANGUAGE_AUTO_DETECTION_ENABLED',
|
966
971
|
ENABLE_CAPTION_PANEL: 'ENABLE_CAPTION_PANEL',
|
967
972
|
DISPLAY_NON_ENGLISH_ASR: 'DISPLAY_NON_ENGLISH_ASR',
|
968
973
|
TRANSCRIPTION_CONTROL_START: 'TRANSCRIPTION_CONTROL_START',
|
@@ -987,7 +992,6 @@ export const DISPLAY_HINTS = {
|
|
987
992
|
CAN_RENAME_SELF_AND_OBSERVED: 'CAN_RENAME_SELF_AND_OBSERVED',
|
988
993
|
CAN_RENAME_OTHERS: 'CAN_RENAME_OTHERS',
|
989
994
|
MOVE_TO_LOBBY: 'MOVE_TO_LOBBY',
|
990
|
-
|
991
995
|
// breakout session
|
992
996
|
BREAKOUT_MANAGEMENT: 'BREAKOUT_MANAGEMENT',
|
993
997
|
BROADCAST_MESSAGE_TO_BREAKOUT: 'BROADCAST_MESSAGE_TO_BREAKOUT',
|
@@ -1188,6 +1192,7 @@ export const QUALITY_LEVELS = {
|
|
1188
1192
|
HIGH: 'HIGH',
|
1189
1193
|
'360p': '360p',
|
1190
1194
|
'480p': '480p',
|
1195
|
+
'540p': '540p',
|
1191
1196
|
'720p': '720p',
|
1192
1197
|
'1080p': '1080p',
|
1193
1198
|
};
|
@@ -1217,6 +1222,18 @@ export const AVAILABLE_RESOLUTIONS = {
|
|
1217
1222
|
},
|
1218
1223
|
},
|
1219
1224
|
},
|
1225
|
+
'540p': {
|
1226
|
+
video: {
|
1227
|
+
width: {
|
1228
|
+
max: 960,
|
1229
|
+
ideal: 960,
|
1230
|
+
},
|
1231
|
+
height: {
|
1232
|
+
max: 540,
|
1233
|
+
ideal: 540,
|
1234
|
+
},
|
1235
|
+
},
|
1236
|
+
},
|
1220
1237
|
'720p': {
|
1221
1238
|
video: {
|
1222
1239
|
width: {
|
@@ -1357,3 +1374,9 @@ export const INITIAL_REGISTRATION_STATUS = {
|
|
1357
1374
|
mercuryConnect: false,
|
1358
1375
|
checkH264Support: false,
|
1359
1376
|
};
|
1377
|
+
|
1378
|
+
export const STAGE_MANAGER_TYPE = {
|
1379
|
+
LOGO: 0b001,
|
1380
|
+
BACKGROUND: 0b010,
|
1381
|
+
NAME_LABEL: 0b100,
|
1382
|
+
};
|
package/src/locus-info/index.ts
CHANGED
@@ -31,6 +31,51 @@ import LocusDeltaParser from './parser';
|
|
31
31
|
import Metrics from '../metrics';
|
32
32
|
import BEHAVIORAL_METRICS from '../metrics/constants';
|
33
33
|
|
34
|
+
export type LocusDTO = {
|
35
|
+
controls?: any;
|
36
|
+
fullState?: {
|
37
|
+
active: boolean;
|
38
|
+
count: number;
|
39
|
+
lastActive: string;
|
40
|
+
locked: boolean;
|
41
|
+
sessionId: string;
|
42
|
+
seessionIds: string[];
|
43
|
+
startTime: number;
|
44
|
+
state: string;
|
45
|
+
type: string;
|
46
|
+
};
|
47
|
+
host?: {
|
48
|
+
id: string;
|
49
|
+
incomingCallProtocols: any[];
|
50
|
+
isExternal: boolean;
|
51
|
+
name: string;
|
52
|
+
orgId: string;
|
53
|
+
};
|
54
|
+
info?: any;
|
55
|
+
links?: any;
|
56
|
+
mediaShares?: any[];
|
57
|
+
meetings?: any[];
|
58
|
+
participants: any[];
|
59
|
+
replaces?: any[];
|
60
|
+
self?: any;
|
61
|
+
sequence?: {
|
62
|
+
dirtyParticipants: number;
|
63
|
+
entries: number[];
|
64
|
+
rangeEnd: number;
|
65
|
+
rangeStart: number;
|
66
|
+
sequenceHash: number;
|
67
|
+
sessionToken: string;
|
68
|
+
since: string;
|
69
|
+
totalParticipants: number;
|
70
|
+
};
|
71
|
+
syncUrl?: string;
|
72
|
+
url?: string;
|
73
|
+
};
|
74
|
+
|
75
|
+
export type LocusApiResponseBody = {
|
76
|
+
locus: LocusDTO; // this LocusDTO here might not be the full one (for example it won't have all the participants, but it should have self)
|
77
|
+
};
|
78
|
+
|
34
79
|
/**
|
35
80
|
* @description LocusInfo extends ChildEmitter to convert locusInfo info a private emitter to parent object
|
36
81
|
* @export
|
@@ -48,7 +93,6 @@ export default class LocusInfo extends EventsScope {
|
|
48
93
|
aclUrl: any;
|
49
94
|
baseSequence: any;
|
50
95
|
created: any;
|
51
|
-
deltaParticipants: any;
|
52
96
|
identities: any;
|
53
97
|
membership: any;
|
54
98
|
participants: any;
|
@@ -94,18 +138,26 @@ export default class LocusInfo extends EventsScope {
|
|
94
138
|
* Does a Locus sync. It tries to get the latest delta DTO or if it can't, it falls back to getting the full Locus DTO.
|
95
139
|
*
|
96
140
|
* @param {Meeting} meeting
|
141
|
+
* @param {boolean} isLocusUrlChanged
|
142
|
+
* @param {Locus} locus
|
97
143
|
* @returns {undefined}
|
98
144
|
*/
|
99
|
-
private doLocusSync(meeting: any) {
|
100
|
-
let isDelta;
|
145
|
+
private doLocusSync(meeting: any, isLocusUrlChanged: boolean, locus: any) {
|
101
146
|
let url;
|
102
|
-
|
103
|
-
|
147
|
+
let isDelta = false;
|
148
|
+
let meetingDestroyed = false;
|
149
|
+
|
150
|
+
if (isLocusUrlChanged) {
|
151
|
+
// for the locus url changed case from breakout to main session, we should always do a full sync, in this case, the url from locus is always on main session,
|
152
|
+
// so use the main session locus url to get the full locus(full participants list in the response).
|
153
|
+
// for the locus url changed case from main session to breakout, we don't need to care about it here,
|
154
|
+
// because it is a USE_INCOMING case, it will not be executed here.
|
155
|
+
url = locus.url;
|
156
|
+
} else if (this.locusParser.workingCopy?.syncUrl) {
|
104
157
|
url = this.locusParser.workingCopy.syncUrl;
|
105
158
|
isDelta = true;
|
106
159
|
} else {
|
107
160
|
url = meeting.locusUrl;
|
108
|
-
isDelta = false;
|
109
161
|
}
|
110
162
|
|
111
163
|
LoggerProxy.logger.info(
|
@@ -134,32 +186,56 @@ export default class LocusInfo extends EventsScope {
|
|
134
186
|
|
135
187
|
isDelta = false;
|
136
188
|
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
189
|
+
// Locus sometimes returns 403, for example if meeting has ended, no point trying the fallback to full sync in that case
|
190
|
+
if (e.statusCode !== 403) {
|
191
|
+
return meeting.meetingRequest.getLocusDTO({url: meeting.locusUrl}).catch((err) => {
|
192
|
+
LoggerProxy.logger.info(
|
193
|
+
'Locus-info:index#doLocusSync --> fallback full sync failed, destroying the meeting'
|
194
|
+
);
|
195
|
+
this.webex.meetings.destroy(meeting, MEETING_REMOVED_REASON.LOCUS_DTO_SYNC_FAILED);
|
196
|
+
meetingDestroyed = true;
|
197
|
+
throw err;
|
198
|
+
});
|
199
|
+
}
|
200
|
+
LoggerProxy.logger.info(
|
201
|
+
'Locus-info:index#doLocusSync --> got 403 from Locus, skipping fallback to full sync, destroying the meeting'
|
202
|
+
);
|
203
|
+
} else {
|
204
|
+
LoggerProxy.logger.info(
|
205
|
+
'Locus-info:index#doLocusSync --> fallback full sync failed, destroying the meeting'
|
206
|
+
);
|
144
207
|
}
|
145
|
-
LoggerProxy.logger.info(
|
146
|
-
'Locus-info:index#doLocusSync --> fallback full sync failed, destroying the meeting'
|
147
|
-
);
|
148
208
|
this.webex.meetings.destroy(meeting, MEETING_REMOVED_REASON.LOCUS_DTO_SYNC_FAILED);
|
209
|
+
meetingDestroyed = true;
|
149
210
|
throw e;
|
150
211
|
})
|
151
212
|
.then((res) => {
|
152
|
-
if (
|
153
|
-
if (
|
154
|
-
meeting.locusInfo.handleLocusDelta(res.body, meeting);
|
155
|
-
} else {
|
213
|
+
if (isEmpty(res.body)) {
|
214
|
+
if (isDelta) {
|
156
215
|
LoggerProxy.logger.info(
|
157
216
|
'Locus-info:index#doLocusSync --> received empty body from syncUrl, so we already have latest Locus DTO'
|
158
217
|
);
|
218
|
+
} else {
|
219
|
+
LoggerProxy.logger.info(
|
220
|
+
'Locus-info:index#doLocusSync --> received empty body from full DTO sync request'
|
221
|
+
);
|
159
222
|
}
|
160
|
-
|
161
|
-
|
223
|
+
|
224
|
+
return;
|
225
|
+
}
|
226
|
+
|
227
|
+
if (isDelta) {
|
228
|
+
if (res.body.baseSequence) {
|
229
|
+
meeting.locusInfo.handleLocusDelta(res.body, meeting);
|
230
|
+
|
231
|
+
return;
|
232
|
+
}
|
233
|
+
// in some cases Locus might return us full DTO even when we asked for a delta
|
234
|
+
LoggerProxy.logger.info(
|
235
|
+
'Locus-info:index#doLocusSync --> got full DTO when we asked for delta'
|
236
|
+
);
|
162
237
|
}
|
238
|
+
meeting.locusInfo.onFullLocus(res.body);
|
163
239
|
})
|
164
240
|
.catch((e) => {
|
165
241
|
LoggerProxy.logger.info(
|
@@ -176,9 +252,11 @@ export default class LocusInfo extends EventsScope {
|
|
176
252
|
});
|
177
253
|
})
|
178
254
|
.finally(() => {
|
179
|
-
|
180
|
-
|
181
|
-
|
255
|
+
if (!meetingDestroyed) {
|
256
|
+
// Notify parser to resume processing delta events.
|
257
|
+
// Any deltas in the queue that have now been superseded by this sync will simply be ignored
|
258
|
+
this.locusParser.resume();
|
259
|
+
}
|
182
260
|
});
|
183
261
|
}
|
184
262
|
|
@@ -191,6 +269,7 @@ export default class LocusInfo extends EventsScope {
|
|
191
269
|
*/
|
192
270
|
applyLocusDeltaData(action: string, locus: any, meeting: any) {
|
193
271
|
const {DESYNC, USE_CURRENT, USE_INCOMING, WAIT, LOCUS_URL_CHANGED} = LocusDeltaParser.loci;
|
272
|
+
const isLocusUrlChanged = action === LOCUS_URL_CHANGED;
|
194
273
|
|
195
274
|
switch (action) {
|
196
275
|
case USE_INCOMING:
|
@@ -202,7 +281,7 @@ export default class LocusInfo extends EventsScope {
|
|
202
281
|
break;
|
203
282
|
case DESYNC:
|
204
283
|
case LOCUS_URL_CHANGED:
|
205
|
-
this.doLocusSync(meeting);
|
284
|
+
this.doLocusSync(meeting, isLocusUrlChanged, locus);
|
206
285
|
break;
|
207
286
|
default:
|
208
287
|
LoggerProxy.logger.info(
|
@@ -257,21 +336,10 @@ export default class LocusInfo extends EventsScope {
|
|
257
336
|
* @property {Object} person - Contains person data.
|
258
337
|
*/
|
259
338
|
|
260
|
-
/**
|
261
|
-
* Stored participant changes between the last event and the current event.
|
262
|
-
* All previously stored events are overwritten between events.
|
263
|
-
*
|
264
|
-
* @instance
|
265
|
-
* @type {Array<DeltaParticipant>}
|
266
|
-
* @private
|
267
|
-
* @member LocusInfo
|
268
|
-
*/
|
269
|
-
this.deltaParticipants = [];
|
270
|
-
|
271
339
|
this.updateLocusCache(locus);
|
272
340
|
// above section only updates the locusInfo object
|
273
341
|
// The below section makes sure it updates the locusInfo as well as updates the meeting object
|
274
|
-
this.updateParticipants(locus.participants);
|
342
|
+
this.updateParticipants(locus.participants, []);
|
275
343
|
// For 1:1 space meeting the conversation Url does not exist in locus.conversation
|
276
344
|
this.updateConversationUrl(locus.conversationUrl, locus.info);
|
277
345
|
this.updateControls(locus.controls, locus.self);
|
@@ -300,6 +368,16 @@ export default class LocusInfo extends EventsScope {
|
|
300
368
|
this.emitChange = true;
|
301
369
|
}
|
302
370
|
|
371
|
+
/**
|
372
|
+
* Handles HTTP response from Locus API call.
|
373
|
+
* @param {Meeting} meeting meeting object
|
374
|
+
* @param {LocusApiResponseBody} responseBody body of the http response from Locus API call
|
375
|
+
* @returns {void}
|
376
|
+
*/
|
377
|
+
handleLocusAPIResponse(meeting, responseBody: LocusApiResponseBody): void {
|
378
|
+
this.handleLocusDelta(responseBody.locus, meeting);
|
379
|
+
}
|
380
|
+
|
303
381
|
/**
|
304
382
|
* @param {Meeting} meeting
|
305
383
|
* @param {Object} data
|
@@ -312,6 +390,8 @@ export default class LocusInfo extends EventsScope {
|
|
312
390
|
const locus = this.getTheLocusToUpdate(data.locus);
|
313
391
|
LoggerProxy.logger.info(`Locus-info:index#parse --> received locus data: ${eventType}`);
|
314
392
|
|
393
|
+
locus.jsSdkMeta = {removedParticipantIds: []};
|
394
|
+
|
315
395
|
switch (eventType) {
|
316
396
|
case LOCUSEVENT.PARTICIPANT_JOIN:
|
317
397
|
case LOCUSEVENT.PARTICIPANT_LEFT:
|
@@ -373,12 +453,15 @@ export default class LocusInfo extends EventsScope {
|
|
373
453
|
return;
|
374
454
|
}
|
375
455
|
|
376
|
-
this.updateParticipantDeltas(locus.participants);
|
377
456
|
this.scheduledMeeting = locus.meeting || null;
|
378
457
|
this.participants = locus.participants;
|
379
458
|
const isReplaceMembers = ControlsUtils.isNeedReplaceMembers(this.controls, locus.controls);
|
380
459
|
this.updateLocusInfo(locus);
|
381
|
-
this.updateParticipants(
|
460
|
+
this.updateParticipants(
|
461
|
+
locus.participants,
|
462
|
+
locus.jsSdkMeta?.removedParticipantIds,
|
463
|
+
isReplaceMembers
|
464
|
+
);
|
382
465
|
this.isMeetingActive();
|
383
466
|
this.handleOneOnOneEvent(eventType);
|
384
467
|
this.updateEmbeddedApps(locus.embeddedApps);
|
@@ -440,7 +523,11 @@ export default class LocusInfo extends EventsScope {
|
|
440
523
|
const isReplaceMembers = ControlsUtils.isNeedReplaceMembers(this.controls, locus.controls);
|
441
524
|
this.mergeParticipants(this.participants, locus.participants);
|
442
525
|
this.updateLocusInfo(locus);
|
443
|
-
this.updateParticipants(
|
526
|
+
this.updateParticipants(
|
527
|
+
locus.participants,
|
528
|
+
locus.jsSdkMeta?.removedParticipantIds,
|
529
|
+
isReplaceMembers
|
530
|
+
);
|
444
531
|
this.isMeetingActive();
|
445
532
|
}
|
446
533
|
|
@@ -462,12 +549,12 @@ export default class LocusInfo extends EventsScope {
|
|
462
549
|
this.updateCreated(locus.created);
|
463
550
|
this.updateFullState(locus.fullState);
|
464
551
|
this.updateHostInfo(locus.host);
|
552
|
+
this.updateLocusUrl(locus.url);
|
465
553
|
this.updateMeetingInfo(locus.info, locus.self);
|
466
554
|
this.updateMediaShares(locus.mediaShares);
|
467
555
|
this.updateParticipantsUrl(locus.participantsUrl);
|
468
556
|
this.updateReplace(locus.replace);
|
469
557
|
this.updateSelf(locus.self);
|
470
|
-
this.updateLocusUrl(locus.url);
|
471
558
|
this.updateAclUrl(locus.aclUrl);
|
472
559
|
this.updateBasequence(locus.baseSequence);
|
473
560
|
this.updateSequence(locus.sequence);
|
@@ -728,63 +815,15 @@ export default class LocusInfo extends EventsScope {
|
|
728
815
|
}
|
729
816
|
}
|
730
817
|
|
731
|
-
/**
|
732
|
-
* Update the deltaParticipants property of this object based on a list of
|
733
|
-
* provided participants.
|
734
|
-
*
|
735
|
-
* @param {Array} [participants] - The participants to update against.
|
736
|
-
* @returns {void}
|
737
|
-
*/
|
738
|
-
updateParticipantDeltas(participants: Array<any> = []) {
|
739
|
-
// Used to find a participant within a participants collection.
|
740
|
-
const findParticipant = (participant, collection) =>
|
741
|
-
collection.find((item) => item.person.id === participant.person.id);
|
742
|
-
|
743
|
-
// Generates an object that indicates which state properties have changed.
|
744
|
-
const generateDelta = (prevState: any = {}, newState: any = {}) => {
|
745
|
-
// Setup deltas.
|
746
|
-
const deltas = {
|
747
|
-
audioStatus: prevState.audioStatus !== newState.audioStatus,
|
748
|
-
videoSlidesStatus: prevState.videoSlidesStatus !== newState.videoSlidesStatus,
|
749
|
-
videoStatus: prevState.videoStatus !== newState.videoStatus,
|
750
|
-
};
|
751
|
-
|
752
|
-
// Clean the object
|
753
|
-
Object.keys(deltas).forEach((key) => {
|
754
|
-
if (deltas[key] !== true) {
|
755
|
-
delete deltas[key];
|
756
|
-
}
|
757
|
-
});
|
758
|
-
|
759
|
-
return deltas;
|
760
|
-
};
|
761
|
-
|
762
|
-
this.deltaParticipants = participants.reduce((collection, participant) => {
|
763
|
-
const existingParticipant = findParticipant(participant, this.participants || []) || {};
|
764
|
-
|
765
|
-
const delta = generateDelta(existingParticipant.status, participant.status);
|
766
|
-
|
767
|
-
const changed = Object.keys(delta).length > 0;
|
768
|
-
|
769
|
-
if (changed) {
|
770
|
-
collection.push({
|
771
|
-
person: participant.person,
|
772
|
-
delta,
|
773
|
-
});
|
774
|
-
}
|
775
|
-
|
776
|
-
return collection;
|
777
|
-
}, []);
|
778
|
-
}
|
779
|
-
|
780
818
|
/**
|
781
819
|
* update meeting's members
|
782
820
|
* @param {Object} participants new participants object
|
821
|
+
* @param {Array} removedParticipantIds list of removed participants
|
783
822
|
* @param {Boolean} isReplace is replace the whole members
|
784
823
|
* @returns {Array} updatedParticipants
|
785
824
|
* @memberof LocusInfo
|
786
825
|
*/
|
787
|
-
updateParticipants(participants: object, isReplace?: boolean) {
|
826
|
+
updateParticipants(participants: object, removedParticipantIds?: string[], isReplace?: boolean) {
|
788
827
|
this.emitScoped(
|
789
828
|
{
|
790
829
|
file: 'locus-info',
|
@@ -793,6 +832,7 @@ export default class LocusInfo extends EventsScope {
|
|
793
832
|
EVENTS.LOCUS_INFO_UPDATE_PARTICIPANTS,
|
794
833
|
{
|
795
834
|
participants,
|
835
|
+
removedParticipantIds,
|
796
836
|
recordingId: this.parsedLocus.controls && this.parsedLocus.controls.record?.modifiedBy,
|
797
837
|
selfIdentity: this.parsedLocus.self && this.parsedLocus.self.selfIdentity,
|
798
838
|
selfId: this.parsedLocus.self && this.parsedLocus.self.selfId,
|
@@ -1289,10 +1329,7 @@ export default class LocusInfo extends EventsScope {
|
|
1289
1329
|
*/
|
1290
1330
|
updateMeetingInfo(info: object, self?: object) {
|
1291
1331
|
const roles = self ? SelfUtils.getRoles(self) : this.parsedLocus.self?.roles || [];
|
1292
|
-
if (
|
1293
|
-
(info && !isEqual(this.info, info)) ||
|
1294
|
-
(roles.length && !isEqual(this.roles, roles) && info)
|
1295
|
-
) {
|
1332
|
+
if ((info && !isEqual(this.info, info)) || (!isEqual(this.roles, roles) && info)) {
|
1296
1333
|
const isJoined = SelfUtils.isJoined(self || this.parsedLocus.self);
|
1297
1334
|
const parsedInfo = InfoUtils.getInfos(this.parsedLocus.info, info, roles, isJoined);
|
1298
1335
|
|
package/src/locus-info/parser.ts
CHANGED
@@ -728,13 +728,17 @@ export default class Parser {
|
|
728
728
|
break;
|
729
729
|
|
730
730
|
case USE_INCOMING:
|
731
|
-
case LOCUS_URL_CHANGED:
|
732
731
|
// update working copy for future comparisons.
|
733
732
|
// Note: The working copy of parser gets updated in .onFullLocus()
|
734
733
|
// and here when USE_INCOMING or LOCUS_URL_CHANGED locus.
|
735
734
|
this.workingCopy = newLoci;
|
736
735
|
break;
|
737
736
|
|
737
|
+
case LOCUS_URL_CHANGED:
|
738
|
+
// clear the working copy completely, do a full locus sync
|
739
|
+
this.workingCopy = null;
|
740
|
+
break;
|
741
|
+
|
738
742
|
case WAIT:
|
739
743
|
// we've taken newLoci from the front of the queue, so put it back there as we have to wait
|
740
744
|
// for the one that should be in front of it, before we can process it
|
package/src/media/properties.ts
CHANGED
@@ -9,9 +9,12 @@ import {
|
|
9
9
|
|
10
10
|
import {parse} from '@webex/ts-sdp';
|
11
11
|
import {ClientEvent} from '@webex/internal-plugin-metrics';
|
12
|
+
import {throttle} from 'lodash';
|
13
|
+
import Metrics from '../metrics';
|
12
14
|
import {MEETINGS, QUALITY_LEVELS} from '../constants';
|
13
15
|
import LoggerProxy from '../common/logs/logger-proxy';
|
14
16
|
import MediaConnectionAwaiter from './MediaConnectionAwaiter';
|
17
|
+
import BEHAVIORAL_METRICS from '../metrics/constants';
|
15
18
|
|
16
19
|
export type MediaDirection = {
|
17
20
|
sendAudio: boolean;
|
@@ -41,6 +44,8 @@ export default class MediaProperties {
|
|
41
44
|
videoDeviceId: any;
|
42
45
|
videoStream?: LocalCameraStream;
|
43
46
|
namespace = MEETINGS;
|
47
|
+
mediaIssueCounters: {[key: string]: number} = {};
|
48
|
+
throttledSendMediaIssueMetric: ReturnType<typeof throttle>;
|
44
49
|
|
45
50
|
/**
|
46
51
|
* @param {Object} [options] -- to auto construct
|
@@ -66,6 +71,15 @@ export default class MediaProperties {
|
|
66
71
|
this.remoteQualityLevel = QUALITY_LEVELS.HIGH;
|
67
72
|
this.mediaSettings = {};
|
68
73
|
this.videoDeviceId = null;
|
74
|
+
|
75
|
+
this.throttledSendMediaIssueMetric = throttle((eventPayload) => {
|
76
|
+
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.MEDIA_ISSUE_DETECTED, {
|
77
|
+
...eventPayload,
|
78
|
+
});
|
79
|
+
Object.keys(this.mediaIssueCounters).forEach((key) => {
|
80
|
+
this.mediaIssueCounters[key] = 0;
|
81
|
+
});
|
82
|
+
}, 1000 * 60 * 5); // at most once every 5 minutes
|
69
83
|
}
|
70
84
|
|
71
85
|
/**
|
@@ -139,8 +153,14 @@ export default class MediaProperties {
|
|
139
153
|
this.videoDeviceId = deviceId;
|
140
154
|
}
|
141
155
|
|
156
|
+
/**
|
157
|
+
* Clears the webrtcMediaConnection. This method should be called after
|
158
|
+
* peer connection is closed and no longer needed.
|
159
|
+
* @returns {void}
|
160
|
+
*/
|
142
161
|
unsetPeerConnection() {
|
143
162
|
this.webrtcMediaConnection = null;
|
163
|
+
this.throttledSendMediaIssueMetric.flush();
|
144
164
|
}
|
145
165
|
|
146
166
|
/**
|
@@ -424,4 +444,27 @@ export default class MediaProperties {
|
|
424
444
|
};
|
425
445
|
}
|
426
446
|
}
|
447
|
+
|
448
|
+
/**
|
449
|
+
* Sends a metric about a media issue. Metrics are throttled so that we don't
|
450
|
+
* send too many of them, but include a count so that we know how many issues
|
451
|
+
* were detected.
|
452
|
+
*
|
453
|
+
* @param {string} issueType
|
454
|
+
* @param {string} issueSubType
|
455
|
+
* @param {string} correlationId
|
456
|
+
* @returns {void}
|
457
|
+
*/
|
458
|
+
public sendMediaIssueMetric(issueType: string, issueSubType: string, correlationId) {
|
459
|
+
const key = `${issueType}_${issueSubType}`;
|
460
|
+
|
461
|
+
const count = (this.mediaIssueCounters[key] || 0) + 1;
|
462
|
+
|
463
|
+
this.mediaIssueCounters[key] = count;
|
464
|
+
|
465
|
+
this.throttledSendMediaIssueMetric({
|
466
|
+
correlationId,
|
467
|
+
...this.mediaIssueCounters,
|
468
|
+
});
|
469
|
+
}
|
427
470
|
}
|