@webex/plugin-meetings 3.11.0-webex-services-ready.1 → 3.12.0-next.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/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 +7 -2
- 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 +850 -410
- 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 +522 -131
- 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 +1128 -868
- 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 +117 -48
- 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 +4 -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 +122 -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 +60 -8
- package/dist/types/locus-info/types.d.ts +7 -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 +48 -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 +4 -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 +745 -252
- 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 +579 -113
- package/src/locus-info/selfUtils.ts +1 -0
- package/src/locus-info/types.ts +8 -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 +221 -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 +157 -44
- 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 +2225 -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 +1134 -55
- 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 +653 -32
- 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
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, HashTreeMessage, 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
|
|
|
@@ -564,6 +568,34 @@ type MediaReachabilityMetrics = ReachabilityMetrics & {
|
|
|
564
568
|
* @memberof Meeting
|
|
565
569
|
*/
|
|
566
570
|
|
|
571
|
+
/**
|
|
572
|
+
* Stores an event so all events can be later retrieved via a console command for debugging.
|
|
573
|
+
* @param {string} type
|
|
574
|
+
* @param {Object} data
|
|
575
|
+
* @returns {void}
|
|
576
|
+
*/
|
|
577
|
+
export function storeEventForDebugging(
|
|
578
|
+
type: string,
|
|
579
|
+
data: {
|
|
580
|
+
eventType: any;
|
|
581
|
+
stateElementsMessage?: HashTreeMessage;
|
|
582
|
+
}
|
|
583
|
+
) {
|
|
584
|
+
if ((window as any)?.locusEvents) {
|
|
585
|
+
// only store non-heartbeat hash tree messages
|
|
586
|
+
if (
|
|
587
|
+
data.eventType === LOCUSEVENT.HASH_TREE_DATA_UPDATED &&
|
|
588
|
+
data.stateElementsMessage?.locusStateElements
|
|
589
|
+
) {
|
|
590
|
+
(window as any).locusEvents.push({
|
|
591
|
+
...data,
|
|
592
|
+
timestamp: new Date().toLocaleString(),
|
|
593
|
+
type,
|
|
594
|
+
});
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
|
|
567
599
|
/**
|
|
568
600
|
* @description Meeting is the crux of the plugin
|
|
569
601
|
* @export
|
|
@@ -575,6 +607,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
575
607
|
breakouts: any;
|
|
576
608
|
simultaneousInterpretation: any;
|
|
577
609
|
annotation: any;
|
|
610
|
+
aiEnableRequest: any;
|
|
578
611
|
webinar: any;
|
|
579
612
|
conversationUrl: string;
|
|
580
613
|
callStateForMetrics: CallStateForMetrics;
|
|
@@ -623,6 +656,13 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
623
656
|
keepAliveTimerId: NodeJS.Timeout;
|
|
624
657
|
lastVideoLayoutInfo: any;
|
|
625
658
|
locusInfo: any;
|
|
659
|
+
// this group of properties is populated via updateMeetingObject() that's registered as a callback with LocusInfo
|
|
660
|
+
isUserUnadmitted?: boolean;
|
|
661
|
+
joinedWith?: any;
|
|
662
|
+
selfId?: string;
|
|
663
|
+
roles: any[];
|
|
664
|
+
// ... there is more ... see SelfUtils.parse()
|
|
665
|
+
// end of the group
|
|
626
666
|
locusMediaRequest?: LocusMediaRequest;
|
|
627
667
|
mediaProperties: MediaProperties;
|
|
628
668
|
mediaRequestManagers: {
|
|
@@ -657,7 +697,6 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
657
697
|
endCallInitJoinReq: any;
|
|
658
698
|
endJoinReqResp: any;
|
|
659
699
|
endLocalSDPGenRemoteSDPRecvDelay: any;
|
|
660
|
-
joinedWith: any;
|
|
661
700
|
locusId: any;
|
|
662
701
|
startCallInitJoinReq: any;
|
|
663
702
|
startJoinReqResp: any;
|
|
@@ -672,12 +711,11 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
672
711
|
permissionTokenReceivedLocalTime: number;
|
|
673
712
|
resourceId: any;
|
|
674
713
|
resourceUrl: string;
|
|
675
|
-
selfId: string;
|
|
676
714
|
state: any;
|
|
677
715
|
localAudioStreamMuteStateHandler: () => void;
|
|
678
716
|
localVideoStreamMuteStateHandler: () => void;
|
|
679
717
|
localOutputTrackChangeHandler: () => void;
|
|
680
|
-
|
|
718
|
+
localConstraintsChangeHandler: () => void;
|
|
681
719
|
environment: string;
|
|
682
720
|
namespace = MEETINGS;
|
|
683
721
|
allowMediaInLobby: boolean;
|
|
@@ -894,6 +932,10 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
894
932
|
*/
|
|
895
933
|
// @ts-ignore
|
|
896
934
|
this.simultaneousInterpretation = new SimultaneousInterpretation({}, {parent: this.webex});
|
|
935
|
+
|
|
936
|
+
// @ts-ignore
|
|
937
|
+
this.aiEnableRequest = new AIEnableRequest({}, {parent: this.webex});
|
|
938
|
+
|
|
897
939
|
/**
|
|
898
940
|
* @instance
|
|
899
941
|
* @type {Annotation}
|
|
@@ -1543,6 +1585,12 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1543
1585
|
}
|
|
1544
1586
|
};
|
|
1545
1587
|
|
|
1588
|
+
this.localConstraintsChangeHandler = () => {
|
|
1589
|
+
if (!this.isMultistream) {
|
|
1590
|
+
this.mediaProperties.webrtcMediaConnection?.updatePreferredBitrateKbps();
|
|
1591
|
+
}
|
|
1592
|
+
};
|
|
1593
|
+
|
|
1546
1594
|
/**
|
|
1547
1595
|
* Promise that exists if SDP offer has been generated, and resolves once sdp answer is received.
|
|
1548
1596
|
* @instance
|
|
@@ -2952,6 +3000,18 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2952
3000
|
);
|
|
2953
3001
|
});
|
|
2954
3002
|
|
|
3003
|
+
this.locusInfo.on(
|
|
3004
|
+
LOCUSINFO.EVENTS.CONTROLS_AI_SUMMARY_NOTIFICATION_UPDATED,
|
|
3005
|
+
({aiSummaryNotification}) => {
|
|
3006
|
+
Trigger.trigger(
|
|
3007
|
+
this,
|
|
3008
|
+
{file: 'meeting/index', function: 'setupLocusControlsListener'},
|
|
3009
|
+
EVENT_TRIGGERS.MEETING_CONTROLS_AI_SUMMARY_NOTIFICATION_UPDATED,
|
|
3010
|
+
{aiSummaryNotification}
|
|
3011
|
+
);
|
|
3012
|
+
}
|
|
3013
|
+
);
|
|
3014
|
+
|
|
2955
3015
|
this.locusInfo.on(LOCUSINFO.EVENTS.CONTROLS_WEBCAST_CHANGED, ({state}) => {
|
|
2956
3016
|
Trigger.trigger(
|
|
2957
3017
|
this,
|
|
@@ -3403,6 +3463,8 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3403
3463
|
this.recordingController.setLocusUrl(this.locusUrl);
|
|
3404
3464
|
this.controlsOptionsManager.setLocusUrl(this.locusUrl, !!isMainLocus);
|
|
3405
3465
|
this.webinar.locusUrlUpdate(url);
|
|
3466
|
+
// @ts-ignore
|
|
3467
|
+
this.webex.internal.llm.setRefreshHandler(() => this.refreshDataChannelToken());
|
|
3406
3468
|
|
|
3407
3469
|
Trigger.trigger(
|
|
3408
3470
|
this,
|
|
@@ -3433,6 +3495,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3433
3495
|
this.breakouts.breakoutServiceUrlUpdate(payload?.services?.breakout?.url);
|
|
3434
3496
|
this.annotation.approvalUrlUpdate(payload?.services?.approval?.url);
|
|
3435
3497
|
this.simultaneousInterpretation.approvalUrlUpdate(payload?.services?.approval?.url);
|
|
3498
|
+
this.aiEnableRequest.approvalUrlUpdate(payload?.services?.approval?.url);
|
|
3436
3499
|
});
|
|
3437
3500
|
}
|
|
3438
3501
|
|
|
@@ -3530,6 +3593,9 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3530
3593
|
// @ts-ignore - config coming from registerPlugin
|
|
3531
3594
|
if (datachannelUrl && this.config.enableAutomaticLLM) {
|
|
3532
3595
|
this.updateLLMConnection();
|
|
3596
|
+
if (this.webinar.isJoinPracticeSessionDataChannel()) {
|
|
3597
|
+
this.webinar.updatePSDataChannel();
|
|
3598
|
+
}
|
|
3533
3599
|
}
|
|
3534
3600
|
}
|
|
3535
3601
|
|
|
@@ -3762,6 +3828,10 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3762
3828
|
);
|
|
3763
3829
|
});
|
|
3764
3830
|
|
|
3831
|
+
this.locusInfo.on(LOCUSINFO.EVENTS.SELF_ID_CHANGED, (payload) => {
|
|
3832
|
+
this.aiEnableRequest.selfParticipantIdUpdate(payload.selfId);
|
|
3833
|
+
});
|
|
3834
|
+
|
|
3765
3835
|
this.locusInfo.on(LOCUSINFO.EVENTS.SELF_MEETING_INTERPRETATION_CHANGED, (payload) => {
|
|
3766
3836
|
const targetChanged = this.simultaneousInterpretation.updateSelfInterpretation(payload);
|
|
3767
3837
|
Trigger.trigger(
|
|
@@ -4264,6 +4334,9 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4264
4334
|
bothLeaveAndEndMeetingAvailable: MeetingUtil.bothLeaveAndEndMeetingAvailable(
|
|
4265
4335
|
this.userDisplayHints
|
|
4266
4336
|
),
|
|
4337
|
+
requireHostEndMeetingBeforeLeave: MeetingUtil.requireHostEndMeetingBeforeLeave(
|
|
4338
|
+
this.userDisplayHints
|
|
4339
|
+
),
|
|
4267
4340
|
canEnableClosedCaption: MeetingUtil.canEnableClosedCaption(this.userDisplayHints),
|
|
4268
4341
|
canStartTranscribing: MeetingUtil.canStartTranscribing(this.userDisplayHints),
|
|
4269
4342
|
canStopTranscribing: MeetingUtil.canStopTranscribing(this.userDisplayHints),
|
|
@@ -4522,6 +4595,12 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4522
4595
|
requiredHints: [DISPLAY_HINTS.DISABLE_ATTENDEE_START_POLLING_QA],
|
|
4523
4596
|
displayHints: this.userDisplayHints,
|
|
4524
4597
|
}),
|
|
4598
|
+
canAttendeeRequestAiAssistantEnabled: MeetingUtil.canAttendeeRequestAiAssistantEnabled(
|
|
4599
|
+
this.userDisplayHints,
|
|
4600
|
+
this.roles
|
|
4601
|
+
),
|
|
4602
|
+
isAttendeeRequestAiAssistantDeclinedAll:
|
|
4603
|
+
MeetingUtil.attendeeRequestAiAssistantDeclinedAll(this.userDisplayHints),
|
|
4525
4604
|
}) || changed;
|
|
4526
4605
|
}
|
|
4527
4606
|
if (changed) {
|
|
@@ -4593,7 +4672,8 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4593
4672
|
mediaId: string;
|
|
4594
4673
|
host: object;
|
|
4595
4674
|
selfId: string;
|
|
4596
|
-
dataSets: DataSet[];
|
|
4675
|
+
dataSets: DataSet[]; // only sent by Locus when hash trees are used
|
|
4676
|
+
metadata: Metadata; // only sent by Locus when hash trees are used
|
|
4597
4677
|
}) {
|
|
4598
4678
|
const mtgLocus: any = data.locus;
|
|
4599
4679
|
|
|
@@ -4609,6 +4689,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4609
4689
|
trigger: 'join-response',
|
|
4610
4690
|
locus: mtgLocus,
|
|
4611
4691
|
dataSets: data.dataSets,
|
|
4692
|
+
metadata: data.metadata,
|
|
4612
4693
|
});
|
|
4613
4694
|
}
|
|
4614
4695
|
|
|
@@ -4818,6 +4899,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4818
4899
|
this.localVideoStreamMuteStateHandler
|
|
4819
4900
|
);
|
|
4820
4901
|
oldStream?.off(LocalStreamEventNames.OutputTrackChange, this.localOutputTrackChangeHandler);
|
|
4902
|
+
oldStream?.off(LocalStreamEventNames.ConstraintsChange, this.localConstraintsChangeHandler);
|
|
4821
4903
|
|
|
4822
4904
|
// we don't update this.mediaProperties.mediaDirection.sendVideo, because we always keep it as true to avoid extra SDP exchanges
|
|
4823
4905
|
this.mediaProperties.setLocalVideoStream(localStream);
|
|
@@ -4833,6 +4915,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4833
4915
|
this.localVideoStreamMuteStateHandler
|
|
4834
4916
|
);
|
|
4835
4917
|
localStream?.on(LocalStreamEventNames.OutputTrackChange, this.localOutputTrackChangeHandler);
|
|
4918
|
+
localStream?.on(LocalStreamEventNames.ConstraintsChange, this.localConstraintsChangeHandler);
|
|
4836
4919
|
|
|
4837
4920
|
if (!this.isMultistream || !localStream) {
|
|
4838
4921
|
// for multistream WCME automatically un-publishes the old stream when we publish a new one
|
|
@@ -4967,6 +5050,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4967
5050
|
this.localVideoStreamMuteStateHandler
|
|
4968
5051
|
);
|
|
4969
5052
|
videoStream?.off(LocalStreamEventNames.OutputTrackChange, this.localOutputTrackChangeHandler);
|
|
5053
|
+
videoStream?.off(LocalStreamEventNames.ConstraintsChange, this.localConstraintsChangeHandler);
|
|
4970
5054
|
|
|
4971
5055
|
shareAudioStream?.off(StreamEventNames.Ended, this.handleShareAudioStreamEnded);
|
|
4972
5056
|
shareAudioStream?.off(
|
|
@@ -5758,6 +5842,11 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5758
5842
|
*/
|
|
5759
5843
|
private processLocusLLMEvent = (event: LocusLLMEvent): void => {
|
|
5760
5844
|
if (event.data.eventType === LOCUSEVENT.HASH_TREE_DATA_UPDATED) {
|
|
5845
|
+
// @ts-ignore
|
|
5846
|
+
if (this.config.experimental.storeLocusHashTreeEventsForDebugging) {
|
|
5847
|
+
storeEventForDebugging('llm', event.data);
|
|
5848
|
+
}
|
|
5849
|
+
|
|
5761
5850
|
this.locusInfo.parse(this, event.data);
|
|
5762
5851
|
} else {
|
|
5763
5852
|
LoggerProxy.logger.warn(
|
|
@@ -5781,7 +5870,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5781
5870
|
this.isReactionsSupported()
|
|
5782
5871
|
) {
|
|
5783
5872
|
const member = this.members.membersCollection.get(e.data.sender.participantId);
|
|
5784
|
-
if (!member) {
|
|
5873
|
+
if (!member && !this.locusInfo?.info?.isWebinar) {
|
|
5785
5874
|
// @ts-ignore -- fix type
|
|
5786
5875
|
LoggerProxy.logger.warn(
|
|
5787
5876
|
`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 +5878,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5789
5878
|
break;
|
|
5790
5879
|
}
|
|
5791
5880
|
|
|
5792
|
-
const
|
|
5881
|
+
const name = (member && member.name) || e.data.sender.displayName;
|
|
5793
5882
|
const processedReaction: ProcessedReaction = {
|
|
5794
5883
|
reaction: e.data.reaction,
|
|
5795
5884
|
sender: {
|
|
@@ -6177,6 +6266,49 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
6177
6266
|
}
|
|
6178
6267
|
}
|
|
6179
6268
|
|
|
6269
|
+
/**
|
|
6270
|
+
* Disconnects and cleans up the default LLM session listeners/timers.
|
|
6271
|
+
* @param {Object} options
|
|
6272
|
+
* @param {boolean} [options.removeOnlineListener=true] removes the one-time online listener
|
|
6273
|
+
* @param {boolean} [options.throwOnError=true] rethrows disconnect errors when true
|
|
6274
|
+
* @returns {Promise<void>}
|
|
6275
|
+
*/
|
|
6276
|
+
private cleanupLLMConneciton = async ({
|
|
6277
|
+
removeOnlineListener = true,
|
|
6278
|
+
throwOnError = true,
|
|
6279
|
+
}: {
|
|
6280
|
+
removeOnlineListener?: boolean;
|
|
6281
|
+
throwOnError?: boolean;
|
|
6282
|
+
} = {}): Promise<void> => {
|
|
6283
|
+
try {
|
|
6284
|
+
// @ts-ignore - Fix type
|
|
6285
|
+
await this.webex.internal.llm.disconnectLLM({
|
|
6286
|
+
code: 3050,
|
|
6287
|
+
reason: 'done (permanent)',
|
|
6288
|
+
});
|
|
6289
|
+
} catch (error) {
|
|
6290
|
+
LoggerProxy.logger.error(
|
|
6291
|
+
'Meeting:index#cleanupLLMConneciton --> Failed to disconnect default LLM session',
|
|
6292
|
+
error
|
|
6293
|
+
);
|
|
6294
|
+
|
|
6295
|
+
if (throwOnError) {
|
|
6296
|
+
throw error;
|
|
6297
|
+
}
|
|
6298
|
+
} finally {
|
|
6299
|
+
if (removeOnlineListener) {
|
|
6300
|
+
// @ts-ignore - Fix type
|
|
6301
|
+
this.webex.internal.llm.off('online', this.handleLLMOnline);
|
|
6302
|
+
}
|
|
6303
|
+
// @ts-ignore - fix types
|
|
6304
|
+
this.webex.internal.llm.off('event:relay.event', this.processRelayEvent);
|
|
6305
|
+
// @ts-ignore - Fix type
|
|
6306
|
+
this.webex.internal.llm.off(LOCUS_LLM_EVENT, this.processLocusLLMEvent);
|
|
6307
|
+
|
|
6308
|
+
this.clearLLMHealthCheckTimer();
|
|
6309
|
+
}
|
|
6310
|
+
};
|
|
6311
|
+
|
|
6180
6312
|
/**
|
|
6181
6313
|
* Connects to low latency mercury and reconnects if the address has changed
|
|
6182
6314
|
* It will also disconnect if called when the meeting has ended
|
|
@@ -6185,15 +6317,26 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
6185
6317
|
*/
|
|
6186
6318
|
async updateLLMConnection() {
|
|
6187
6319
|
// @ts-ignore - Fix type
|
|
6188
|
-
const {
|
|
6320
|
+
const {
|
|
6321
|
+
url = undefined,
|
|
6322
|
+
info: {datachannelUrl = undefined} = {},
|
|
6323
|
+
self: {datachannelToken = undefined} = {},
|
|
6324
|
+
} = this.locusInfo || {};
|
|
6189
6325
|
|
|
6190
6326
|
const isJoined = this.isJoined();
|
|
6191
6327
|
|
|
6328
|
+
// @ts-ignore
|
|
6329
|
+
const currentToken = this.webex.internal.llm.getDatachannelToken(DataChannelTokenType.Default);
|
|
6330
|
+
|
|
6331
|
+
const finalToken = currentToken ?? datachannelToken;
|
|
6332
|
+
|
|
6333
|
+
if (!currentToken && datachannelToken) {
|
|
6334
|
+
// @ts-ignore
|
|
6335
|
+
this.webex.internal.llm.setDatachannelToken(datachannelToken, DataChannelTokenType.Default);
|
|
6336
|
+
}
|
|
6337
|
+
|
|
6192
6338
|
// webinar panelist should use new data channel in practice session
|
|
6193
|
-
const dataChannelUrl =
|
|
6194
|
-
this.webinar.isJoinPracticeSessionDataChannel() && practiceSessionDatachannelUrl
|
|
6195
|
-
? practiceSessionDatachannelUrl
|
|
6196
|
-
: datachannelUrl;
|
|
6339
|
+
const dataChannelUrl = datachannelUrl;
|
|
6197
6340
|
|
|
6198
6341
|
// @ts-ignore - Fix type
|
|
6199
6342
|
if (this.webex.internal.llm.isConnected()) {
|
|
@@ -6206,21 +6349,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
6206
6349
|
) {
|
|
6207
6350
|
return undefined;
|
|
6208
6351
|
}
|
|
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();
|
|
6352
|
+
await this.cleanupLLMConneciton({removeOnlineListener: false});
|
|
6224
6353
|
}
|
|
6225
6354
|
|
|
6226
6355
|
if (!isJoined) {
|
|
@@ -6229,7 +6358,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
6229
6358
|
|
|
6230
6359
|
// @ts-ignore - Fix type
|
|
6231
6360
|
return this.webex.internal.llm
|
|
6232
|
-
.registerAndConnect(url, dataChannelUrl)
|
|
6361
|
+
.registerAndConnect(url, dataChannelUrl, finalToken)
|
|
6233
6362
|
.then((registerAndConnectResult) => {
|
|
6234
6363
|
// @ts-ignore - Fix type
|
|
6235
6364
|
this.webex.internal.llm.off('event:relay.event', this.processRelayEvent);
|
|
@@ -7433,7 +7562,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
7433
7562
|
*/
|
|
7434
7563
|
private async waitForMediaConnectionConnected(): Promise<void> {
|
|
7435
7564
|
try {
|
|
7436
|
-
await this.mediaProperties.waitForMediaConnectionConnected();
|
|
7565
|
+
await this.mediaProperties.waitForMediaConnectionConnected(this.correlationId);
|
|
7437
7566
|
} catch (error) {
|
|
7438
7567
|
const {iceConnected} = error;
|
|
7439
7568
|
|
|
@@ -8026,6 +8155,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
8026
8155
|
remoteMediaManagerConfig,
|
|
8027
8156
|
bundlePolicy = 'max-bundle',
|
|
8028
8157
|
additionalMediaOptions = {},
|
|
8158
|
+
allowPublishMediaInLobby = false,
|
|
8029
8159
|
} = options;
|
|
8030
8160
|
|
|
8031
8161
|
const {
|
|
@@ -8046,7 +8176,6 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
8046
8176
|
const ipver = MeetingUtil.getIpVersion(this.webex); // used just for metrics
|
|
8047
8177
|
|
|
8048
8178
|
// If the user is unjoined or guest waiting in lobby dont allow the user to addMedia
|
|
8049
|
-
// @ts-ignore - isUserUnadmitted coming from SelfUtil
|
|
8050
8179
|
if (this.isUserUnadmitted && !this.wirelessShare && !this.allowMediaInLobby) {
|
|
8051
8180
|
throw new UserInLobbyError();
|
|
8052
8181
|
}
|
|
@@ -8091,7 +8220,13 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
8091
8220
|
this.brbState = createBrbState(this, false);
|
|
8092
8221
|
|
|
8093
8222
|
try {
|
|
8094
|
-
|
|
8223
|
+
// if we're in a lobby and allowPublishMediaInLobby==false, we don't want to
|
|
8224
|
+
// setup local streams for publishing, because if we ever end up admitted to the meeting
|
|
8225
|
+
// but Locus event about it for us is delayed or missed, others could see/hear our user's video/audio
|
|
8226
|
+
// while the user would still think they're in the lobby
|
|
8227
|
+
if (allowPublishMediaInLobby || !this.isUserUnadmitted) {
|
|
8228
|
+
await this.setUpLocalStreamReferences(localStreams);
|
|
8229
|
+
}
|
|
8095
8230
|
|
|
8096
8231
|
this.setMercuryListener();
|
|
8097
8232
|
|
|
@@ -8559,12 +8694,12 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
8559
8694
|
LoggerProxy.logger.log('Meeting:index#leave --> Leaving a meeting');
|
|
8560
8695
|
|
|
8561
8696
|
return MeetingUtil.leaveMeeting(this, options)
|
|
8562
|
-
.then((leave) => {
|
|
8697
|
+
.then(async (leave) => {
|
|
8563
8698
|
// CA team recommends submitting this *after* locus /leave
|
|
8564
8699
|
submitLeaveMetric();
|
|
8565
8700
|
|
|
8566
8701
|
this.meetingFiniteStateMachine.leave();
|
|
8567
|
-
this.clearMeetingData();
|
|
8702
|
+
await this.clearMeetingData();
|
|
8568
8703
|
|
|
8569
8704
|
// upload logs on leave irrespective of meeting delete
|
|
8570
8705
|
Trigger.trigger(
|
|
@@ -9423,10 +9558,10 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
9423
9558
|
});
|
|
9424
9559
|
|
|
9425
9560
|
return MeetingUtil.endMeetingForAll(this)
|
|
9426
|
-
.then((end) => {
|
|
9561
|
+
.then(async (end) => {
|
|
9427
9562
|
this.meetingFiniteStateMachine.end();
|
|
9428
9563
|
|
|
9429
|
-
this.clearMeetingData();
|
|
9564
|
+
await this.clearMeetingData();
|
|
9430
9565
|
// upload logs on leave irrespective of meeting delete
|
|
9431
9566
|
Trigger.trigger(
|
|
9432
9567
|
this,
|
|
@@ -9474,7 +9609,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
9474
9609
|
* @public
|
|
9475
9610
|
* @memberof Meeting
|
|
9476
9611
|
*/
|
|
9477
|
-
clearMeetingData = () => {
|
|
9612
|
+
clearMeetingData = async () => {
|
|
9478
9613
|
this.audio = null;
|
|
9479
9614
|
this.video = null;
|
|
9480
9615
|
this.screenShareFloorState = ScreenShareFloorStatus.RELEASED;
|
|
@@ -9490,12 +9625,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
9490
9625
|
|
|
9491
9626
|
this.annotation.deregisterEvents();
|
|
9492
9627
|
|
|
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();
|
|
9628
|
+
await this.cleanupLLMConneciton({throwOnError: false});
|
|
9499
9629
|
};
|
|
9500
9630
|
|
|
9501
9631
|
/**
|
|
@@ -10195,4 +10325,52 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
10195
10325
|
cancelSipCallOut(participantId: string) {
|
|
10196
10326
|
return this.meetingRequest.cancelSipCallOut(participantId);
|
|
10197
10327
|
}
|
|
10328
|
+
|
|
10329
|
+
/**
|
|
10330
|
+
* Method to get new data
|
|
10331
|
+
* @returns {Promise}
|
|
10332
|
+
*/
|
|
10333
|
+
public async refreshDataChannelToken() {
|
|
10334
|
+
const isPracticeSession = this.webinar.isJoinPracticeSessionDataChannel();
|
|
10335
|
+
const dataChannelTokenType = this.getDataChannelTokenType();
|
|
10336
|
+
|
|
10337
|
+
try {
|
|
10338
|
+
const res = await this.meetingRequest.fetchDatachannelToken({
|
|
10339
|
+
locusUrl: this.locusUrl,
|
|
10340
|
+
requestingParticipantId: this.members.selfId,
|
|
10341
|
+
isPracticeSession,
|
|
10342
|
+
});
|
|
10343
|
+
|
|
10344
|
+
return {
|
|
10345
|
+
body: {
|
|
10346
|
+
datachannelToken: res.body.datachannelToken,
|
|
10347
|
+
dataChannelTokenType,
|
|
10348
|
+
},
|
|
10349
|
+
};
|
|
10350
|
+
} catch (e) {
|
|
10351
|
+
const msg = e?.message || String(e);
|
|
10352
|
+
|
|
10353
|
+
LoggerProxy.logger.warn(
|
|
10354
|
+
`Meeting:index#refreshDataChannelToken --> DataChannel token refresh failed (likely locus changed or participant left): ${msg}`,
|
|
10355
|
+
{statusCode: e?.statusCode}
|
|
10356
|
+
);
|
|
10357
|
+
|
|
10358
|
+
return null;
|
|
10359
|
+
}
|
|
10360
|
+
}
|
|
10361
|
+
|
|
10362
|
+
/**
|
|
10363
|
+
* Determines the current data channel token type based on the meeting state.
|
|
10364
|
+
*
|
|
10365
|
+
* variant should be used when connecting to the LLM data channel.
|
|
10366
|
+
*
|
|
10367
|
+
* @returns {DataChannelTokenType} The token type representing the current session mode.
|
|
10368
|
+
*/
|
|
10369
|
+
public getDataChannelTokenType(): DataChannelTokenType {
|
|
10370
|
+
if (this.webinar.isJoinPracticeSessionDataChannel()) {
|
|
10371
|
+
return DataChannelTokenType.PracticeSession;
|
|
10372
|
+
}
|
|
10373
|
+
|
|
10374
|
+
return DataChannelTokenType.Default;
|
|
10375
|
+
}
|
|
10198
10376
|
}
|
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;
|