@webex/plugin-meetings 3.11.0-webex-services-ready.1 → 3.12.0
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/aiEnableRequest/index.js +184 -0
- package/dist/aiEnableRequest/index.js.map +1 -0
- package/dist/aiEnableRequest/utils.js +36 -0
- package/dist/aiEnableRequest/utils.js.map +1 -0
- package/dist/annotation/index.js +14 -5
- package/dist/annotation/index.js.map +1 -1
- package/dist/breakouts/breakout.js +1 -1
- package/dist/breakouts/index.js +1 -1
- package/dist/config.js +5 -1
- package/dist/config.js.map +1 -1
- package/dist/constants.js +28 -6
- package/dist/constants.js.map +1 -1
- package/dist/hashTree/constants.js +3 -1
- package/dist/hashTree/constants.js.map +1 -1
- package/dist/hashTree/hashTree.js +18 -0
- package/dist/hashTree/hashTree.js.map +1 -1
- package/dist/hashTree/hashTreeParser.js +709 -380
- package/dist/hashTree/hashTreeParser.js.map +1 -1
- package/dist/hashTree/types.js +4 -2
- package/dist/hashTree/types.js.map +1 -1
- package/dist/hashTree/utils.js +10 -0
- package/dist/hashTree/utils.js.map +1 -1
- package/dist/index.js +11 -2
- package/dist/index.js.map +1 -1
- package/dist/interceptors/constant.js +12 -0
- package/dist/interceptors/constant.js.map +1 -0
- package/dist/interceptors/dataChannelAuthToken.js +290 -0
- package/dist/interceptors/dataChannelAuthToken.js.map +1 -0
- package/dist/interceptors/index.js +7 -0
- package/dist/interceptors/index.js.map +1 -1
- package/dist/interceptors/utils.js +27 -0
- package/dist/interceptors/utils.js.map +1 -0
- package/dist/interpretation/index.js +2 -2
- package/dist/interpretation/index.js.map +1 -1
- package/dist/interpretation/siLanguage.js +1 -1
- package/dist/locus-info/controlsUtils.js +5 -3
- package/dist/locus-info/controlsUtils.js.map +1 -1
- package/dist/locus-info/index.js +217 -79
- package/dist/locus-info/index.js.map +1 -1
- package/dist/locus-info/selfUtils.js +1 -0
- package/dist/locus-info/selfUtils.js.map +1 -1
- package/dist/locus-info/types.js.map +1 -1
- package/dist/media/MediaConnectionAwaiter.js +57 -1
- package/dist/media/MediaConnectionAwaiter.js.map +1 -1
- package/dist/media/properties.js +4 -2
- package/dist/media/properties.js.map +1 -1
- package/dist/meeting/in-meeting-actions.js +7 -1
- package/dist/meeting/in-meeting-actions.js.map +1 -1
- package/dist/meeting/index.js +1071 -862
- package/dist/meeting/index.js.map +1 -1
- package/dist/meeting/request.js +50 -0
- package/dist/meeting/request.js.map +1 -1
- package/dist/meeting/request.type.js.map +1 -1
- package/dist/meeting/util.js +133 -3
- package/dist/meeting/util.js.map +1 -1
- package/dist/meetings/index.js +100 -45
- package/dist/meetings/index.js.map +1 -1
- package/dist/member/index.js +10 -0
- package/dist/member/index.js.map +1 -1
- package/dist/member/util.js +10 -0
- package/dist/member/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 +9 -60
- package/dist/multistream/mediaRequestManager.js.map +1 -1
- package/dist/multistream/remoteMediaManager.js +11 -0
- package/dist/multistream/remoteMediaManager.js.map +1 -1
- package/dist/reactions/reactions.type.js.map +1 -1
- package/dist/reconnection-manager/index.js +0 -1
- package/dist/reconnection-manager/index.js.map +1 -1
- package/dist/types/aiEnableRequest/index.d.ts +5 -0
- package/dist/types/aiEnableRequest/utils.d.ts +2 -0
- package/dist/types/config.d.ts +3 -0
- package/dist/types/constants.d.ts +23 -1
- package/dist/types/hashTree/constants.d.ts +1 -0
- package/dist/types/hashTree/hashTree.d.ts +7 -0
- package/dist/types/hashTree/hashTreeParser.d.ts +99 -14
- package/dist/types/hashTree/types.d.ts +3 -0
- package/dist/types/hashTree/utils.d.ts +6 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/interceptors/constant.d.ts +5 -0
- package/dist/types/interceptors/dataChannelAuthToken.d.ts +43 -0
- package/dist/types/interceptors/index.d.ts +2 -1
- package/dist/types/interceptors/utils.d.ts +1 -0
- package/dist/types/locus-info/index.d.ts +21 -2
- package/dist/types/locus-info/types.d.ts +1 -0
- package/dist/types/media/MediaConnectionAwaiter.d.ts +10 -1
- package/dist/types/media/properties.d.ts +2 -1
- package/dist/types/meeting/in-meeting-actions.d.ts +6 -0
- package/dist/types/meeting/index.d.ts +38 -6
- package/dist/types/meeting/request.d.ts +16 -1
- package/dist/types/meeting/request.type.d.ts +5 -0
- package/dist/types/meeting/util.d.ts +31 -0
- package/dist/types/meetings/index.d.ts +4 -2
- package/dist/types/member/index.d.ts +1 -0
- package/dist/types/member/util.d.ts +5 -0
- package/dist/types/metrics/constants.d.ts +1 -0
- package/dist/types/multistream/mediaRequestManager.d.ts +0 -23
- package/dist/types/reactions/reactions.type.d.ts +1 -0
- package/dist/types/webinar/utils.d.ts +6 -0
- package/dist/webinar/index.js +260 -90
- package/dist/webinar/index.js.map +1 -1
- package/dist/webinar/utils.js +25 -0
- package/dist/webinar/utils.js.map +1 -0
- package/package.json +24 -23
- package/src/aiEnableRequest/README.md +84 -0
- package/src/aiEnableRequest/index.ts +170 -0
- package/src/aiEnableRequest/utils.ts +25 -0
- package/src/annotation/index.ts +27 -7
- package/src/config.ts +3 -0
- package/src/constants.ts +29 -1
- package/src/hashTree/constants.ts +1 -0
- package/src/hashTree/hashTree.ts +17 -0
- package/src/hashTree/hashTreeParser.ts +627 -249
- package/src/hashTree/types.ts +4 -0
- package/src/hashTree/utils.ts +9 -0
- package/src/index.ts +8 -1
- package/src/interceptors/constant.ts +6 -0
- package/src/interceptors/dataChannelAuthToken.ts +170 -0
- package/src/interceptors/index.ts +2 -1
- package/src/interceptors/utils.ts +16 -0
- package/src/interpretation/index.ts +2 -2
- package/src/locus-info/controlsUtils.ts +11 -0
- package/src/locus-info/index.ts +231 -61
- package/src/locus-info/selfUtils.ts +1 -0
- package/src/locus-info/types.ts +1 -0
- package/src/media/MediaConnectionAwaiter.ts +41 -1
- package/src/media/properties.ts +3 -1
- package/src/meeting/in-meeting-actions.ts +12 -0
- package/src/meeting/index.ts +188 -43
- package/src/meeting/request.ts +42 -0
- package/src/meeting/request.type.ts +6 -0
- package/src/meeting/util.ts +160 -2
- package/src/meetings/index.ts +135 -41
- package/src/member/index.ts +10 -0
- package/src/member/util.ts +12 -0
- package/src/metrics/constants.ts +1 -0
- package/src/multistream/mediaRequestManager.ts +4 -54
- package/src/multistream/remoteMediaManager.ts +13 -0
- package/src/reactions/reactions.type.ts +1 -0
- package/src/reconnection-manager/index.ts +0 -1
- package/src/webinar/index.ts +162 -5
- package/src/webinar/utils.ts +16 -0
- package/test/unit/spec/aiEnableRequest/index.ts +981 -0
- package/test/unit/spec/aiEnableRequest/utils.ts +130 -0
- package/test/unit/spec/annotation/index.ts +69 -7
- package/test/unit/spec/hashTree/hashTree.ts +66 -0
- package/test/unit/spec/hashTree/hashTreeParser.ts +1869 -189
- package/test/unit/spec/interceptors/dataChannelAuthToken.ts +210 -0
- package/test/unit/spec/interceptors/utils.ts +75 -0
- package/test/unit/spec/locus-info/controlsUtils.js +29 -0
- package/test/unit/spec/locus-info/index.js +383 -46
- package/test/unit/spec/media/MediaConnectionAwaiter.ts +41 -1
- package/test/unit/spec/media/properties.ts +12 -3
- package/test/unit/spec/meeting/in-meeting-actions.ts +8 -2
- package/test/unit/spec/meeting/index.js +662 -85
- package/test/unit/spec/meeting/request.js +70 -0
- package/test/unit/spec/meeting/utils.js +438 -26
- package/test/unit/spec/meetings/index.js +652 -31
- package/test/unit/spec/member/index.js +28 -4
- package/test/unit/spec/member/util.js +65 -27
- package/test/unit/spec/multistream/mediaRequestManager.ts +2 -85
- package/test/unit/spec/multistream/remoteMediaManager.ts +30 -0
- package/test/unit/spec/reconnection-manager/index.js +4 -8
- package/test/unit/spec/webinar/index.ts +348 -36
- package/test/unit/spec/webinar/utils.ts +39 -0
|
@@ -32,6 +32,7 @@ interface IInMeetingActions {
|
|
|
32
32
|
canLowerAllHands?: boolean;
|
|
33
33
|
canLowerSomeoneElsesHand?: boolean;
|
|
34
34
|
bothLeaveAndEndMeetingAvailable?: boolean;
|
|
35
|
+
requireHostEndMeetingBeforeLeave?: boolean;
|
|
35
36
|
canEnableClosedCaption?: boolean;
|
|
36
37
|
canStartTranscribing?: boolean;
|
|
37
38
|
canStopTranscribing?: boolean;
|
|
@@ -117,6 +118,8 @@ interface IInMeetingActions {
|
|
|
117
118
|
canMoveToLobby?: boolean;
|
|
118
119
|
canEnablePollingQA?: boolean;
|
|
119
120
|
canDisablePollingQA?: boolean;
|
|
121
|
+
canAttendeeRequestAiAssistantEnabled?: boolean;
|
|
122
|
+
isAttendeeRequestAiAssistantDeclinedAll?: boolean;
|
|
120
123
|
}
|
|
121
124
|
|
|
122
125
|
/**
|
|
@@ -169,6 +172,8 @@ export default class InMeetingActions implements IInMeetingActions {
|
|
|
169
172
|
|
|
170
173
|
bothLeaveAndEndMeetingAvailable = null;
|
|
171
174
|
|
|
175
|
+
requireHostEndMeetingBeforeLeave = null;
|
|
176
|
+
|
|
172
177
|
canEnableClosedCaption = null;
|
|
173
178
|
|
|
174
179
|
canStartTranscribing = null;
|
|
@@ -337,6 +342,10 @@ export default class InMeetingActions implements IInMeetingActions {
|
|
|
337
342
|
|
|
338
343
|
canDisablePollingQA = null;
|
|
339
344
|
|
|
345
|
+
canAttendeeRequestAiAssistantEnabled = null;
|
|
346
|
+
|
|
347
|
+
isAttendeeRequestAiAssistantDeclinedAll = null;
|
|
348
|
+
|
|
340
349
|
/**
|
|
341
350
|
* Returns all meeting action options
|
|
342
351
|
* @returns {Object}
|
|
@@ -364,6 +373,7 @@ export default class InMeetingActions implements IInMeetingActions {
|
|
|
364
373
|
canLowerAllHands: this.canLowerAllHands,
|
|
365
374
|
canLowerSomeoneElsesHand: this.canLowerSomeoneElsesHand,
|
|
366
375
|
bothLeaveAndEndMeetingAvailable: this.bothLeaveAndEndMeetingAvailable,
|
|
376
|
+
requireHostEndMeetingBeforeLeave: this.requireHostEndMeetingBeforeLeave,
|
|
367
377
|
canEnableClosedCaption: this.canEnableClosedCaption,
|
|
368
378
|
canStartTranscribing: this.canStartTranscribing,
|
|
369
379
|
canStopTranscribing: this.canStopTranscribing,
|
|
@@ -448,6 +458,8 @@ export default class InMeetingActions implements IInMeetingActions {
|
|
|
448
458
|
canMoveToLobby: this.canMoveToLobby,
|
|
449
459
|
canEnablePollingQA: this.canEnablePollingQA,
|
|
450
460
|
canDisablePollingQA: this.canDisablePollingQA,
|
|
461
|
+
canAttendeeRequestAiAssistantEnabled: this.canAttendeeRequestAiAssistantEnabled,
|
|
462
|
+
isAttendeeRequestAiAssistantDeclinedAll: this.isAttendeeRequestAiAssistantDeclinedAll,
|
|
451
463
|
});
|
|
452
464
|
|
|
453
465
|
/**
|
package/src/meeting/index.ts
CHANGED
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
CALL_DIAGNOSTIC_CONFIG,
|
|
14
14
|
RtcMetrics,
|
|
15
15
|
} from '@webex/internal-plugin-metrics';
|
|
16
|
-
import {ClientEvent as RawClientEvent} from '@webex/event-dictionary-ts';
|
|
16
|
+
import type {ClientEvent as RawClientEvent} from '@webex/event-dictionary-ts';
|
|
17
17
|
|
|
18
18
|
import {
|
|
19
19
|
ConnectionState,
|
|
@@ -33,6 +33,8 @@ import {
|
|
|
33
33
|
InboundAudioIssueSubTypes,
|
|
34
34
|
} from '@webex/internal-media-core';
|
|
35
35
|
|
|
36
|
+
import {DataChannelTokenType} from '@webex/internal-plugin-llm';
|
|
37
|
+
|
|
36
38
|
import {
|
|
37
39
|
LocalStream,
|
|
38
40
|
LocalCameraStream,
|
|
@@ -179,8 +181,9 @@ import JoinForbiddenError from '../common/errors/join-forbidden-error';
|
|
|
179
181
|
import {ReachabilityMetrics} from '../reachability/reachability.types';
|
|
180
182
|
import {SetStageOptions, SetStageVideoLayout, UnsetStageVideoLayout} from './request.type';
|
|
181
183
|
import {Invitee} from './type';
|
|
182
|
-
import {DataSet} from '../hashTree/hashTreeParser';
|
|
184
|
+
import {DataSet, Metadata} from '../hashTree/hashTreeParser';
|
|
183
185
|
import {LocusDTO} from '../locus-info/types';
|
|
186
|
+
import AIEnableRequest from '../aiEnableRequest';
|
|
184
187
|
|
|
185
188
|
// default callback so we don't call an undefined function, but in practice it should never be used
|
|
186
189
|
const DEFAULT_ICE_PHASE_CALLBACK = () => 'JOIN_MEETING_FINAL';
|
|
@@ -250,6 +253,7 @@ export type AddMediaOptions = {
|
|
|
250
253
|
remoteMediaManagerConfig?: RemoteMediaManagerConfiguration; // applies only to multistream meetings
|
|
251
254
|
bundlePolicy?: BundlePolicy; // applies only to multistream meetings
|
|
252
255
|
allowMediaInLobby?: boolean; // allows adding media when in the lobby
|
|
256
|
+
allowPublishMediaInLobby?: boolean; // allows publishing media when in the lobby, if not specified, default value false is used
|
|
253
257
|
additionalMediaOptions?: AdditionalMediaOptions; // allows adding additional options like send/receive audio/video
|
|
254
258
|
};
|
|
255
259
|
|
|
@@ -575,6 +579,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
575
579
|
breakouts: any;
|
|
576
580
|
simultaneousInterpretation: any;
|
|
577
581
|
annotation: any;
|
|
582
|
+
aiEnableRequest: any;
|
|
578
583
|
webinar: any;
|
|
579
584
|
conversationUrl: string;
|
|
580
585
|
callStateForMetrics: CallStateForMetrics;
|
|
@@ -623,6 +628,13 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
623
628
|
keepAliveTimerId: NodeJS.Timeout;
|
|
624
629
|
lastVideoLayoutInfo: any;
|
|
625
630
|
locusInfo: any;
|
|
631
|
+
// this group of properties is populated via updateMeetingObject() that's registered as a callback with LocusInfo
|
|
632
|
+
isUserUnadmitted?: boolean;
|
|
633
|
+
joinedWith?: any;
|
|
634
|
+
selfId?: string;
|
|
635
|
+
roles: any[];
|
|
636
|
+
// ... there is more ... see SelfUtils.parse()
|
|
637
|
+
// end of the group
|
|
626
638
|
locusMediaRequest?: LocusMediaRequest;
|
|
627
639
|
mediaProperties: MediaProperties;
|
|
628
640
|
mediaRequestManagers: {
|
|
@@ -657,7 +669,6 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
657
669
|
endCallInitJoinReq: any;
|
|
658
670
|
endJoinReqResp: any;
|
|
659
671
|
endLocalSDPGenRemoteSDPRecvDelay: any;
|
|
660
|
-
joinedWith: any;
|
|
661
672
|
locusId: any;
|
|
662
673
|
startCallInitJoinReq: any;
|
|
663
674
|
startJoinReqResp: any;
|
|
@@ -672,12 +683,11 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
672
683
|
permissionTokenReceivedLocalTime: number;
|
|
673
684
|
resourceId: any;
|
|
674
685
|
resourceUrl: string;
|
|
675
|
-
selfId: string;
|
|
676
686
|
state: any;
|
|
677
687
|
localAudioStreamMuteStateHandler: () => void;
|
|
678
688
|
localVideoStreamMuteStateHandler: () => void;
|
|
679
689
|
localOutputTrackChangeHandler: () => void;
|
|
680
|
-
|
|
690
|
+
localConstraintsChangeHandler: () => void;
|
|
681
691
|
environment: string;
|
|
682
692
|
namespace = MEETINGS;
|
|
683
693
|
allowMediaInLobby: boolean;
|
|
@@ -894,6 +904,10 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
894
904
|
*/
|
|
895
905
|
// @ts-ignore
|
|
896
906
|
this.simultaneousInterpretation = new SimultaneousInterpretation({}, {parent: this.webex});
|
|
907
|
+
|
|
908
|
+
// @ts-ignore
|
|
909
|
+
this.aiEnableRequest = new AIEnableRequest({}, {parent: this.webex});
|
|
910
|
+
|
|
897
911
|
/**
|
|
898
912
|
* @instance
|
|
899
913
|
* @type {Annotation}
|
|
@@ -1543,6 +1557,12 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1543
1557
|
}
|
|
1544
1558
|
};
|
|
1545
1559
|
|
|
1560
|
+
this.localConstraintsChangeHandler = () => {
|
|
1561
|
+
if (!this.isMultistream) {
|
|
1562
|
+
this.mediaProperties.webrtcMediaConnection?.updatePreferredBitrateKbps();
|
|
1563
|
+
}
|
|
1564
|
+
};
|
|
1565
|
+
|
|
1546
1566
|
/**
|
|
1547
1567
|
* Promise that exists if SDP offer has been generated, and resolves once sdp answer is received.
|
|
1548
1568
|
* @instance
|
|
@@ -2952,6 +2972,18 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2952
2972
|
);
|
|
2953
2973
|
});
|
|
2954
2974
|
|
|
2975
|
+
this.locusInfo.on(
|
|
2976
|
+
LOCUSINFO.EVENTS.CONTROLS_AI_SUMMARY_NOTIFICATION_UPDATED,
|
|
2977
|
+
({aiSummaryNotification}) => {
|
|
2978
|
+
Trigger.trigger(
|
|
2979
|
+
this,
|
|
2980
|
+
{file: 'meeting/index', function: 'setupLocusControlsListener'},
|
|
2981
|
+
EVENT_TRIGGERS.MEETING_CONTROLS_AI_SUMMARY_NOTIFICATION_UPDATED,
|
|
2982
|
+
{aiSummaryNotification}
|
|
2983
|
+
);
|
|
2984
|
+
}
|
|
2985
|
+
);
|
|
2986
|
+
|
|
2955
2987
|
this.locusInfo.on(LOCUSINFO.EVENTS.CONTROLS_WEBCAST_CHANGED, ({state}) => {
|
|
2956
2988
|
Trigger.trigger(
|
|
2957
2989
|
this,
|
|
@@ -3403,6 +3435,8 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3403
3435
|
this.recordingController.setLocusUrl(this.locusUrl);
|
|
3404
3436
|
this.controlsOptionsManager.setLocusUrl(this.locusUrl, !!isMainLocus);
|
|
3405
3437
|
this.webinar.locusUrlUpdate(url);
|
|
3438
|
+
// @ts-ignore
|
|
3439
|
+
this.webex.internal.llm.setRefreshHandler(() => this.refreshDataChannelToken());
|
|
3406
3440
|
|
|
3407
3441
|
Trigger.trigger(
|
|
3408
3442
|
this,
|
|
@@ -3433,6 +3467,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3433
3467
|
this.breakouts.breakoutServiceUrlUpdate(payload?.services?.breakout?.url);
|
|
3434
3468
|
this.annotation.approvalUrlUpdate(payload?.services?.approval?.url);
|
|
3435
3469
|
this.simultaneousInterpretation.approvalUrlUpdate(payload?.services?.approval?.url);
|
|
3470
|
+
this.aiEnableRequest.approvalUrlUpdate(payload?.services?.approval?.url);
|
|
3436
3471
|
});
|
|
3437
3472
|
}
|
|
3438
3473
|
|
|
@@ -3530,6 +3565,9 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3530
3565
|
// @ts-ignore - config coming from registerPlugin
|
|
3531
3566
|
if (datachannelUrl && this.config.enableAutomaticLLM) {
|
|
3532
3567
|
this.updateLLMConnection();
|
|
3568
|
+
if (this.webinar.isJoinPracticeSessionDataChannel()) {
|
|
3569
|
+
this.webinar.updatePSDataChannel();
|
|
3570
|
+
}
|
|
3533
3571
|
}
|
|
3534
3572
|
}
|
|
3535
3573
|
|
|
@@ -3762,6 +3800,10 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3762
3800
|
);
|
|
3763
3801
|
});
|
|
3764
3802
|
|
|
3803
|
+
this.locusInfo.on(LOCUSINFO.EVENTS.SELF_ID_CHANGED, (payload) => {
|
|
3804
|
+
this.aiEnableRequest.selfParticipantIdUpdate(payload.selfId);
|
|
3805
|
+
});
|
|
3806
|
+
|
|
3765
3807
|
this.locusInfo.on(LOCUSINFO.EVENTS.SELF_MEETING_INTERPRETATION_CHANGED, (payload) => {
|
|
3766
3808
|
const targetChanged = this.simultaneousInterpretation.updateSelfInterpretation(payload);
|
|
3767
3809
|
Trigger.trigger(
|
|
@@ -4264,6 +4306,9 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4264
4306
|
bothLeaveAndEndMeetingAvailable: MeetingUtil.bothLeaveAndEndMeetingAvailable(
|
|
4265
4307
|
this.userDisplayHints
|
|
4266
4308
|
),
|
|
4309
|
+
requireHostEndMeetingBeforeLeave: MeetingUtil.requireHostEndMeetingBeforeLeave(
|
|
4310
|
+
this.userDisplayHints
|
|
4311
|
+
),
|
|
4267
4312
|
canEnableClosedCaption: MeetingUtil.canEnableClosedCaption(this.userDisplayHints),
|
|
4268
4313
|
canStartTranscribing: MeetingUtil.canStartTranscribing(this.userDisplayHints),
|
|
4269
4314
|
canStopTranscribing: MeetingUtil.canStopTranscribing(this.userDisplayHints),
|
|
@@ -4522,6 +4567,12 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4522
4567
|
requiredHints: [DISPLAY_HINTS.DISABLE_ATTENDEE_START_POLLING_QA],
|
|
4523
4568
|
displayHints: this.userDisplayHints,
|
|
4524
4569
|
}),
|
|
4570
|
+
canAttendeeRequestAiAssistantEnabled: MeetingUtil.canAttendeeRequestAiAssistantEnabled(
|
|
4571
|
+
this.userDisplayHints,
|
|
4572
|
+
this.roles
|
|
4573
|
+
),
|
|
4574
|
+
isAttendeeRequestAiAssistantDeclinedAll:
|
|
4575
|
+
MeetingUtil.attendeeRequestAiAssistantDeclinedAll(this.userDisplayHints),
|
|
4525
4576
|
}) || changed;
|
|
4526
4577
|
}
|
|
4527
4578
|
if (changed) {
|
|
@@ -4593,7 +4644,8 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4593
4644
|
mediaId: string;
|
|
4594
4645
|
host: object;
|
|
4595
4646
|
selfId: string;
|
|
4596
|
-
dataSets: DataSet[];
|
|
4647
|
+
dataSets: DataSet[]; // only sent by Locus when hash trees are used
|
|
4648
|
+
metadata: Metadata; // only sent by Locus when hash trees are used
|
|
4597
4649
|
}) {
|
|
4598
4650
|
const mtgLocus: any = data.locus;
|
|
4599
4651
|
|
|
@@ -4609,6 +4661,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4609
4661
|
trigger: 'join-response',
|
|
4610
4662
|
locus: mtgLocus,
|
|
4611
4663
|
dataSets: data.dataSets,
|
|
4664
|
+
metadata: data.metadata,
|
|
4612
4665
|
});
|
|
4613
4666
|
}
|
|
4614
4667
|
|
|
@@ -4818,6 +4871,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4818
4871
|
this.localVideoStreamMuteStateHandler
|
|
4819
4872
|
);
|
|
4820
4873
|
oldStream?.off(LocalStreamEventNames.OutputTrackChange, this.localOutputTrackChangeHandler);
|
|
4874
|
+
oldStream?.off(LocalStreamEventNames.ConstraintsChange, this.localConstraintsChangeHandler);
|
|
4821
4875
|
|
|
4822
4876
|
// we don't update this.mediaProperties.mediaDirection.sendVideo, because we always keep it as true to avoid extra SDP exchanges
|
|
4823
4877
|
this.mediaProperties.setLocalVideoStream(localStream);
|
|
@@ -4833,6 +4887,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4833
4887
|
this.localVideoStreamMuteStateHandler
|
|
4834
4888
|
);
|
|
4835
4889
|
localStream?.on(LocalStreamEventNames.OutputTrackChange, this.localOutputTrackChangeHandler);
|
|
4890
|
+
localStream?.on(LocalStreamEventNames.ConstraintsChange, this.localConstraintsChangeHandler);
|
|
4836
4891
|
|
|
4837
4892
|
if (!this.isMultistream || !localStream) {
|
|
4838
4893
|
// for multistream WCME automatically un-publishes the old stream when we publish a new one
|
|
@@ -4967,6 +5022,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4967
5022
|
this.localVideoStreamMuteStateHandler
|
|
4968
5023
|
);
|
|
4969
5024
|
videoStream?.off(LocalStreamEventNames.OutputTrackChange, this.localOutputTrackChangeHandler);
|
|
5025
|
+
videoStream?.off(LocalStreamEventNames.ConstraintsChange, this.localConstraintsChangeHandler);
|
|
4970
5026
|
|
|
4971
5027
|
shareAudioStream?.off(StreamEventNames.Ended, this.handleShareAudioStreamEnded);
|
|
4972
5028
|
shareAudioStream?.off(
|
|
@@ -5781,7 +5837,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5781
5837
|
this.isReactionsSupported()
|
|
5782
5838
|
) {
|
|
5783
5839
|
const member = this.members.membersCollection.get(e.data.sender.participantId);
|
|
5784
|
-
if (!member) {
|
|
5840
|
+
if (!member && !this.locusInfo?.info?.isWebinar) {
|
|
5785
5841
|
// @ts-ignore -- fix type
|
|
5786
5842
|
LoggerProxy.logger.warn(
|
|
5787
5843
|
`Meeting:index#processRelayEvent --> Skipping handling of ${REACTION_RELAY_TYPES.REACTION} for ${this.id}. participantId ${e.data.sender.participantId} does not exist in membersCollection.`
|
|
@@ -5789,7 +5845,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5789
5845
|
break;
|
|
5790
5846
|
}
|
|
5791
5847
|
|
|
5792
|
-
const
|
|
5848
|
+
const name = (member && member.name) || e.data.sender.displayName;
|
|
5793
5849
|
const processedReaction: ProcessedReaction = {
|
|
5794
5850
|
reaction: e.data.reaction,
|
|
5795
5851
|
sender: {
|
|
@@ -6177,6 +6233,49 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
6177
6233
|
}
|
|
6178
6234
|
}
|
|
6179
6235
|
|
|
6236
|
+
/**
|
|
6237
|
+
* Disconnects and cleans up the default LLM session listeners/timers.
|
|
6238
|
+
* @param {Object} options
|
|
6239
|
+
* @param {boolean} [options.removeOnlineListener=true] removes the one-time online listener
|
|
6240
|
+
* @param {boolean} [options.throwOnError=true] rethrows disconnect errors when true
|
|
6241
|
+
* @returns {Promise<void>}
|
|
6242
|
+
*/
|
|
6243
|
+
private cleanupLLMConneciton = async ({
|
|
6244
|
+
removeOnlineListener = true,
|
|
6245
|
+
throwOnError = true,
|
|
6246
|
+
}: {
|
|
6247
|
+
removeOnlineListener?: boolean;
|
|
6248
|
+
throwOnError?: boolean;
|
|
6249
|
+
} = {}): Promise<void> => {
|
|
6250
|
+
try {
|
|
6251
|
+
// @ts-ignore - Fix type
|
|
6252
|
+
await this.webex.internal.llm.disconnectLLM({
|
|
6253
|
+
code: 3050,
|
|
6254
|
+
reason: 'done (permanent)',
|
|
6255
|
+
});
|
|
6256
|
+
} catch (error) {
|
|
6257
|
+
LoggerProxy.logger.error(
|
|
6258
|
+
'Meeting:index#cleanupLLMConneciton --> Failed to disconnect default LLM session',
|
|
6259
|
+
error
|
|
6260
|
+
);
|
|
6261
|
+
|
|
6262
|
+
if (throwOnError) {
|
|
6263
|
+
throw error;
|
|
6264
|
+
}
|
|
6265
|
+
} finally {
|
|
6266
|
+
if (removeOnlineListener) {
|
|
6267
|
+
// @ts-ignore - Fix type
|
|
6268
|
+
this.webex.internal.llm.off('online', this.handleLLMOnline);
|
|
6269
|
+
}
|
|
6270
|
+
// @ts-ignore - fix types
|
|
6271
|
+
this.webex.internal.llm.off('event:relay.event', this.processRelayEvent);
|
|
6272
|
+
// @ts-ignore - Fix type
|
|
6273
|
+
this.webex.internal.llm.off(LOCUS_LLM_EVENT, this.processLocusLLMEvent);
|
|
6274
|
+
|
|
6275
|
+
this.clearLLMHealthCheckTimer();
|
|
6276
|
+
}
|
|
6277
|
+
};
|
|
6278
|
+
|
|
6180
6279
|
/**
|
|
6181
6280
|
* Connects to low latency mercury and reconnects if the address has changed
|
|
6182
6281
|
* It will also disconnect if called when the meeting has ended
|
|
@@ -6185,15 +6284,26 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
6185
6284
|
*/
|
|
6186
6285
|
async updateLLMConnection() {
|
|
6187
6286
|
// @ts-ignore - Fix type
|
|
6188
|
-
const {
|
|
6287
|
+
const {
|
|
6288
|
+
url = undefined,
|
|
6289
|
+
info: {datachannelUrl = undefined} = {},
|
|
6290
|
+
self: {datachannelToken = undefined} = {},
|
|
6291
|
+
} = this.locusInfo || {};
|
|
6189
6292
|
|
|
6190
6293
|
const isJoined = this.isJoined();
|
|
6191
6294
|
|
|
6295
|
+
// @ts-ignore
|
|
6296
|
+
const currentToken = this.webex.internal.llm.getDatachannelToken(DataChannelTokenType.Default);
|
|
6297
|
+
|
|
6298
|
+
const finalToken = currentToken ?? datachannelToken;
|
|
6299
|
+
|
|
6300
|
+
if (!currentToken && datachannelToken) {
|
|
6301
|
+
// @ts-ignore
|
|
6302
|
+
this.webex.internal.llm.setDatachannelToken(datachannelToken, DataChannelTokenType.Default);
|
|
6303
|
+
}
|
|
6304
|
+
|
|
6192
6305
|
// webinar panelist should use new data channel in practice session
|
|
6193
|
-
const dataChannelUrl =
|
|
6194
|
-
this.webinar.isJoinPracticeSessionDataChannel() && practiceSessionDatachannelUrl
|
|
6195
|
-
? practiceSessionDatachannelUrl
|
|
6196
|
-
: datachannelUrl;
|
|
6306
|
+
const dataChannelUrl = datachannelUrl;
|
|
6197
6307
|
|
|
6198
6308
|
// @ts-ignore - Fix type
|
|
6199
6309
|
if (this.webex.internal.llm.isConnected()) {
|
|
@@ -6206,21 +6316,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
6206
6316
|
) {
|
|
6207
6317
|
return undefined;
|
|
6208
6318
|
}
|
|
6209
|
-
|
|
6210
|
-
await this.webex.internal.llm.disconnectLLM(
|
|
6211
|
-
isJoined
|
|
6212
|
-
? {
|
|
6213
|
-
code: 3050,
|
|
6214
|
-
reason: 'done (permanent)',
|
|
6215
|
-
}
|
|
6216
|
-
: undefined
|
|
6217
|
-
);
|
|
6218
|
-
// @ts-ignore - Fix type
|
|
6219
|
-
this.webex.internal.llm.off('event:relay.event', this.processRelayEvent);
|
|
6220
|
-
// @ts-ignore - Fix type
|
|
6221
|
-
this.webex.internal.llm.off(LOCUS_LLM_EVENT, this.processLocusLLMEvent);
|
|
6222
|
-
|
|
6223
|
-
this.clearLLMHealthCheckTimer();
|
|
6319
|
+
await this.cleanupLLMConneciton({removeOnlineListener: false});
|
|
6224
6320
|
}
|
|
6225
6321
|
|
|
6226
6322
|
if (!isJoined) {
|
|
@@ -6229,7 +6325,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
6229
6325
|
|
|
6230
6326
|
// @ts-ignore - Fix type
|
|
6231
6327
|
return this.webex.internal.llm
|
|
6232
|
-
.registerAndConnect(url, dataChannelUrl)
|
|
6328
|
+
.registerAndConnect(url, dataChannelUrl, finalToken)
|
|
6233
6329
|
.then((registerAndConnectResult) => {
|
|
6234
6330
|
// @ts-ignore - Fix type
|
|
6235
6331
|
this.webex.internal.llm.off('event:relay.event', this.processRelayEvent);
|
|
@@ -7433,7 +7529,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
7433
7529
|
*/
|
|
7434
7530
|
private async waitForMediaConnectionConnected(): Promise<void> {
|
|
7435
7531
|
try {
|
|
7436
|
-
await this.mediaProperties.waitForMediaConnectionConnected();
|
|
7532
|
+
await this.mediaProperties.waitForMediaConnectionConnected(this.correlationId);
|
|
7437
7533
|
} catch (error) {
|
|
7438
7534
|
const {iceConnected} = error;
|
|
7439
7535
|
|
|
@@ -8026,6 +8122,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
8026
8122
|
remoteMediaManagerConfig,
|
|
8027
8123
|
bundlePolicy = 'max-bundle',
|
|
8028
8124
|
additionalMediaOptions = {},
|
|
8125
|
+
allowPublishMediaInLobby = false,
|
|
8029
8126
|
} = options;
|
|
8030
8127
|
|
|
8031
8128
|
const {
|
|
@@ -8046,7 +8143,6 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
8046
8143
|
const ipver = MeetingUtil.getIpVersion(this.webex); // used just for metrics
|
|
8047
8144
|
|
|
8048
8145
|
// If the user is unjoined or guest waiting in lobby dont allow the user to addMedia
|
|
8049
|
-
// @ts-ignore - isUserUnadmitted coming from SelfUtil
|
|
8050
8146
|
if (this.isUserUnadmitted && !this.wirelessShare && !this.allowMediaInLobby) {
|
|
8051
8147
|
throw new UserInLobbyError();
|
|
8052
8148
|
}
|
|
@@ -8091,7 +8187,13 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
8091
8187
|
this.brbState = createBrbState(this, false);
|
|
8092
8188
|
|
|
8093
8189
|
try {
|
|
8094
|
-
|
|
8190
|
+
// if we're in a lobby and allowPublishMediaInLobby==false, we don't want to
|
|
8191
|
+
// setup local streams for publishing, because if we ever end up admitted to the meeting
|
|
8192
|
+
// but Locus event about it for us is delayed or missed, others could see/hear our user's video/audio
|
|
8193
|
+
// while the user would still think they're in the lobby
|
|
8194
|
+
if (allowPublishMediaInLobby || !this.isUserUnadmitted) {
|
|
8195
|
+
await this.setUpLocalStreamReferences(localStreams);
|
|
8196
|
+
}
|
|
8095
8197
|
|
|
8096
8198
|
this.setMercuryListener();
|
|
8097
8199
|
|
|
@@ -8559,12 +8661,12 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
8559
8661
|
LoggerProxy.logger.log('Meeting:index#leave --> Leaving a meeting');
|
|
8560
8662
|
|
|
8561
8663
|
return MeetingUtil.leaveMeeting(this, options)
|
|
8562
|
-
.then((leave) => {
|
|
8664
|
+
.then(async (leave) => {
|
|
8563
8665
|
// CA team recommends submitting this *after* locus /leave
|
|
8564
8666
|
submitLeaveMetric();
|
|
8565
8667
|
|
|
8566
8668
|
this.meetingFiniteStateMachine.leave();
|
|
8567
|
-
this.clearMeetingData();
|
|
8669
|
+
await this.clearMeetingData();
|
|
8568
8670
|
|
|
8569
8671
|
// upload logs on leave irrespective of meeting delete
|
|
8570
8672
|
Trigger.trigger(
|
|
@@ -9423,10 +9525,10 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
9423
9525
|
});
|
|
9424
9526
|
|
|
9425
9527
|
return MeetingUtil.endMeetingForAll(this)
|
|
9426
|
-
.then((end) => {
|
|
9528
|
+
.then(async (end) => {
|
|
9427
9529
|
this.meetingFiniteStateMachine.end();
|
|
9428
9530
|
|
|
9429
|
-
this.clearMeetingData();
|
|
9531
|
+
await this.clearMeetingData();
|
|
9430
9532
|
// upload logs on leave irrespective of meeting delete
|
|
9431
9533
|
Trigger.trigger(
|
|
9432
9534
|
this,
|
|
@@ -9474,7 +9576,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
9474
9576
|
* @public
|
|
9475
9577
|
* @memberof Meeting
|
|
9476
9578
|
*/
|
|
9477
|
-
clearMeetingData = () => {
|
|
9579
|
+
clearMeetingData = async () => {
|
|
9478
9580
|
this.audio = null;
|
|
9479
9581
|
this.video = null;
|
|
9480
9582
|
this.screenShareFloorState = ScreenShareFloorStatus.RELEASED;
|
|
@@ -9490,12 +9592,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
9490
9592
|
|
|
9491
9593
|
this.annotation.deregisterEvents();
|
|
9492
9594
|
|
|
9493
|
-
|
|
9494
|
-
this.webex.internal.llm.off('event:relay.event', this.processRelayEvent);
|
|
9495
|
-
// @ts-ignore - Fix type
|
|
9496
|
-
this.webex.internal.llm.off(LOCUS_LLM_EVENT, this.processLocusLLMEvent);
|
|
9497
|
-
|
|
9498
|
-
this.clearLLMHealthCheckTimer();
|
|
9595
|
+
await this.cleanupLLMConneciton({throwOnError: false});
|
|
9499
9596
|
};
|
|
9500
9597
|
|
|
9501
9598
|
/**
|
|
@@ -10195,4 +10292,52 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
10195
10292
|
cancelSipCallOut(participantId: string) {
|
|
10196
10293
|
return this.meetingRequest.cancelSipCallOut(participantId);
|
|
10197
10294
|
}
|
|
10295
|
+
|
|
10296
|
+
/**
|
|
10297
|
+
* Method to get new data
|
|
10298
|
+
* @returns {Promise}
|
|
10299
|
+
*/
|
|
10300
|
+
public async refreshDataChannelToken() {
|
|
10301
|
+
const isPracticeSession = this.webinar.isJoinPracticeSessionDataChannel();
|
|
10302
|
+
const dataChannelTokenType = this.getDataChannelTokenType();
|
|
10303
|
+
|
|
10304
|
+
try {
|
|
10305
|
+
const res = await this.meetingRequest.fetchDatachannelToken({
|
|
10306
|
+
locusUrl: this.locusUrl,
|
|
10307
|
+
requestingParticipantId: this.members.selfId,
|
|
10308
|
+
isPracticeSession,
|
|
10309
|
+
});
|
|
10310
|
+
|
|
10311
|
+
return {
|
|
10312
|
+
body: {
|
|
10313
|
+
datachannelToken: res.body.datachannelToken,
|
|
10314
|
+
dataChannelTokenType,
|
|
10315
|
+
},
|
|
10316
|
+
};
|
|
10317
|
+
} catch (e) {
|
|
10318
|
+
const msg = e?.message || String(e);
|
|
10319
|
+
|
|
10320
|
+
LoggerProxy.logger.warn(
|
|
10321
|
+
`Meeting:index#refreshDataChannelToken --> DataChannel token refresh failed (likely locus changed or participant left): ${msg}`,
|
|
10322
|
+
{statusCode: e?.statusCode}
|
|
10323
|
+
);
|
|
10324
|
+
|
|
10325
|
+
return null;
|
|
10326
|
+
}
|
|
10327
|
+
}
|
|
10328
|
+
|
|
10329
|
+
/**
|
|
10330
|
+
* Determines the current data channel token type based on the meeting state.
|
|
10331
|
+
*
|
|
10332
|
+
* variant should be used when connecting to the LLM data channel.
|
|
10333
|
+
*
|
|
10334
|
+
* @returns {DataChannelTokenType} The token type representing the current session mode.
|
|
10335
|
+
*/
|
|
10336
|
+
public getDataChannelTokenType(): DataChannelTokenType {
|
|
10337
|
+
if (this.webinar.isJoinPracticeSessionDataChannel()) {
|
|
10338
|
+
return DataChannelTokenType.PracticeSession;
|
|
10339
|
+
}
|
|
10340
|
+
|
|
10341
|
+
return DataChannelTokenType.Default;
|
|
10342
|
+
}
|
|
10198
10343
|
}
|
package/src/meeting/request.ts
CHANGED
|
@@ -33,6 +33,7 @@ import {
|
|
|
33
33
|
ToggleReactionsOptions,
|
|
34
34
|
PostMeetingDataConsentOptions,
|
|
35
35
|
SynchronizeVideoLayout,
|
|
36
|
+
fetchDataChannelTokenOptions,
|
|
36
37
|
} from './request.type';
|
|
37
38
|
import MeetingUtil from './util';
|
|
38
39
|
import {AnnotationInfo} from '../annotation/annotation.types';
|
|
@@ -1126,4 +1127,45 @@ export default class MeetingRequest extends StatelessWebexPlugin {
|
|
|
1126
1127
|
throw err;
|
|
1127
1128
|
}
|
|
1128
1129
|
}
|
|
1130
|
+
|
|
1131
|
+
/**
|
|
1132
|
+
* Sends a request to retrieve the datachannel authorization token for a participant.
|
|
1133
|
+
*
|
|
1134
|
+
* For regular meeting data channel:
|
|
1135
|
+
* GET /locus/api/v1/loci/{uuid:lid}/participant/{uuid:pid}/datachannel/token
|
|
1136
|
+
*
|
|
1137
|
+
* For practice session data channel:
|
|
1138
|
+
* GET /locus/api/v1/loci/{uuid:lid}/participant/{uuid:pid}/practiceSession/datachannel/token
|
|
1139
|
+
*
|
|
1140
|
+
* @param {string} locusUrl - The locus url.
|
|
1141
|
+
* @param {string} requestingParticipantId - The participant UUID.
|
|
1142
|
+
* @param {boolean} [isPracticeSession=false] - Whether to get the practice session token.
|
|
1143
|
+
* @returns {Promise<{datachannelToken: string}>}
|
|
1144
|
+
*/
|
|
1145
|
+
public async fetchDatachannelToken({
|
|
1146
|
+
locusUrl,
|
|
1147
|
+
requestingParticipantId,
|
|
1148
|
+
isPracticeSession = false,
|
|
1149
|
+
}: fetchDataChannelTokenOptions) {
|
|
1150
|
+
if (!locusUrl || !requestingParticipantId) {
|
|
1151
|
+
return Promise.reject(new Error('locusUrl and participantId are required'));
|
|
1152
|
+
}
|
|
1153
|
+
const practicePrefix = isPracticeSession ? '/practiceSession' : '';
|
|
1154
|
+
|
|
1155
|
+
const uri = `${locusUrl}/${PARTICIPANT}/${requestingParticipantId}${practicePrefix}/datachannel/token`;
|
|
1156
|
+
|
|
1157
|
+
// @ts-ignore
|
|
1158
|
+
return this.locusDeltaRequest({
|
|
1159
|
+
method: HTTP_VERBS.GET,
|
|
1160
|
+
uri,
|
|
1161
|
+
}).catch((err) => {
|
|
1162
|
+
LoggerProxy.logger.warn(
|
|
1163
|
+
`Meeting:request#fetchDatachannelToken --> Failed to retrieve ${
|
|
1164
|
+
isPracticeSession ? 'practice session ' : ''
|
|
1165
|
+
}datachannel token: ${err?.message || err}`
|
|
1166
|
+
);
|
|
1167
|
+
|
|
1168
|
+
return null;
|
|
1169
|
+
});
|
|
1170
|
+
}
|
|
1129
1171
|
}
|
|
@@ -88,4 +88,10 @@ export type UnsetStageVideoLayout = {
|
|
|
88
88
|
overrideDefault: false;
|
|
89
89
|
};
|
|
90
90
|
|
|
91
|
+
export type fetchDataChannelTokenOptions = {
|
|
92
|
+
locusUrl: string;
|
|
93
|
+
requestingParticipantId: string;
|
|
94
|
+
isPracticeSession: boolean;
|
|
95
|
+
};
|
|
96
|
+
|
|
91
97
|
export type SynchronizeVideoLayout = SetStageVideoLayout | UnsetStageVideoLayout;
|