@webex/plugin-meetings 3.0.0 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/breakouts/breakout.js +1 -1
- package/dist/breakouts/index.js +1 -1
- package/dist/config.d.ts +1 -0
- package/dist/config.js +2 -1
- package/dist/config.js.map +1 -1
- package/dist/constants.d.ts +5 -4
- package/dist/constants.js +8 -4
- package/dist/constants.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/interpretation/index.js +16 -2
- package/dist/interpretation/index.js.map +1 -1
- package/dist/interpretation/siLanguage.js +1 -1
- package/dist/locus-info/mediaSharesUtils.js +15 -1
- package/dist/locus-info/mediaSharesUtils.js.map +1 -1
- package/dist/locus-info/selfUtils.js +5 -0
- package/dist/locus-info/selfUtils.js.map +1 -1
- package/dist/media/MediaConnectionAwaiter.d.ts +61 -0
- package/dist/media/MediaConnectionAwaiter.js +163 -0
- package/dist/media/MediaConnectionAwaiter.js.map +1 -0
- package/dist/media/index.js +4 -1
- package/dist/media/index.js.map +1 -1
- package/dist/media/properties.js +4 -24
- package/dist/media/properties.js.map +1 -1
- package/dist/meeting/index.d.ts +26 -7
- package/dist/meeting/index.js +893 -677
- package/dist/meeting/index.js.map +1 -1
- package/dist/meeting/muteState.d.ts +2 -8
- package/dist/meeting/muteState.js +37 -25
- package/dist/meeting/muteState.js.map +1 -1
- package/dist/meeting/request.d.ts +3 -0
- package/dist/meeting/request.js +32 -23
- package/dist/meeting/request.js.map +1 -1
- package/dist/meeting/util.js +1 -0
- package/dist/meeting/util.js.map +1 -1
- package/dist/meeting-info/utilv2.js +4 -1
- package/dist/meeting-info/utilv2.js.map +1 -1
- package/dist/meetings/index.d.ts +8 -0
- package/dist/meetings/index.js +20 -0
- package/dist/meetings/index.js.map +1 -1
- package/dist/multistream/mediaRequestManager.d.ts +2 -1
- package/dist/multistream/mediaRequestManager.js +1 -1
- package/dist/multistream/mediaRequestManager.js.map +1 -1
- package/dist/multistream/remoteMediaGroup.d.ts +2 -0
- package/dist/multistream/remoteMediaGroup.js +16 -2
- package/dist/multistream/remoteMediaGroup.js.map +1 -1
- package/dist/multistream/remoteMediaManager.d.ts +15 -0
- package/dist/multistream/remoteMediaManager.js +179 -65
- package/dist/multistream/remoteMediaManager.js.map +1 -1
- package/dist/multistream/sendSlotManager.d.ts +9 -1
- package/dist/multistream/sendSlotManager.js +22 -0
- package/dist/multistream/sendSlotManager.js.map +1 -1
- package/dist/reachability/clusterReachability.d.ts +1 -0
- package/dist/reachability/clusterReachability.js +29 -15
- package/dist/reachability/clusterReachability.js.map +1 -1
- package/dist/reachability/index.d.ts +4 -0
- package/dist/reachability/index.js +18 -2
- package/dist/reachability/index.js.map +1 -1
- package/dist/reachability/request.js +12 -10
- package/dist/reachability/request.js.map +1 -1
- package/dist/reachability/util.d.ts +7 -0
- package/dist/reachability/util.js +19 -0
- package/dist/reachability/util.js.map +1 -1
- package/dist/reconnection-manager/index.js +2 -1
- package/dist/reconnection-manager/index.js.map +1 -1
- package/dist/roap/index.d.ts +10 -2
- package/dist/roap/index.js +15 -0
- package/dist/roap/index.js.map +1 -1
- package/dist/roap/request.js +3 -3
- package/dist/roap/request.js.map +1 -1
- package/dist/roap/turnDiscovery.d.ts +64 -17
- package/dist/roap/turnDiscovery.js +307 -126
- package/dist/roap/turnDiscovery.js.map +1 -1
- package/dist/statsAnalyzer/index.js +53 -30
- package/dist/statsAnalyzer/index.js.map +1 -1
- package/dist/webinar/index.js +1 -1
- package/package.json +22 -22
- package/src/config.ts +1 -0
- package/src/constants.ts +7 -3
- package/src/index.ts +1 -0
- package/src/interpretation/index.ts +18 -1
- package/src/locus-info/mediaSharesUtils.ts +16 -0
- package/src/locus-info/selfUtils.ts +5 -0
- package/src/media/MediaConnectionAwaiter.ts +174 -0
- package/src/media/index.ts +3 -1
- package/src/media/properties.ts +6 -31
- package/src/meeting/index.ts +321 -106
- package/src/meeting/muteState.ts +34 -20
- package/src/meeting/request.ts +18 -2
- package/src/meeting/util.ts +1 -0
- package/src/meeting-info/utilv2.ts +2 -1
- package/src/meetings/index.ts +18 -0
- package/src/multistream/mediaRequestManager.ts +4 -1
- package/src/multistream/remoteMediaGroup.ts +19 -0
- package/src/multistream/remoteMediaManager.ts +101 -16
- package/src/multistream/sendSlotManager.ts +28 -0
- package/src/reachability/clusterReachability.ts +20 -5
- package/src/reachability/index.ts +24 -1
- package/src/reachability/request.ts +15 -11
- package/src/reachability/util.ts +21 -0
- package/src/reconnection-manager/index.ts +1 -1
- package/src/roap/index.ts +25 -3
- package/src/roap/request.ts +3 -3
- package/src/roap/turnDiscovery.ts +244 -78
- package/src/statsAnalyzer/index.ts +63 -27
- package/test/integration/spec/journey.js +14 -14
- package/test/integration/spec/space-meeting.js +1 -1
- package/test/unit/spec/interpretation/index.ts +39 -3
- package/test/unit/spec/locus-info/index.js +28 -19
- package/test/unit/spec/locus-info/mediaSharesUtils.ts +9 -0
- package/test/unit/spec/locus-info/selfUtils.js +42 -12
- package/test/unit/spec/media/MediaConnectionAwaiter.ts +344 -0
- package/test/unit/spec/media/index.ts +89 -78
- package/test/unit/spec/media/properties.ts +16 -70
- package/test/unit/spec/meeting/index.js +638 -139
- package/test/unit/spec/meeting/muteState.js +219 -67
- package/test/unit/spec/meeting/request.js +21 -0
- package/test/unit/spec/meeting/utils.js +6 -1
- package/test/unit/spec/meeting-info/utilv2.js +6 -0
- package/test/unit/spec/meetings/index.js +40 -20
- package/test/unit/spec/multistream/mediaRequestManager.ts +20 -2
- package/test/unit/spec/multistream/remoteMediaGroup.ts +79 -1
- package/test/unit/spec/multistream/remoteMediaManager.ts +199 -1
- package/test/unit/spec/multistream/sendSlotManager.ts +50 -18
- package/test/unit/spec/reachability/clusterReachability.ts +86 -22
- package/test/unit/spec/reachability/index.ts +197 -60
- package/test/unit/spec/reachability/request.js +15 -7
- package/test/unit/spec/reachability/util.ts +32 -2
- package/test/unit/spec/reconnection-manager/index.js +28 -0
- package/test/unit/spec/roap/index.ts +61 -6
- package/test/unit/spec/roap/turnDiscovery.ts +298 -16
- package/test/unit/spec/stats-analyzer/index.js +179 -0
- package/dist/member/member.types.d.ts +0 -11
- package/dist/member/member.types.js +0 -17
- package/dist/member/member.types.js.map +0 -1
- package/src/member/member.types.ts +0 -13
- /package/test/unit/spec/locus-info/{lib/selfConstant.js → selfConstant.js} +0 -0
package/src/meeting/index.ts
CHANGED
|
@@ -10,6 +10,8 @@ import {
|
|
|
10
10
|
ClientEventLeaveReason,
|
|
11
11
|
CallDiagnosticUtils,
|
|
12
12
|
} from '@webex/internal-plugin-metrics';
|
|
13
|
+
import {ClientEvent as RawClientEvent} from '@webex/event-dictionary-ts';
|
|
14
|
+
|
|
13
15
|
import {
|
|
14
16
|
ConnectionState,
|
|
15
17
|
Errors,
|
|
@@ -50,8 +52,13 @@ import {
|
|
|
50
52
|
import {StatsAnalyzer, EVENTS as StatsAnalyzerEvents} from '../statsAnalyzer';
|
|
51
53
|
import NetworkQualityMonitor from '../networkQualityMonitor';
|
|
52
54
|
import LoggerProxy from '../common/logs/logger-proxy';
|
|
55
|
+
import EventsUtil from '../common/events/util';
|
|
53
56
|
import Trigger from '../common/events/trigger-proxy';
|
|
54
|
-
import Roap
|
|
57
|
+
import Roap, {
|
|
58
|
+
type TurnDiscoveryResult,
|
|
59
|
+
type TurnServerInfo,
|
|
60
|
+
type TurnDiscoverySkipReason,
|
|
61
|
+
} from '../roap/index';
|
|
55
62
|
import Media, {type BundlePolicy} from '../media';
|
|
56
63
|
import MediaProperties from '../media/properties';
|
|
57
64
|
import MeetingStateMachine from './state';
|
|
@@ -110,6 +117,7 @@ import {
|
|
|
110
117
|
MEETING_PERMISSION_TOKEN_REFRESH_REASON,
|
|
111
118
|
ROAP_OFFER_ANSWER_EXCHANGE_TIMEOUT,
|
|
112
119
|
RECONNECTION,
|
|
120
|
+
NAMED_MEDIA_GROUP_TYPE_AUDIO,
|
|
113
121
|
LANGUAGE_ENGLISH,
|
|
114
122
|
} from '../constants';
|
|
115
123
|
import BEHAVIORAL_METRICS from '../metrics/constants';
|
|
@@ -119,7 +127,6 @@ import {
|
|
|
119
127
|
MeetingInfoV2CaptchaError,
|
|
120
128
|
MeetingInfoV2PolicyError,
|
|
121
129
|
} from '../meeting-info/meeting-info-v2';
|
|
122
|
-
import BrowserDetection from '../common/browser-detection';
|
|
123
130
|
import {CSI, ReceiveSlotManager} from '../multistream/receiveSlotManager';
|
|
124
131
|
import SendSlotManager from '../multistream/sendSlotManager';
|
|
125
132
|
import {MediaRequestManager} from '../multistream/mediaRequestManager';
|
|
@@ -147,8 +154,6 @@ import ControlsOptionsManager from '../controls-options-manager';
|
|
|
147
154
|
import PermissionError from '../common/errors/permission';
|
|
148
155
|
import {LocusMediaRequest} from './locusMediaRequest';
|
|
149
156
|
|
|
150
|
-
const {isBrowser} = BrowserDetection();
|
|
151
|
-
|
|
152
157
|
const logRequest = (request: any, {logText = ''}) => {
|
|
153
158
|
LoggerProxy.logger.info(`${logText} - sending request`);
|
|
154
159
|
|
|
@@ -614,8 +619,8 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
614
619
|
resourceUrl: string;
|
|
615
620
|
selfId: string;
|
|
616
621
|
state: any;
|
|
617
|
-
localAudioStreamMuteStateHandler: (
|
|
618
|
-
localVideoStreamMuteStateHandler: (
|
|
622
|
+
localAudioStreamMuteStateHandler: () => void;
|
|
623
|
+
localVideoStreamMuteStateHandler: () => void;
|
|
619
624
|
localOutputTrackChangeHandler: () => void;
|
|
620
625
|
roles: any[];
|
|
621
626
|
environment: string;
|
|
@@ -623,21 +628,23 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
623
628
|
allowMediaInLobby: boolean;
|
|
624
629
|
localShareInstanceId: string;
|
|
625
630
|
remoteShareInstanceId: string;
|
|
626
|
-
turnDiscoverySkippedReason:
|
|
631
|
+
turnDiscoverySkippedReason: TurnDiscoverySkipReason;
|
|
627
632
|
turnServerUsed: boolean;
|
|
628
633
|
areVoiceaEventsSetup = false;
|
|
634
|
+
|
|
629
635
|
voiceaListenerCallbacks: object = {
|
|
630
636
|
[VOICEAEVENTS.VOICEA_ANNOUNCEMENT]: (payload: Transcription['languageOptions']) => {
|
|
631
637
|
this.transcription.languageOptions = payload;
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
{
|
|
638
|
+
|
|
639
|
+
LoggerProxy.logger.debug(
|
|
640
|
+
`${EventsUtil.getScopeLog({
|
|
635
641
|
file: 'meeting/index',
|
|
636
642
|
function: 'setUpVoiceaListeners',
|
|
637
|
-
}
|
|
638
|
-
EVENT_TRIGGERS.MEETING_STARTED_RECEIVING_TRANSCRIPTION,
|
|
639
|
-
payload
|
|
643
|
+
})}event#${EVENT_TRIGGERS.MEETING_STARTED_RECEIVING_TRANSCRIPTION}`
|
|
640
644
|
);
|
|
645
|
+
|
|
646
|
+
// @ts-ignore
|
|
647
|
+
this.trigger(EVENT_TRIGGERS.MEETING_STARTED_RECEIVING_TRANSCRIPTION, payload);
|
|
641
648
|
},
|
|
642
649
|
[VOICEAEVENTS.CAPTIONS_TURNED_ON]: () => {
|
|
643
650
|
this.transcription.status = TURN_ON_CAPTION_STATUS.ENABLED;
|
|
@@ -650,18 +657,19 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
650
657
|
},
|
|
651
658
|
[VOICEAEVENTS.NEW_CAPTION]: (data) => {
|
|
652
659
|
processNewCaptions({data, meeting: this});
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
{
|
|
660
|
+
|
|
661
|
+
LoggerProxy.logger.debug(
|
|
662
|
+
`${EventsUtil.getScopeLog({
|
|
656
663
|
file: 'meeting/index',
|
|
657
664
|
function: 'setUpVoiceaListeners',
|
|
658
|
-
}
|
|
659
|
-
EVENT_TRIGGERS.MEETING_CAPTION_RECEIVED,
|
|
660
|
-
{
|
|
661
|
-
captions: this.transcription.captions,
|
|
662
|
-
interimCaptions: this.transcription.interimCaptions,
|
|
663
|
-
}
|
|
665
|
+
})}event#${EVENT_TRIGGERS.MEETING_CAPTION_RECEIVED}`
|
|
664
666
|
);
|
|
667
|
+
|
|
668
|
+
// @ts-ignore
|
|
669
|
+
this.trigger(EVENT_TRIGGERS.MEETING_CAPTION_RECEIVED, {
|
|
670
|
+
captions: this.transcription.captions,
|
|
671
|
+
interimCaptions: this.transcription.interimCaptions,
|
|
672
|
+
});
|
|
665
673
|
},
|
|
666
674
|
};
|
|
667
675
|
|
|
@@ -1380,12 +1388,12 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1380
1388
|
*/
|
|
1381
1389
|
this.remoteMediaManager = null;
|
|
1382
1390
|
|
|
1383
|
-
this.localAudioStreamMuteStateHandler = (
|
|
1384
|
-
this.audio.handleLocalStreamMuteStateChange(this
|
|
1391
|
+
this.localAudioStreamMuteStateHandler = () => {
|
|
1392
|
+
this.audio.handleLocalStreamMuteStateChange(this);
|
|
1385
1393
|
};
|
|
1386
1394
|
|
|
1387
|
-
this.localVideoStreamMuteStateHandler = (
|
|
1388
|
-
this.video.handleLocalStreamMuteStateChange(this
|
|
1395
|
+
this.localVideoStreamMuteStateHandler = () => {
|
|
1396
|
+
this.video.handleLocalStreamMuteStateChange(this);
|
|
1389
1397
|
};
|
|
1390
1398
|
|
|
1391
1399
|
// The handling of output track changes should be done inside
|
|
@@ -2518,6 +2526,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2518
2526
|
{
|
|
2519
2527
|
annotationInfo: contentShare?.annotation,
|
|
2520
2528
|
meetingId: this.id,
|
|
2529
|
+
resourceType: contentShare?.resourceType,
|
|
2521
2530
|
}
|
|
2522
2531
|
);
|
|
2523
2532
|
}
|
|
@@ -2546,7 +2555,8 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2546
2555
|
contentShare.deviceUrlSharing === previousContentShare.deviceUrlSharing &&
|
|
2547
2556
|
whiteboardShare.beneficiaryId === previousWhiteboardShare?.beneficiaryId &&
|
|
2548
2557
|
whiteboardShare.disposition === previousWhiteboardShare?.disposition &&
|
|
2549
|
-
whiteboardShare.resourceUrl === previousWhiteboardShare?.resourceUrl
|
|
2558
|
+
whiteboardShare.resourceUrl === previousWhiteboardShare?.resourceUrl &&
|
|
2559
|
+
contentShare.resourceType === previousContentShare?.resourceType
|
|
2550
2560
|
) {
|
|
2551
2561
|
// nothing changed, so ignore
|
|
2552
2562
|
// (this happens when we steal presentation from remote)
|
|
@@ -2668,6 +2678,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2668
2678
|
url: contentShare.url,
|
|
2669
2679
|
shareInstanceId: this.remoteShareInstanceId,
|
|
2670
2680
|
annotationInfo: contentShare.annotation,
|
|
2681
|
+
resourceType: contentShare.resourceType,
|
|
2671
2682
|
}
|
|
2672
2683
|
);
|
|
2673
2684
|
};
|
|
@@ -2760,6 +2771,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2760
2771
|
url: contentShare.url,
|
|
2761
2772
|
shareInstanceId: this.remoteShareInstanceId,
|
|
2762
2773
|
annotationInfo: contentShare.annotation,
|
|
2774
|
+
resourceType: contentShare.resourceType,
|
|
2763
2775
|
}
|
|
2764
2776
|
);
|
|
2765
2777
|
this.members.locusMediaSharesUpdate(payload);
|
|
@@ -3069,6 +3081,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3069
3081
|
options: {meetingId: this.id},
|
|
3070
3082
|
});
|
|
3071
3083
|
}
|
|
3084
|
+
this.updateLLMConnection();
|
|
3072
3085
|
});
|
|
3073
3086
|
|
|
3074
3087
|
// @ts-ignore - check if MEDIA_INACTIVITY exists
|
|
@@ -3127,7 +3140,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3127
3140
|
});
|
|
3128
3141
|
|
|
3129
3142
|
this.locusInfo.on(LOCUSINFO.EVENTS.SELF_MEETING_INTERPRETATION_CHANGED, (payload) => {
|
|
3130
|
-
this.simultaneousInterpretation.updateSelfInterpretation(payload);
|
|
3143
|
+
const targetChanged = this.simultaneousInterpretation.updateSelfInterpretation(payload);
|
|
3131
3144
|
Trigger.trigger(
|
|
3132
3145
|
this,
|
|
3133
3146
|
{
|
|
@@ -3136,6 +3149,9 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3136
3149
|
},
|
|
3137
3150
|
EVENT_TRIGGERS.MEETING_INTERPRETATION_UPDATE
|
|
3138
3151
|
);
|
|
3152
|
+
if (targetChanged && this.mediaProperties.audioStream) {
|
|
3153
|
+
this.setSendNamedMediaGroup(MediaType.AudioMain);
|
|
3154
|
+
}
|
|
3139
3155
|
});
|
|
3140
3156
|
|
|
3141
3157
|
this.locusInfo.on(LOCUSINFO.EVENTS.SELF_ROLES_CHANGED, (payload) => {
|
|
@@ -3450,8 +3466,10 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3450
3466
|
this.owner =
|
|
3451
3467
|
locusMeetingObject?.info.owner || meetingInfo?.owner || meetingInfo?.hostId || this.owner;
|
|
3452
3468
|
this.permissionToken = meetingInfo?.permissionToken;
|
|
3453
|
-
this.
|
|
3454
|
-
|
|
3469
|
+
if (this.permissionToken) {
|
|
3470
|
+
this.setPermissionTokenPayload(meetingInfo?.permissionToken);
|
|
3471
|
+
this.setSelfUserPolicies();
|
|
3472
|
+
}
|
|
3455
3473
|
// Need to populate environment when sending CA event
|
|
3456
3474
|
this.environment = locusMeetingObject?.info.channel || meetingInfo?.channel;
|
|
3457
3475
|
}
|
|
@@ -3887,7 +3905,14 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3887
3905
|
private async setLocalAudioStream(localStream?: LocalMicrophoneStream) {
|
|
3888
3906
|
const oldStream = this.mediaProperties.audioStream;
|
|
3889
3907
|
|
|
3890
|
-
oldStream?.off(
|
|
3908
|
+
oldStream?.off(
|
|
3909
|
+
LocalStreamEventNames.UserMuteStateChange,
|
|
3910
|
+
this.localAudioStreamMuteStateHandler
|
|
3911
|
+
);
|
|
3912
|
+
oldStream?.off(
|
|
3913
|
+
LocalStreamEventNames.SystemMuteStateChange,
|
|
3914
|
+
this.localAudioStreamMuteStateHandler
|
|
3915
|
+
);
|
|
3891
3916
|
oldStream?.off(LocalStreamEventNames.OutputTrackChange, this.localOutputTrackChangeHandler);
|
|
3892
3917
|
|
|
3893
3918
|
// we don't update this.mediaProperties.mediaDirection.sendAudio, because we always keep it as true to avoid extra SDP exchanges
|
|
@@ -3895,7 +3920,14 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3895
3920
|
|
|
3896
3921
|
this.audio.handleLocalStreamChange(this);
|
|
3897
3922
|
|
|
3898
|
-
localStream?.on(
|
|
3923
|
+
localStream?.on(
|
|
3924
|
+
LocalStreamEventNames.UserMuteStateChange,
|
|
3925
|
+
this.localAudioStreamMuteStateHandler
|
|
3926
|
+
);
|
|
3927
|
+
localStream?.on(
|
|
3928
|
+
LocalStreamEventNames.SystemMuteStateChange,
|
|
3929
|
+
this.localAudioStreamMuteStateHandler
|
|
3930
|
+
);
|
|
3899
3931
|
localStream?.on(LocalStreamEventNames.OutputTrackChange, this.localOutputTrackChangeHandler);
|
|
3900
3932
|
|
|
3901
3933
|
if (!this.isMultistream || !localStream) {
|
|
@@ -3915,7 +3947,14 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3915
3947
|
private async setLocalVideoStream(localStream?: LocalCameraStream) {
|
|
3916
3948
|
const oldStream = this.mediaProperties.videoStream;
|
|
3917
3949
|
|
|
3918
|
-
oldStream?.off(
|
|
3950
|
+
oldStream?.off(
|
|
3951
|
+
LocalStreamEventNames.UserMuteStateChange,
|
|
3952
|
+
this.localVideoStreamMuteStateHandler
|
|
3953
|
+
);
|
|
3954
|
+
oldStream?.off(
|
|
3955
|
+
LocalStreamEventNames.SystemMuteStateChange,
|
|
3956
|
+
this.localVideoStreamMuteStateHandler
|
|
3957
|
+
);
|
|
3919
3958
|
oldStream?.off(LocalStreamEventNames.OutputTrackChange, this.localOutputTrackChangeHandler);
|
|
3920
3959
|
|
|
3921
3960
|
// we don't update this.mediaProperties.mediaDirection.sendVideo, because we always keep it as true to avoid extra SDP exchanges
|
|
@@ -3923,7 +3962,14 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3923
3962
|
|
|
3924
3963
|
this.video.handleLocalStreamChange(this);
|
|
3925
3964
|
|
|
3926
|
-
localStream?.on(
|
|
3965
|
+
localStream?.on(
|
|
3966
|
+
LocalStreamEventNames.UserMuteStateChange,
|
|
3967
|
+
this.localVideoStreamMuteStateHandler
|
|
3968
|
+
);
|
|
3969
|
+
localStream?.on(
|
|
3970
|
+
LocalStreamEventNames.SystemMuteStateChange,
|
|
3971
|
+
this.localVideoStreamMuteStateHandler
|
|
3972
|
+
);
|
|
3927
3973
|
localStream?.on(LocalStreamEventNames.OutputTrackChange, this.localOutputTrackChangeHandler);
|
|
3928
3974
|
|
|
3929
3975
|
if (!this.isMultistream || !localStream) {
|
|
@@ -3944,14 +3990,17 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3944
3990
|
private async setLocalShareVideoStream(localDisplayStream?: LocalDisplayStream) {
|
|
3945
3991
|
const oldStream = this.mediaProperties.shareVideoStream;
|
|
3946
3992
|
|
|
3947
|
-
oldStream?.off(
|
|
3993
|
+
oldStream?.off(
|
|
3994
|
+
LocalStreamEventNames.SystemMuteStateChange,
|
|
3995
|
+
this.handleShareVideoStreamMuteStateChange
|
|
3996
|
+
);
|
|
3948
3997
|
oldStream?.off(StreamEventNames.Ended, this.handleShareVideoStreamEnded);
|
|
3949
3998
|
oldStream?.off(LocalStreamEventNames.OutputTrackChange, this.localOutputTrackChangeHandler);
|
|
3950
3999
|
|
|
3951
4000
|
this.mediaProperties.setLocalShareVideoStream(localDisplayStream);
|
|
3952
4001
|
|
|
3953
4002
|
localDisplayStream?.on(
|
|
3954
|
-
|
|
4003
|
+
LocalStreamEventNames.SystemMuteStateChange,
|
|
3955
4004
|
this.handleShareVideoStreamMuteStateChange
|
|
3956
4005
|
);
|
|
3957
4006
|
localDisplayStream?.on(StreamEventNames.Ended, this.handleShareVideoStreamEnded);
|
|
@@ -4037,10 +4086,24 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4037
4086
|
public cleanupLocalStreams() {
|
|
4038
4087
|
const {audioStream, videoStream, shareAudioStream, shareVideoStream} = this.mediaProperties;
|
|
4039
4088
|
|
|
4040
|
-
audioStream?.off(
|
|
4089
|
+
audioStream?.off(
|
|
4090
|
+
LocalStreamEventNames.UserMuteStateChange,
|
|
4091
|
+
this.localAudioStreamMuteStateHandler
|
|
4092
|
+
);
|
|
4093
|
+
audioStream?.off(
|
|
4094
|
+
LocalStreamEventNames.SystemMuteStateChange,
|
|
4095
|
+
this.localAudioStreamMuteStateHandler
|
|
4096
|
+
);
|
|
4041
4097
|
audioStream?.off(LocalStreamEventNames.OutputTrackChange, this.localOutputTrackChangeHandler);
|
|
4042
4098
|
|
|
4043
|
-
videoStream?.off(
|
|
4099
|
+
videoStream?.off(
|
|
4100
|
+
LocalStreamEventNames.UserMuteStateChange,
|
|
4101
|
+
this.localVideoStreamMuteStateHandler
|
|
4102
|
+
);
|
|
4103
|
+
videoStream?.off(
|
|
4104
|
+
LocalStreamEventNames.SystemMuteStateChange,
|
|
4105
|
+
this.localVideoStreamMuteStateHandler
|
|
4106
|
+
);
|
|
4044
4107
|
videoStream?.off(LocalStreamEventNames.OutputTrackChange, this.localOutputTrackChangeHandler);
|
|
4045
4108
|
|
|
4046
4109
|
shareAudioStream?.off(StreamEventNames.Ended, this.handleShareAudioStreamEnded);
|
|
@@ -4048,8 +4111,9 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4048
4111
|
LocalStreamEventNames.OutputTrackChange,
|
|
4049
4112
|
this.localOutputTrackChangeHandler
|
|
4050
4113
|
);
|
|
4114
|
+
|
|
4051
4115
|
shareVideoStream?.off(
|
|
4052
|
-
|
|
4116
|
+
LocalStreamEventNames.SystemMuteStateChange,
|
|
4053
4117
|
this.handleShareVideoStreamMuteStateChange
|
|
4054
4118
|
);
|
|
4055
4119
|
shareVideoStream?.off(StreamEventNames.Ended, this.handleShareVideoStreamEnded);
|
|
@@ -4441,47 +4505,90 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4441
4505
|
* }
|
|
4442
4506
|
* })
|
|
4443
4507
|
*/
|
|
4444
|
-
public joinWithMedia(
|
|
4508
|
+
public async joinWithMedia(
|
|
4445
4509
|
options: {
|
|
4446
4510
|
joinOptions?: any;
|
|
4447
4511
|
mediaOptions?: AddMediaOptions;
|
|
4448
4512
|
} = {}
|
|
4449
4513
|
) {
|
|
4450
|
-
const {mediaOptions, joinOptions} = options;
|
|
4514
|
+
const {mediaOptions, joinOptions = {}} = options;
|
|
4451
4515
|
|
|
4452
4516
|
if (!mediaOptions?.allowMediaInLobby) {
|
|
4453
4517
|
return Promise.reject(
|
|
4454
4518
|
new ParameterError('joinWithMedia() can only be used with allowMediaInLobby set to true')
|
|
4455
4519
|
);
|
|
4456
4520
|
}
|
|
4521
|
+
this.allowMediaInLobby = true;
|
|
4457
4522
|
|
|
4458
4523
|
LoggerProxy.logger.info('Meeting:index#joinWithMedia called');
|
|
4459
4524
|
|
|
4460
|
-
|
|
4461
|
-
.then((joinResponse) =>
|
|
4462
|
-
this.addMedia(mediaOptions).then((mediaResponse) => ({
|
|
4463
|
-
join: joinResponse,
|
|
4464
|
-
media: mediaResponse,
|
|
4465
|
-
}))
|
|
4466
|
-
)
|
|
4467
|
-
.catch((error) => {
|
|
4468
|
-
LoggerProxy.logger.error('Meeting:index#joinWithMedia --> ', error);
|
|
4525
|
+
let joined = false;
|
|
4469
4526
|
|
|
4470
|
-
|
|
4471
|
-
|
|
4472
|
-
|
|
4473
|
-
correlation_id: this.correlationId,
|
|
4474
|
-
locus_id: this.locusUrl.split('/').pop(),
|
|
4475
|
-
reason: error.message,
|
|
4476
|
-
stack: error.stack,
|
|
4477
|
-
},
|
|
4478
|
-
{
|
|
4479
|
-
type: error.name,
|
|
4480
|
-
}
|
|
4481
|
-
);
|
|
4527
|
+
try {
|
|
4528
|
+
let turnServerInfo;
|
|
4529
|
+
let turnDiscoverySkippedReason;
|
|
4482
4530
|
|
|
4483
|
-
|
|
4484
|
-
|
|
4531
|
+
// @ts-ignore
|
|
4532
|
+
joinOptions.reachability = await this.webex.meetings.reachability.getReachabilityResults();
|
|
4533
|
+
const turnDiscoveryRequest = await this.roap.generateTurnDiscoveryRequestMessage(this, true);
|
|
4534
|
+
|
|
4535
|
+
({turnDiscoverySkippedReason} = turnDiscoveryRequest);
|
|
4536
|
+
joinOptions.roapMessage = turnDiscoveryRequest.roapMessage;
|
|
4537
|
+
|
|
4538
|
+
const joinResponse = await this.join(joinOptions);
|
|
4539
|
+
|
|
4540
|
+
joined = true;
|
|
4541
|
+
|
|
4542
|
+
if (joinOptions.roapMessage) {
|
|
4543
|
+
({turnServerInfo, turnDiscoverySkippedReason} =
|
|
4544
|
+
await this.roap.handleTurnDiscoveryHttpResponse(this, joinResponse));
|
|
4545
|
+
|
|
4546
|
+
this.turnDiscoverySkippedReason = turnDiscoverySkippedReason;
|
|
4547
|
+
this.turnServerUsed = !!turnServerInfo;
|
|
4548
|
+
|
|
4549
|
+
if (turnServerInfo === undefined) {
|
|
4550
|
+
this.roap.abortTurnDiscovery();
|
|
4551
|
+
}
|
|
4552
|
+
}
|
|
4553
|
+
|
|
4554
|
+
const mediaResponse = await this.addMedia(mediaOptions, turnServerInfo);
|
|
4555
|
+
|
|
4556
|
+
return {
|
|
4557
|
+
join: joinResponse,
|
|
4558
|
+
media: mediaResponse,
|
|
4559
|
+
};
|
|
4560
|
+
} catch (error) {
|
|
4561
|
+
LoggerProxy.logger.error('Meeting:index#joinWithMedia --> ', error);
|
|
4562
|
+
|
|
4563
|
+
let leaveError;
|
|
4564
|
+
|
|
4565
|
+
this.roap.abortTurnDiscovery();
|
|
4566
|
+
|
|
4567
|
+
if (joined) {
|
|
4568
|
+
try {
|
|
4569
|
+
await this.leave({resourceId: joinOptions?.resourceId, reason: 'joinWithMedia failure'});
|
|
4570
|
+
} catch (e) {
|
|
4571
|
+
LoggerProxy.logger.error('Meeting:index#joinWithMedia --> leave error', e);
|
|
4572
|
+
leaveError = e;
|
|
4573
|
+
}
|
|
4574
|
+
}
|
|
4575
|
+
|
|
4576
|
+
Metrics.sendBehavioralMetric(
|
|
4577
|
+
BEHAVIORAL_METRICS.JOIN_WITH_MEDIA_FAILURE,
|
|
4578
|
+
{
|
|
4579
|
+
correlation_id: this.correlationId,
|
|
4580
|
+
locus_id: this.locusUrl?.split('/').pop(), // if join fails, we may end up with no locusUrl
|
|
4581
|
+
reason: error.message,
|
|
4582
|
+
stack: error.stack,
|
|
4583
|
+
leaveErrorReason: leaveError?.message,
|
|
4584
|
+
},
|
|
4585
|
+
{
|
|
4586
|
+
type: error.name,
|
|
4587
|
+
}
|
|
4588
|
+
);
|
|
4589
|
+
|
|
4590
|
+
throw error;
|
|
4591
|
+
}
|
|
4485
4592
|
}
|
|
4486
4593
|
|
|
4487
4594
|
/**
|
|
@@ -5604,7 +5711,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5604
5711
|
logText: `${LOG_HEADER} Roap Offer`,
|
|
5605
5712
|
}
|
|
5606
5713
|
).catch(() => {
|
|
5607
|
-
this.deferSDPAnswer.reject();
|
|
5714
|
+
this.deferSDPAnswer.reject(new Error('failed to send ROAP SDP offer'));
|
|
5608
5715
|
clearTimeout(this.sdpResponseTimer);
|
|
5609
5716
|
this.sdpResponseTimer = undefined;
|
|
5610
5717
|
});
|
|
@@ -5951,6 +6058,20 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5951
6058
|
meetingId: this.id,
|
|
5952
6059
|
},
|
|
5953
6060
|
});
|
|
6061
|
+
|
|
6062
|
+
if (data.type === 'share') {
|
|
6063
|
+
// @ts-ignore
|
|
6064
|
+
this.webex.internal.newMetrics.submitClientEvent({
|
|
6065
|
+
name: 'client.media.render.start',
|
|
6066
|
+
payload: {
|
|
6067
|
+
mediaType: 'share',
|
|
6068
|
+
shareInstanceId: this.remoteShareInstanceId,
|
|
6069
|
+
},
|
|
6070
|
+
options: {
|
|
6071
|
+
meetingId: this.id,
|
|
6072
|
+
},
|
|
6073
|
+
});
|
|
6074
|
+
}
|
|
5954
6075
|
});
|
|
5955
6076
|
this.statsAnalyzer.on(StatsAnalyzerEvents.REMOTE_MEDIA_STOPPED, (data) => {
|
|
5956
6077
|
// @ts-ignore
|
|
@@ -5964,6 +6085,20 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5964
6085
|
meetingId: this.id,
|
|
5965
6086
|
},
|
|
5966
6087
|
});
|
|
6088
|
+
|
|
6089
|
+
if (data.type === 'share') {
|
|
6090
|
+
// @ts-ignore
|
|
6091
|
+
this.webex.internal.newMetrics.submitClientEvent({
|
|
6092
|
+
name: 'client.media.render.stop',
|
|
6093
|
+
payload: {
|
|
6094
|
+
mediaType: 'share',
|
|
6095
|
+
shareInstanceId: this.remoteShareInstanceId,
|
|
6096
|
+
},
|
|
6097
|
+
options: {
|
|
6098
|
+
meetingId: this.id,
|
|
6099
|
+
},
|
|
6100
|
+
});
|
|
6101
|
+
}
|
|
5967
6102
|
});
|
|
5968
6103
|
};
|
|
5969
6104
|
|
|
@@ -6020,6 +6155,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
6020
6155
|
|
|
6021
6156
|
// publish the streams
|
|
6022
6157
|
if (this.mediaProperties.audioStream) {
|
|
6158
|
+
this.setSendNamedMediaGroup(MediaType.AudioMain);
|
|
6023
6159
|
await this.publishStream(MediaType.AudioMain, this.mediaProperties.audioStream);
|
|
6024
6160
|
}
|
|
6025
6161
|
if (this.mediaProperties.videoStream) {
|
|
@@ -6069,16 +6205,22 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
6069
6205
|
private async setUpLocalStreamReferences(localStreams: LocalStreams) {
|
|
6070
6206
|
const setUpStreamPromises = [];
|
|
6071
6207
|
|
|
6072
|
-
if (localStreams?.microphone) {
|
|
6208
|
+
if (localStreams?.microphone && localStreams?.microphone?.readyState !== 'ended') {
|
|
6073
6209
|
setUpStreamPromises.push(this.setLocalAudioStream(localStreams.microphone));
|
|
6074
6210
|
}
|
|
6075
|
-
if (localStreams?.camera) {
|
|
6211
|
+
if (localStreams?.camera && localStreams?.camera?.readyState !== 'ended') {
|
|
6076
6212
|
setUpStreamPromises.push(this.setLocalVideoStream(localStreams.camera));
|
|
6077
6213
|
}
|
|
6078
|
-
if (
|
|
6214
|
+
if (
|
|
6215
|
+
localStreams?.screenShare?.video &&
|
|
6216
|
+
localStreams?.screenShare?.video?.readyState !== 'ended'
|
|
6217
|
+
) {
|
|
6079
6218
|
setUpStreamPromises.push(this.setLocalShareVideoStream(localStreams.screenShare.video));
|
|
6080
6219
|
}
|
|
6081
|
-
if (
|
|
6220
|
+
if (
|
|
6221
|
+
localStreams?.screenShare?.audio &&
|
|
6222
|
+
localStreams?.screenShare?.audio?.readyState !== 'ended'
|
|
6223
|
+
) {
|
|
6082
6224
|
setUpStreamPromises.push(this.setLocalShareAudioStream(localStreams.screenShare.audio));
|
|
6083
6225
|
}
|
|
6084
6226
|
|
|
@@ -6323,6 +6465,44 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
6323
6465
|
}
|
|
6324
6466
|
}
|
|
6325
6467
|
|
|
6468
|
+
/**
|
|
6469
|
+
* Performs TURN discovery as a separate call to the Locus /media API
|
|
6470
|
+
*
|
|
6471
|
+
* @param {boolean} isRetry
|
|
6472
|
+
* @param {boolean} isForced
|
|
6473
|
+
* @returns {Promise}
|
|
6474
|
+
*/
|
|
6475
|
+
private async doTurnDiscovery(isRetry: boolean, isForced: boolean): Promise<TurnDiscoveryResult> {
|
|
6476
|
+
// @ts-ignore
|
|
6477
|
+
const cdl = this.webex.internal.newMetrics.callDiagnosticLatencies;
|
|
6478
|
+
|
|
6479
|
+
// @ts-ignore
|
|
6480
|
+
this.webex.internal.newMetrics.submitInternalEvent({
|
|
6481
|
+
name: 'internal.client.add-media.turn-discovery.start',
|
|
6482
|
+
});
|
|
6483
|
+
|
|
6484
|
+
const turnDiscoveryResult = await this.roap.doTurnDiscovery(this, isRetry, isForced);
|
|
6485
|
+
|
|
6486
|
+
this.turnDiscoverySkippedReason = turnDiscoveryResult?.turnDiscoverySkippedReason;
|
|
6487
|
+
this.turnServerUsed = !this.turnDiscoverySkippedReason;
|
|
6488
|
+
|
|
6489
|
+
// @ts-ignore
|
|
6490
|
+
this.webex.internal.newMetrics.submitInternalEvent({
|
|
6491
|
+
name: 'internal.client.add-media.turn-discovery.end',
|
|
6492
|
+
});
|
|
6493
|
+
|
|
6494
|
+
if (this.turnServerUsed && turnDiscoveryResult.turnServerInfo) {
|
|
6495
|
+
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.TURN_DISCOVERY_LATENCY, {
|
|
6496
|
+
correlation_id: this.correlationId,
|
|
6497
|
+
latency: cdl.getTurnDiscoveryTime(),
|
|
6498
|
+
turnServerUsed: this.turnServerUsed,
|
|
6499
|
+
retriedWithTurnServer: this.retriedWithTurnServer,
|
|
6500
|
+
});
|
|
6501
|
+
}
|
|
6502
|
+
|
|
6503
|
+
return turnDiscoveryResult;
|
|
6504
|
+
}
|
|
6505
|
+
|
|
6326
6506
|
/**
|
|
6327
6507
|
* Does TURN discovery, SDP offer/answer exhange, establishes ICE connection and DTLS handshake.
|
|
6328
6508
|
*
|
|
@@ -6330,43 +6510,21 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
6330
6510
|
* @param {RemoteMediaManagerConfiguration} [remoteMediaManagerConfig]
|
|
6331
6511
|
* @param {BundlePolicy} [bundlePolicy]
|
|
6332
6512
|
* @param {boolean} [isForced] - let isForced be true to do turn discovery regardless of reachability results
|
|
6513
|
+
* @param {TurnServerInfo} [turnServerInfo]
|
|
6333
6514
|
* @returns {Promise<void>}
|
|
6334
6515
|
*/
|
|
6335
6516
|
private async establishMediaConnection(
|
|
6336
6517
|
remoteMediaManagerConfig?: RemoteMediaManagerConfiguration,
|
|
6337
6518
|
bundlePolicy?: BundlePolicy,
|
|
6338
|
-
isForced?: boolean
|
|
6519
|
+
isForced?: boolean,
|
|
6520
|
+
turnServerInfo?: TurnServerInfo
|
|
6339
6521
|
): Promise<void> {
|
|
6340
6522
|
const LOG_HEADER = 'Meeting:index#addMedia():establishMediaConnection -->';
|
|
6341
|
-
// @ts-ignore
|
|
6342
|
-
const cdl = this.webex.internal.newMetrics.callDiagnosticLatencies;
|
|
6343
6523
|
const isRetry = this.retriedWithTurnServer;
|
|
6344
6524
|
|
|
6345
6525
|
try {
|
|
6346
|
-
|
|
6347
|
-
|
|
6348
|
-
name: 'internal.client.add-media.turn-discovery.start',
|
|
6349
|
-
});
|
|
6350
|
-
|
|
6351
|
-
const turnDiscoveryObject = await this.roap.doTurnDiscovery(this, isRetry, isForced);
|
|
6352
|
-
|
|
6353
|
-
this.turnDiscoverySkippedReason = turnDiscoveryObject?.turnDiscoverySkippedReason;
|
|
6354
|
-
this.turnServerUsed = !this.turnDiscoverySkippedReason;
|
|
6355
|
-
|
|
6356
|
-
// @ts-ignore
|
|
6357
|
-
this.webex.internal.newMetrics.submitInternalEvent({
|
|
6358
|
-
name: 'internal.client.add-media.turn-discovery.end',
|
|
6359
|
-
});
|
|
6360
|
-
|
|
6361
|
-
const {turnServerInfo} = turnDiscoveryObject;
|
|
6362
|
-
|
|
6363
|
-
if (this.turnServerUsed && turnServerInfo) {
|
|
6364
|
-
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.TURN_DISCOVERY_LATENCY, {
|
|
6365
|
-
correlation_id: this.correlationId,
|
|
6366
|
-
latency: cdl.getTurnDiscoveryTime(),
|
|
6367
|
-
turnServerUsed: this.turnServerUsed,
|
|
6368
|
-
retriedWithTurnServer: this.retriedWithTurnServer,
|
|
6369
|
-
});
|
|
6526
|
+
if (!turnServerInfo) {
|
|
6527
|
+
({turnServerInfo} = await this.doTurnDiscovery(isRetry, isForced));
|
|
6370
6528
|
}
|
|
6371
6529
|
|
|
6372
6530
|
const mc = await this.createMediaConnection(turnServerInfo, bundlePolicy);
|
|
@@ -6385,6 +6543,11 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
6385
6543
|
RemoteMediaManagerEvent.AudioCreated,
|
|
6386
6544
|
EVENT_TRIGGERS.REMOTE_MEDIA_AUDIO_CREATED
|
|
6387
6545
|
);
|
|
6546
|
+
this.forwardEvent(
|
|
6547
|
+
this.remoteMediaManager,
|
|
6548
|
+
RemoteMediaManagerEvent.InterpretationAudioCreated,
|
|
6549
|
+
EVENT_TRIGGERS.REMOTE_MEDIA_INTERPRETATION_AUDIO_CREATED
|
|
6550
|
+
);
|
|
6388
6551
|
this.forwardEvent(
|
|
6389
6552
|
this.remoteMediaManager,
|
|
6390
6553
|
RemoteMediaManagerEvent.ScreenShareAudioCreated,
|
|
@@ -6478,15 +6641,21 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
6478
6641
|
* Creates a media connection to the server. Media connection is required for sending or receiving any audio/video.
|
|
6479
6642
|
*
|
|
6480
6643
|
* @param {AddMediaOptions} options
|
|
6644
|
+
* @param {TurnServerInfo} turnServerInfo - TURN server information (used only internally by the SDK)
|
|
6481
6645
|
* @returns {Promise<void>}
|
|
6482
6646
|
* @public
|
|
6483
6647
|
* @memberof Meeting
|
|
6484
6648
|
*/
|
|
6485
|
-
async addMedia(
|
|
6649
|
+
async addMedia(
|
|
6650
|
+
options: AddMediaOptions = {},
|
|
6651
|
+
turnServerInfo: TurnServerInfo = undefined
|
|
6652
|
+
): Promise<void> {
|
|
6486
6653
|
this.retriedWithTurnServer = false;
|
|
6487
6654
|
this.hasMediaConnectionConnectedAtLeastOnce = false;
|
|
6488
6655
|
const LOG_HEADER = 'Meeting:index#addMedia -->';
|
|
6489
|
-
LoggerProxy.logger.info(
|
|
6656
|
+
LoggerProxy.logger.info(
|
|
6657
|
+
`${LOG_HEADER} called with: ${JSON.stringify(options)}, ${JSON.stringify(turnServerInfo)}`
|
|
6658
|
+
);
|
|
6490
6659
|
|
|
6491
6660
|
if (options.allowMediaInLobby !== true && this.meetingState !== FULL_STATE.ACTIVE) {
|
|
6492
6661
|
throw new MeetingNotActiveError();
|
|
@@ -6504,14 +6673,13 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
6504
6673
|
shareVideoEnabled = true,
|
|
6505
6674
|
remoteMediaManagerConfig,
|
|
6506
6675
|
bundlePolicy,
|
|
6507
|
-
allowMediaInLobby,
|
|
6508
6676
|
} = options;
|
|
6509
6677
|
|
|
6510
6678
|
this.allowMediaInLobby = options?.allowMediaInLobby;
|
|
6511
6679
|
|
|
6512
6680
|
// If the user is unjoined or guest waiting in lobby dont allow the user to addMedia
|
|
6513
6681
|
// @ts-ignore - isUserUnadmitted coming from SelfUtil
|
|
6514
|
-
if (this.isUserUnadmitted && !this.wirelessShare && !allowMediaInLobby) {
|
|
6682
|
+
if (this.isUserUnadmitted && !this.wirelessShare && !this.allowMediaInLobby) {
|
|
6515
6683
|
throw new UserInLobbyError();
|
|
6516
6684
|
}
|
|
6517
6685
|
|
|
@@ -6580,9 +6748,18 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
6580
6748
|
|
|
6581
6749
|
this.createStatsAnalyzer();
|
|
6582
6750
|
|
|
6583
|
-
await this.establishMediaConnection(
|
|
6751
|
+
await this.establishMediaConnection(
|
|
6752
|
+
remoteMediaManagerConfig,
|
|
6753
|
+
bundlePolicy,
|
|
6754
|
+
false,
|
|
6755
|
+
turnServerInfo
|
|
6756
|
+
);
|
|
6584
6757
|
|
|
6585
|
-
|
|
6758
|
+
if (audioEnabled || videoEnabled) {
|
|
6759
|
+
await Meeting.handleDeviceLogging();
|
|
6760
|
+
} else {
|
|
6761
|
+
LoggerProxy.logger.info(`${LOG_HEADER} device logging not required`);
|
|
6762
|
+
}
|
|
6586
6763
|
|
|
6587
6764
|
if (this.mediaProperties.hasLocalShareStream()) {
|
|
6588
6765
|
await this.enqueueScreenShareFloorRequest();
|
|
@@ -7774,9 +7951,9 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
7774
7951
|
|
|
7775
7952
|
/**
|
|
7776
7953
|
*
|
|
7777
|
-
* @returns {string} one of 'attendee','host','cohost', returns the user type of the current user
|
|
7954
|
+
* @returns {string} one of 'panelist', 'attendee', 'host', 'cohost', returns the user type of the current user
|
|
7778
7955
|
*/
|
|
7779
|
-
getCurUserType() {
|
|
7956
|
+
getCurUserType(): RawClientEvent['userType'] | null {
|
|
7780
7957
|
const {roles} = this;
|
|
7781
7958
|
if (roles) {
|
|
7782
7959
|
if (roles.includes(SELF_ROLES.MODERATOR)) {
|
|
@@ -7785,8 +7962,8 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
7785
7962
|
if (roles.includes(SELF_ROLES.COHOST)) {
|
|
7786
7963
|
return 'cohost';
|
|
7787
7964
|
}
|
|
7788
|
-
if (roles.includes(SELF_ROLES.
|
|
7789
|
-
return '
|
|
7965
|
+
if (roles.includes(SELF_ROLES.PANELIST)) {
|
|
7966
|
+
return 'panelist';
|
|
7790
7967
|
}
|
|
7791
7968
|
if (roles.includes(SELF_ROLES.ATTENDEE)) {
|
|
7792
7969
|
return 'attendee';
|
|
@@ -8096,6 +8273,33 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
8096
8273
|
});
|
|
8097
8274
|
}
|
|
8098
8275
|
|
|
8276
|
+
/**
|
|
8277
|
+
* set sending named media group which the audio should send to
|
|
8278
|
+
* @param {MediaType} mediaType of the stream
|
|
8279
|
+
* @param {number} languageCode of the stream
|
|
8280
|
+
* @returns {void}
|
|
8281
|
+
*/
|
|
8282
|
+
public setSendNamedMediaGroup(mediaType: MediaType, languageCode = 0): void {
|
|
8283
|
+
if (mediaType !== MediaType.AudioMain) {
|
|
8284
|
+
throw new Error(`cannot set send named media group which media type is ${mediaType}`);
|
|
8285
|
+
}
|
|
8286
|
+
|
|
8287
|
+
const value = languageCode || this.simultaneousInterpretation.getTargetLanguageCode();
|
|
8288
|
+
let groups = [];
|
|
8289
|
+
|
|
8290
|
+
if (value) {
|
|
8291
|
+
groups = [
|
|
8292
|
+
{
|
|
8293
|
+
type: NAMED_MEDIA_GROUP_TYPE_AUDIO,
|
|
8294
|
+
value,
|
|
8295
|
+
},
|
|
8296
|
+
];
|
|
8297
|
+
}
|
|
8298
|
+
if (this.isMultistream && this.mediaProperties.webrtcMediaConnection) {
|
|
8299
|
+
this.sendSlotManager.setNamedMediaGroups(mediaType, groups);
|
|
8300
|
+
}
|
|
8301
|
+
}
|
|
8302
|
+
|
|
8099
8303
|
/**
|
|
8100
8304
|
* Publishes a stream.
|
|
8101
8305
|
*
|
|
@@ -8164,6 +8368,17 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
8164
8368
|
return;
|
|
8165
8369
|
}
|
|
8166
8370
|
|
|
8371
|
+
if (
|
|
8372
|
+
streams?.microphone?.readyState === 'ended' ||
|
|
8373
|
+
streams?.camera?.readyState === 'ended' ||
|
|
8374
|
+
streams?.screenShare?.audio?.readyState === 'ended' ||
|
|
8375
|
+
streams?.screenShare?.video?.readyState === 'ended'
|
|
8376
|
+
) {
|
|
8377
|
+
throw new Error(
|
|
8378
|
+
`Attempted to publish stream with ended readyState, correlationId=${this.correlationId}`
|
|
8379
|
+
);
|
|
8380
|
+
}
|
|
8381
|
+
|
|
8167
8382
|
let floorRequestNeeded = false;
|
|
8168
8383
|
|
|
8169
8384
|
// Screenshare Audio is supported only in multi stream. So we check for screenshare audio presence only if it's a multi stream meeting
|