@webex/plugin-meetings 3.11.0 → 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 +1304 -928
- 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/reachability/index.js +18 -10
- package/dist/reachability/index.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 +389 -87
- 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/reachability/index.ts +9 -0
- 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 +884 -152
- 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/reachability/index.ts +23 -0
- 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,
|
|
@@ -55,6 +58,7 @@ import {
|
|
|
55
58
|
isBrowserMediaError,
|
|
56
59
|
isBrowserMediaErrorName,
|
|
57
60
|
} from '@webex/internal-plugin-metrics/src/call-diagnostic/call-diagnostic-metrics.util';
|
|
61
|
+
import {CapabilityState, WebCapabilities} from '@webex/web-capabilities';
|
|
58
62
|
import {processNewCaptions} from './voicea-meeting';
|
|
59
63
|
|
|
60
64
|
import {
|
|
@@ -178,8 +182,9 @@ import JoinForbiddenError from '../common/errors/join-forbidden-error';
|
|
|
178
182
|
import {ReachabilityMetrics} from '../reachability/reachability.types';
|
|
179
183
|
import {SetStageOptions, SetStageVideoLayout, UnsetStageVideoLayout} from './request.type';
|
|
180
184
|
import {Invitee} from './type';
|
|
181
|
-
import {DataSet} from '../hashTree/hashTreeParser';
|
|
185
|
+
import {DataSet, HashTreeMessage, Metadata} from '../hashTree/hashTreeParser';
|
|
182
186
|
import {LocusDTO} from '../locus-info/types';
|
|
187
|
+
import AIEnableRequest from '../aiEnableRequest';
|
|
183
188
|
|
|
184
189
|
// default callback so we don't call an undefined function, but in practice it should never be used
|
|
185
190
|
const DEFAULT_ICE_PHASE_CALLBACK = () => 'JOIN_MEETING_FINAL';
|
|
@@ -249,6 +254,7 @@ export type AddMediaOptions = {
|
|
|
249
254
|
remoteMediaManagerConfig?: RemoteMediaManagerConfiguration; // applies only to multistream meetings
|
|
250
255
|
bundlePolicy?: BundlePolicy; // applies only to multistream meetings
|
|
251
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
|
|
252
258
|
additionalMediaOptions?: AdditionalMediaOptions; // allows adding additional options like send/receive audio/video
|
|
253
259
|
};
|
|
254
260
|
|
|
@@ -563,6 +569,34 @@ type MediaReachabilityMetrics = ReachabilityMetrics & {
|
|
|
563
569
|
* @memberof Meeting
|
|
564
570
|
*/
|
|
565
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
|
+
|
|
566
600
|
/**
|
|
567
601
|
* @description Meeting is the crux of the plugin
|
|
568
602
|
* @export
|
|
@@ -574,6 +608,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
574
608
|
breakouts: any;
|
|
575
609
|
simultaneousInterpretation: any;
|
|
576
610
|
annotation: any;
|
|
611
|
+
aiEnableRequest: any;
|
|
577
612
|
webinar: any;
|
|
578
613
|
conversationUrl: string;
|
|
579
614
|
callStateForMetrics: CallStateForMetrics;
|
|
@@ -622,6 +657,13 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
622
657
|
keepAliveTimerId: NodeJS.Timeout;
|
|
623
658
|
lastVideoLayoutInfo: any;
|
|
624
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
|
|
625
667
|
locusMediaRequest?: LocusMediaRequest;
|
|
626
668
|
mediaProperties: MediaProperties;
|
|
627
669
|
mediaRequestManagers: {
|
|
@@ -656,7 +698,6 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
656
698
|
endCallInitJoinReq: any;
|
|
657
699
|
endJoinReqResp: any;
|
|
658
700
|
endLocalSDPGenRemoteSDPRecvDelay: any;
|
|
659
|
-
joinedWith: any;
|
|
660
701
|
locusId: any;
|
|
661
702
|
startCallInitJoinReq: any;
|
|
662
703
|
startJoinReqResp: any;
|
|
@@ -671,12 +712,11 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
671
712
|
permissionTokenReceivedLocalTime: number;
|
|
672
713
|
resourceId: any;
|
|
673
714
|
resourceUrl: string;
|
|
674
|
-
selfId: string;
|
|
675
715
|
state: any;
|
|
676
716
|
localAudioStreamMuteStateHandler: () => void;
|
|
677
717
|
localVideoStreamMuteStateHandler: () => void;
|
|
678
718
|
localOutputTrackChangeHandler: () => void;
|
|
679
|
-
|
|
719
|
+
localConstraintsChangeHandler: () => void;
|
|
680
720
|
environment: string;
|
|
681
721
|
namespace = MEETINGS;
|
|
682
722
|
allowMediaInLobby: boolean;
|
|
@@ -893,6 +933,10 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
893
933
|
*/
|
|
894
934
|
// @ts-ignore
|
|
895
935
|
this.simultaneousInterpretation = new SimultaneousInterpretation({}, {parent: this.webex});
|
|
936
|
+
|
|
937
|
+
// @ts-ignore
|
|
938
|
+
this.aiEnableRequest = new AIEnableRequest({}, {parent: this.webex});
|
|
939
|
+
|
|
896
940
|
/**
|
|
897
941
|
* @instance
|
|
898
942
|
* @type {Annotation}
|
|
@@ -1542,6 +1586,12 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1542
1586
|
}
|
|
1543
1587
|
};
|
|
1544
1588
|
|
|
1589
|
+
this.localConstraintsChangeHandler = () => {
|
|
1590
|
+
if (!this.isMultistream) {
|
|
1591
|
+
this.mediaProperties.webrtcMediaConnection?.updatePreferredBitrateKbps();
|
|
1592
|
+
}
|
|
1593
|
+
};
|
|
1594
|
+
|
|
1545
1595
|
/**
|
|
1546
1596
|
* Promise that exists if SDP offer has been generated, and resolves once sdp answer is received.
|
|
1547
1597
|
* @instance
|
|
@@ -2951,6 +3001,18 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2951
3001
|
);
|
|
2952
3002
|
});
|
|
2953
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
|
+
|
|
2954
3016
|
this.locusInfo.on(LOCUSINFO.EVENTS.CONTROLS_WEBCAST_CHANGED, ({state}) => {
|
|
2955
3017
|
Trigger.trigger(
|
|
2956
3018
|
this,
|
|
@@ -3402,6 +3464,8 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3402
3464
|
this.recordingController.setLocusUrl(this.locusUrl);
|
|
3403
3465
|
this.controlsOptionsManager.setLocusUrl(this.locusUrl, !!isMainLocus);
|
|
3404
3466
|
this.webinar.locusUrlUpdate(url);
|
|
3467
|
+
// @ts-ignore
|
|
3468
|
+
this.webex.internal.llm.setRefreshHandler(() => this.refreshDataChannelToken());
|
|
3405
3469
|
|
|
3406
3470
|
Trigger.trigger(
|
|
3407
3471
|
this,
|
|
@@ -3432,6 +3496,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3432
3496
|
this.breakouts.breakoutServiceUrlUpdate(payload?.services?.breakout?.url);
|
|
3433
3497
|
this.annotation.approvalUrlUpdate(payload?.services?.approval?.url);
|
|
3434
3498
|
this.simultaneousInterpretation.approvalUrlUpdate(payload?.services?.approval?.url);
|
|
3499
|
+
this.aiEnableRequest.approvalUrlUpdate(payload?.services?.approval?.url);
|
|
3435
3500
|
});
|
|
3436
3501
|
}
|
|
3437
3502
|
|
|
@@ -3529,6 +3594,9 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3529
3594
|
// @ts-ignore - config coming from registerPlugin
|
|
3530
3595
|
if (datachannelUrl && this.config.enableAutomaticLLM) {
|
|
3531
3596
|
this.updateLLMConnection();
|
|
3597
|
+
if (this.webinar.isJoinPracticeSessionDataChannel()) {
|
|
3598
|
+
this.webinar.updatePSDataChannel();
|
|
3599
|
+
}
|
|
3532
3600
|
}
|
|
3533
3601
|
}
|
|
3534
3602
|
|
|
@@ -3666,7 +3734,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3666
3734
|
});
|
|
3667
3735
|
this.updateLLMConnection();
|
|
3668
3736
|
});
|
|
3669
|
-
this.locusInfo.on(LOCUSINFO.EVENTS.SELF_ADMITTED_GUEST,
|
|
3737
|
+
this.locusInfo.on(LOCUSINFO.EVENTS.SELF_ADMITTED_GUEST, (payload) => {
|
|
3670
3738
|
this.stopKeepAlive();
|
|
3671
3739
|
|
|
3672
3740
|
if (payload) {
|
|
@@ -3692,6 +3760,15 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3692
3760
|
});
|
|
3693
3761
|
}
|
|
3694
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
|
+
|
|
3695
3772
|
this.updateLLMConnection();
|
|
3696
3773
|
});
|
|
3697
3774
|
|
|
@@ -3761,6 +3838,10 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3761
3838
|
);
|
|
3762
3839
|
});
|
|
3763
3840
|
|
|
3841
|
+
this.locusInfo.on(LOCUSINFO.EVENTS.SELF_ID_CHANGED, (payload) => {
|
|
3842
|
+
this.aiEnableRequest.selfParticipantIdUpdate(payload.selfId);
|
|
3843
|
+
});
|
|
3844
|
+
|
|
3764
3845
|
this.locusInfo.on(LOCUSINFO.EVENTS.SELF_MEETING_INTERPRETATION_CHANGED, (payload) => {
|
|
3765
3846
|
const targetChanged = this.simultaneousInterpretation.updateSelfInterpretation(payload);
|
|
3766
3847
|
Trigger.trigger(
|
|
@@ -4263,6 +4344,9 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4263
4344
|
bothLeaveAndEndMeetingAvailable: MeetingUtil.bothLeaveAndEndMeetingAvailable(
|
|
4264
4345
|
this.userDisplayHints
|
|
4265
4346
|
),
|
|
4347
|
+
requireHostEndMeetingBeforeLeave: MeetingUtil.requireHostEndMeetingBeforeLeave(
|
|
4348
|
+
this.userDisplayHints
|
|
4349
|
+
),
|
|
4266
4350
|
canEnableClosedCaption: MeetingUtil.canEnableClosedCaption(this.userDisplayHints),
|
|
4267
4351
|
canStartTranscribing: MeetingUtil.canStartTranscribing(this.userDisplayHints),
|
|
4268
4352
|
canStopTranscribing: MeetingUtil.canStopTranscribing(this.userDisplayHints),
|
|
@@ -4521,6 +4605,12 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4521
4605
|
requiredHints: [DISPLAY_HINTS.DISABLE_ATTENDEE_START_POLLING_QA],
|
|
4522
4606
|
displayHints: this.userDisplayHints,
|
|
4523
4607
|
}),
|
|
4608
|
+
canAttendeeRequestAiAssistantEnabled: MeetingUtil.canAttendeeRequestAiAssistantEnabled(
|
|
4609
|
+
this.userDisplayHints,
|
|
4610
|
+
this.roles
|
|
4611
|
+
),
|
|
4612
|
+
isAttendeeRequestAiAssistantDeclinedAll:
|
|
4613
|
+
MeetingUtil.attendeeRequestAiAssistantDeclinedAll(this.userDisplayHints),
|
|
4524
4614
|
}) || changed;
|
|
4525
4615
|
}
|
|
4526
4616
|
if (changed) {
|
|
@@ -4592,7 +4682,8 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4592
4682
|
mediaId: string;
|
|
4593
4683
|
host: object;
|
|
4594
4684
|
selfId: string;
|
|
4595
|
-
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
|
|
4596
4687
|
}) {
|
|
4597
4688
|
const mtgLocus: any = data.locus;
|
|
4598
4689
|
|
|
@@ -4608,6 +4699,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4608
4699
|
trigger: 'join-response',
|
|
4609
4700
|
locus: mtgLocus,
|
|
4610
4701
|
dataSets: data.dataSets,
|
|
4702
|
+
metadata: data.metadata,
|
|
4611
4703
|
});
|
|
4612
4704
|
}
|
|
4613
4705
|
|
|
@@ -4817,6 +4909,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4817
4909
|
this.localVideoStreamMuteStateHandler
|
|
4818
4910
|
);
|
|
4819
4911
|
oldStream?.off(LocalStreamEventNames.OutputTrackChange, this.localOutputTrackChangeHandler);
|
|
4912
|
+
oldStream?.off(LocalStreamEventNames.ConstraintsChange, this.localConstraintsChangeHandler);
|
|
4820
4913
|
|
|
4821
4914
|
// we don't update this.mediaProperties.mediaDirection.sendVideo, because we always keep it as true to avoid extra SDP exchanges
|
|
4822
4915
|
this.mediaProperties.setLocalVideoStream(localStream);
|
|
@@ -4832,6 +4925,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4832
4925
|
this.localVideoStreamMuteStateHandler
|
|
4833
4926
|
);
|
|
4834
4927
|
localStream?.on(LocalStreamEventNames.OutputTrackChange, this.localOutputTrackChangeHandler);
|
|
4928
|
+
localStream?.on(LocalStreamEventNames.ConstraintsChange, this.localConstraintsChangeHandler);
|
|
4835
4929
|
|
|
4836
4930
|
if (!this.isMultistream || !localStream) {
|
|
4837
4931
|
// for multistream WCME automatically un-publishes the old stream when we publish a new one
|
|
@@ -4966,6 +5060,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4966
5060
|
this.localVideoStreamMuteStateHandler
|
|
4967
5061
|
);
|
|
4968
5062
|
videoStream?.off(LocalStreamEventNames.OutputTrackChange, this.localOutputTrackChangeHandler);
|
|
5063
|
+
videoStream?.off(LocalStreamEventNames.ConstraintsChange, this.localConstraintsChangeHandler);
|
|
4969
5064
|
|
|
4970
5065
|
shareAudioStream?.off(StreamEventNames.Ended, this.handleShareAudioStreamEnded);
|
|
4971
5066
|
shareAudioStream?.off(
|
|
@@ -5379,6 +5474,18 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5379
5474
|
let joined = false;
|
|
5380
5475
|
let joinResponse = prevJoinResponse;
|
|
5381
5476
|
|
|
5477
|
+
/* Before we do anything, check if RTCPeerConnection is available. Normally this is checked
|
|
5478
|
+
by addMediaInternal() itself when creating the media connection, but since joinWithMedia()
|
|
5479
|
+
is a convenience method that does both join() and addMedia(), we want to fail fast here
|
|
5480
|
+
in case WebRTC is not available at all.
|
|
5481
|
+
*/
|
|
5482
|
+
if (WebCapabilities.supportsRTCPeerConnection() === CapabilityState.NOT_CAPABLE) {
|
|
5483
|
+
// throw the same error that would be thrown by addMediaInternal()
|
|
5484
|
+
throw new Errors.WebrtcApiNotAvailableError(
|
|
5485
|
+
'RTCPeerConnection API is not available in this environment'
|
|
5486
|
+
);
|
|
5487
|
+
}
|
|
5488
|
+
|
|
5382
5489
|
try {
|
|
5383
5490
|
let turnServerInfo;
|
|
5384
5491
|
let turnDiscoverySkippedReason;
|
|
@@ -5449,7 +5556,10 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5449
5556
|
// if this was the first attempt, let's do a retry
|
|
5450
5557
|
let shouldRetry = !isRetry;
|
|
5451
5558
|
|
|
5452
|
-
if (
|
|
5559
|
+
if (
|
|
5560
|
+
CallDiagnosticUtils.isSdpOfferCreationError(error) ||
|
|
5561
|
+
CallDiagnosticUtils.isWebrtcApiNotAvailableError(error)
|
|
5562
|
+
) {
|
|
5453
5563
|
// errors related to offer creation (for example missing H264 codec) will happen again no matter how many times we try,
|
|
5454
5564
|
// so there is no point doing a retry
|
|
5455
5565
|
shouldRetry = false;
|
|
@@ -5742,6 +5852,11 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5742
5852
|
*/
|
|
5743
5853
|
private processLocusLLMEvent = (event: LocusLLMEvent): void => {
|
|
5744
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
|
+
|
|
5745
5860
|
this.locusInfo.parse(this, event.data);
|
|
5746
5861
|
} else {
|
|
5747
5862
|
LoggerProxy.logger.warn(
|
|
@@ -5765,7 +5880,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5765
5880
|
this.isReactionsSupported()
|
|
5766
5881
|
) {
|
|
5767
5882
|
const member = this.members.membersCollection.get(e.data.sender.participantId);
|
|
5768
|
-
if (!member) {
|
|
5883
|
+
if (!member && !this.locusInfo?.info?.isWebinar) {
|
|
5769
5884
|
// @ts-ignore -- fix type
|
|
5770
5885
|
LoggerProxy.logger.warn(
|
|
5771
5886
|
`Meeting:index#processRelayEvent --> Skipping handling of ${REACTION_RELAY_TYPES.REACTION} for ${this.id}. participantId ${e.data.sender.participantId} does not exist in membersCollection.`
|
|
@@ -5773,7 +5888,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5773
5888
|
break;
|
|
5774
5889
|
}
|
|
5775
5890
|
|
|
5776
|
-
const
|
|
5891
|
+
const name = (member && member.name) || e.data.sender.displayName;
|
|
5777
5892
|
const processedReaction: ProcessedReaction = {
|
|
5778
5893
|
reaction: e.data.reaction,
|
|
5779
5894
|
sender: {
|
|
@@ -5802,37 +5917,35 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5802
5917
|
* @returns {void}
|
|
5803
5918
|
*/
|
|
5804
5919
|
stopTranscription() {
|
|
5805
|
-
|
|
5806
|
-
|
|
5807
|
-
|
|
5808
|
-
|
|
5809
|
-
|
|
5810
|
-
);
|
|
5920
|
+
// @ts-ignore
|
|
5921
|
+
this.webex.internal.voicea.off(
|
|
5922
|
+
VOICEAEVENTS.VOICEA_ANNOUNCEMENT,
|
|
5923
|
+
this.voiceaListenerCallbacks[VOICEAEVENTS.VOICEA_ANNOUNCEMENT]
|
|
5924
|
+
);
|
|
5811
5925
|
|
|
5812
|
-
|
|
5813
|
-
|
|
5814
|
-
|
|
5815
|
-
|
|
5816
|
-
|
|
5926
|
+
// @ts-ignore
|
|
5927
|
+
this.webex.internal.voicea.off(
|
|
5928
|
+
VOICEAEVENTS.CAPTIONS_TURNED_ON,
|
|
5929
|
+
this.voiceaListenerCallbacks[VOICEAEVENTS.CAPTIONS_TURNED_ON]
|
|
5930
|
+
);
|
|
5817
5931
|
|
|
5818
|
-
|
|
5819
|
-
|
|
5820
|
-
|
|
5821
|
-
|
|
5822
|
-
|
|
5932
|
+
// @ts-ignore
|
|
5933
|
+
this.webex.internal.voicea.off(
|
|
5934
|
+
VOICEAEVENTS.EVA_COMMAND,
|
|
5935
|
+
this.voiceaListenerCallbacks[VOICEAEVENTS.EVA_COMMAND]
|
|
5936
|
+
);
|
|
5823
5937
|
|
|
5824
|
-
|
|
5825
|
-
|
|
5826
|
-
|
|
5827
|
-
|
|
5828
|
-
|
|
5938
|
+
// @ts-ignore
|
|
5939
|
+
this.webex.internal.voicea.off(
|
|
5940
|
+
VOICEAEVENTS.NEW_CAPTION,
|
|
5941
|
+
this.voiceaListenerCallbacks[VOICEAEVENTS.NEW_CAPTION]
|
|
5942
|
+
);
|
|
5829
5943
|
|
|
5830
|
-
|
|
5831
|
-
|
|
5944
|
+
// @ts-ignore
|
|
5945
|
+
this.webex.internal.voicea.deregisterEvents();
|
|
5832
5946
|
|
|
5833
|
-
|
|
5834
|
-
|
|
5835
|
-
}
|
|
5947
|
+
this.areVoiceaEventsSetup = false;
|
|
5948
|
+
this.triggerStopReceivingTranscriptionEvent();
|
|
5836
5949
|
}
|
|
5837
5950
|
|
|
5838
5951
|
/**
|
|
@@ -5856,6 +5969,30 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5856
5969
|
);
|
|
5857
5970
|
}
|
|
5858
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
|
+
|
|
5859
5996
|
/**
|
|
5860
5997
|
* This is a callback for the LLM event that is triggered when it comes online
|
|
5861
5998
|
* This method in turn will trigger an event to the developers that the LLM is connected
|
|
@@ -5864,8 +6001,8 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5864
6001
|
* @returns {null}
|
|
5865
6002
|
*/
|
|
5866
6003
|
private handleLLMOnline = (): void => {
|
|
5867
|
-
|
|
5868
|
-
|
|
6004
|
+
this.restoreLLMSubscriptionsIfNeeded();
|
|
6005
|
+
|
|
5869
6006
|
Trigger.trigger(
|
|
5870
6007
|
this,
|
|
5871
6008
|
{
|
|
@@ -6093,8 +6230,11 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
6093
6230
|
return Promise.reject(error);
|
|
6094
6231
|
})
|
|
6095
6232
|
.then((join) => {
|
|
6233
|
+
this.saveDataChannelToken(join);
|
|
6096
6234
|
// @ts-ignore - config coming from registerPlugin
|
|
6097
6235
|
if (this.config.enableAutomaticLLM) {
|
|
6236
|
+
// @ts-ignore
|
|
6237
|
+
this.webex.internal.llm.off('online', this.handleLLMOnline);
|
|
6098
6238
|
// @ts-ignore
|
|
6099
6239
|
this.webex.internal.llm.on('online', this.handleLLMOnline);
|
|
6100
6240
|
this.updateLLMConnection()
|
|
@@ -6161,23 +6301,146 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
6161
6301
|
}
|
|
6162
6302
|
}
|
|
6163
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
|
+
|
|
6164
6427
|
/**
|
|
6165
6428
|
* Connects to low latency mercury and reconnects if the address has changed
|
|
6166
6429
|
* It will also disconnect if called when the meeting has ended
|
|
6167
|
-
* @param {String} datachannelUrl
|
|
6168
6430
|
* @returns {Promise}
|
|
6169
6431
|
*/
|
|
6170
6432
|
async updateLLMConnection() {
|
|
6171
6433
|
// @ts-ignore - Fix type
|
|
6172
|
-
const {url, info: {datachannelUrl
|
|
6434
|
+
const {url = undefined, info: {datachannelUrl = undefined} = {}} = this.locusInfo || {};
|
|
6173
6435
|
|
|
6174
6436
|
const isJoined = this.isJoined();
|
|
6175
6437
|
|
|
6176
|
-
//
|
|
6177
|
-
const
|
|
6178
|
-
|
|
6179
|
-
|
|
6180
|
-
|
|
6438
|
+
// @ts-ignore
|
|
6439
|
+
const datachannelToken = this.webex.internal.llm.getDatachannelToken(
|
|
6440
|
+
DataChannelTokenType.Default
|
|
6441
|
+
);
|
|
6442
|
+
|
|
6443
|
+
const dataChannelUrl = datachannelUrl;
|
|
6181
6444
|
|
|
6182
6445
|
// @ts-ignore - Fix type
|
|
6183
6446
|
if (this.webex.internal.llm.isConnected()) {
|
|
@@ -6190,21 +6453,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
6190
6453
|
) {
|
|
6191
6454
|
return undefined;
|
|
6192
6455
|
}
|
|
6193
|
-
|
|
6194
|
-
await this.webex.internal.llm.disconnectLLM(
|
|
6195
|
-
isJoined
|
|
6196
|
-
? {
|
|
6197
|
-
code: 3050,
|
|
6198
|
-
reason: 'done (permanent)',
|
|
6199
|
-
}
|
|
6200
|
-
: undefined
|
|
6201
|
-
);
|
|
6202
|
-
// @ts-ignore - Fix type
|
|
6203
|
-
this.webex.internal.llm.off('event:relay.event', this.processRelayEvent);
|
|
6204
|
-
// @ts-ignore - Fix type
|
|
6205
|
-
this.webex.internal.llm.off(LOCUS_LLM_EVENT, this.processLocusLLMEvent);
|
|
6206
|
-
|
|
6207
|
-
this.clearLLMHealthCheckTimer();
|
|
6456
|
+
await this.cleanupLLMConneciton({removeOnlineListener: false});
|
|
6208
6457
|
}
|
|
6209
6458
|
|
|
6210
6459
|
if (!isJoined) {
|
|
@@ -6213,7 +6462,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
6213
6462
|
|
|
6214
6463
|
// @ts-ignore - Fix type
|
|
6215
6464
|
return this.webex.internal.llm
|
|
6216
|
-
.registerAndConnect(url, dataChannelUrl)
|
|
6465
|
+
.registerAndConnect(url, dataChannelUrl, datachannelToken)
|
|
6217
6466
|
.then((registerAndConnectResult) => {
|
|
6218
6467
|
// @ts-ignore - Fix type
|
|
6219
6468
|
this.webex.internal.llm.off('event:relay.event', this.processRelayEvent);
|
|
@@ -7417,7 +7666,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
7417
7666
|
*/
|
|
7418
7667
|
private async waitForMediaConnectionConnected(): Promise<void> {
|
|
7419
7668
|
try {
|
|
7420
|
-
await this.mediaProperties.waitForMediaConnectionConnected();
|
|
7669
|
+
await this.mediaProperties.waitForMediaConnectionConnected(this.correlationId);
|
|
7421
7670
|
} catch (error) {
|
|
7422
7671
|
const {iceConnected} = error;
|
|
7423
7672
|
|
|
@@ -8010,6 +8259,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
8010
8259
|
remoteMediaManagerConfig,
|
|
8011
8260
|
bundlePolicy = 'max-bundle',
|
|
8012
8261
|
additionalMediaOptions = {},
|
|
8262
|
+
allowPublishMediaInLobby = false,
|
|
8013
8263
|
} = options;
|
|
8014
8264
|
|
|
8015
8265
|
const {
|
|
@@ -8030,7 +8280,6 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
8030
8280
|
const ipver = MeetingUtil.getIpVersion(this.webex); // used just for metrics
|
|
8031
8281
|
|
|
8032
8282
|
// If the user is unjoined or guest waiting in lobby dont allow the user to addMedia
|
|
8033
|
-
// @ts-ignore - isUserUnadmitted coming from SelfUtil
|
|
8034
8283
|
if (this.isUserUnadmitted && !this.wirelessShare && !this.allowMediaInLobby) {
|
|
8035
8284
|
throw new UserInLobbyError();
|
|
8036
8285
|
}
|
|
@@ -8075,7 +8324,13 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
8075
8324
|
this.brbState = createBrbState(this, false);
|
|
8076
8325
|
|
|
8077
8326
|
try {
|
|
8078
|
-
|
|
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
|
+
}
|
|
8079
8334
|
|
|
8080
8335
|
this.setMercuryListener();
|
|
8081
8336
|
|
|
@@ -8543,12 +8798,12 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
8543
8798
|
LoggerProxy.logger.log('Meeting:index#leave --> Leaving a meeting');
|
|
8544
8799
|
|
|
8545
8800
|
return MeetingUtil.leaveMeeting(this, options)
|
|
8546
|
-
.then((leave) => {
|
|
8801
|
+
.then(async (leave) => {
|
|
8547
8802
|
// CA team recommends submitting this *after* locus /leave
|
|
8548
8803
|
submitLeaveMetric();
|
|
8549
8804
|
|
|
8550
8805
|
this.meetingFiniteStateMachine.leave();
|
|
8551
|
-
this.clearMeetingData();
|
|
8806
|
+
await this.clearMeetingData();
|
|
8552
8807
|
|
|
8553
8808
|
// upload logs on leave irrespective of meeting delete
|
|
8554
8809
|
Trigger.trigger(
|
|
@@ -9407,10 +9662,10 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
9407
9662
|
});
|
|
9408
9663
|
|
|
9409
9664
|
return MeetingUtil.endMeetingForAll(this)
|
|
9410
|
-
.then((end) => {
|
|
9665
|
+
.then(async (end) => {
|
|
9411
9666
|
this.meetingFiniteStateMachine.end();
|
|
9412
9667
|
|
|
9413
|
-
this.clearMeetingData();
|
|
9668
|
+
await this.clearMeetingData();
|
|
9414
9669
|
// upload logs on leave irrespective of meeting delete
|
|
9415
9670
|
Trigger.trigger(
|
|
9416
9671
|
this,
|
|
@@ -9458,7 +9713,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
9458
9713
|
* @public
|
|
9459
9714
|
* @memberof Meeting
|
|
9460
9715
|
*/
|
|
9461
|
-
clearMeetingData = () => {
|
|
9716
|
+
clearMeetingData = async () => {
|
|
9462
9717
|
this.audio = null;
|
|
9463
9718
|
this.video = null;
|
|
9464
9719
|
this.screenShareFloorState = ScreenShareFloorStatus.RELEASED;
|
|
@@ -9467,19 +9722,13 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
9467
9722
|
}
|
|
9468
9723
|
this.queuedMediaUpdates = [];
|
|
9469
9724
|
|
|
9470
|
-
|
|
9471
|
-
|
|
9472
|
-
this.transcription = undefined;
|
|
9473
|
-
}
|
|
9725
|
+
this.stopTranscription();
|
|
9726
|
+
this.transcription = undefined;
|
|
9474
9727
|
|
|
9475
9728
|
this.annotation.deregisterEvents();
|
|
9476
9729
|
|
|
9477
|
-
|
|
9478
|
-
this.
|
|
9479
|
-
// @ts-ignore - Fix type
|
|
9480
|
-
this.webex.internal.llm.off(LOCUS_LLM_EVENT, this.processLocusLLMEvent);
|
|
9481
|
-
|
|
9482
|
-
this.clearLLMHealthCheckTimer();
|
|
9730
|
+
this.clearDataChannelToken();
|
|
9731
|
+
await this.cleanupLLMConneciton({throwOnError: false});
|
|
9483
9732
|
};
|
|
9484
9733
|
|
|
9485
9734
|
/**
|
|
@@ -9672,15 +9921,20 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
9672
9921
|
}
|
|
9673
9922
|
|
|
9674
9923
|
if (shouldEnableMusicMode) {
|
|
9675
|
-
await this.sendSlotManager.
|
|
9676
|
-
|
|
9677
|
-
|
|
9678
|
-
|
|
9924
|
+
await this.sendSlotManager.setCustomCodecParameters(
|
|
9925
|
+
MediaType.AudioMain,
|
|
9926
|
+
MediaCodecMimeType.OPUS,
|
|
9927
|
+
{
|
|
9928
|
+
maxaveragebitrate: '64000',
|
|
9929
|
+
maxplaybackrate: '48000',
|
|
9930
|
+
}
|
|
9931
|
+
);
|
|
9679
9932
|
} else {
|
|
9680
|
-
await this.sendSlotManager.
|
|
9681
|
-
|
|
9682
|
-
|
|
9683
|
-
|
|
9933
|
+
await this.sendSlotManager.markCustomCodecParametersForDeletion(
|
|
9934
|
+
MediaType.AudioMain,
|
|
9935
|
+
MediaCodecMimeType.OPUS,
|
|
9936
|
+
['maxaveragebitrate', 'maxplaybackrate']
|
|
9937
|
+
);
|
|
9684
9938
|
}
|
|
9685
9939
|
}
|
|
9686
9940
|
|
|
@@ -10179,4 +10433,52 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
10179
10433
|
cancelSipCallOut(participantId: string) {
|
|
10180
10434
|
return this.meetingRequest.cancelSipCallOut(participantId);
|
|
10181
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
|
+
}
|
|
10182
10484
|
}
|