@webex/plugin-meetings 3.4.0 → 3.5.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/breakouts/breakout.js +1 -1
- package/dist/breakouts/index.js +1 -1
- package/dist/constants.js +1 -0
- package/dist/constants.js.map +1 -1
- package/dist/interpretation/index.js +1 -1
- package/dist/interpretation/siLanguage.js +1 -1
- package/dist/media/index.js +6 -9
- package/dist/media/index.js.map +1 -1
- package/dist/meeting/in-meeting-actions.js +3 -1
- package/dist/meeting/in-meeting-actions.js.map +1 -1
- package/dist/meeting/index.js +154 -50
- package/dist/meeting/index.js.map +1 -1
- package/dist/meeting/util.js +1 -0
- package/dist/meeting/util.js.map +1 -1
- package/dist/meetings/index.js +11 -2
- package/dist/meetings/index.js.map +1 -1
- package/dist/reachability/index.js +175 -103
- package/dist/reachability/index.js.map +1 -1
- package/dist/reconnection-manager/index.js +1 -1
- package/dist/reconnection-manager/index.js.map +1 -1
- package/dist/types/constants.d.ts +2 -1
- package/dist/types/meeting/in-meeting-actions.d.ts +2 -0
- package/dist/types/meeting/index.d.ts +22 -2
- package/dist/types/meetings/index.d.ts +4 -2
- package/dist/types/reachability/index.d.ts +14 -2
- package/dist/webinar/index.js +1 -1
- package/package.json +22 -22
- package/src/constants.ts +1 -0
- package/src/media/index.ts +6 -10
- package/src/meeting/in-meeting-actions.ts +3 -0
- package/src/meeting/index.ts +92 -10
- package/src/meeting/util.ts +2 -0
- package/src/meetings/index.ts +11 -4
- package/src/reachability/index.ts +49 -4
- package/src/reconnection-manager/index.ts +1 -1
- package/test/integration/spec/converged-space-meetings.js +1 -1
- package/test/unit/spec/breakouts/index.ts +1 -0
- package/test/unit/spec/interceptors/locusRetry.ts +11 -10
- package/test/unit/spec/media/MediaConnectionAwaiter.ts +1 -0
- package/test/unit/spec/media/index.ts +34 -7
- package/test/unit/spec/media/properties.ts +1 -1
- package/test/unit/spec/meeting/connectionStateHandler.ts +1 -0
- package/test/unit/spec/meeting/in-meeting-actions.ts +2 -0
- package/test/unit/spec/meeting/index.js +119 -12
- package/test/unit/spec/meeting/locusMediaRequest.ts +3 -2
- package/test/unit/spec/meeting/request.js +1 -0
- package/test/unit/spec/meeting/utils.js +4 -0
- package/test/unit/spec/meeting-info/meetinginfov2.js +10 -11
- package/test/unit/spec/meeting-info/request.js +1 -1
- package/test/unit/spec/meetings/index.js +40 -5
- package/test/unit/spec/members/request.js +2 -1
- package/test/unit/spec/multistream/mediaRequestManager.ts +1 -0
- package/test/unit/spec/multistream/receiveSlot.ts +1 -0
- package/test/unit/spec/multistream/receiveSlotManager.ts +1 -0
- package/test/unit/spec/multistream/remoteMedia.ts +1 -0
- package/test/unit/spec/multistream/remoteMediaGroup.ts +1 -0
- package/test/unit/spec/multistream/remoteMediaManager.ts +1 -0
- package/test/unit/spec/multistream/sendSlotManager.ts +1 -0
- package/test/unit/spec/personal-meeting-room/personal-meeting-room.js +0 -1
- package/test/unit/spec/reachability/index.ts +211 -13
- package/test/unit/spec/reachability/request.js +1 -0
- package/test/unit/spec/roap/request.ts +1 -0
- package/dist/networkQualityMonitor/index.js +0 -227
- package/dist/networkQualityMonitor/index.js.map +0 -1
- package/dist/rtcMetrics/constants.js +0 -11
- package/dist/rtcMetrics/constants.js.map +0 -1
- package/dist/rtcMetrics/index.js +0 -177
- package/dist/rtcMetrics/index.js.map +0 -1
- 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 -61
- package/src/networkQualityMonitor/index.ts +0 -211
- package/src/rtcMetrics/constants.ts +0 -3
- package/src/rtcMetrics/index.ts +0 -166
- package/test/unit/spec/networkQualityMonitor/index.js +0 -99
- package/test/unit/spec/rtcMetrics/index.ts +0 -123
|
@@ -253,11 +253,12 @@ export default class Meetings extends WebexPlugin {
|
|
|
253
253
|
getReachability(): Reachability;
|
|
254
254
|
/**
|
|
255
255
|
* initializes and starts gathering reachability for Meetings
|
|
256
|
+
* @param {string} trigger - explains the reason for starting reachability
|
|
256
257
|
* @returns {Promise}
|
|
257
258
|
* @public
|
|
258
259
|
* @memberof Meetings
|
|
259
260
|
*/
|
|
260
|
-
startReachability(): Promise<import("../reachability").ReachabilityResults>;
|
|
261
|
+
startReachability(trigger?: string): Promise<import("../reachability").ReachabilityResults>;
|
|
261
262
|
/**
|
|
262
263
|
* Get geoHint for info for meetings
|
|
263
264
|
* @returns {Promise}
|
|
@@ -303,11 +304,12 @@ export default class Meetings extends WebexPlugin {
|
|
|
303
304
|
* @param {CallStateForMetrics} callStateForMetrics - information about call state for metrics
|
|
304
305
|
* @param {Object} [meetingInfo] - Pre-fetched complete meeting info
|
|
305
306
|
* @param {String} [meetingLookupUrl] - meeting info prefetch url
|
|
307
|
+
* @param {string} sessionCorrelationId - the optional specified sessionCorrelationId (callStateForMetrics.sessionCorrelationId) can be provided instead
|
|
306
308
|
* @returns {Promise<Meeting>} A new Meeting.
|
|
307
309
|
* @public
|
|
308
310
|
* @memberof Meetings
|
|
309
311
|
*/
|
|
310
|
-
create(destination: string, type?: DESTINATION_TYPE, useRandomDelayForInfo?: boolean, infoExtraParams?: {}, correlationId?: string, failOnMissingMeetingInfo?: boolean, callStateForMetrics?: CallStateForMetrics, meetingInfo?: any, meetingLookupUrl?: any): any;
|
|
312
|
+
create(destination: string, type?: DESTINATION_TYPE, useRandomDelayForInfo?: boolean, infoExtraParams?: {}, correlationId?: string, failOnMissingMeetingInfo?: boolean, callStateForMetrics?: CallStateForMetrics, meetingInfo?: any, meetingLookupUrl?: any, sessionCorrelationId?: string): any;
|
|
311
313
|
/**
|
|
312
314
|
* Create meeting
|
|
313
315
|
*
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
|
|
3
3
|
*/
|
|
4
4
|
import { Defer } from '@webex/common';
|
|
5
|
-
import ReachabilityRequest from './request';
|
|
5
|
+
import ReachabilityRequest, { ClusterList } from './request';
|
|
6
6
|
import { ClusterReachability, ClusterReachabilityResult } from './clusterReachability';
|
|
7
7
|
import EventsScope from '../common/events/events-scope';
|
|
8
8
|
export type ReachabilityMetrics = {
|
|
@@ -73,19 +73,31 @@ export default class Reachability extends EventsScope {
|
|
|
73
73
|
xtls: number;
|
|
74
74
|
};
|
|
75
75
|
};
|
|
76
|
+
protected lastTrigger?: string;
|
|
76
77
|
/**
|
|
77
78
|
* Creates an instance of Reachability.
|
|
78
79
|
* @param {object} webex
|
|
79
80
|
* @memberof Reachability
|
|
80
81
|
*/
|
|
81
82
|
constructor(webex: object);
|
|
83
|
+
/**
|
|
84
|
+
* Fetches the list of media clusters from the backend
|
|
85
|
+
* @param {boolean} isRetry
|
|
86
|
+
* @private
|
|
87
|
+
* @returns {Promise<{clusters: ClusterList, joinCookie: any}>}
|
|
88
|
+
*/
|
|
89
|
+
getClusters(isRetry?: boolean): Promise<{
|
|
90
|
+
clusters: ClusterList;
|
|
91
|
+
joinCookie: any;
|
|
92
|
+
}>;
|
|
82
93
|
/**
|
|
83
94
|
* Gets a list of media clusters from the backend and performs reachability checks on all the clusters
|
|
95
|
+
* @param {string} trigger - explains the reason for starting reachability
|
|
84
96
|
* @returns {Promise<ReachabilityResults>} reachability results
|
|
85
97
|
* @public
|
|
86
98
|
* @memberof Reachability
|
|
87
99
|
*/
|
|
88
|
-
gatherReachability(): Promise<ReachabilityResults>;
|
|
100
|
+
gatherReachability(trigger: string): Promise<ReachabilityResults>;
|
|
89
101
|
/**
|
|
90
102
|
* Returns statistics about last reachability results. The returned value is an object
|
|
91
103
|
* with a flat list of properties so that it can be easily sent with metrics
|
package/dist/webinar/index.js
CHANGED
|
@@ -62,7 +62,7 @@ var Webinar = _webexCore.WebexPlugin.extend({
|
|
|
62
62
|
updateCanManageWebcast: function updateCanManageWebcast(canManageWebcast) {
|
|
63
63
|
this.set('canManageWebcast', canManageWebcast);
|
|
64
64
|
},
|
|
65
|
-
version: "3.
|
|
65
|
+
version: "3.5.0-next.10"
|
|
66
66
|
});
|
|
67
67
|
var _default = exports.default = Webinar;
|
|
68
68
|
//# sourceMappingURL=index.js.map
|
package/package.json
CHANGED
|
@@ -43,13 +43,13 @@
|
|
|
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-meetings": "3.
|
|
47
|
-
"@webex/plugin-rooms": "3.
|
|
48
|
-
"@webex/test-helper-chai": "3.
|
|
49
|
-
"@webex/test-helper-mocha": "3.
|
|
50
|
-
"@webex/test-helper-mock-webex": "3.
|
|
51
|
-
"@webex/test-helper-retry": "3.
|
|
52
|
-
"@webex/test-helper-test-users": "3.
|
|
46
|
+
"@webex/plugin-meetings": "3.5.0-next.10",
|
|
47
|
+
"@webex/plugin-rooms": "3.5.0-next.7",
|
|
48
|
+
"@webex/test-helper-chai": "3.5.0-next.6",
|
|
49
|
+
"@webex/test-helper-mocha": "3.5.0-next.6",
|
|
50
|
+
"@webex/test-helper-mock-webex": "3.5.0-next.6",
|
|
51
|
+
"@webex/test-helper-retry": "3.5.0-next.6",
|
|
52
|
+
"@webex/test-helper-test-users": "3.5.0-next.6",
|
|
53
53
|
"chai": "^4.3.4",
|
|
54
54
|
"chai-as-promised": "^7.1.1",
|
|
55
55
|
"eslint": "^8.24.0",
|
|
@@ -61,21 +61,21 @@
|
|
|
61
61
|
"typescript": "^4.7.4"
|
|
62
62
|
},
|
|
63
63
|
"dependencies": {
|
|
64
|
-
"@webex/common": "3.
|
|
65
|
-
"@webex/internal-media-core": "2.
|
|
66
|
-
"@webex/internal-plugin-conversation": "3.
|
|
67
|
-
"@webex/internal-plugin-device": "3.
|
|
68
|
-
"@webex/internal-plugin-llm": "3.
|
|
69
|
-
"@webex/internal-plugin-mercury": "3.
|
|
70
|
-
"@webex/internal-plugin-metrics": "3.
|
|
71
|
-
"@webex/internal-plugin-support": "3.
|
|
72
|
-
"@webex/internal-plugin-user": "3.
|
|
73
|
-
"@webex/internal-plugin-voicea": "3.
|
|
74
|
-
"@webex/media-helpers": "3.
|
|
75
|
-
"@webex/plugin-people": "3.
|
|
76
|
-
"@webex/plugin-rooms": "3.
|
|
64
|
+
"@webex/common": "3.5.0-next.6",
|
|
65
|
+
"@webex/internal-media-core": "2.11.3",
|
|
66
|
+
"@webex/internal-plugin-conversation": "3.5.0-next.7",
|
|
67
|
+
"@webex/internal-plugin-device": "3.5.0-next.6",
|
|
68
|
+
"@webex/internal-plugin-llm": "3.5.0-next.6",
|
|
69
|
+
"@webex/internal-plugin-mercury": "3.5.0-next.6",
|
|
70
|
+
"@webex/internal-plugin-metrics": "3.5.0-next.6",
|
|
71
|
+
"@webex/internal-plugin-support": "3.5.0-next.7",
|
|
72
|
+
"@webex/internal-plugin-user": "3.5.0-next.6",
|
|
73
|
+
"@webex/internal-plugin-voicea": "3.5.0-next.10",
|
|
74
|
+
"@webex/media-helpers": "3.5.0-next.7",
|
|
75
|
+
"@webex/plugin-people": "3.5.0-next.6",
|
|
76
|
+
"@webex/plugin-rooms": "3.5.0-next.7",
|
|
77
77
|
"@webex/web-capabilities": "^1.4.0",
|
|
78
|
-
"@webex/webex-core": "3.
|
|
78
|
+
"@webex/webex-core": "3.5.0-next.6",
|
|
79
79
|
"ampersand-collection": "^2.0.2",
|
|
80
80
|
"bowser": "^2.11.0",
|
|
81
81
|
"btoa": "^1.2.1",
|
|
@@ -91,5 +91,5 @@
|
|
|
91
91
|
"//": [
|
|
92
92
|
"TODO: upgrade jwt-decode when moving to node 18"
|
|
93
93
|
],
|
|
94
|
-
"version": "3.
|
|
94
|
+
"version": "3.5.0-next.10"
|
|
95
95
|
}
|
package/src/constants.ts
CHANGED
package/src/media/index.ts
CHANGED
|
@@ -15,12 +15,12 @@ import {
|
|
|
15
15
|
LocalSystemAudioStream,
|
|
16
16
|
LocalMicrophoneStream,
|
|
17
17
|
} from '@webex/media-helpers';
|
|
18
|
+
import {RtcMetrics} from '@webex/internal-plugin-metrics';
|
|
18
19
|
import LoggerProxy from '../common/logs/logger-proxy';
|
|
19
20
|
import {MEDIA_TRACK_CONSTRAINT} from '../constants';
|
|
20
21
|
import Config from '../config';
|
|
21
22
|
import StaticConfig from '../common/config';
|
|
22
23
|
import BrowserDetection from '../common/browser-detection';
|
|
23
|
-
import RtcMetrics from '../rtcMetrics';
|
|
24
24
|
|
|
25
25
|
const {isBrowser} = BrowserDetection();
|
|
26
26
|
|
|
@@ -104,9 +104,7 @@ Media.getDirection = (forceSendRecv: boolean, receive: boolean, send: boolean) =
|
|
|
104
104
|
*
|
|
105
105
|
* @param {boolean} isMultistream
|
|
106
106
|
* @param {string} debugId string useful for debugging (will appear in media connection logs)
|
|
107
|
-
* @param {object} webex main `webex` object.
|
|
108
107
|
* @param {string} meetingId id for the meeting using this connection
|
|
109
|
-
* @param {string} correlationId id used in requests to correlate to this session
|
|
110
108
|
* @param {Object} options
|
|
111
109
|
* @param {Object} [options.mediaProperties] contains mediaDirection and local tracks:
|
|
112
110
|
* audioTrack, videoTrack, shareVideoTrack, and shareAudioTrack
|
|
@@ -120,10 +118,9 @@ Media.getDirection = (forceSendRecv: boolean, receive: boolean, send: boolean) =
|
|
|
120
118
|
Media.createMediaConnection = (
|
|
121
119
|
isMultistream: boolean,
|
|
122
120
|
debugId: string,
|
|
123
|
-
webex: object,
|
|
124
121
|
meetingId: string,
|
|
125
|
-
correlationId: string,
|
|
126
122
|
options: {
|
|
123
|
+
rtcMetrics?: RtcMetrics;
|
|
127
124
|
mediaProperties: {
|
|
128
125
|
mediaDirection?: {
|
|
129
126
|
receiveAudio: boolean;
|
|
@@ -150,6 +147,7 @@ Media.createMediaConnection = (
|
|
|
150
147
|
}
|
|
151
148
|
) => {
|
|
152
149
|
const {
|
|
150
|
+
rtcMetrics,
|
|
153
151
|
mediaProperties,
|
|
154
152
|
remoteQualityLevel,
|
|
155
153
|
enableRtx,
|
|
@@ -192,15 +190,13 @@ Media.createMediaConnection = (
|
|
|
192
190
|
config.bundlePolicy = bundlePolicy;
|
|
193
191
|
}
|
|
194
192
|
|
|
195
|
-
const rtcMetrics = new RtcMetrics(webex, meetingId, correlationId);
|
|
196
|
-
|
|
197
193
|
return new MultistreamRoapMediaConnection(
|
|
198
194
|
config,
|
|
199
195
|
meetingId,
|
|
200
196
|
/* the rtc metrics objects callbacks */
|
|
201
|
-
(data) => rtcMetrics
|
|
202
|
-
() => rtcMetrics
|
|
203
|
-
() => rtcMetrics
|
|
197
|
+
(data) => rtcMetrics?.addMetrics(data),
|
|
198
|
+
() => rtcMetrics?.closeMetrics(),
|
|
199
|
+
() => rtcMetrics?.sendMetricsInQueue()
|
|
204
200
|
);
|
|
205
201
|
}
|
|
206
202
|
|
|
@@ -82,6 +82,7 @@ interface IInMeetingActions {
|
|
|
82
82
|
supportHDV?: boolean;
|
|
83
83
|
canShareWhiteBoard?: boolean;
|
|
84
84
|
enforceVirtualBackground?: boolean;
|
|
85
|
+
canPollingAndQA?: boolean;
|
|
85
86
|
}
|
|
86
87
|
|
|
87
88
|
/**
|
|
@@ -236,6 +237,7 @@ export default class InMeetingActions implements IInMeetingActions {
|
|
|
236
237
|
|
|
237
238
|
canShareWhiteBoard = null;
|
|
238
239
|
|
|
240
|
+
canPollingAndQA = null;
|
|
239
241
|
/**
|
|
240
242
|
* Returns all meeting action options
|
|
241
243
|
* @returns {Object}
|
|
@@ -314,6 +316,7 @@ export default class InMeetingActions implements IInMeetingActions {
|
|
|
314
316
|
supportHQV: this.supportHQV,
|
|
315
317
|
supportHDV: this.supportHDV,
|
|
316
318
|
canShareWhiteBoard: this.canShareWhiteBoard,
|
|
319
|
+
canPollingAndQA: this.canPollingAndQA,
|
|
317
320
|
});
|
|
318
321
|
|
|
319
322
|
/**
|
package/src/meeting/index.ts
CHANGED
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
ClientEventLeaveReason,
|
|
11
11
|
CallDiagnosticUtils,
|
|
12
12
|
CALL_DIAGNOSTIC_CONFIG,
|
|
13
|
+
RtcMetrics,
|
|
13
14
|
} from '@webex/internal-plugin-metrics';
|
|
14
15
|
import {ClientEvent as RawClientEvent} from '@webex/event-dictionary-ts';
|
|
15
16
|
|
|
@@ -24,6 +25,8 @@ import {
|
|
|
24
25
|
RoapMessage,
|
|
25
26
|
StatsAnalyzer,
|
|
26
27
|
StatsAnalyzerEventNames,
|
|
28
|
+
NetworkQualityEventNames,
|
|
29
|
+
NetworkQualityMonitor,
|
|
27
30
|
} from '@webex/internal-media-core';
|
|
28
31
|
|
|
29
32
|
import {
|
|
@@ -54,7 +57,6 @@ import {
|
|
|
54
57
|
AddMediaFailed,
|
|
55
58
|
} from '../common/errors/webex-errors';
|
|
56
59
|
|
|
57
|
-
import NetworkQualityMonitor from '../networkQualityMonitor';
|
|
58
60
|
import LoggerProxy from '../common/logs/logger-proxy';
|
|
59
61
|
import EventsUtil from '../common/events/util';
|
|
60
62
|
import Trigger from '../common/events/trigger-proxy';
|
|
@@ -225,6 +227,7 @@ export type AddMediaOptions = {
|
|
|
225
227
|
|
|
226
228
|
export type CallStateForMetrics = {
|
|
227
229
|
correlationId?: string;
|
|
230
|
+
sessionCorrelationId?: string;
|
|
228
231
|
joinTrigger?: string;
|
|
229
232
|
loginType?: string;
|
|
230
233
|
};
|
|
@@ -536,6 +539,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
536
539
|
id: string;
|
|
537
540
|
isMultistream: boolean;
|
|
538
541
|
locusUrl: string;
|
|
542
|
+
#isoLocalClientMeetingJoinTime?: string;
|
|
539
543
|
mediaConnections: any[];
|
|
540
544
|
mediaId?: string;
|
|
541
545
|
meetingFiniteStateMachine: any;
|
|
@@ -695,6 +699,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
695
699
|
private connectionStateHandler?: ConnectionStateHandler;
|
|
696
700
|
private iceCandidateErrors: Map<string, number>;
|
|
697
701
|
private iceCandidatesCount: number;
|
|
702
|
+
private rtcMetrics?: RtcMetrics;
|
|
698
703
|
|
|
699
704
|
/**
|
|
700
705
|
* @param {Object} attrs
|
|
@@ -738,12 +743,29 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
738
743
|
*/
|
|
739
744
|
this.callStateForMetrics = attrs.callStateForMetrics || {};
|
|
740
745
|
const correlationId = attrs.correlationId || attrs.callStateForMetrics?.correlationId;
|
|
746
|
+
const sessionCorrelationId =
|
|
747
|
+
attrs.sessionCorrelationId || attrs.callStateForMetrics?.sessionCorrelationId;
|
|
748
|
+
if (sessionCorrelationId) {
|
|
749
|
+
LoggerProxy.logger.log(
|
|
750
|
+
`Meetings:index#constructor --> Initializing the meeting object with session correlation id from app ${correlationId}`
|
|
751
|
+
);
|
|
752
|
+
this.callStateForMetrics.sessionCorrelationId = sessionCorrelationId;
|
|
753
|
+
} else {
|
|
754
|
+
LoggerProxy.logger.log(
|
|
755
|
+
`Meetings:index#constructor --> No session correlation id supplied. None will be generated and this field will remain blank`
|
|
756
|
+
);
|
|
757
|
+
// TODO: supply a session from the meetings instance
|
|
758
|
+
this.callStateForMetrics.sessionCorrelationId = '';
|
|
759
|
+
}
|
|
741
760
|
if (correlationId) {
|
|
742
761
|
LoggerProxy.logger.log(
|
|
743
762
|
`Meetings:index#constructor --> Initializing the meeting object with correlation id from app ${correlationId}`
|
|
744
763
|
);
|
|
745
764
|
this.callStateForMetrics.correlationId = correlationId;
|
|
746
765
|
} else {
|
|
766
|
+
LoggerProxy.logger.log(
|
|
767
|
+
`Meetings:index#constructor --> Initializing the meeting object with generated correlation id from sdk ${this.id}`
|
|
768
|
+
);
|
|
747
769
|
this.callStateForMetrics.correlationId = this.id;
|
|
748
770
|
}
|
|
749
771
|
/**
|
|
@@ -1518,6 +1540,17 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1518
1540
|
* @memberof Meeting
|
|
1519
1541
|
*/
|
|
1520
1542
|
this.iceCandidatesCount = 0;
|
|
1543
|
+
|
|
1544
|
+
/**
|
|
1545
|
+
* Start time of meeting as an ISO string
|
|
1546
|
+
* based on browser time, so can only be used to compute durations client side
|
|
1547
|
+
* undefined if meeting has not been joined, set once on meeting join, and not updated again
|
|
1548
|
+
* @instance
|
|
1549
|
+
* @type {string}
|
|
1550
|
+
* @private
|
|
1551
|
+
* @memberof Meeting
|
|
1552
|
+
*/
|
|
1553
|
+
this.#isoLocalClientMeetingJoinTime = undefined;
|
|
1521
1554
|
}
|
|
1522
1555
|
|
|
1523
1556
|
/**
|
|
@@ -1566,6 +1599,31 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1566
1599
|
this.callStateForMetrics.correlationId = correlationId;
|
|
1567
1600
|
}
|
|
1568
1601
|
|
|
1602
|
+
/**
|
|
1603
|
+
* Getter - Returns callStateForMetrics.sessionCorrelationId
|
|
1604
|
+
* @returns {string}
|
|
1605
|
+
*/
|
|
1606
|
+
get sessionCorrelationId() {
|
|
1607
|
+
return this.callStateForMetrics.sessionCorrelationId;
|
|
1608
|
+
}
|
|
1609
|
+
|
|
1610
|
+
/**
|
|
1611
|
+
* Setter - sets callStateForMetrics.sessionCorrelationId
|
|
1612
|
+
* @param {string} sessionCorrelationId
|
|
1613
|
+
*/
|
|
1614
|
+
set sessionCorrelationId(sessionCorrelationId: string) {
|
|
1615
|
+
this.callStateForMetrics.sessionCorrelationId = sessionCorrelationId;
|
|
1616
|
+
}
|
|
1617
|
+
|
|
1618
|
+
/**
|
|
1619
|
+
* Getter - Returns isoLocalClientMeetingJoinTime
|
|
1620
|
+
* This will be set once on meeting join, and not updated again
|
|
1621
|
+
* @returns {string | undefined}
|
|
1622
|
+
*/
|
|
1623
|
+
get isoLocalClientMeetingJoinTime(): string | undefined {
|
|
1624
|
+
return this.#isoLocalClientMeetingJoinTime;
|
|
1625
|
+
}
|
|
1626
|
+
|
|
1569
1627
|
/**
|
|
1570
1628
|
* Set meeting info and trigger `MEETING_INFO_AVAILABLE` event
|
|
1571
1629
|
* @param {any} info
|
|
@@ -3155,6 +3213,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3155
3213
|
options: {meetingId: this.id},
|
|
3156
3214
|
});
|
|
3157
3215
|
}
|
|
3216
|
+
this.rtcMetrics?.sendNextMetrics();
|
|
3158
3217
|
this.updateLLMConnection();
|
|
3159
3218
|
});
|
|
3160
3219
|
|
|
@@ -3767,6 +3826,10 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3767
3826
|
requiredPolicies: [SELF_POLICY.SUPPORT_CHAT],
|
|
3768
3827
|
policies: this.selfUserPolicies,
|
|
3769
3828
|
}),
|
|
3829
|
+
canPollingAndQA: ControlsOptionsUtil.hasPolicies({
|
|
3830
|
+
requiredPolicies: [SELF_POLICY.SUPPORT_POLLING_AND_QA],
|
|
3831
|
+
policies: this.selfUserPolicies,
|
|
3832
|
+
}),
|
|
3770
3833
|
canShareApplication:
|
|
3771
3834
|
(ControlsOptionsUtil.hasHints({
|
|
3772
3835
|
requiredHints: [DISPLAY_HINTS.SHARE_APPLICATION],
|
|
@@ -5228,6 +5291,11 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5228
5291
|
this.meetingFiniteStateMachine.join();
|
|
5229
5292
|
this.setupLocusMediaRequest();
|
|
5230
5293
|
|
|
5294
|
+
// @ts-ignore
|
|
5295
|
+
this.webex.internal.device.meetingStarted();
|
|
5296
|
+
|
|
5297
|
+
this.#isoLocalClientMeetingJoinTime = new Date().toISOString();
|
|
5298
|
+
|
|
5231
5299
|
LoggerProxy.logger.log('Meeting:index#join --> Success');
|
|
5232
5300
|
|
|
5233
5301
|
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.JOIN_SUCCESS, {
|
|
@@ -6306,14 +6374,17 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
6306
6374
|
* @returns {RoapMediaConnection | MultistreamRoapMediaConnection}
|
|
6307
6375
|
*/
|
|
6308
6376
|
private async createMediaConnection(turnServerInfo, bundlePolicy?: BundlePolicy) {
|
|
6377
|
+
this.rtcMetrics = this.isMultistream
|
|
6378
|
+
? // @ts-ignore
|
|
6379
|
+
new RtcMetrics(this.webex, this.id, this.correlationId)
|
|
6380
|
+
: undefined;
|
|
6381
|
+
|
|
6309
6382
|
const mc = Media.createMediaConnection(
|
|
6310
6383
|
this.isMultistream,
|
|
6311
6384
|
this.getMediaConnectionDebugId(),
|
|
6312
|
-
// @ts-ignore
|
|
6313
|
-
this.webex,
|
|
6314
6385
|
this.id,
|
|
6315
|
-
this.correlationId,
|
|
6316
6386
|
{
|
|
6387
|
+
rtcMetrics: this.rtcMetrics,
|
|
6317
6388
|
mediaProperties: this.mediaProperties,
|
|
6318
6389
|
remoteQualityLevel: this.mediaProperties.remoteQualityLevel,
|
|
6319
6390
|
// @ts-ignore - config coming from registerPlugin
|
|
@@ -6500,7 +6571,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
6500
6571
|
});
|
|
6501
6572
|
this.setupStatsAnalyzerEventHandlers();
|
|
6502
6573
|
this.networkQualityMonitor.on(
|
|
6503
|
-
|
|
6574
|
+
NetworkQualityEventNames.NETWORK_QUALITY,
|
|
6504
6575
|
this.sendNetworkQualityEvent.bind(this)
|
|
6505
6576
|
);
|
|
6506
6577
|
}
|
|
@@ -6511,12 +6582,21 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
6511
6582
|
*
|
|
6512
6583
|
* @private
|
|
6513
6584
|
* @static
|
|
6585
|
+
* @param {boolean} isAudioEnabled
|
|
6586
|
+
* @param {boolean} isVideoEnabled
|
|
6514
6587
|
* @returns {Promise<void>}
|
|
6515
6588
|
*/
|
|
6516
|
-
private static async handleDeviceLogging(): Promise<void> {
|
|
6517
|
-
try {
|
|
6518
|
-
const devices = await getDevices();
|
|
6519
6589
|
|
|
6590
|
+
private static async handleDeviceLogging(isAudioEnabled, isVideoEnabled): Promise<void> {
|
|
6591
|
+
try {
|
|
6592
|
+
let devices = [];
|
|
6593
|
+
if (isVideoEnabled && isAudioEnabled) {
|
|
6594
|
+
devices = await getDevices();
|
|
6595
|
+
} else if (isVideoEnabled) {
|
|
6596
|
+
devices = await getDevices(Media.DeviceKind.VIDEO_INPUT);
|
|
6597
|
+
} else if (isAudioEnabled) {
|
|
6598
|
+
devices = await getDevices(Media.DeviceKind.AUDIO_INPUT);
|
|
6599
|
+
}
|
|
6520
6600
|
MeetingUtil.handleDeviceLogging(devices);
|
|
6521
6601
|
} catch {
|
|
6522
6602
|
// getDevices may fail if we don't have browser permissions, that's ok, we still can have a media connection
|
|
@@ -7009,7 +7089,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
7009
7089
|
);
|
|
7010
7090
|
|
|
7011
7091
|
if (audioEnabled || videoEnabled) {
|
|
7012
|
-
await Meeting.handleDeviceLogging();
|
|
7092
|
+
await Meeting.handleDeviceLogging(audioEnabled, videoEnabled);
|
|
7013
7093
|
} else {
|
|
7014
7094
|
LoggerProxy.logger.info(`${LOG_HEADER} device logging not required`);
|
|
7015
7095
|
}
|
|
@@ -7022,6 +7102,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
7022
7102
|
await this.mediaProperties.getCurrentConnectionInfo();
|
|
7023
7103
|
// @ts-ignore
|
|
7024
7104
|
const reachabilityStats = await this.webex.meetings.reachability.getReachabilityMetrics();
|
|
7105
|
+
const iceCandidateErrors = Object.fromEntries(this.iceCandidateErrors);
|
|
7025
7106
|
|
|
7026
7107
|
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.ADD_MEDIA_SUCCESS, {
|
|
7027
7108
|
correlation_id: this.correlationId,
|
|
@@ -7033,6 +7114,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
7033
7114
|
retriedWithTurnServer: this.addMediaData.retriedWithTurnServer,
|
|
7034
7115
|
isJoinWithMediaRetry: this.joinWithMediaRetryInfo.isRetry,
|
|
7035
7116
|
...reachabilityStats,
|
|
7117
|
+
...iceCandidateErrors,
|
|
7036
7118
|
iceCandidatesCount: this.iceCandidatesCount,
|
|
7037
7119
|
});
|
|
7038
7120
|
// @ts-ignore
|
|
@@ -8191,7 +8273,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
8191
8273
|
* @private
|
|
8192
8274
|
* @memberof Meeting
|
|
8193
8275
|
*/
|
|
8194
|
-
private sendNetworkQualityEvent(res:
|
|
8276
|
+
private sendNetworkQualityEvent(res: {networkQualityScore: number; mediaType: string}) {
|
|
8195
8277
|
Trigger.trigger(
|
|
8196
8278
|
this,
|
|
8197
8279
|
{
|
package/src/meeting/util.ts
CHANGED
package/src/meetings/index.ts
CHANGED
|
@@ -765,7 +765,7 @@ export default class Meetings extends WebexPlugin {
|
|
|
765
765
|
return Promise.all([
|
|
766
766
|
this.fetchUserPreferredWebexSite(),
|
|
767
767
|
this.getGeoHint(),
|
|
768
|
-
this.startReachability().catch((error) => {
|
|
768
|
+
this.startReachability('registration').catch((error) => {
|
|
769
769
|
LoggerProxy.logger.error(`Meetings:index#register --> GDM error, ${error.message}`);
|
|
770
770
|
}),
|
|
771
771
|
// @ts-ignore
|
|
@@ -967,12 +967,13 @@ export default class Meetings extends WebexPlugin {
|
|
|
967
967
|
|
|
968
968
|
/**
|
|
969
969
|
* initializes and starts gathering reachability for Meetings
|
|
970
|
+
* @param {string} trigger - explains the reason for starting reachability
|
|
970
971
|
* @returns {Promise}
|
|
971
972
|
* @public
|
|
972
973
|
* @memberof Meetings
|
|
973
974
|
*/
|
|
974
|
-
startReachability() {
|
|
975
|
-
return this.getReachability().gatherReachability();
|
|
975
|
+
startReachability(trigger = 'client') {
|
|
976
|
+
return this.getReachability().gatherReachability(trigger);
|
|
976
977
|
}
|
|
977
978
|
|
|
978
979
|
/**
|
|
@@ -1080,6 +1081,7 @@ export default class Meetings extends WebexPlugin {
|
|
|
1080
1081
|
* @param {CallStateForMetrics} callStateForMetrics - information about call state for metrics
|
|
1081
1082
|
* @param {Object} [meetingInfo] - Pre-fetched complete meeting info
|
|
1082
1083
|
* @param {String} [meetingLookupUrl] - meeting info prefetch url
|
|
1084
|
+
* @param {string} sessionCorrelationId - the optional specified sessionCorrelationId (callStateForMetrics.sessionCorrelationId) can be provided instead
|
|
1083
1085
|
* @returns {Promise<Meeting>} A new Meeting.
|
|
1084
1086
|
* @public
|
|
1085
1087
|
* @memberof Meetings
|
|
@@ -1093,7 +1095,8 @@ export default class Meetings extends WebexPlugin {
|
|
|
1093
1095
|
failOnMissingMeetingInfo = false,
|
|
1094
1096
|
callStateForMetrics: CallStateForMetrics = undefined,
|
|
1095
1097
|
meetingInfo = undefined,
|
|
1096
|
-
meetingLookupUrl = undefined
|
|
1098
|
+
meetingLookupUrl = undefined,
|
|
1099
|
+
sessionCorrelationId: string = undefined
|
|
1097
1100
|
) {
|
|
1098
1101
|
// Validate meeting information based on the provided destination and
|
|
1099
1102
|
// type. This must be performed prior to determining if the meeting is
|
|
@@ -1104,6 +1107,10 @@ export default class Meetings extends WebexPlugin {
|
|
|
1104
1107
|
callStateForMetrics = {...(callStateForMetrics || {}), correlationId};
|
|
1105
1108
|
}
|
|
1106
1109
|
|
|
1110
|
+
if (sessionCorrelationId) {
|
|
1111
|
+
callStateForMetrics = {...(callStateForMetrics || {}), sessionCorrelationId};
|
|
1112
|
+
}
|
|
1113
|
+
|
|
1107
1114
|
return (
|
|
1108
1115
|
this.meetingInfo
|
|
1109
1116
|
.fetchInfoOptions(destination, type)
|
|
@@ -93,6 +93,8 @@ export default class Reachability extends EventsScope {
|
|
|
93
93
|
expectedResultsCount = {videoMesh: {udp: 0}, public: {udp: 0, tcp: 0, xtls: 0}};
|
|
94
94
|
resultsCount = {videoMesh: {udp: 0}, public: {udp: 0, tcp: 0, xtls: 0}};
|
|
95
95
|
|
|
96
|
+
protected lastTrigger?: string;
|
|
97
|
+
|
|
96
98
|
/**
|
|
97
99
|
* Creates an instance of Reachability.
|
|
98
100
|
* @param {object} webex
|
|
@@ -114,18 +116,50 @@ export default class Reachability extends EventsScope {
|
|
|
114
116
|
this.clusterReachability = {};
|
|
115
117
|
}
|
|
116
118
|
|
|
119
|
+
/**
|
|
120
|
+
* Fetches the list of media clusters from the backend
|
|
121
|
+
* @param {boolean} isRetry
|
|
122
|
+
* @private
|
|
123
|
+
* @returns {Promise<{clusters: ClusterList, joinCookie: any}>}
|
|
124
|
+
*/
|
|
125
|
+
async getClusters(isRetry = false): Promise<{clusters: ClusterList; joinCookie: any}> {
|
|
126
|
+
try {
|
|
127
|
+
const {clusters, joinCookie} = await this.reachabilityRequest.getClusters(
|
|
128
|
+
MeetingUtil.getIpVersion(this.webex)
|
|
129
|
+
);
|
|
130
|
+
|
|
131
|
+
return {clusters, joinCookie};
|
|
132
|
+
} catch (error) {
|
|
133
|
+
if (isRetry) {
|
|
134
|
+
throw error;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
LoggerProxy.logger.error(
|
|
138
|
+
`Reachability:index#getClusters --> Failed with error: ${error}, retrying...`
|
|
139
|
+
);
|
|
140
|
+
|
|
141
|
+
return this.getClusters(true);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
117
145
|
/**
|
|
118
146
|
* Gets a list of media clusters from the backend and performs reachability checks on all the clusters
|
|
147
|
+
* @param {string} trigger - explains the reason for starting reachability
|
|
119
148
|
* @returns {Promise<ReachabilityResults>} reachability results
|
|
120
149
|
* @public
|
|
121
150
|
* @memberof Reachability
|
|
122
151
|
*/
|
|
123
|
-
public async gatherReachability(): Promise<ReachabilityResults> {
|
|
152
|
+
public async gatherReachability(trigger: string): Promise<ReachabilityResults> {
|
|
124
153
|
// Fetch clusters and measure latency
|
|
125
154
|
try {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
155
|
+
this.lastTrigger = trigger;
|
|
156
|
+
|
|
157
|
+
// kick off ip version detection. For now we don't await it, as we're doing it
|
|
158
|
+
// to gather the timings and send them with our reachability metrics
|
|
159
|
+
// @ts-ignore
|
|
160
|
+
this.webex.internal.device.ipNetworkDetector.detect();
|
|
161
|
+
|
|
162
|
+
const {clusters, joinCookie} = await this.getClusters();
|
|
129
163
|
|
|
130
164
|
// @ts-ignore
|
|
131
165
|
await this.webex.boundedStorage.put(
|
|
@@ -513,6 +547,17 @@ export default class Reachability extends EventsScope {
|
|
|
513
547
|
tcp: this.getStatistics(results, 'tcp', false),
|
|
514
548
|
xtls: this.getStatistics(results, 'xtls', false),
|
|
515
549
|
},
|
|
550
|
+
ipver: {
|
|
551
|
+
// @ts-ignore
|
|
552
|
+
firstIpV4: this.webex.internal.device.ipNetworkDetector.firstIpV4,
|
|
553
|
+
// @ts-ignore
|
|
554
|
+
firstIpV6: this.webex.internal.device.ipNetworkDetector.firstIpV6,
|
|
555
|
+
// @ts-ignore
|
|
556
|
+
firstMdns: this.webex.internal.device.ipNetworkDetector.firstMdns,
|
|
557
|
+
// @ts-ignore
|
|
558
|
+
totalTime: this.webex.internal.device.ipNetworkDetector.totalTime,
|
|
559
|
+
},
|
|
560
|
+
trigger: this.lastTrigger,
|
|
516
561
|
};
|
|
517
562
|
Metrics.sendBehavioralMetric(
|
|
518
563
|
BEHAVIORAL_METRICS.REACHABILITY_COMPLETED,
|
|
@@ -342,7 +342,7 @@ export default class ReconnectionManager {
|
|
|
342
342
|
}
|
|
343
343
|
|
|
344
344
|
try {
|
|
345
|
-
await this.webex.meetings.startReachability();
|
|
345
|
+
await this.webex.meetings.startReachability('reconnection');
|
|
346
346
|
} catch (err) {
|
|
347
347
|
LoggerProxy.logger.info(
|
|
348
348
|
'ReconnectionManager:index#reconnect --> Reachability failed, continuing with reconnection attempt, err: ',
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { config } from 'dotenv';
|
|
2
1
|
import 'jsdom-global/register';
|
|
2
|
+
import {config} from 'dotenv';
|
|
3
3
|
import {assert} from '@webex/test-helper-chai';
|
|
4
4
|
import {skipInNode} from '@webex/test-helper-mocha';
|
|
5
5
|
import BrowserDetection from '@webex/plugin-meetings/dist/common/browser-detection';
|