@webex/plugin-meetings 3.9.0 → 3.10.0-multi-llms.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/common/errors/webex-errors.js +21 -1
- package/dist/common/errors/webex-errors.js.map +1 -1
- package/dist/constants.js +9 -0
- package/dist/constants.js.map +1 -1
- package/dist/controls-options-manager/index.js +22 -5
- package/dist/controls-options-manager/index.js.map +1 -1
- package/dist/index.js +9 -1
- package/dist/index.js.map +1 -1
- package/dist/interceptors/index.js +7 -0
- package/dist/interceptors/index.js.map +1 -1
- package/dist/interceptors/locusRouteToken.js +116 -0
- package/dist/interceptors/locusRouteToken.js.map +1 -0
- package/dist/interpretation/index.js +1 -1
- package/dist/interpretation/siLanguage.js +1 -1
- package/dist/locus-info/controlsUtils.js +11 -2
- package/dist/locus-info/controlsUtils.js.map +1 -1
- package/dist/locus-info/index.js +56 -14
- 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/index.js +5 -0
- package/dist/media/index.js.map +1 -1
- package/dist/media/properties.js +53 -5
- package/dist/media/properties.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 +340 -186
- 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 +177 -14
- package/dist/meeting/request.js.map +1 -1
- package/dist/meeting/util.js +39 -11
- 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 +31 -25
- package/dist/meetings/index.js.map +1 -1
- package/dist/member/index.js +9 -0
- package/dist/member/index.js.map +1 -1
- package/dist/member/types.js.map +1 -1
- package/dist/member/util.js +10 -0
- package/dist/member/util.js.map +1 -1
- package/dist/members/collection.js +13 -0
- package/dist/members/collection.js.map +1 -1
- package/dist/members/index.js +42 -20
- package/dist/members/index.js.map +1 -1
- package/dist/members/util.js +7 -2
- 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/reachability/index.js +3 -3
- package/dist/reachability/index.js.map +1 -1
- package/dist/types/common/errors/webex-errors.d.ts +12 -0
- package/dist/types/constants.d.ts +7 -0
- package/dist/types/controls-options-manager/index.d.ts +9 -1
- package/dist/types/index.d.ts +2 -1
- package/dist/types/interceptors/index.d.ts +2 -1
- package/dist/types/interceptors/locusRouteToken.d.ts +38 -0
- package/dist/types/locus-info/index.d.ts +56 -2
- package/dist/types/media/properties.d.ts +21 -0
- package/dist/types/meeting/in-meeting-actions.d.ts +8 -0
- package/dist/types/meeting/index.d.ts +41 -1
- package/dist/types/meeting/request.d.ts +42 -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/index.d.ts +1 -0
- package/dist/types/member/types.d.ts +1 -0
- package/dist/types/member/util.d.ts +5 -0
- package/dist/types/members/collection.d.ts +6 -0
- package/dist/types/members/index.d.ts +12 -2
- package/dist/types/members/util.d.ts +6 -3
- package/dist/types/metrics/constants.d.ts +1 -0
- package/dist/webinar/index.js +1 -1
- package/package.json +24 -24
- package/src/common/errors/webex-errors.ts +19 -0
- package/src/constants.ts +10 -0
- package/src/controls-options-manager/index.ts +26 -5
- package/src/index.ts +4 -1
- package/src/interceptors/index.ts +2 -1
- package/src/interceptors/locusRouteToken.ts +80 -0
- package/src/locus-info/controlsUtils.ts +18 -0
- package/src/locus-info/index.ts +99 -17
- package/src/locus-info/parser.ts +5 -1
- package/src/media/index.ts +6 -0
- package/src/media/properties.ts +43 -0
- package/src/meeting/in-meeting-actions.ts +16 -0
- package/src/meeting/index.ts +207 -25
- package/src/meeting/muteState.ts +2 -6
- package/src/meeting/request.ts +141 -0
- package/src/meeting/util.ts +50 -20
- package/src/meeting-info/meeting-info-v2.ts +24 -5
- package/src/meetings/index.ts +9 -3
- package/src/member/index.ts +10 -0
- package/src/member/types.ts +1 -0
- package/src/member/util.ts +14 -0
- package/src/members/collection.ts +11 -0
- package/src/members/index.ts +38 -5
- package/src/members/util.ts +18 -2
- package/src/metrics/constants.ts +1 -0
- package/src/reachability/index.ts +3 -3
- package/test/unit/spec/common/browser-detection.js +0 -24
- package/test/unit/spec/controls-options-manager/index.js +47 -0
- package/test/unit/spec/fixture/locus.js +1 -0
- package/test/unit/spec/interceptors/locusRouteToken.ts +87 -0
- package/test/unit/spec/locus-info/index.js +91 -15
- package/test/unit/spec/locus-info/parser.js +3 -2
- package/test/unit/spec/media/index.ts +140 -9
- package/test/unit/spec/media/properties.ts +137 -0
- package/test/unit/spec/meeting/in-meeting-actions.ts +8 -0
- package/test/unit/spec/meeting/index.js +469 -88
- package/test/unit/spec/meeting/muteState.js +32 -6
- package/test/unit/spec/meeting/request.js +21 -0
- package/test/unit/spec/meeting/utils.js +48 -16
- package/test/unit/spec/meeting-info/meetinginfov2.js +8 -3
- package/test/unit/spec/meetings/index.js +10 -7
- package/test/unit/spec/member/util.js +24 -0
- package/test/unit/spec/members/collection.js +120 -0
- package/test/unit/spec/members/index.js +72 -3
- package/test/unit/spec/members/request.js +55 -0
- package/test/unit/spec/members/utils.js +116 -14
- package/test/unit/spec/reachability/index.ts +158 -3
- package/test/unit/spec/roap/turnDiscovery.ts +3 -3
package/src/meeting/index.ts
CHANGED
|
@@ -28,6 +28,9 @@ import {
|
|
|
28
28
|
StatsAnalyzerEventNames,
|
|
29
29
|
NetworkQualityEventNames,
|
|
30
30
|
NetworkQualityMonitor,
|
|
31
|
+
StatsMonitor,
|
|
32
|
+
StatsMonitorEventNames,
|
|
33
|
+
InboundAudioIssueSubTypes,
|
|
31
34
|
} from '@webex/internal-media-core';
|
|
32
35
|
|
|
33
36
|
import {
|
|
@@ -55,6 +58,7 @@ import {
|
|
|
55
58
|
NoMediaEstablishedYetError,
|
|
56
59
|
UserNotJoinedError,
|
|
57
60
|
AddMediaFailed,
|
|
61
|
+
SdpResponseTimeoutError,
|
|
58
62
|
} from '../common/errors/webex-errors';
|
|
59
63
|
|
|
60
64
|
import LoggerProxy from '../common/logs/logger-proxy';
|
|
@@ -269,6 +273,7 @@ export enum ScreenShareFloorStatus {
|
|
|
269
273
|
type FetchMeetingInfoParams = {
|
|
270
274
|
password?: string;
|
|
271
275
|
registrationId?: string;
|
|
276
|
+
classificationId?: string;
|
|
272
277
|
captchaCode?: string;
|
|
273
278
|
extraParams?: Record<string, any>;
|
|
274
279
|
sendCAevents?: boolean;
|
|
@@ -633,6 +638,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
633
638
|
shareStatus: string;
|
|
634
639
|
screenShareFloorState: ScreenShareFloorStatus;
|
|
635
640
|
statsAnalyzer: StatsAnalyzer;
|
|
641
|
+
statsMonitor: StatsMonitor;
|
|
636
642
|
transcription: Transcription;
|
|
637
643
|
updateMediaConnections: (mediaConnections: any[]) => void;
|
|
638
644
|
userDisplayHints: any;
|
|
@@ -1286,6 +1292,13 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1286
1292
|
* @memberof Meeting
|
|
1287
1293
|
*/
|
|
1288
1294
|
this.networkQualityMonitor = null;
|
|
1295
|
+
/**
|
|
1296
|
+
* @instance
|
|
1297
|
+
* @type {StatsMonitor}
|
|
1298
|
+
* @private
|
|
1299
|
+
* @memberof Meeting
|
|
1300
|
+
*/
|
|
1301
|
+
this.statsMonitor = null;
|
|
1289
1302
|
/**
|
|
1290
1303
|
* Indicates network status of the webrtc media connection
|
|
1291
1304
|
* @instance
|
|
@@ -1902,6 +1915,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1902
1915
|
extraParams = {},
|
|
1903
1916
|
sendCAevents = false,
|
|
1904
1917
|
registrationId = null,
|
|
1918
|
+
classificationId = null,
|
|
1905
1919
|
}): Promise<void> {
|
|
1906
1920
|
try {
|
|
1907
1921
|
const captchaInfo = captchaCode
|
|
@@ -1918,7 +1932,9 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1918
1932
|
this.locusId,
|
|
1919
1933
|
extraParams,
|
|
1920
1934
|
{meetingId: this.id, sendCAevents},
|
|
1921
|
-
registrationId
|
|
1935
|
+
registrationId,
|
|
1936
|
+
null,
|
|
1937
|
+
classificationId
|
|
1922
1938
|
);
|
|
1923
1939
|
|
|
1924
1940
|
this.parseMeetingInfo(info?.body, this.destination, info?.errors);
|
|
@@ -2962,6 +2978,18 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2962
2978
|
);
|
|
2963
2979
|
});
|
|
2964
2980
|
|
|
2981
|
+
this.locusInfo.on(LOCUSINFO.EVENTS.CONTROLS_AUTO_END_MEETING_WARNING_CHANGED, ({state}) => {
|
|
2982
|
+
Trigger.trigger(
|
|
2983
|
+
this,
|
|
2984
|
+
{
|
|
2985
|
+
file: 'meeting/index',
|
|
2986
|
+
function: 'setupLocusControlsListener',
|
|
2987
|
+
},
|
|
2988
|
+
EVENT_TRIGGERS.MEETING_CONTROLS_AUTO_END_MEETING_WARNING_UPDATED,
|
|
2989
|
+
{state}
|
|
2990
|
+
);
|
|
2991
|
+
});
|
|
2992
|
+
|
|
2965
2993
|
this.locusInfo.on(LOCUSINFO.EVENTS.CONTROLS_ANNOTATION_CHANGED, ({state}) => {
|
|
2966
2994
|
Trigger.trigger(
|
|
2967
2995
|
this,
|
|
@@ -3149,6 +3177,23 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3149
3177
|
},
|
|
3150
3178
|
EVENT_TRIGGERS.MEETING_STOPPED_SHARING_WHITEBOARD
|
|
3151
3179
|
);
|
|
3180
|
+
// @ts-ignore
|
|
3181
|
+
this.webex.internal.newMetrics.callDiagnosticLatencies.saveTimestamp({
|
|
3182
|
+
key: 'internal.client.share.stopped',
|
|
3183
|
+
});
|
|
3184
|
+
// @ts-ignore
|
|
3185
|
+
this.webex.internal.newMetrics.submitClientEvent({
|
|
3186
|
+
name: 'client.share.stopped',
|
|
3187
|
+
payload: {
|
|
3188
|
+
mediaType: 'whiteboard',
|
|
3189
|
+
shareDuration:
|
|
3190
|
+
// @ts-ignore
|
|
3191
|
+
this.webex.internal.newMetrics.callDiagnosticLatencies.getShareDuration(),
|
|
3192
|
+
},
|
|
3193
|
+
options: {
|
|
3194
|
+
meetingId: this.id,
|
|
3195
|
+
},
|
|
3196
|
+
});
|
|
3152
3197
|
break;
|
|
3153
3198
|
|
|
3154
3199
|
case SHARE_STATUS.NO_SHARE:
|
|
@@ -3167,6 +3212,14 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3167
3212
|
this.shareCAEventSentStatus.receiveStart = false;
|
|
3168
3213
|
this.shareCAEventSentStatus.receiveStop = false;
|
|
3169
3214
|
|
|
3215
|
+
let finalBeneficiaryId = contentShare.beneficiaryId;
|
|
3216
|
+
// In case of attendee in webinar, the whiteboard is shared by other participants
|
|
3217
|
+
if (this.locusInfo?.info?.isWebinar && this.webinar?.selfIsAttendee) {
|
|
3218
|
+
if (!finalBeneficiaryId && whiteboardShare.beneficiaryId) {
|
|
3219
|
+
finalBeneficiaryId = whiteboardShare.beneficiaryId;
|
|
3220
|
+
}
|
|
3221
|
+
}
|
|
3222
|
+
|
|
3170
3223
|
Trigger.trigger(
|
|
3171
3224
|
this,
|
|
3172
3225
|
{
|
|
@@ -3175,7 +3228,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3175
3228
|
},
|
|
3176
3229
|
EVENT_TRIGGERS.MEETING_STARTED_SHARING_REMOTE,
|
|
3177
3230
|
{
|
|
3178
|
-
memberId:
|
|
3231
|
+
memberId: finalBeneficiaryId,
|
|
3179
3232
|
url: contentShare.url,
|
|
3180
3233
|
shareInstanceId: this.remoteShareInstanceId,
|
|
3181
3234
|
annotationInfo: contentShare.annotation,
|
|
@@ -3317,27 +3370,31 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3317
3370
|
* @memberof Meeting
|
|
3318
3371
|
*/
|
|
3319
3372
|
private setUpLocusUrlListener() {
|
|
3320
|
-
this.locusInfo.on(
|
|
3321
|
-
|
|
3322
|
-
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
|
|
3329
|
-
|
|
3373
|
+
this.locusInfo.on(
|
|
3374
|
+
EVENTS.LOCUS_INFO_UPDATE_URL,
|
|
3375
|
+
(payload: {url: string; isMainLocus?: boolean}) => {
|
|
3376
|
+
const {url, isMainLocus} = payload;
|
|
3377
|
+
this.members.locusUrlUpdate(url);
|
|
3378
|
+
this.breakouts.locusUrlUpdate(url);
|
|
3379
|
+
this.simultaneousInterpretation.locusUrlUpdate(url);
|
|
3380
|
+
this.annotation.locusUrlUpdate(url);
|
|
3381
|
+
this.locusUrl = url;
|
|
3382
|
+
this.locusId = this.locusUrl?.split('/').pop();
|
|
3383
|
+
this.recordingController.setLocusUrl(this.locusUrl);
|
|
3384
|
+
this.controlsOptionsManager.setLocusUrl(this.locusUrl, !!isMainLocus);
|
|
3385
|
+
this.webinar.locusUrlUpdate(url);
|
|
3330
3386
|
|
|
3331
|
-
|
|
3332
|
-
|
|
3333
|
-
|
|
3334
|
-
|
|
3335
|
-
|
|
3336
|
-
|
|
3337
|
-
|
|
3338
|
-
|
|
3339
|
-
|
|
3340
|
-
|
|
3387
|
+
Trigger.trigger(
|
|
3388
|
+
this,
|
|
3389
|
+
{
|
|
3390
|
+
file: 'meeting/index',
|
|
3391
|
+
function: 'setUpLocusSelfListener',
|
|
3392
|
+
},
|
|
3393
|
+
EVENT_TRIGGERS.MEETING_LOCUS_URL_UPDATE,
|
|
3394
|
+
{locusUrl: url}
|
|
3395
|
+
);
|
|
3396
|
+
}
|
|
3397
|
+
);
|
|
3341
3398
|
}
|
|
3342
3399
|
|
|
3343
3400
|
/**
|
|
@@ -4180,6 +4237,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4180
4237
|
this.userDisplayHints,
|
|
4181
4238
|
this.selfUserPolicies
|
|
4182
4239
|
),
|
|
4240
|
+
showAutoEndMeetingWarning: MeetingUtil.showAutoEndMeetingWarning(this.userDisplayHints),
|
|
4183
4241
|
canRaiseHand: MeetingUtil.canUserRaiseHand(this.userDisplayHints),
|
|
4184
4242
|
canLowerAllHands: MeetingUtil.canUserLowerAllHands(this.userDisplayHints),
|
|
4185
4243
|
canLowerSomeoneElsesHand: MeetingUtil.canUserLowerSomeoneElsesHand(this.userDisplayHints),
|
|
@@ -4195,8 +4253,13 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4195
4253
|
isLocalRecordingStarted: MeetingUtil.isLocalRecordingStarted(this.userDisplayHints),
|
|
4196
4254
|
isLocalRecordingStopped: MeetingUtil.isLocalRecordingStopped(this.userDisplayHints),
|
|
4197
4255
|
isLocalRecordingPaused: MeetingUtil.isLocalRecordingPaused(this.userDisplayHints),
|
|
4256
|
+
isLocalStreamingStarted: MeetingUtil.isLocalStreamingStarted(this.userDisplayHints),
|
|
4257
|
+
isLocalStreamingStopped: MeetingUtil.isLocalStreamingStopped(this.userDisplayHints),
|
|
4198
4258
|
isManualCaptionActive: MeetingUtil.isManualCaptionActive(this.userDisplayHints),
|
|
4199
4259
|
isSaveTranscriptsEnabled: MeetingUtil.isSaveTranscriptsEnabled(this.userDisplayHints),
|
|
4260
|
+
isSpokenLanguageAutoDetectionEnabled: MeetingUtil.isSpokenLanguageAutoDetectionEnabled(
|
|
4261
|
+
this.userDisplayHints
|
|
4262
|
+
),
|
|
4200
4263
|
isWebexAssistantActive: MeetingUtil.isWebexAssistantActive(this.userDisplayHints),
|
|
4201
4264
|
canViewCaptionPanel: MeetingUtil.canViewCaptionPanel(this.userDisplayHints),
|
|
4202
4265
|
isRealTimeTranslationEnabled: MeetingUtil.isRealTimeTranslationEnabled(
|
|
@@ -6779,6 +6842,10 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
6779
6842
|
// @ts-ignore
|
|
6780
6843
|
this.webex.internal.newMetrics.submitClientEvent({
|
|
6781
6844
|
name: 'client.ice.start',
|
|
6845
|
+
payload: {
|
|
6846
|
+
// @ts-ignore
|
|
6847
|
+
labels: MeetingUtil.getCaEventLabelsForIpVersion(this.webex),
|
|
6848
|
+
},
|
|
6782
6849
|
options: {
|
|
6783
6850
|
meetingId: this.id,
|
|
6784
6851
|
},
|
|
@@ -6948,10 +7015,10 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
6948
7015
|
}
|
|
6949
7016
|
}
|
|
6950
7017
|
|
|
6951
|
-
// Count members that are in the meeting.
|
|
7018
|
+
// Count members that are in the meeting or in the lobby.
|
|
6952
7019
|
const {members} = this.getMembers().membersCollection;
|
|
6953
7020
|
event.data.intervalMetadata.meetingUserCount = Object.values(members).filter(
|
|
6954
|
-
(member: Member) => member.isInMeeting
|
|
7021
|
+
(member: Member) => member.isInMeeting || member.isInLobby
|
|
6955
7022
|
).length;
|
|
6956
7023
|
|
|
6957
7024
|
// @ts-ignore
|
|
@@ -7310,10 +7377,12 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
7310
7377
|
if (this.config.stats.enableStatsAnalyzer) {
|
|
7311
7378
|
// @ts-ignore - config coming from registerPlugin
|
|
7312
7379
|
this.networkQualityMonitor = new NetworkQualityMonitor(this.config.stats);
|
|
7380
|
+
this.statsMonitor = new StatsMonitor();
|
|
7313
7381
|
this.statsAnalyzer = new StatsAnalyzer({
|
|
7314
7382
|
// @ts-ignore - config coming from registerPlugin
|
|
7315
7383
|
config: this.config.stats,
|
|
7316
7384
|
networkQualityMonitor: this.networkQualityMonitor,
|
|
7385
|
+
statsMonitor: this.statsMonitor,
|
|
7317
7386
|
isMultistream: this.isMultistream,
|
|
7318
7387
|
});
|
|
7319
7388
|
this.shareCAEventSentStatus = {
|
|
@@ -7327,6 +7396,33 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
7327
7396
|
NetworkQualityEventNames.NETWORK_QUALITY,
|
|
7328
7397
|
this.sendNetworkQualityEvent.bind(this)
|
|
7329
7398
|
);
|
|
7399
|
+
|
|
7400
|
+
this.statsMonitor.on(StatsMonitorEventNames.INBOUND_AUDIO_ISSUE, (data) => {
|
|
7401
|
+
// Before forwarding any inbound audio issues to the app, make sure that we have at least one other
|
|
7402
|
+
// participant in the meeting with unmuted audio.
|
|
7403
|
+
// We don't check this.mediaProperties.mediaDirection here, because that's already handled in statsAnalyzer,
|
|
7404
|
+
// so we won't get this event if we are not setup to receive any audio
|
|
7405
|
+
const atLeastOneUnmutedOtherMember = Object.values(
|
|
7406
|
+
this.members.membersCollection.getAll()
|
|
7407
|
+
).find((member) => {
|
|
7408
|
+
return !member.isSelf && !member.isPairedWithSelf && !member.isAudioMuted;
|
|
7409
|
+
});
|
|
7410
|
+
|
|
7411
|
+
if (atLeastOneUnmutedOtherMember) {
|
|
7412
|
+
this.mediaProperties.sendMediaIssueMetric(
|
|
7413
|
+
'inbound_audio',
|
|
7414
|
+
data.issueSubType,
|
|
7415
|
+
this.correlationId
|
|
7416
|
+
);
|
|
7417
|
+
|
|
7418
|
+
Trigger.trigger(
|
|
7419
|
+
this,
|
|
7420
|
+
{file: 'meeting/index', function: 'createStatsAnalyzer'},
|
|
7421
|
+
EVENT_TRIGGERS.MEDIA_INBOUND_AUDIO_ISSUE_DETECTED,
|
|
7422
|
+
data
|
|
7423
|
+
);
|
|
7424
|
+
}
|
|
7425
|
+
});
|
|
7330
7426
|
}
|
|
7331
7427
|
}
|
|
7332
7428
|
|
|
@@ -7357,7 +7453,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
7357
7453
|
} seconds`
|
|
7358
7454
|
);
|
|
7359
7455
|
|
|
7360
|
-
const error = new
|
|
7456
|
+
const error = new SdpResponseTimeoutError();
|
|
7361
7457
|
|
|
7362
7458
|
// @ts-ignore
|
|
7363
7459
|
this.webex.internal.newMetrics.submitClientEvent({
|
|
@@ -7625,6 +7721,10 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
7625
7721
|
}
|
|
7626
7722
|
|
|
7627
7723
|
this.statsAnalyzer = null;
|
|
7724
|
+
this.networkQualityMonitor?.removeAllListeners();
|
|
7725
|
+
this.networkQualityMonitor = null;
|
|
7726
|
+
this.statsMonitor?.removeAllListeners();
|
|
7727
|
+
this.statsMonitor = null;
|
|
7628
7728
|
|
|
7629
7729
|
// when media fails, we want to upload a webrtc dump to see whats going on
|
|
7630
7730
|
// this function is async, but returns once the stats have been gathered
|
|
@@ -7648,6 +7748,10 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
7648
7748
|
await this.statsAnalyzer.stopAnalyzer();
|
|
7649
7749
|
}
|
|
7650
7750
|
this.statsAnalyzer = null;
|
|
7751
|
+
this.networkQualityMonitor?.removeAllListeners();
|
|
7752
|
+
this.networkQualityMonitor = null;
|
|
7753
|
+
this.statsMonitor?.removeAllListeners();
|
|
7754
|
+
this.statsMonitor = null;
|
|
7651
7755
|
|
|
7652
7756
|
this.isMultistream = false;
|
|
7653
7757
|
|
|
@@ -7819,6 +7923,9 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
7819
7923
|
|
|
7820
7924
|
this.allowMediaInLobby = options?.allowMediaInLobby;
|
|
7821
7925
|
|
|
7926
|
+
// @ts-ignore
|
|
7927
|
+
const ipver = MeetingUtil.getIpVersion(this.webex); // used just for metrics
|
|
7928
|
+
|
|
7822
7929
|
// If the user is unjoined or guest waiting in lobby dont allow the user to addMedia
|
|
7823
7930
|
// @ts-ignore - isUserUnadmitted coming from SelfUtil
|
|
7824
7931
|
if (this.isUserUnadmitted && !this.wirelessShare && !this.allowMediaInLobby) {
|
|
@@ -7917,6 +8024,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
7917
8024
|
locus_id: this.locusUrl.split('/').pop(),
|
|
7918
8025
|
connectionType,
|
|
7919
8026
|
ipVersion,
|
|
8027
|
+
ipver,
|
|
7920
8028
|
selectedCandidatePairChanges,
|
|
7921
8029
|
numTransports,
|
|
7922
8030
|
isMultistream: this.isMultistream,
|
|
@@ -7985,6 +8093,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
7985
8093
|
...reachabilityMetrics,
|
|
7986
8094
|
...iceCandidateErrors,
|
|
7987
8095
|
iceCandidatesCount: this.iceCandidatesCount,
|
|
8096
|
+
ipver,
|
|
7988
8097
|
});
|
|
7989
8098
|
|
|
7990
8099
|
await this.cleanUpOnAddMediaFailure();
|
|
@@ -9361,6 +9470,36 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
9361
9470
|
return Promise.reject(new Error('Error sending reaction, service url not found.'));
|
|
9362
9471
|
}
|
|
9363
9472
|
|
|
9473
|
+
/**
|
|
9474
|
+
* Extend the current meeting duration.
|
|
9475
|
+
*
|
|
9476
|
+
* @param {number} extensionMinutes - how many minutes to extend
|
|
9477
|
+
* @returns {Promise}
|
|
9478
|
+
* @public
|
|
9479
|
+
* @memberof Meeting
|
|
9480
|
+
*/
|
|
9481
|
+
public extendMeeting({
|
|
9482
|
+
meetingPolicyUrl,
|
|
9483
|
+
meetingInstanceId,
|
|
9484
|
+
participantId,
|
|
9485
|
+
extensionMinutes = 30,
|
|
9486
|
+
}) {
|
|
9487
|
+
if (!meetingInstanceId || !participantId) {
|
|
9488
|
+
return Promise.reject(new Error('Missing meetingInstanceId or participantId'));
|
|
9489
|
+
}
|
|
9490
|
+
|
|
9491
|
+
if (!meetingPolicyUrl) {
|
|
9492
|
+
return Promise.reject(new Error('Missing meetingPolicyUrl'));
|
|
9493
|
+
}
|
|
9494
|
+
|
|
9495
|
+
return this.meetingRequest.extendMeeting({
|
|
9496
|
+
meetingInstanceId,
|
|
9497
|
+
participantId,
|
|
9498
|
+
extensionMinutes,
|
|
9499
|
+
meetingPolicyUrl,
|
|
9500
|
+
});
|
|
9501
|
+
}
|
|
9502
|
+
|
|
9364
9503
|
/**
|
|
9365
9504
|
* Method to enable or disable reactions inside the meeting.
|
|
9366
9505
|
*
|
|
@@ -9890,4 +10029,47 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
9890
10029
|
|
|
9891
10030
|
return this.meetingRequest.synchronizeStage(this.locusUrl, videoLayout);
|
|
9892
10031
|
}
|
|
10032
|
+
|
|
10033
|
+
/**
|
|
10034
|
+
* Notifies the host with the given meeting UUID and display names.
|
|
10035
|
+
*
|
|
10036
|
+
* @param {string} meetingUuid - The UUID of the meeting.
|
|
10037
|
+
* @param {string[]} displayName - An array of display names to notify the host with.
|
|
10038
|
+
* @returns {Promise<any>} The result of the notifyHost request.
|
|
10039
|
+
*/
|
|
10040
|
+
notifyHost(meetingUuid: string, displayName: string[]) {
|
|
10041
|
+
return this.meetingRequest.notifyHost(
|
|
10042
|
+
this.meetingInfo.siteFullUrl,
|
|
10043
|
+
this.locusId,
|
|
10044
|
+
meetingUuid,
|
|
10045
|
+
displayName
|
|
10046
|
+
);
|
|
10047
|
+
}
|
|
10048
|
+
|
|
10049
|
+
/**
|
|
10050
|
+
* Call out a SIP participant to a meeting
|
|
10051
|
+
* @param {string} address - The SIP address or phone number
|
|
10052
|
+
* @param {string} displayName - The display name for the participant
|
|
10053
|
+
* @param {string} [correlationId] - Optional correlation ID
|
|
10054
|
+
* @returns {Promise} Promise that resolves when the call-out is initiated
|
|
10055
|
+
*/
|
|
10056
|
+
sipCallOut(address: string, displayName: string) {
|
|
10057
|
+
return this.meetingRequest.sipCallOut(
|
|
10058
|
+
this.meetingInfo.meetingId,
|
|
10059
|
+
this.meetingInfo.meetingId,
|
|
10060
|
+
address,
|
|
10061
|
+
displayName
|
|
10062
|
+
);
|
|
10063
|
+
}
|
|
10064
|
+
|
|
10065
|
+
/**
|
|
10066
|
+
* Cancel an ongoing SIP call-out
|
|
10067
|
+
* @param {string} participantId - The participant ID to cancel
|
|
10068
|
+
* @returns {Promise} Promise that resolves when the call-out is cancelled
|
|
10069
|
+
* @public
|
|
10070
|
+
* @memberof Meetings
|
|
10071
|
+
*/
|
|
10072
|
+
cancelSipCallOut(participantId: string) {
|
|
10073
|
+
return this.meetingRequest.cancelSipCallOut(participantId);
|
|
10074
|
+
}
|
|
9893
10075
|
}
|
package/src/meeting/muteState.ts
CHANGED
|
@@ -291,18 +291,14 @@ export class MuteState {
|
|
|
291
291
|
);
|
|
292
292
|
|
|
293
293
|
return MeetingUtil.remoteUpdateAudioVideo(meeting, audioMuted, videoMuted)
|
|
294
|
-
.then((
|
|
294
|
+
.then((response) => {
|
|
295
295
|
LoggerProxy.logger.info(
|
|
296
296
|
`Meeting:muteState#sendLocalMuteRequestToServer --> ${this.type}: local mute (audio=${audioMuted}, video=${videoMuted}) applied to server`
|
|
297
297
|
);
|
|
298
298
|
|
|
299
299
|
this.state.server.localMute = this.type === AUDIO ? audioMuted : videoMuted;
|
|
300
300
|
|
|
301
|
-
|
|
302
|
-
meeting.locusInfo.handleLocusDelta(locus, meeting);
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
return locus;
|
|
301
|
+
return MeetingUtil.updateLocusFromApiResponse(meeting, response);
|
|
306
302
|
})
|
|
307
303
|
.catch((remoteUpdateError) => {
|
|
308
304
|
LoggerProxy.logger.warn(
|
package/src/meeting/request.ts
CHANGED
|
@@ -886,6 +886,44 @@ export default class MeetingRequest extends StatelessWebexPlugin {
|
|
|
886
886
|
});
|
|
887
887
|
}
|
|
888
888
|
|
|
889
|
+
/**
|
|
890
|
+
* Extend the current meeting duration.
|
|
891
|
+
*
|
|
892
|
+
* @param {Object} params - Parameters for extending the meeting.
|
|
893
|
+
* @param {string} params.meetingInstanceId - The unique ID of the meeting instance.
|
|
894
|
+
* @param {string} params.participantId - The ID of the participant requesting the extension.
|
|
895
|
+
* @param {number} params.extensionMinutes - The number of minutes to extend the meeting by.
|
|
896
|
+
* @param {string} params.meetingPolicyUrl - The base URL for meeting policy service (dynamic, from locus links)
|
|
897
|
+
* @returns {Promise<any>} A promise that resolves with the server response.
|
|
898
|
+
*/
|
|
899
|
+
extendMeeting({
|
|
900
|
+
meetingInstanceId,
|
|
901
|
+
participantId,
|
|
902
|
+
extensionMinutes,
|
|
903
|
+
meetingPolicyUrl,
|
|
904
|
+
}: {
|
|
905
|
+
meetingInstanceId: string;
|
|
906
|
+
participantId: string;
|
|
907
|
+
extensionMinutes: number;
|
|
908
|
+
meetingPolicyUrl: string;
|
|
909
|
+
}) {
|
|
910
|
+
if (!meetingPolicyUrl) {
|
|
911
|
+
return Promise.reject(new Error('meetingPolicyUrl is required'));
|
|
912
|
+
}
|
|
913
|
+
const uri = `${meetingPolicyUrl}/continueMeeting`;
|
|
914
|
+
|
|
915
|
+
// @ts-ignore
|
|
916
|
+
return this.request({
|
|
917
|
+
method: HTTP_VERBS.POST,
|
|
918
|
+
uri,
|
|
919
|
+
body: {
|
|
920
|
+
meetingInstanceId,
|
|
921
|
+
requestParticipantId: participantId,
|
|
922
|
+
extensionMinutes,
|
|
923
|
+
},
|
|
924
|
+
});
|
|
925
|
+
}
|
|
926
|
+
|
|
889
927
|
/**
|
|
890
928
|
* Make a network request to enable or disable reactions.
|
|
891
929
|
* @param {boolean} options.enable - determines if we need to enable or disable.
|
|
@@ -985,4 +1023,107 @@ export default class MeetingRequest extends StatelessWebexPlugin {
|
|
|
985
1023
|
body: {videoLayout},
|
|
986
1024
|
});
|
|
987
1025
|
}
|
|
1026
|
+
|
|
1027
|
+
/**
|
|
1028
|
+
* Sends a request to notify the host of a meeting.
|
|
1029
|
+
* @param {string} siteFullUrl - The site URL.
|
|
1030
|
+
* @param {string} locusId - The locus ID.
|
|
1031
|
+
* @param {string} meetingUuid - The meeting UUID.
|
|
1032
|
+
* @param {Array<string>} displayName - The display names to notify the host about.
|
|
1033
|
+
* @returns {Promise}
|
|
1034
|
+
*/
|
|
1035
|
+
notifyHost(siteFullUrl: string, locusId: string, meetingUuid: string, displayName: string[]) {
|
|
1036
|
+
// @ts-ignore
|
|
1037
|
+
return this.request({
|
|
1038
|
+
method: HTTP_VERBS.POST,
|
|
1039
|
+
uri: `https://${siteFullUrl}/wbxappapi/v1/meetings/${meetingUuid}/notifyhost`,
|
|
1040
|
+
body: {
|
|
1041
|
+
displayName,
|
|
1042
|
+
size: displayName?.length,
|
|
1043
|
+
},
|
|
1044
|
+
headers: {
|
|
1045
|
+
locusId,
|
|
1046
|
+
},
|
|
1047
|
+
});
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
/**
|
|
1051
|
+
* Call out to a SIP participant
|
|
1052
|
+
*
|
|
1053
|
+
* @param {any} meetingId - The meeting ID.
|
|
1054
|
+
* @param {any} meetingNumber - The meeting number.
|
|
1055
|
+
* @param {string} address - The SIP address to call out.
|
|
1056
|
+
* @param {string} displayName - The display name for the participant.
|
|
1057
|
+
* @returns {Promise} The API response
|
|
1058
|
+
*/
|
|
1059
|
+
public async sipCallOut(meetingId, meetingNumber, address, displayName) {
|
|
1060
|
+
const body: any = {
|
|
1061
|
+
meetingId,
|
|
1062
|
+
meetingNumber,
|
|
1063
|
+
address,
|
|
1064
|
+
displayName,
|
|
1065
|
+
};
|
|
1066
|
+
try {
|
|
1067
|
+
// @ts-ignore
|
|
1068
|
+
const response = await this.request({
|
|
1069
|
+
method: HTTP_VERBS.POST,
|
|
1070
|
+
service: 'hydra',
|
|
1071
|
+
resource: 'meetingParticipants/callout',
|
|
1072
|
+
body,
|
|
1073
|
+
headers: {
|
|
1074
|
+
Accept: 'application/json',
|
|
1075
|
+
},
|
|
1076
|
+
});
|
|
1077
|
+
|
|
1078
|
+
LoggerProxy.logger.info('Meetings:request#sipCallOut --> SIP call-out successful', response);
|
|
1079
|
+
|
|
1080
|
+
return response.body;
|
|
1081
|
+
} catch (err) {
|
|
1082
|
+
LoggerProxy.logger.error(
|
|
1083
|
+
`Meetings:request#sipCallOut --> Error calling out SIP participant, error ${JSON.stringify(
|
|
1084
|
+
err
|
|
1085
|
+
)}`
|
|
1086
|
+
);
|
|
1087
|
+
throw err;
|
|
1088
|
+
}
|
|
1089
|
+
}
|
|
1090
|
+
|
|
1091
|
+
/**
|
|
1092
|
+
* Cancel an ongoing SIP call-out
|
|
1093
|
+
*
|
|
1094
|
+
* @param {string} participantId - The ID of the participant whose SIP call-out should be cancelled.
|
|
1095
|
+
* @returns {Promise} The API response
|
|
1096
|
+
*/
|
|
1097
|
+
public async cancelSipCallOut(participantId) {
|
|
1098
|
+
const body = {
|
|
1099
|
+
participantId,
|
|
1100
|
+
};
|
|
1101
|
+
|
|
1102
|
+
try {
|
|
1103
|
+
// @ts-ignore
|
|
1104
|
+
const response = await this.request({
|
|
1105
|
+
method: HTTP_VERBS.POST,
|
|
1106
|
+
service: 'hydra',
|
|
1107
|
+
resource: 'meetingParticipants/cancelCallout',
|
|
1108
|
+
body,
|
|
1109
|
+
headers: {
|
|
1110
|
+
Accept: 'application/json',
|
|
1111
|
+
},
|
|
1112
|
+
});
|
|
1113
|
+
|
|
1114
|
+
LoggerProxy.logger.info(
|
|
1115
|
+
'Meetings:request#cancelSipCallOut --> SIP call-out cancelled successfully',
|
|
1116
|
+
response
|
|
1117
|
+
);
|
|
1118
|
+
|
|
1119
|
+
return response.body;
|
|
1120
|
+
} catch (err) {
|
|
1121
|
+
LoggerProxy.logger.error(
|
|
1122
|
+
`Meetings:request#cancelSipCallOut --> Error cancelling SIP participant call-out, error ${JSON.stringify(
|
|
1123
|
+
err
|
|
1124
|
+
)}`
|
|
1125
|
+
);
|
|
1126
|
+
throw err;
|
|
1127
|
+
}
|
|
1128
|
+
}
|
|
988
1129
|
}
|