@webex/plugin-meetings 3.11.0-webex-services-ready.1 → 3.12.0-mobius-socket.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 +868 -419
- 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 +1293 -929
- 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 +6 -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/multistream/sendSlotManager.js +116 -2
- package/dist/multistream/sendSlotManager.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 +72 -7
- 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 +5 -0
- package/dist/types/multistream/mediaRequestManager.d.ts +0 -23
- package/dist/types/multistream/sendSlotManager.d.ts +23 -1
- package/dist/types/reactions/reactions.type.d.ts +1 -0
- package/dist/types/webinar/utils.d.ts +6 -0
- package/dist/webinar/index.js +438 -163
- 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 +761 -260
- 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 +372 -86
- 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 +6 -0
- package/src/multistream/mediaRequestManager.ts +4 -54
- package/src/multistream/remoteMediaManager.ts +13 -0
- package/src/multistream/sendSlotManager.ts +97 -3
- package/src/reactions/reactions.type.ts +1 -0
- package/src/reconnection-manager/index.ts +0 -1
- package/src/webinar/index.ts +265 -6
- 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 +2321 -175
- 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 +829 -121
- 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/multistream/sendSlotManager.ts +135 -36
- package/test/unit/spec/reconnection-manager/index.js +4 -8
- package/test/unit/spec/webinar/index.ts +534 -37
- 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,
|
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
MediaConnectionEventNames,
|
|
23
23
|
MediaContent,
|
|
24
24
|
MediaType,
|
|
25
|
+
MediaCodecMimeType,
|
|
25
26
|
RemoteTrackType,
|
|
26
27
|
RoapMessage,
|
|
27
28
|
StatsAnalyzer,
|
|
@@ -33,6 +34,8 @@ import {
|
|
|
33
34
|
InboundAudioIssueSubTypes,
|
|
34
35
|
} from '@webex/internal-media-core';
|
|
35
36
|
|
|
37
|
+
import {DataChannelTokenType} from '@webex/internal-plugin-llm';
|
|
38
|
+
|
|
36
39
|
import {
|
|
37
40
|
LocalStream,
|
|
38
41
|
LocalCameraStream,
|
|
@@ -179,8 +182,9 @@ import JoinForbiddenError from '../common/errors/join-forbidden-error';
|
|
|
179
182
|
import {ReachabilityMetrics} from '../reachability/reachability.types';
|
|
180
183
|
import {SetStageOptions, SetStageVideoLayout, UnsetStageVideoLayout} from './request.type';
|
|
181
184
|
import {Invitee} from './type';
|
|
182
|
-
import {DataSet} from '../hashTree/hashTreeParser';
|
|
185
|
+
import {DataSet, HashTreeMessage, Metadata} from '../hashTree/hashTreeParser';
|
|
183
186
|
import {LocusDTO} from '../locus-info/types';
|
|
187
|
+
import AIEnableRequest from '../aiEnableRequest';
|
|
184
188
|
|
|
185
189
|
// default callback so we don't call an undefined function, but in practice it should never be used
|
|
186
190
|
const DEFAULT_ICE_PHASE_CALLBACK = () => 'JOIN_MEETING_FINAL';
|
|
@@ -250,6 +254,7 @@ export type AddMediaOptions = {
|
|
|
250
254
|
remoteMediaManagerConfig?: RemoteMediaManagerConfiguration; // applies only to multistream meetings
|
|
251
255
|
bundlePolicy?: BundlePolicy; // applies only to multistream meetings
|
|
252
256
|
allowMediaInLobby?: boolean; // allows adding media when in the lobby
|
|
257
|
+
allowPublishMediaInLobby?: boolean; // allows publishing media when in the lobby, if not specified, default value false is used
|
|
253
258
|
additionalMediaOptions?: AdditionalMediaOptions; // allows adding additional options like send/receive audio/video
|
|
254
259
|
};
|
|
255
260
|
|
|
@@ -564,6 +569,34 @@ type MediaReachabilityMetrics = ReachabilityMetrics & {
|
|
|
564
569
|
* @memberof Meeting
|
|
565
570
|
*/
|
|
566
571
|
|
|
572
|
+
/**
|
|
573
|
+
* Stores an event so all events can be later retrieved via a console command for debugging.
|
|
574
|
+
* @param {string} type
|
|
575
|
+
* @param {Object} data
|
|
576
|
+
* @returns {void}
|
|
577
|
+
*/
|
|
578
|
+
export function storeEventForDebugging(
|
|
579
|
+
type: string,
|
|
580
|
+
data: {
|
|
581
|
+
eventType: any;
|
|
582
|
+
stateElementsMessage?: HashTreeMessage;
|
|
583
|
+
}
|
|
584
|
+
) {
|
|
585
|
+
if ((window as any)?.locusEvents) {
|
|
586
|
+
// only store non-heartbeat hash tree messages
|
|
587
|
+
if (
|
|
588
|
+
data.eventType === LOCUSEVENT.HASH_TREE_DATA_UPDATED &&
|
|
589
|
+
data.stateElementsMessage?.locusStateElements
|
|
590
|
+
) {
|
|
591
|
+
(window as any).locusEvents.push({
|
|
592
|
+
...data,
|
|
593
|
+
timestamp: new Date().toLocaleString(),
|
|
594
|
+
type,
|
|
595
|
+
});
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
|
|
567
600
|
/**
|
|
568
601
|
* @description Meeting is the crux of the plugin
|
|
569
602
|
* @export
|
|
@@ -575,6 +608,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
575
608
|
breakouts: any;
|
|
576
609
|
simultaneousInterpretation: any;
|
|
577
610
|
annotation: any;
|
|
611
|
+
aiEnableRequest: any;
|
|
578
612
|
webinar: any;
|
|
579
613
|
conversationUrl: string;
|
|
580
614
|
callStateForMetrics: CallStateForMetrics;
|
|
@@ -623,6 +657,13 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
623
657
|
keepAliveTimerId: NodeJS.Timeout;
|
|
624
658
|
lastVideoLayoutInfo: any;
|
|
625
659
|
locusInfo: any;
|
|
660
|
+
// this group of properties is populated via updateMeetingObject() that's registered as a callback with LocusInfo
|
|
661
|
+
isUserUnadmitted?: boolean;
|
|
662
|
+
joinedWith?: any;
|
|
663
|
+
selfId?: string;
|
|
664
|
+
roles: any[];
|
|
665
|
+
// ... there is more ... see SelfUtils.parse()
|
|
666
|
+
// end of the group
|
|
626
667
|
locusMediaRequest?: LocusMediaRequest;
|
|
627
668
|
mediaProperties: MediaProperties;
|
|
628
669
|
mediaRequestManagers: {
|
|
@@ -657,7 +698,6 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
657
698
|
endCallInitJoinReq: any;
|
|
658
699
|
endJoinReqResp: any;
|
|
659
700
|
endLocalSDPGenRemoteSDPRecvDelay: any;
|
|
660
|
-
joinedWith: any;
|
|
661
701
|
locusId: any;
|
|
662
702
|
startCallInitJoinReq: any;
|
|
663
703
|
startJoinReqResp: any;
|
|
@@ -672,12 +712,11 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
672
712
|
permissionTokenReceivedLocalTime: number;
|
|
673
713
|
resourceId: any;
|
|
674
714
|
resourceUrl: string;
|
|
675
|
-
selfId: string;
|
|
676
715
|
state: any;
|
|
677
716
|
localAudioStreamMuteStateHandler: () => void;
|
|
678
717
|
localVideoStreamMuteStateHandler: () => void;
|
|
679
718
|
localOutputTrackChangeHandler: () => void;
|
|
680
|
-
|
|
719
|
+
localConstraintsChangeHandler: () => void;
|
|
681
720
|
environment: string;
|
|
682
721
|
namespace = MEETINGS;
|
|
683
722
|
allowMediaInLobby: boolean;
|
|
@@ -894,6 +933,10 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
894
933
|
*/
|
|
895
934
|
// @ts-ignore
|
|
896
935
|
this.simultaneousInterpretation = new SimultaneousInterpretation({}, {parent: this.webex});
|
|
936
|
+
|
|
937
|
+
// @ts-ignore
|
|
938
|
+
this.aiEnableRequest = new AIEnableRequest({}, {parent: this.webex});
|
|
939
|
+
|
|
897
940
|
/**
|
|
898
941
|
* @instance
|
|
899
942
|
* @type {Annotation}
|
|
@@ -1543,6 +1586,12 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1543
1586
|
}
|
|
1544
1587
|
};
|
|
1545
1588
|
|
|
1589
|
+
this.localConstraintsChangeHandler = () => {
|
|
1590
|
+
if (!this.isMultistream) {
|
|
1591
|
+
this.mediaProperties.webrtcMediaConnection?.updatePreferredBitrateKbps();
|
|
1592
|
+
}
|
|
1593
|
+
};
|
|
1594
|
+
|
|
1546
1595
|
/**
|
|
1547
1596
|
* Promise that exists if SDP offer has been generated, and resolves once sdp answer is received.
|
|
1548
1597
|
* @instance
|
|
@@ -2952,6 +3001,18 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2952
3001
|
);
|
|
2953
3002
|
});
|
|
2954
3003
|
|
|
3004
|
+
this.locusInfo.on(
|
|
3005
|
+
LOCUSINFO.EVENTS.CONTROLS_AI_SUMMARY_NOTIFICATION_UPDATED,
|
|
3006
|
+
({aiSummaryNotification}) => {
|
|
3007
|
+
Trigger.trigger(
|
|
3008
|
+
this,
|
|
3009
|
+
{file: 'meeting/index', function: 'setupLocusControlsListener'},
|
|
3010
|
+
EVENT_TRIGGERS.MEETING_CONTROLS_AI_SUMMARY_NOTIFICATION_UPDATED,
|
|
3011
|
+
{aiSummaryNotification}
|
|
3012
|
+
);
|
|
3013
|
+
}
|
|
3014
|
+
);
|
|
3015
|
+
|
|
2955
3016
|
this.locusInfo.on(LOCUSINFO.EVENTS.CONTROLS_WEBCAST_CHANGED, ({state}) => {
|
|
2956
3017
|
Trigger.trigger(
|
|
2957
3018
|
this,
|
|
@@ -3403,6 +3464,8 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3403
3464
|
this.recordingController.setLocusUrl(this.locusUrl);
|
|
3404
3465
|
this.controlsOptionsManager.setLocusUrl(this.locusUrl, !!isMainLocus);
|
|
3405
3466
|
this.webinar.locusUrlUpdate(url);
|
|
3467
|
+
// @ts-ignore
|
|
3468
|
+
this.webex.internal.llm.setRefreshHandler(() => this.refreshDataChannelToken());
|
|
3406
3469
|
|
|
3407
3470
|
Trigger.trigger(
|
|
3408
3471
|
this,
|
|
@@ -3433,6 +3496,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3433
3496
|
this.breakouts.breakoutServiceUrlUpdate(payload?.services?.breakout?.url);
|
|
3434
3497
|
this.annotation.approvalUrlUpdate(payload?.services?.approval?.url);
|
|
3435
3498
|
this.simultaneousInterpretation.approvalUrlUpdate(payload?.services?.approval?.url);
|
|
3499
|
+
this.aiEnableRequest.approvalUrlUpdate(payload?.services?.approval?.url);
|
|
3436
3500
|
});
|
|
3437
3501
|
}
|
|
3438
3502
|
|
|
@@ -3530,6 +3594,9 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3530
3594
|
// @ts-ignore - config coming from registerPlugin
|
|
3531
3595
|
if (datachannelUrl && this.config.enableAutomaticLLM) {
|
|
3532
3596
|
this.updateLLMConnection();
|
|
3597
|
+
if (this.webinar.isJoinPracticeSessionDataChannel()) {
|
|
3598
|
+
this.webinar.updatePSDataChannel();
|
|
3599
|
+
}
|
|
3533
3600
|
}
|
|
3534
3601
|
}
|
|
3535
3602
|
|
|
@@ -3667,7 +3734,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3667
3734
|
});
|
|
3668
3735
|
this.updateLLMConnection();
|
|
3669
3736
|
});
|
|
3670
|
-
this.locusInfo.on(LOCUSINFO.EVENTS.SELF_ADMITTED_GUEST,
|
|
3737
|
+
this.locusInfo.on(LOCUSINFO.EVENTS.SELF_ADMITTED_GUEST, (payload) => {
|
|
3671
3738
|
this.stopKeepAlive();
|
|
3672
3739
|
|
|
3673
3740
|
if (payload) {
|
|
@@ -3693,6 +3760,15 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3693
3760
|
});
|
|
3694
3761
|
}
|
|
3695
3762
|
this.rtcMetrics?.sendNextMetrics();
|
|
3763
|
+
|
|
3764
|
+
this.ensureDefaultDatachannelTokenAfterAdmit().catch((error) => {
|
|
3765
|
+
LoggerProxy.logger.warn(
|
|
3766
|
+
`Meeting:index#setUpLocusInfoSelfListener --> failed post-admit token prefetch flow: ${
|
|
3767
|
+
error?.message || String(error)
|
|
3768
|
+
}`
|
|
3769
|
+
);
|
|
3770
|
+
});
|
|
3771
|
+
|
|
3696
3772
|
this.updateLLMConnection();
|
|
3697
3773
|
});
|
|
3698
3774
|
|
|
@@ -3762,6 +3838,10 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3762
3838
|
);
|
|
3763
3839
|
});
|
|
3764
3840
|
|
|
3841
|
+
this.locusInfo.on(LOCUSINFO.EVENTS.SELF_ID_CHANGED, (payload) => {
|
|
3842
|
+
this.aiEnableRequest.selfParticipantIdUpdate(payload.selfId);
|
|
3843
|
+
});
|
|
3844
|
+
|
|
3765
3845
|
this.locusInfo.on(LOCUSINFO.EVENTS.SELF_MEETING_INTERPRETATION_CHANGED, (payload) => {
|
|
3766
3846
|
const targetChanged = this.simultaneousInterpretation.updateSelfInterpretation(payload);
|
|
3767
3847
|
Trigger.trigger(
|
|
@@ -4264,6 +4344,9 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4264
4344
|
bothLeaveAndEndMeetingAvailable: MeetingUtil.bothLeaveAndEndMeetingAvailable(
|
|
4265
4345
|
this.userDisplayHints
|
|
4266
4346
|
),
|
|
4347
|
+
requireHostEndMeetingBeforeLeave: MeetingUtil.requireHostEndMeetingBeforeLeave(
|
|
4348
|
+
this.userDisplayHints
|
|
4349
|
+
),
|
|
4267
4350
|
canEnableClosedCaption: MeetingUtil.canEnableClosedCaption(this.userDisplayHints),
|
|
4268
4351
|
canStartTranscribing: MeetingUtil.canStartTranscribing(this.userDisplayHints),
|
|
4269
4352
|
canStopTranscribing: MeetingUtil.canStopTranscribing(this.userDisplayHints),
|
|
@@ -4522,6 +4605,12 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4522
4605
|
requiredHints: [DISPLAY_HINTS.DISABLE_ATTENDEE_START_POLLING_QA],
|
|
4523
4606
|
displayHints: this.userDisplayHints,
|
|
4524
4607
|
}),
|
|
4608
|
+
canAttendeeRequestAiAssistantEnabled: MeetingUtil.canAttendeeRequestAiAssistantEnabled(
|
|
4609
|
+
this.userDisplayHints,
|
|
4610
|
+
this.roles
|
|
4611
|
+
),
|
|
4612
|
+
isAttendeeRequestAiAssistantDeclinedAll:
|
|
4613
|
+
MeetingUtil.attendeeRequestAiAssistantDeclinedAll(this.userDisplayHints),
|
|
4525
4614
|
}) || changed;
|
|
4526
4615
|
}
|
|
4527
4616
|
if (changed) {
|
|
@@ -4593,7 +4682,8 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4593
4682
|
mediaId: string;
|
|
4594
4683
|
host: object;
|
|
4595
4684
|
selfId: string;
|
|
4596
|
-
dataSets: DataSet[];
|
|
4685
|
+
dataSets: DataSet[]; // only sent by Locus when hash trees are used
|
|
4686
|
+
metadata: Metadata; // only sent by Locus when hash trees are used
|
|
4597
4687
|
}) {
|
|
4598
4688
|
const mtgLocus: any = data.locus;
|
|
4599
4689
|
|
|
@@ -4609,6 +4699,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4609
4699
|
trigger: 'join-response',
|
|
4610
4700
|
locus: mtgLocus,
|
|
4611
4701
|
dataSets: data.dataSets,
|
|
4702
|
+
metadata: data.metadata,
|
|
4612
4703
|
});
|
|
4613
4704
|
}
|
|
4614
4705
|
|
|
@@ -4818,6 +4909,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4818
4909
|
this.localVideoStreamMuteStateHandler
|
|
4819
4910
|
);
|
|
4820
4911
|
oldStream?.off(LocalStreamEventNames.OutputTrackChange, this.localOutputTrackChangeHandler);
|
|
4912
|
+
oldStream?.off(LocalStreamEventNames.ConstraintsChange, this.localConstraintsChangeHandler);
|
|
4821
4913
|
|
|
4822
4914
|
// we don't update this.mediaProperties.mediaDirection.sendVideo, because we always keep it as true to avoid extra SDP exchanges
|
|
4823
4915
|
this.mediaProperties.setLocalVideoStream(localStream);
|
|
@@ -4833,6 +4925,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4833
4925
|
this.localVideoStreamMuteStateHandler
|
|
4834
4926
|
);
|
|
4835
4927
|
localStream?.on(LocalStreamEventNames.OutputTrackChange, this.localOutputTrackChangeHandler);
|
|
4928
|
+
localStream?.on(LocalStreamEventNames.ConstraintsChange, this.localConstraintsChangeHandler);
|
|
4836
4929
|
|
|
4837
4930
|
if (!this.isMultistream || !localStream) {
|
|
4838
4931
|
// for multistream WCME automatically un-publishes the old stream when we publish a new one
|
|
@@ -4967,6 +5060,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4967
5060
|
this.localVideoStreamMuteStateHandler
|
|
4968
5061
|
);
|
|
4969
5062
|
videoStream?.off(LocalStreamEventNames.OutputTrackChange, this.localOutputTrackChangeHandler);
|
|
5063
|
+
videoStream?.off(LocalStreamEventNames.ConstraintsChange, this.localConstraintsChangeHandler);
|
|
4970
5064
|
|
|
4971
5065
|
shareAudioStream?.off(StreamEventNames.Ended, this.handleShareAudioStreamEnded);
|
|
4972
5066
|
shareAudioStream?.off(
|
|
@@ -5758,6 +5852,11 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5758
5852
|
*/
|
|
5759
5853
|
private processLocusLLMEvent = (event: LocusLLMEvent): void => {
|
|
5760
5854
|
if (event.data.eventType === LOCUSEVENT.HASH_TREE_DATA_UPDATED) {
|
|
5855
|
+
// @ts-ignore
|
|
5856
|
+
if (this.config.experimental.storeLocusHashTreeEventsForDebugging) {
|
|
5857
|
+
storeEventForDebugging('llm', event.data);
|
|
5858
|
+
}
|
|
5859
|
+
|
|
5761
5860
|
this.locusInfo.parse(this, event.data);
|
|
5762
5861
|
} else {
|
|
5763
5862
|
LoggerProxy.logger.warn(
|
|
@@ -5781,7 +5880,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5781
5880
|
this.isReactionsSupported()
|
|
5782
5881
|
) {
|
|
5783
5882
|
const member = this.members.membersCollection.get(e.data.sender.participantId);
|
|
5784
|
-
if (!member) {
|
|
5883
|
+
if (!member && !this.locusInfo?.info?.isWebinar) {
|
|
5785
5884
|
// @ts-ignore -- fix type
|
|
5786
5885
|
LoggerProxy.logger.warn(
|
|
5787
5886
|
`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 +5888,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5789
5888
|
break;
|
|
5790
5889
|
}
|
|
5791
5890
|
|
|
5792
|
-
const
|
|
5891
|
+
const name = (member && member.name) || e.data.sender.displayName;
|
|
5793
5892
|
const processedReaction: ProcessedReaction = {
|
|
5794
5893
|
reaction: e.data.reaction,
|
|
5795
5894
|
sender: {
|
|
@@ -5818,37 +5917,35 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5818
5917
|
* @returns {void}
|
|
5819
5918
|
*/
|
|
5820
5919
|
stopTranscription() {
|
|
5821
|
-
|
|
5822
|
-
|
|
5823
|
-
|
|
5824
|
-
|
|
5825
|
-
|
|
5826
|
-
);
|
|
5920
|
+
// @ts-ignore
|
|
5921
|
+
this.webex.internal.voicea.off(
|
|
5922
|
+
VOICEAEVENTS.VOICEA_ANNOUNCEMENT,
|
|
5923
|
+
this.voiceaListenerCallbacks[VOICEAEVENTS.VOICEA_ANNOUNCEMENT]
|
|
5924
|
+
);
|
|
5827
5925
|
|
|
5828
|
-
|
|
5829
|
-
|
|
5830
|
-
|
|
5831
|
-
|
|
5832
|
-
|
|
5926
|
+
// @ts-ignore
|
|
5927
|
+
this.webex.internal.voicea.off(
|
|
5928
|
+
VOICEAEVENTS.CAPTIONS_TURNED_ON,
|
|
5929
|
+
this.voiceaListenerCallbacks[VOICEAEVENTS.CAPTIONS_TURNED_ON]
|
|
5930
|
+
);
|
|
5833
5931
|
|
|
5834
|
-
|
|
5835
|
-
|
|
5836
|
-
|
|
5837
|
-
|
|
5838
|
-
|
|
5932
|
+
// @ts-ignore
|
|
5933
|
+
this.webex.internal.voicea.off(
|
|
5934
|
+
VOICEAEVENTS.EVA_COMMAND,
|
|
5935
|
+
this.voiceaListenerCallbacks[VOICEAEVENTS.EVA_COMMAND]
|
|
5936
|
+
);
|
|
5839
5937
|
|
|
5840
|
-
|
|
5841
|
-
|
|
5842
|
-
|
|
5843
|
-
|
|
5844
|
-
|
|
5938
|
+
// @ts-ignore
|
|
5939
|
+
this.webex.internal.voicea.off(
|
|
5940
|
+
VOICEAEVENTS.NEW_CAPTION,
|
|
5941
|
+
this.voiceaListenerCallbacks[VOICEAEVENTS.NEW_CAPTION]
|
|
5942
|
+
);
|
|
5845
5943
|
|
|
5846
|
-
|
|
5847
|
-
|
|
5944
|
+
// @ts-ignore
|
|
5945
|
+
this.webex.internal.voicea.deregisterEvents();
|
|
5848
5946
|
|
|
5849
|
-
|
|
5850
|
-
|
|
5851
|
-
}
|
|
5947
|
+
this.areVoiceaEventsSetup = false;
|
|
5948
|
+
this.triggerStopReceivingTranscriptionEvent();
|
|
5852
5949
|
}
|
|
5853
5950
|
|
|
5854
5951
|
/**
|
|
@@ -5872,6 +5969,30 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5872
5969
|
);
|
|
5873
5970
|
}
|
|
5874
5971
|
|
|
5972
|
+
/**
|
|
5973
|
+
* Restores LLM subchannel subscriptions after reconnect when captions are active.
|
|
5974
|
+
* @returns {void}
|
|
5975
|
+
*/
|
|
5976
|
+
private restoreLLMSubscriptionsIfNeeded(): void {
|
|
5977
|
+
try {
|
|
5978
|
+
// @ts-ignore
|
|
5979
|
+
const isCaptionBoxOn = this.webex.internal.voicea?.getIsCaptionBoxOn?.();
|
|
5980
|
+
|
|
5981
|
+
if (!isCaptionBoxOn) {
|
|
5982
|
+
return;
|
|
5983
|
+
}
|
|
5984
|
+
|
|
5985
|
+
// @ts-ignore
|
|
5986
|
+
this.webex.internal.voicea.updateSubchannelSubscriptions({subscribe: ['transcription']});
|
|
5987
|
+
} catch (error) {
|
|
5988
|
+
const msg = error?.message || String(error);
|
|
5989
|
+
|
|
5990
|
+
LoggerProxy.logger.warn(
|
|
5991
|
+
`Meeting:index#restoreLLMSubscriptionsIfNeeded --> failed to restore subscriptions after LLM online: ${msg}`
|
|
5992
|
+
);
|
|
5993
|
+
}
|
|
5994
|
+
}
|
|
5995
|
+
|
|
5875
5996
|
/**
|
|
5876
5997
|
* This is a callback for the LLM event that is triggered when it comes online
|
|
5877
5998
|
* This method in turn will trigger an event to the developers that the LLM is connected
|
|
@@ -5880,8 +6001,8 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5880
6001
|
* @returns {null}
|
|
5881
6002
|
*/
|
|
5882
6003
|
private handleLLMOnline = (): void => {
|
|
5883
|
-
|
|
5884
|
-
|
|
6004
|
+
this.restoreLLMSubscriptionsIfNeeded();
|
|
6005
|
+
|
|
5885
6006
|
Trigger.trigger(
|
|
5886
6007
|
this,
|
|
5887
6008
|
{
|
|
@@ -6109,8 +6230,11 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
6109
6230
|
return Promise.reject(error);
|
|
6110
6231
|
})
|
|
6111
6232
|
.then((join) => {
|
|
6233
|
+
this.saveDataChannelToken(join);
|
|
6112
6234
|
// @ts-ignore - config coming from registerPlugin
|
|
6113
6235
|
if (this.config.enableAutomaticLLM) {
|
|
6236
|
+
// @ts-ignore
|
|
6237
|
+
this.webex.internal.llm.off('online', this.handleLLMOnline);
|
|
6114
6238
|
// @ts-ignore
|
|
6115
6239
|
this.webex.internal.llm.on('online', this.handleLLMOnline);
|
|
6116
6240
|
this.updateLLMConnection()
|
|
@@ -6177,23 +6301,146 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
6177
6301
|
}
|
|
6178
6302
|
}
|
|
6179
6303
|
|
|
6304
|
+
/**
|
|
6305
|
+
* Disconnects and cleans up the default LLM session listeners/timers.
|
|
6306
|
+
* @param {Object} options
|
|
6307
|
+
* @param {boolean} [options.removeOnlineListener=true] removes the one-time online listener
|
|
6308
|
+
* @param {boolean} [options.throwOnError=true] rethrows disconnect errors when true
|
|
6309
|
+
* @returns {Promise<void>}
|
|
6310
|
+
*/
|
|
6311
|
+
private cleanupLLMConneciton = async ({
|
|
6312
|
+
removeOnlineListener = true,
|
|
6313
|
+
throwOnError = true,
|
|
6314
|
+
}: {
|
|
6315
|
+
removeOnlineListener?: boolean;
|
|
6316
|
+
throwOnError?: boolean;
|
|
6317
|
+
} = {}): Promise<void> => {
|
|
6318
|
+
try {
|
|
6319
|
+
// @ts-ignore - Fix type
|
|
6320
|
+
await this.webex.internal.llm.disconnectLLM({
|
|
6321
|
+
code: 3050,
|
|
6322
|
+
reason: 'done (permanent)',
|
|
6323
|
+
});
|
|
6324
|
+
} catch (error) {
|
|
6325
|
+
LoggerProxy.logger.error(
|
|
6326
|
+
'Meeting:index#cleanupLLMConneciton --> Failed to disconnect default LLM session',
|
|
6327
|
+
error
|
|
6328
|
+
);
|
|
6329
|
+
|
|
6330
|
+
if (throwOnError) {
|
|
6331
|
+
throw error;
|
|
6332
|
+
}
|
|
6333
|
+
} finally {
|
|
6334
|
+
if (removeOnlineListener) {
|
|
6335
|
+
// @ts-ignore - Fix type
|
|
6336
|
+
this.webex.internal.llm.off('online', this.handleLLMOnline);
|
|
6337
|
+
}
|
|
6338
|
+
// @ts-ignore - fix types
|
|
6339
|
+
this.webex.internal.llm.off('event:relay.event', this.processRelayEvent);
|
|
6340
|
+
// @ts-ignore - Fix type
|
|
6341
|
+
this.webex.internal.llm.off(LOCUS_LLM_EVENT, this.processLocusLLMEvent);
|
|
6342
|
+
|
|
6343
|
+
this.clearLLMHealthCheckTimer();
|
|
6344
|
+
}
|
|
6345
|
+
};
|
|
6346
|
+
|
|
6347
|
+
/**
|
|
6348
|
+
* Clears all data channel tokens stored in LLM.
|
|
6349
|
+
* Called during meeting cleanup to ensure stale tokens are not reused.
|
|
6350
|
+
* @returns {void}
|
|
6351
|
+
*/
|
|
6352
|
+
clearDataChannelToken(): void {
|
|
6353
|
+
// @ts-ignore
|
|
6354
|
+
this.webex.internal.llm.resetDatachannelTokens();
|
|
6355
|
+
}
|
|
6356
|
+
|
|
6357
|
+
/**
|
|
6358
|
+
* Saves the data channel tokens from the join response into LLM so that
|
|
6359
|
+
* updateLLMConnection / updatePSDataChannel don't need to fetch them from locusInfo.
|
|
6360
|
+
* @param {Object} join - The parsed join response (from MeetingUtil.parseLocusJoin)
|
|
6361
|
+
* @returns {void}
|
|
6362
|
+
*/
|
|
6363
|
+
saveDataChannelToken(join: any): void {
|
|
6364
|
+
const datachannelToken = join?.locus?.self?.datachannelToken;
|
|
6365
|
+
const practiceSessionDatachannelToken = join?.locus?.self?.practiceSessionDatachannelToken;
|
|
6366
|
+
|
|
6367
|
+
if (datachannelToken) {
|
|
6368
|
+
// @ts-ignore
|
|
6369
|
+
this.webex.internal.llm.setDatachannelToken(datachannelToken, DataChannelTokenType.Default);
|
|
6370
|
+
}
|
|
6371
|
+
|
|
6372
|
+
if (practiceSessionDatachannelToken) {
|
|
6373
|
+
// @ts-ignore
|
|
6374
|
+
this.webex.internal.llm.setDatachannelToken(
|
|
6375
|
+
practiceSessionDatachannelToken,
|
|
6376
|
+
DataChannelTokenType.PracticeSession
|
|
6377
|
+
);
|
|
6378
|
+
}
|
|
6379
|
+
}
|
|
6380
|
+
|
|
6381
|
+
/**
|
|
6382
|
+
* Ensures default-session data channel token exists after lobby admission.
|
|
6383
|
+
* Some lobby users do not receive a token until they are admitted.
|
|
6384
|
+
* @returns {Promise<boolean>} true when a new token is fetched and cached
|
|
6385
|
+
*/
|
|
6386
|
+
private async ensureDefaultDatachannelTokenAfterAdmit(): Promise<boolean> {
|
|
6387
|
+
try {
|
|
6388
|
+
// @ts-ignore
|
|
6389
|
+
const datachannelToken = this.webex.internal.llm.getDatachannelToken();
|
|
6390
|
+
// @ts-ignore
|
|
6391
|
+
const isDataChannelTokenEnabled = await this.webex.internal.llm.isDataChannelTokenEnabled();
|
|
6392
|
+
|
|
6393
|
+
if (!isDataChannelTokenEnabled || datachannelToken) {
|
|
6394
|
+
return false;
|
|
6395
|
+
}
|
|
6396
|
+
|
|
6397
|
+
const response = await this.meetingRequest.fetchDatachannelToken({
|
|
6398
|
+
locusUrl: this.locusUrl,
|
|
6399
|
+
requestingParticipantId: this.members.selfId,
|
|
6400
|
+
isPracticeSession: false,
|
|
6401
|
+
});
|
|
6402
|
+
const fetchedDatachannelToken = response?.body?.datachannelToken;
|
|
6403
|
+
|
|
6404
|
+
if (!fetchedDatachannelToken) {
|
|
6405
|
+
return false;
|
|
6406
|
+
}
|
|
6407
|
+
|
|
6408
|
+
// @ts-ignore
|
|
6409
|
+
this.webex.internal.llm.setDatachannelToken(
|
|
6410
|
+
fetchedDatachannelToken,
|
|
6411
|
+
DataChannelTokenType.Default
|
|
6412
|
+
);
|
|
6413
|
+
|
|
6414
|
+
return true;
|
|
6415
|
+
} catch (error) {
|
|
6416
|
+
const msg = error?.message || String(error);
|
|
6417
|
+
|
|
6418
|
+
LoggerProxy.logger.warn(
|
|
6419
|
+
`Meeting:index#ensureDefaultDatachannelTokenAfterAdmit --> failed to proactively fetch default data channel token after admit: ${msg}`,
|
|
6420
|
+
{statusCode: error?.statusCode}
|
|
6421
|
+
);
|
|
6422
|
+
|
|
6423
|
+
return false;
|
|
6424
|
+
}
|
|
6425
|
+
}
|
|
6426
|
+
|
|
6180
6427
|
/**
|
|
6181
6428
|
* Connects to low latency mercury and reconnects if the address has changed
|
|
6182
6429
|
* It will also disconnect if called when the meeting has ended
|
|
6183
|
-
* @param {String} datachannelUrl
|
|
6184
6430
|
* @returns {Promise}
|
|
6185
6431
|
*/
|
|
6186
6432
|
async updateLLMConnection() {
|
|
6187
6433
|
// @ts-ignore - Fix type
|
|
6188
|
-
const {url, info: {datachannelUrl
|
|
6434
|
+
const {url = undefined, info: {datachannelUrl = undefined} = {}} = this.locusInfo || {};
|
|
6189
6435
|
|
|
6190
6436
|
const isJoined = this.isJoined();
|
|
6191
6437
|
|
|
6192
|
-
//
|
|
6193
|
-
const
|
|
6194
|
-
|
|
6195
|
-
|
|
6196
|
-
|
|
6438
|
+
// @ts-ignore
|
|
6439
|
+
const datachannelToken = this.webex.internal.llm.getDatachannelToken(
|
|
6440
|
+
DataChannelTokenType.Default
|
|
6441
|
+
);
|
|
6442
|
+
|
|
6443
|
+
const dataChannelUrl = datachannelUrl;
|
|
6197
6444
|
|
|
6198
6445
|
// @ts-ignore - Fix type
|
|
6199
6446
|
if (this.webex.internal.llm.isConnected()) {
|
|
@@ -6206,21 +6453,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
6206
6453
|
) {
|
|
6207
6454
|
return undefined;
|
|
6208
6455
|
}
|
|
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();
|
|
6456
|
+
await this.cleanupLLMConneciton({removeOnlineListener: false});
|
|
6224
6457
|
}
|
|
6225
6458
|
|
|
6226
6459
|
if (!isJoined) {
|
|
@@ -6229,7 +6462,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
6229
6462
|
|
|
6230
6463
|
// @ts-ignore - Fix type
|
|
6231
6464
|
return this.webex.internal.llm
|
|
6232
|
-
.registerAndConnect(url, dataChannelUrl)
|
|
6465
|
+
.registerAndConnect(url, dataChannelUrl, datachannelToken)
|
|
6233
6466
|
.then((registerAndConnectResult) => {
|
|
6234
6467
|
// @ts-ignore - Fix type
|
|
6235
6468
|
this.webex.internal.llm.off('event:relay.event', this.processRelayEvent);
|
|
@@ -7433,7 +7666,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
7433
7666
|
*/
|
|
7434
7667
|
private async waitForMediaConnectionConnected(): Promise<void> {
|
|
7435
7668
|
try {
|
|
7436
|
-
await this.mediaProperties.waitForMediaConnectionConnected();
|
|
7669
|
+
await this.mediaProperties.waitForMediaConnectionConnected(this.correlationId);
|
|
7437
7670
|
} catch (error) {
|
|
7438
7671
|
const {iceConnected} = error;
|
|
7439
7672
|
|
|
@@ -8026,6 +8259,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
8026
8259
|
remoteMediaManagerConfig,
|
|
8027
8260
|
bundlePolicy = 'max-bundle',
|
|
8028
8261
|
additionalMediaOptions = {},
|
|
8262
|
+
allowPublishMediaInLobby = false,
|
|
8029
8263
|
} = options;
|
|
8030
8264
|
|
|
8031
8265
|
const {
|
|
@@ -8046,7 +8280,6 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
8046
8280
|
const ipver = MeetingUtil.getIpVersion(this.webex); // used just for metrics
|
|
8047
8281
|
|
|
8048
8282
|
// If the user is unjoined or guest waiting in lobby dont allow the user to addMedia
|
|
8049
|
-
// @ts-ignore - isUserUnadmitted coming from SelfUtil
|
|
8050
8283
|
if (this.isUserUnadmitted && !this.wirelessShare && !this.allowMediaInLobby) {
|
|
8051
8284
|
throw new UserInLobbyError();
|
|
8052
8285
|
}
|
|
@@ -8091,7 +8324,13 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
8091
8324
|
this.brbState = createBrbState(this, false);
|
|
8092
8325
|
|
|
8093
8326
|
try {
|
|
8094
|
-
|
|
8327
|
+
// if we're in a lobby and allowPublishMediaInLobby==false, we don't want to
|
|
8328
|
+
// setup local streams for publishing, because if we ever end up admitted to the meeting
|
|
8329
|
+
// but Locus event about it for us is delayed or missed, others could see/hear our user's video/audio
|
|
8330
|
+
// while the user would still think they're in the lobby
|
|
8331
|
+
if (allowPublishMediaInLobby || !this.isUserUnadmitted) {
|
|
8332
|
+
await this.setUpLocalStreamReferences(localStreams);
|
|
8333
|
+
}
|
|
8095
8334
|
|
|
8096
8335
|
this.setMercuryListener();
|
|
8097
8336
|
|
|
@@ -8559,12 +8798,12 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
8559
8798
|
LoggerProxy.logger.log('Meeting:index#leave --> Leaving a meeting');
|
|
8560
8799
|
|
|
8561
8800
|
return MeetingUtil.leaveMeeting(this, options)
|
|
8562
|
-
.then((leave) => {
|
|
8801
|
+
.then(async (leave) => {
|
|
8563
8802
|
// CA team recommends submitting this *after* locus /leave
|
|
8564
8803
|
submitLeaveMetric();
|
|
8565
8804
|
|
|
8566
8805
|
this.meetingFiniteStateMachine.leave();
|
|
8567
|
-
this.clearMeetingData();
|
|
8806
|
+
await this.clearMeetingData();
|
|
8568
8807
|
|
|
8569
8808
|
// upload logs on leave irrespective of meeting delete
|
|
8570
8809
|
Trigger.trigger(
|
|
@@ -9423,10 +9662,10 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
9423
9662
|
});
|
|
9424
9663
|
|
|
9425
9664
|
return MeetingUtil.endMeetingForAll(this)
|
|
9426
|
-
.then((end) => {
|
|
9665
|
+
.then(async (end) => {
|
|
9427
9666
|
this.meetingFiniteStateMachine.end();
|
|
9428
9667
|
|
|
9429
|
-
this.clearMeetingData();
|
|
9668
|
+
await this.clearMeetingData();
|
|
9430
9669
|
// upload logs on leave irrespective of meeting delete
|
|
9431
9670
|
Trigger.trigger(
|
|
9432
9671
|
this,
|
|
@@ -9474,7 +9713,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
9474
9713
|
* @public
|
|
9475
9714
|
* @memberof Meeting
|
|
9476
9715
|
*/
|
|
9477
|
-
clearMeetingData = () => {
|
|
9716
|
+
clearMeetingData = async () => {
|
|
9478
9717
|
this.audio = null;
|
|
9479
9718
|
this.video = null;
|
|
9480
9719
|
this.screenShareFloorState = ScreenShareFloorStatus.RELEASED;
|
|
@@ -9483,19 +9722,13 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
9483
9722
|
}
|
|
9484
9723
|
this.queuedMediaUpdates = [];
|
|
9485
9724
|
|
|
9486
|
-
|
|
9487
|
-
|
|
9488
|
-
this.transcription = undefined;
|
|
9489
|
-
}
|
|
9725
|
+
this.stopTranscription();
|
|
9726
|
+
this.transcription = undefined;
|
|
9490
9727
|
|
|
9491
9728
|
this.annotation.deregisterEvents();
|
|
9492
9729
|
|
|
9493
|
-
|
|
9494
|
-
this.
|
|
9495
|
-
// @ts-ignore - Fix type
|
|
9496
|
-
this.webex.internal.llm.off(LOCUS_LLM_EVENT, this.processLocusLLMEvent);
|
|
9497
|
-
|
|
9498
|
-
this.clearLLMHealthCheckTimer();
|
|
9730
|
+
this.clearDataChannelToken();
|
|
9731
|
+
await this.cleanupLLMConneciton({throwOnError: false});
|
|
9499
9732
|
};
|
|
9500
9733
|
|
|
9501
9734
|
/**
|
|
@@ -9688,15 +9921,20 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
9688
9921
|
}
|
|
9689
9922
|
|
|
9690
9923
|
if (shouldEnableMusicMode) {
|
|
9691
|
-
await this.sendSlotManager.
|
|
9692
|
-
|
|
9693
|
-
|
|
9694
|
-
|
|
9924
|
+
await this.sendSlotManager.setCustomCodecParameters(
|
|
9925
|
+
MediaType.AudioMain,
|
|
9926
|
+
MediaCodecMimeType.OPUS,
|
|
9927
|
+
{
|
|
9928
|
+
maxaveragebitrate: '64000',
|
|
9929
|
+
maxplaybackrate: '48000',
|
|
9930
|
+
}
|
|
9931
|
+
);
|
|
9695
9932
|
} else {
|
|
9696
|
-
await this.sendSlotManager.
|
|
9697
|
-
|
|
9698
|
-
|
|
9699
|
-
|
|
9933
|
+
await this.sendSlotManager.markCustomCodecParametersForDeletion(
|
|
9934
|
+
MediaType.AudioMain,
|
|
9935
|
+
MediaCodecMimeType.OPUS,
|
|
9936
|
+
['maxaveragebitrate', 'maxplaybackrate']
|
|
9937
|
+
);
|
|
9700
9938
|
}
|
|
9701
9939
|
}
|
|
9702
9940
|
|
|
@@ -10195,4 +10433,52 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
10195
10433
|
cancelSipCallOut(participantId: string) {
|
|
10196
10434
|
return this.meetingRequest.cancelSipCallOut(participantId);
|
|
10197
10435
|
}
|
|
10436
|
+
|
|
10437
|
+
/**
|
|
10438
|
+
* Method to get new data
|
|
10439
|
+
* @returns {Promise}
|
|
10440
|
+
*/
|
|
10441
|
+
public async refreshDataChannelToken() {
|
|
10442
|
+
const isPracticeSession = this.webinar.isJoinPracticeSessionDataChannel();
|
|
10443
|
+
const dataChannelTokenType = this.getDataChannelTokenType();
|
|
10444
|
+
|
|
10445
|
+
try {
|
|
10446
|
+
const res = await this.meetingRequest.fetchDatachannelToken({
|
|
10447
|
+
locusUrl: this.locusUrl,
|
|
10448
|
+
requestingParticipantId: this.members.selfId,
|
|
10449
|
+
isPracticeSession,
|
|
10450
|
+
});
|
|
10451
|
+
|
|
10452
|
+
return {
|
|
10453
|
+
body: {
|
|
10454
|
+
datachannelToken: res.body.datachannelToken,
|
|
10455
|
+
dataChannelTokenType,
|
|
10456
|
+
},
|
|
10457
|
+
};
|
|
10458
|
+
} catch (e) {
|
|
10459
|
+
const msg = e?.message || String(e);
|
|
10460
|
+
|
|
10461
|
+
LoggerProxy.logger.warn(
|
|
10462
|
+
`Meeting:index#refreshDataChannelToken --> DataChannel token refresh failed (likely locus changed or participant left): ${msg}`,
|
|
10463
|
+
{statusCode: e?.statusCode}
|
|
10464
|
+
);
|
|
10465
|
+
|
|
10466
|
+
return null;
|
|
10467
|
+
}
|
|
10468
|
+
}
|
|
10469
|
+
|
|
10470
|
+
/**
|
|
10471
|
+
* Determines the current data channel token type based on the meeting state.
|
|
10472
|
+
*
|
|
10473
|
+
* variant should be used when connecting to the LLM data channel.
|
|
10474
|
+
*
|
|
10475
|
+
* @returns {DataChannelTokenType} The token type representing the current session mode.
|
|
10476
|
+
*/
|
|
10477
|
+
public getDataChannelTokenType(): DataChannelTokenType {
|
|
10478
|
+
if (this.webinar.isJoinPracticeSessionDataChannel()) {
|
|
10479
|
+
return DataChannelTokenType.PracticeSession;
|
|
10480
|
+
}
|
|
10481
|
+
|
|
10482
|
+
return DataChannelTokenType.Default;
|
|
10483
|
+
}
|
|
10198
10484
|
}
|