@webex/plugin-meetings 3.0.0-next.3 → 3.0.0-next.30
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 +3 -4
- package/dist/constants.js +2 -2
- 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 +3 -3
- 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 +18 -7
- package/dist/meeting/index.js +859 -674
- 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 +1 -2
- package/dist/multistream/mediaRequestManager.js.map +1 -1
- package/dist/multistream/remoteMediaGroup.d.ts +1 -1
- package/dist/multistream/remoteMediaGroup.js.map +1 -1
- package/dist/multistream/remoteMediaManager.d.ts +1 -2
- package/dist/multistream/remoteMediaManager.js.map +1 -1
- package/dist/multistream/sendSlotManager.d.ts +1 -2
- 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 +2 -2
- 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 +3 -3
- package/src/index.ts +1 -0
- package/src/interpretation/index.ts +2 -2
- 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 +283 -105
- 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 +1 -1
- package/src/multistream/remoteMediaGroup.ts +1 -1
- package/src/multistream/remoteMediaManager.ts +1 -2
- package/src/multistream/sendSlotManager.ts +1 -2
- 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 +2 -2
- 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 +4 -1
- package/test/unit/spec/locus-info/mediaSharesUtils.ts +9 -0
- package/test/unit/spec/locus-info/selfUtils.js +35 -0
- 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 +618 -143
- 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/remoteMediaGroup.ts +0 -1
- package/test/unit/spec/multistream/remoteMediaManager.ts +0 -1
- 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/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';
|
|
@@ -120,7 +127,6 @@ import {
|
|
|
120
127
|
MeetingInfoV2CaptchaError,
|
|
121
128
|
MeetingInfoV2PolicyError,
|
|
122
129
|
} from '../meeting-info/meeting-info-v2';
|
|
123
|
-
import BrowserDetection from '../common/browser-detection';
|
|
124
130
|
import {CSI, ReceiveSlotManager} from '../multistream/receiveSlotManager';
|
|
125
131
|
import SendSlotManager from '../multistream/sendSlotManager';
|
|
126
132
|
import {MediaRequestManager} from '../multistream/mediaRequestManager';
|
|
@@ -148,8 +154,6 @@ import ControlsOptionsManager from '../controls-options-manager';
|
|
|
148
154
|
import PermissionError from '../common/errors/permission';
|
|
149
155
|
import {LocusMediaRequest} from './locusMediaRequest';
|
|
150
156
|
|
|
151
|
-
const {isBrowser} = BrowserDetection();
|
|
152
|
-
|
|
153
157
|
const logRequest = (request: any, {logText = ''}) => {
|
|
154
158
|
LoggerProxy.logger.info(`${logText} - sending request`);
|
|
155
159
|
|
|
@@ -615,8 +619,8 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
615
619
|
resourceUrl: string;
|
|
616
620
|
selfId: string;
|
|
617
621
|
state: any;
|
|
618
|
-
localAudioStreamMuteStateHandler: (
|
|
619
|
-
localVideoStreamMuteStateHandler: (
|
|
622
|
+
localAudioStreamMuteStateHandler: () => void;
|
|
623
|
+
localVideoStreamMuteStateHandler: () => void;
|
|
620
624
|
localOutputTrackChangeHandler: () => void;
|
|
621
625
|
roles: any[];
|
|
622
626
|
environment: string;
|
|
@@ -624,21 +628,23 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
624
628
|
allowMediaInLobby: boolean;
|
|
625
629
|
localShareInstanceId: string;
|
|
626
630
|
remoteShareInstanceId: string;
|
|
627
|
-
turnDiscoverySkippedReason:
|
|
631
|
+
turnDiscoverySkippedReason: TurnDiscoverySkipReason;
|
|
628
632
|
turnServerUsed: boolean;
|
|
629
633
|
areVoiceaEventsSetup = false;
|
|
634
|
+
|
|
630
635
|
voiceaListenerCallbacks: object = {
|
|
631
636
|
[VOICEAEVENTS.VOICEA_ANNOUNCEMENT]: (payload: Transcription['languageOptions']) => {
|
|
632
637
|
this.transcription.languageOptions = payload;
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
{
|
|
638
|
+
|
|
639
|
+
LoggerProxy.logger.debug(
|
|
640
|
+
`${EventsUtil.getScopeLog({
|
|
636
641
|
file: 'meeting/index',
|
|
637
642
|
function: 'setUpVoiceaListeners',
|
|
638
|
-
}
|
|
639
|
-
EVENT_TRIGGERS.MEETING_STARTED_RECEIVING_TRANSCRIPTION,
|
|
640
|
-
payload
|
|
643
|
+
})}event#${EVENT_TRIGGERS.MEETING_STARTED_RECEIVING_TRANSCRIPTION}`
|
|
641
644
|
);
|
|
645
|
+
|
|
646
|
+
// @ts-ignore
|
|
647
|
+
this.trigger(EVENT_TRIGGERS.MEETING_STARTED_RECEIVING_TRANSCRIPTION, payload);
|
|
642
648
|
},
|
|
643
649
|
[VOICEAEVENTS.CAPTIONS_TURNED_ON]: () => {
|
|
644
650
|
this.transcription.status = TURN_ON_CAPTION_STATUS.ENABLED;
|
|
@@ -651,18 +657,19 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
651
657
|
},
|
|
652
658
|
[VOICEAEVENTS.NEW_CAPTION]: (data) => {
|
|
653
659
|
processNewCaptions({data, meeting: this});
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
{
|
|
660
|
+
|
|
661
|
+
LoggerProxy.logger.debug(
|
|
662
|
+
`${EventsUtil.getScopeLog({
|
|
657
663
|
file: 'meeting/index',
|
|
658
664
|
function: 'setUpVoiceaListeners',
|
|
659
|
-
}
|
|
660
|
-
EVENT_TRIGGERS.MEETING_CAPTION_RECEIVED,
|
|
661
|
-
{
|
|
662
|
-
captions: this.transcription.captions,
|
|
663
|
-
interimCaptions: this.transcription.interimCaptions,
|
|
664
|
-
}
|
|
665
|
+
})}event#${EVENT_TRIGGERS.MEETING_CAPTION_RECEIVED}`
|
|
665
666
|
);
|
|
667
|
+
|
|
668
|
+
// @ts-ignore
|
|
669
|
+
this.trigger(EVENT_TRIGGERS.MEETING_CAPTION_RECEIVED, {
|
|
670
|
+
captions: this.transcription.captions,
|
|
671
|
+
interimCaptions: this.transcription.interimCaptions,
|
|
672
|
+
});
|
|
666
673
|
},
|
|
667
674
|
};
|
|
668
675
|
|
|
@@ -1381,12 +1388,12 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1381
1388
|
*/
|
|
1382
1389
|
this.remoteMediaManager = null;
|
|
1383
1390
|
|
|
1384
|
-
this.localAudioStreamMuteStateHandler = (
|
|
1385
|
-
this.audio.handleLocalStreamMuteStateChange(this
|
|
1391
|
+
this.localAudioStreamMuteStateHandler = () => {
|
|
1392
|
+
this.audio.handleLocalStreamMuteStateChange(this);
|
|
1386
1393
|
};
|
|
1387
1394
|
|
|
1388
|
-
this.localVideoStreamMuteStateHandler = (
|
|
1389
|
-
this.video.handleLocalStreamMuteStateChange(this
|
|
1395
|
+
this.localVideoStreamMuteStateHandler = () => {
|
|
1396
|
+
this.video.handleLocalStreamMuteStateChange(this);
|
|
1390
1397
|
};
|
|
1391
1398
|
|
|
1392
1399
|
// The handling of output track changes should be done inside
|
|
@@ -2519,6 +2526,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2519
2526
|
{
|
|
2520
2527
|
annotationInfo: contentShare?.annotation,
|
|
2521
2528
|
meetingId: this.id,
|
|
2529
|
+
resourceType: contentShare?.resourceType,
|
|
2522
2530
|
}
|
|
2523
2531
|
);
|
|
2524
2532
|
}
|
|
@@ -2547,7 +2555,8 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2547
2555
|
contentShare.deviceUrlSharing === previousContentShare.deviceUrlSharing &&
|
|
2548
2556
|
whiteboardShare.beneficiaryId === previousWhiteboardShare?.beneficiaryId &&
|
|
2549
2557
|
whiteboardShare.disposition === previousWhiteboardShare?.disposition &&
|
|
2550
|
-
whiteboardShare.resourceUrl === previousWhiteboardShare?.resourceUrl
|
|
2558
|
+
whiteboardShare.resourceUrl === previousWhiteboardShare?.resourceUrl &&
|
|
2559
|
+
contentShare.resourceType === previousContentShare?.resourceType
|
|
2551
2560
|
) {
|
|
2552
2561
|
// nothing changed, so ignore
|
|
2553
2562
|
// (this happens when we steal presentation from remote)
|
|
@@ -2669,6 +2678,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2669
2678
|
url: contentShare.url,
|
|
2670
2679
|
shareInstanceId: this.remoteShareInstanceId,
|
|
2671
2680
|
annotationInfo: contentShare.annotation,
|
|
2681
|
+
resourceType: contentShare.resourceType,
|
|
2672
2682
|
}
|
|
2673
2683
|
);
|
|
2674
2684
|
};
|
|
@@ -2761,6 +2771,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2761
2771
|
url: contentShare.url,
|
|
2762
2772
|
shareInstanceId: this.remoteShareInstanceId,
|
|
2763
2773
|
annotationInfo: contentShare.annotation,
|
|
2774
|
+
resourceType: contentShare.resourceType,
|
|
2764
2775
|
}
|
|
2765
2776
|
);
|
|
2766
2777
|
this.members.locusMediaSharesUpdate(payload);
|
|
@@ -3070,6 +3081,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3070
3081
|
options: {meetingId: this.id},
|
|
3071
3082
|
});
|
|
3072
3083
|
}
|
|
3084
|
+
this.updateLLMConnection();
|
|
3073
3085
|
});
|
|
3074
3086
|
|
|
3075
3087
|
// @ts-ignore - check if MEDIA_INACTIVITY exists
|
|
@@ -3454,8 +3466,10 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3454
3466
|
this.owner =
|
|
3455
3467
|
locusMeetingObject?.info.owner || meetingInfo?.owner || meetingInfo?.hostId || this.owner;
|
|
3456
3468
|
this.permissionToken = meetingInfo?.permissionToken;
|
|
3457
|
-
this.
|
|
3458
|
-
|
|
3469
|
+
if (this.permissionToken) {
|
|
3470
|
+
this.setPermissionTokenPayload(meetingInfo?.permissionToken);
|
|
3471
|
+
this.setSelfUserPolicies();
|
|
3472
|
+
}
|
|
3459
3473
|
// Need to populate environment when sending CA event
|
|
3460
3474
|
this.environment = locusMeetingObject?.info.channel || meetingInfo?.channel;
|
|
3461
3475
|
}
|
|
@@ -3891,7 +3905,14 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3891
3905
|
private async setLocalAudioStream(localStream?: LocalMicrophoneStream) {
|
|
3892
3906
|
const oldStream = this.mediaProperties.audioStream;
|
|
3893
3907
|
|
|
3894
|
-
oldStream?.off(
|
|
3908
|
+
oldStream?.off(
|
|
3909
|
+
LocalStreamEventNames.UserMuteStateChange,
|
|
3910
|
+
this.localAudioStreamMuteStateHandler
|
|
3911
|
+
);
|
|
3912
|
+
oldStream?.off(
|
|
3913
|
+
LocalStreamEventNames.SystemMuteStateChange,
|
|
3914
|
+
this.localAudioStreamMuteStateHandler
|
|
3915
|
+
);
|
|
3895
3916
|
oldStream?.off(LocalStreamEventNames.OutputTrackChange, this.localOutputTrackChangeHandler);
|
|
3896
3917
|
|
|
3897
3918
|
// we don't update this.mediaProperties.mediaDirection.sendAudio, because we always keep it as true to avoid extra SDP exchanges
|
|
@@ -3899,7 +3920,14 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3899
3920
|
|
|
3900
3921
|
this.audio.handleLocalStreamChange(this);
|
|
3901
3922
|
|
|
3902
|
-
localStream?.on(
|
|
3923
|
+
localStream?.on(
|
|
3924
|
+
LocalStreamEventNames.UserMuteStateChange,
|
|
3925
|
+
this.localAudioStreamMuteStateHandler
|
|
3926
|
+
);
|
|
3927
|
+
localStream?.on(
|
|
3928
|
+
LocalStreamEventNames.SystemMuteStateChange,
|
|
3929
|
+
this.localAudioStreamMuteStateHandler
|
|
3930
|
+
);
|
|
3903
3931
|
localStream?.on(LocalStreamEventNames.OutputTrackChange, this.localOutputTrackChangeHandler);
|
|
3904
3932
|
|
|
3905
3933
|
if (!this.isMultistream || !localStream) {
|
|
@@ -3919,7 +3947,14 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3919
3947
|
private async setLocalVideoStream(localStream?: LocalCameraStream) {
|
|
3920
3948
|
const oldStream = this.mediaProperties.videoStream;
|
|
3921
3949
|
|
|
3922
|
-
oldStream?.off(
|
|
3950
|
+
oldStream?.off(
|
|
3951
|
+
LocalStreamEventNames.UserMuteStateChange,
|
|
3952
|
+
this.localVideoStreamMuteStateHandler
|
|
3953
|
+
);
|
|
3954
|
+
oldStream?.off(
|
|
3955
|
+
LocalStreamEventNames.SystemMuteStateChange,
|
|
3956
|
+
this.localVideoStreamMuteStateHandler
|
|
3957
|
+
);
|
|
3923
3958
|
oldStream?.off(LocalStreamEventNames.OutputTrackChange, this.localOutputTrackChangeHandler);
|
|
3924
3959
|
|
|
3925
3960
|
// we don't update this.mediaProperties.mediaDirection.sendVideo, because we always keep it as true to avoid extra SDP exchanges
|
|
@@ -3927,7 +3962,14 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3927
3962
|
|
|
3928
3963
|
this.video.handleLocalStreamChange(this);
|
|
3929
3964
|
|
|
3930
|
-
localStream?.on(
|
|
3965
|
+
localStream?.on(
|
|
3966
|
+
LocalStreamEventNames.UserMuteStateChange,
|
|
3967
|
+
this.localVideoStreamMuteStateHandler
|
|
3968
|
+
);
|
|
3969
|
+
localStream?.on(
|
|
3970
|
+
LocalStreamEventNames.SystemMuteStateChange,
|
|
3971
|
+
this.localVideoStreamMuteStateHandler
|
|
3972
|
+
);
|
|
3931
3973
|
localStream?.on(LocalStreamEventNames.OutputTrackChange, this.localOutputTrackChangeHandler);
|
|
3932
3974
|
|
|
3933
3975
|
if (!this.isMultistream || !localStream) {
|
|
@@ -3948,14 +3990,17 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3948
3990
|
private async setLocalShareVideoStream(localDisplayStream?: LocalDisplayStream) {
|
|
3949
3991
|
const oldStream = this.mediaProperties.shareVideoStream;
|
|
3950
3992
|
|
|
3951
|
-
oldStream?.off(
|
|
3993
|
+
oldStream?.off(
|
|
3994
|
+
LocalStreamEventNames.SystemMuteStateChange,
|
|
3995
|
+
this.handleShareVideoStreamMuteStateChange
|
|
3996
|
+
);
|
|
3952
3997
|
oldStream?.off(StreamEventNames.Ended, this.handleShareVideoStreamEnded);
|
|
3953
3998
|
oldStream?.off(LocalStreamEventNames.OutputTrackChange, this.localOutputTrackChangeHandler);
|
|
3954
3999
|
|
|
3955
4000
|
this.mediaProperties.setLocalShareVideoStream(localDisplayStream);
|
|
3956
4001
|
|
|
3957
4002
|
localDisplayStream?.on(
|
|
3958
|
-
|
|
4003
|
+
LocalStreamEventNames.SystemMuteStateChange,
|
|
3959
4004
|
this.handleShareVideoStreamMuteStateChange
|
|
3960
4005
|
);
|
|
3961
4006
|
localDisplayStream?.on(StreamEventNames.Ended, this.handleShareVideoStreamEnded);
|
|
@@ -4041,10 +4086,24 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4041
4086
|
public cleanupLocalStreams() {
|
|
4042
4087
|
const {audioStream, videoStream, shareAudioStream, shareVideoStream} = this.mediaProperties;
|
|
4043
4088
|
|
|
4044
|
-
audioStream?.off(
|
|
4089
|
+
audioStream?.off(
|
|
4090
|
+
LocalStreamEventNames.UserMuteStateChange,
|
|
4091
|
+
this.localAudioStreamMuteStateHandler
|
|
4092
|
+
);
|
|
4093
|
+
audioStream?.off(
|
|
4094
|
+
LocalStreamEventNames.SystemMuteStateChange,
|
|
4095
|
+
this.localAudioStreamMuteStateHandler
|
|
4096
|
+
);
|
|
4045
4097
|
audioStream?.off(LocalStreamEventNames.OutputTrackChange, this.localOutputTrackChangeHandler);
|
|
4046
4098
|
|
|
4047
|
-
videoStream?.off(
|
|
4099
|
+
videoStream?.off(
|
|
4100
|
+
LocalStreamEventNames.UserMuteStateChange,
|
|
4101
|
+
this.localVideoStreamMuteStateHandler
|
|
4102
|
+
);
|
|
4103
|
+
videoStream?.off(
|
|
4104
|
+
LocalStreamEventNames.SystemMuteStateChange,
|
|
4105
|
+
this.localVideoStreamMuteStateHandler
|
|
4106
|
+
);
|
|
4048
4107
|
videoStream?.off(LocalStreamEventNames.OutputTrackChange, this.localOutputTrackChangeHandler);
|
|
4049
4108
|
|
|
4050
4109
|
shareAudioStream?.off(StreamEventNames.Ended, this.handleShareAudioStreamEnded);
|
|
@@ -4052,8 +4111,9 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4052
4111
|
LocalStreamEventNames.OutputTrackChange,
|
|
4053
4112
|
this.localOutputTrackChangeHandler
|
|
4054
4113
|
);
|
|
4114
|
+
|
|
4055
4115
|
shareVideoStream?.off(
|
|
4056
|
-
|
|
4116
|
+
LocalStreamEventNames.SystemMuteStateChange,
|
|
4057
4117
|
this.handleShareVideoStreamMuteStateChange
|
|
4058
4118
|
);
|
|
4059
4119
|
shareVideoStream?.off(StreamEventNames.Ended, this.handleShareVideoStreamEnded);
|
|
@@ -4445,47 +4505,90 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4445
4505
|
* }
|
|
4446
4506
|
* })
|
|
4447
4507
|
*/
|
|
4448
|
-
public joinWithMedia(
|
|
4508
|
+
public async joinWithMedia(
|
|
4449
4509
|
options: {
|
|
4450
4510
|
joinOptions?: any;
|
|
4451
4511
|
mediaOptions?: AddMediaOptions;
|
|
4452
4512
|
} = {}
|
|
4453
4513
|
) {
|
|
4454
|
-
const {mediaOptions, joinOptions} = options;
|
|
4514
|
+
const {mediaOptions, joinOptions = {}} = options;
|
|
4455
4515
|
|
|
4456
4516
|
if (!mediaOptions?.allowMediaInLobby) {
|
|
4457
4517
|
return Promise.reject(
|
|
4458
4518
|
new ParameterError('joinWithMedia() can only be used with allowMediaInLobby set to true')
|
|
4459
4519
|
);
|
|
4460
4520
|
}
|
|
4521
|
+
this.allowMediaInLobby = true;
|
|
4461
4522
|
|
|
4462
4523
|
LoggerProxy.logger.info('Meeting:index#joinWithMedia called');
|
|
4463
4524
|
|
|
4464
|
-
|
|
4465
|
-
.then((joinResponse) =>
|
|
4466
|
-
this.addMedia(mediaOptions).then((mediaResponse) => ({
|
|
4467
|
-
join: joinResponse,
|
|
4468
|
-
media: mediaResponse,
|
|
4469
|
-
}))
|
|
4470
|
-
)
|
|
4471
|
-
.catch((error) => {
|
|
4472
|
-
LoggerProxy.logger.error('Meeting:index#joinWithMedia --> ', error);
|
|
4525
|
+
let joined = false;
|
|
4473
4526
|
|
|
4474
|
-
|
|
4475
|
-
|
|
4476
|
-
|
|
4477
|
-
correlation_id: this.correlationId,
|
|
4478
|
-
locus_id: this.locusUrl.split('/').pop(),
|
|
4479
|
-
reason: error.message,
|
|
4480
|
-
stack: error.stack,
|
|
4481
|
-
},
|
|
4482
|
-
{
|
|
4483
|
-
type: error.name,
|
|
4484
|
-
}
|
|
4485
|
-
);
|
|
4527
|
+
try {
|
|
4528
|
+
let turnServerInfo;
|
|
4529
|
+
let turnDiscoverySkippedReason;
|
|
4486
4530
|
|
|
4487
|
-
|
|
4488
|
-
|
|
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
|
+
}
|
|
4489
4592
|
}
|
|
4490
4593
|
|
|
4491
4594
|
/**
|
|
@@ -5608,7 +5711,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5608
5711
|
logText: `${LOG_HEADER} Roap Offer`,
|
|
5609
5712
|
}
|
|
5610
5713
|
).catch(() => {
|
|
5611
|
-
this.deferSDPAnswer.reject();
|
|
5714
|
+
this.deferSDPAnswer.reject(new Error('failed to send ROAP SDP offer'));
|
|
5612
5715
|
clearTimeout(this.sdpResponseTimer);
|
|
5613
5716
|
this.sdpResponseTimer = undefined;
|
|
5614
5717
|
});
|
|
@@ -5955,6 +6058,20 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5955
6058
|
meetingId: this.id,
|
|
5956
6059
|
},
|
|
5957
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
|
+
}
|
|
5958
6075
|
});
|
|
5959
6076
|
this.statsAnalyzer.on(StatsAnalyzerEvents.REMOTE_MEDIA_STOPPED, (data) => {
|
|
5960
6077
|
// @ts-ignore
|
|
@@ -5968,6 +6085,20 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5968
6085
|
meetingId: this.id,
|
|
5969
6086
|
},
|
|
5970
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
|
+
}
|
|
5971
6102
|
});
|
|
5972
6103
|
};
|
|
5973
6104
|
|
|
@@ -6074,16 +6205,22 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
6074
6205
|
private async setUpLocalStreamReferences(localStreams: LocalStreams) {
|
|
6075
6206
|
const setUpStreamPromises = [];
|
|
6076
6207
|
|
|
6077
|
-
if (localStreams?.microphone) {
|
|
6208
|
+
if (localStreams?.microphone && localStreams?.microphone?.readyState !== 'ended') {
|
|
6078
6209
|
setUpStreamPromises.push(this.setLocalAudioStream(localStreams.microphone));
|
|
6079
6210
|
}
|
|
6080
|
-
if (localStreams?.camera) {
|
|
6211
|
+
if (localStreams?.camera && localStreams?.camera?.readyState !== 'ended') {
|
|
6081
6212
|
setUpStreamPromises.push(this.setLocalVideoStream(localStreams.camera));
|
|
6082
6213
|
}
|
|
6083
|
-
if (
|
|
6214
|
+
if (
|
|
6215
|
+
localStreams?.screenShare?.video &&
|
|
6216
|
+
localStreams?.screenShare?.video?.readyState !== 'ended'
|
|
6217
|
+
) {
|
|
6084
6218
|
setUpStreamPromises.push(this.setLocalShareVideoStream(localStreams.screenShare.video));
|
|
6085
6219
|
}
|
|
6086
|
-
if (
|
|
6220
|
+
if (
|
|
6221
|
+
localStreams?.screenShare?.audio &&
|
|
6222
|
+
localStreams?.screenShare?.audio?.readyState !== 'ended'
|
|
6223
|
+
) {
|
|
6087
6224
|
setUpStreamPromises.push(this.setLocalShareAudioStream(localStreams.screenShare.audio));
|
|
6088
6225
|
}
|
|
6089
6226
|
|
|
@@ -6328,6 +6465,44 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
6328
6465
|
}
|
|
6329
6466
|
}
|
|
6330
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
|
+
|
|
6331
6506
|
/**
|
|
6332
6507
|
* Does TURN discovery, SDP offer/answer exhange, establishes ICE connection and DTLS handshake.
|
|
6333
6508
|
*
|
|
@@ -6335,43 +6510,21 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
6335
6510
|
* @param {RemoteMediaManagerConfiguration} [remoteMediaManagerConfig]
|
|
6336
6511
|
* @param {BundlePolicy} [bundlePolicy]
|
|
6337
6512
|
* @param {boolean} [isForced] - let isForced be true to do turn discovery regardless of reachability results
|
|
6513
|
+
* @param {TurnServerInfo} [turnServerInfo]
|
|
6338
6514
|
* @returns {Promise<void>}
|
|
6339
6515
|
*/
|
|
6340
6516
|
private async establishMediaConnection(
|
|
6341
6517
|
remoteMediaManagerConfig?: RemoteMediaManagerConfiguration,
|
|
6342
6518
|
bundlePolicy?: BundlePolicy,
|
|
6343
|
-
isForced?: boolean
|
|
6519
|
+
isForced?: boolean,
|
|
6520
|
+
turnServerInfo?: TurnServerInfo
|
|
6344
6521
|
): Promise<void> {
|
|
6345
6522
|
const LOG_HEADER = 'Meeting:index#addMedia():establishMediaConnection -->';
|
|
6346
|
-
// @ts-ignore
|
|
6347
|
-
const cdl = this.webex.internal.newMetrics.callDiagnosticLatencies;
|
|
6348
6523
|
const isRetry = this.retriedWithTurnServer;
|
|
6349
6524
|
|
|
6350
6525
|
try {
|
|
6351
|
-
|
|
6352
|
-
|
|
6353
|
-
name: 'internal.client.add-media.turn-discovery.start',
|
|
6354
|
-
});
|
|
6355
|
-
|
|
6356
|
-
const turnDiscoveryObject = await this.roap.doTurnDiscovery(this, isRetry, isForced);
|
|
6357
|
-
|
|
6358
|
-
this.turnDiscoverySkippedReason = turnDiscoveryObject?.turnDiscoverySkippedReason;
|
|
6359
|
-
this.turnServerUsed = !this.turnDiscoverySkippedReason;
|
|
6360
|
-
|
|
6361
|
-
// @ts-ignore
|
|
6362
|
-
this.webex.internal.newMetrics.submitInternalEvent({
|
|
6363
|
-
name: 'internal.client.add-media.turn-discovery.end',
|
|
6364
|
-
});
|
|
6365
|
-
|
|
6366
|
-
const {turnServerInfo} = turnDiscoveryObject;
|
|
6367
|
-
|
|
6368
|
-
if (this.turnServerUsed && turnServerInfo) {
|
|
6369
|
-
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.TURN_DISCOVERY_LATENCY, {
|
|
6370
|
-
correlation_id: this.correlationId,
|
|
6371
|
-
latency: cdl.getTurnDiscoveryTime(),
|
|
6372
|
-
turnServerUsed: this.turnServerUsed,
|
|
6373
|
-
retriedWithTurnServer: this.retriedWithTurnServer,
|
|
6374
|
-
});
|
|
6526
|
+
if (!turnServerInfo) {
|
|
6527
|
+
({turnServerInfo} = await this.doTurnDiscovery(isRetry, isForced));
|
|
6375
6528
|
}
|
|
6376
6529
|
|
|
6377
6530
|
const mc = await this.createMediaConnection(turnServerInfo, bundlePolicy);
|
|
@@ -6488,15 +6641,21 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
6488
6641
|
* Creates a media connection to the server. Media connection is required for sending or receiving any audio/video.
|
|
6489
6642
|
*
|
|
6490
6643
|
* @param {AddMediaOptions} options
|
|
6644
|
+
* @param {TurnServerInfo} turnServerInfo - TURN server information (used only internally by the SDK)
|
|
6491
6645
|
* @returns {Promise<void>}
|
|
6492
6646
|
* @public
|
|
6493
6647
|
* @memberof Meeting
|
|
6494
6648
|
*/
|
|
6495
|
-
async addMedia(
|
|
6649
|
+
async addMedia(
|
|
6650
|
+
options: AddMediaOptions = {},
|
|
6651
|
+
turnServerInfo: TurnServerInfo = undefined
|
|
6652
|
+
): Promise<void> {
|
|
6496
6653
|
this.retriedWithTurnServer = false;
|
|
6497
6654
|
this.hasMediaConnectionConnectedAtLeastOnce = false;
|
|
6498
6655
|
const LOG_HEADER = 'Meeting:index#addMedia -->';
|
|
6499
|
-
LoggerProxy.logger.info(
|
|
6656
|
+
LoggerProxy.logger.info(
|
|
6657
|
+
`${LOG_HEADER} called with: ${JSON.stringify(options)}, ${JSON.stringify(turnServerInfo)}`
|
|
6658
|
+
);
|
|
6500
6659
|
|
|
6501
6660
|
if (options.allowMediaInLobby !== true && this.meetingState !== FULL_STATE.ACTIVE) {
|
|
6502
6661
|
throw new MeetingNotActiveError();
|
|
@@ -6514,14 +6673,13 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
6514
6673
|
shareVideoEnabled = true,
|
|
6515
6674
|
remoteMediaManagerConfig,
|
|
6516
6675
|
bundlePolicy,
|
|
6517
|
-
allowMediaInLobby,
|
|
6518
6676
|
} = options;
|
|
6519
6677
|
|
|
6520
6678
|
this.allowMediaInLobby = options?.allowMediaInLobby;
|
|
6521
6679
|
|
|
6522
6680
|
// If the user is unjoined or guest waiting in lobby dont allow the user to addMedia
|
|
6523
6681
|
// @ts-ignore - isUserUnadmitted coming from SelfUtil
|
|
6524
|
-
if (this.isUserUnadmitted && !this.wirelessShare && !allowMediaInLobby) {
|
|
6682
|
+
if (this.isUserUnadmitted && !this.wirelessShare && !this.allowMediaInLobby) {
|
|
6525
6683
|
throw new UserInLobbyError();
|
|
6526
6684
|
}
|
|
6527
6685
|
|
|
@@ -6590,9 +6748,18 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
6590
6748
|
|
|
6591
6749
|
this.createStatsAnalyzer();
|
|
6592
6750
|
|
|
6593
|
-
await this.establishMediaConnection(
|
|
6751
|
+
await this.establishMediaConnection(
|
|
6752
|
+
remoteMediaManagerConfig,
|
|
6753
|
+
bundlePolicy,
|
|
6754
|
+
false,
|
|
6755
|
+
turnServerInfo
|
|
6756
|
+
);
|
|
6594
6757
|
|
|
6595
|
-
|
|
6758
|
+
if (audioEnabled || videoEnabled) {
|
|
6759
|
+
await Meeting.handleDeviceLogging();
|
|
6760
|
+
} else {
|
|
6761
|
+
LoggerProxy.logger.info(`${LOG_HEADER} device logging not required`);
|
|
6762
|
+
}
|
|
6596
6763
|
|
|
6597
6764
|
if (this.mediaProperties.hasLocalShareStream()) {
|
|
6598
6765
|
await this.enqueueScreenShareFloorRequest();
|
|
@@ -7784,9 +7951,9 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
7784
7951
|
|
|
7785
7952
|
/**
|
|
7786
7953
|
*
|
|
7787
|
-
* @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
|
|
7788
7955
|
*/
|
|
7789
|
-
getCurUserType() {
|
|
7956
|
+
getCurUserType(): RawClientEvent['userType'] | null {
|
|
7790
7957
|
const {roles} = this;
|
|
7791
7958
|
if (roles) {
|
|
7792
7959
|
if (roles.includes(SELF_ROLES.MODERATOR)) {
|
|
@@ -7795,8 +7962,8 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
7795
7962
|
if (roles.includes(SELF_ROLES.COHOST)) {
|
|
7796
7963
|
return 'cohost';
|
|
7797
7964
|
}
|
|
7798
|
-
if (roles.includes(SELF_ROLES.
|
|
7799
|
-
return '
|
|
7965
|
+
if (roles.includes(SELF_ROLES.PANELIST)) {
|
|
7966
|
+
return 'panelist';
|
|
7800
7967
|
}
|
|
7801
7968
|
if (roles.includes(SELF_ROLES.ATTENDEE)) {
|
|
7802
7969
|
return 'attendee';
|
|
@@ -8201,6 +8368,17 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
8201
8368
|
return;
|
|
8202
8369
|
}
|
|
8203
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
|
+
|
|
8204
8382
|
let floorRequestNeeded = false;
|
|
8205
8383
|
|
|
8206
8384
|
// Screenshare Audio is supported only in multi stream. So we check for screenshare audio presence only if it's a multi stream meeting
|