@webex/plugin-meetings 3.7.0-next.6 → 3.7.0-next.60
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/annotation/index.js +17 -0
- package/dist/annotation/index.js.map +1 -1
- package/dist/breakouts/breakout.js +1 -1
- package/dist/breakouts/index.js +1 -1
- package/dist/common/errors/join-forbidden-error.js +52 -0
- package/dist/common/errors/join-forbidden-error.js.map +1 -0
- package/dist/common/errors/{webinar-registration-error.js → join-webinar-error.js} +12 -12
- package/dist/common/errors/join-webinar-error.js.map +1 -0
- package/dist/common/errors/multistream-not-supported-error.js +53 -0
- package/dist/common/errors/multistream-not-supported-error.js.map +1 -0
- package/dist/config.js +1 -1
- package/dist/config.js.map +1 -1
- package/dist/constants.js +46 -5
- package/dist/constants.js.map +1 -1
- package/dist/index.js +16 -11
- package/dist/index.js.map +1 -1
- package/dist/interpretation/index.js +1 -1
- package/dist/interpretation/siLanguage.js +1 -1
- package/dist/locus-info/index.js +14 -3
- package/dist/locus-info/index.js.map +1 -1
- package/dist/locus-info/selfUtils.js +35 -17
- package/dist/locus-info/selfUtils.js.map +1 -1
- package/dist/meeting/brbState.js +167 -0
- package/dist/meeting/brbState.js.map +1 -0
- package/dist/meeting/in-meeting-actions.js +2 -0
- package/dist/meeting/in-meeting-actions.js.map +1 -1
- package/dist/meeting/index.js +774 -649
- package/dist/meeting/index.js.map +1 -1
- package/dist/meeting/locusMediaRequest.js +9 -0
- package/dist/meeting/locusMediaRequest.js.map +1 -1
- package/dist/meeting/muteState.js +1 -6
- package/dist/meeting/muteState.js.map +1 -1
- package/dist/meeting/request.js +30 -0
- package/dist/meeting/request.js.map +1 -1
- package/dist/meeting/request.type.js.map +1 -1
- package/dist/meeting/util.js +16 -16
- package/dist/meeting/util.js.map +1 -1
- package/dist/meeting-info/meeting-info-v2.js +96 -33
- package/dist/meeting-info/meeting-info-v2.js.map +1 -1
- package/dist/meeting-info/utilv2.js +1 -1
- package/dist/meeting-info/utilv2.js.map +1 -1
- package/dist/meetings/index.js +107 -55
- package/dist/meetings/index.js.map +1 -1
- package/dist/meetings/meetings.types.js +2 -0
- package/dist/meetings/meetings.types.js.map +1 -1
- package/dist/meetings/util.js +1 -1
- package/dist/meetings/util.js.map +1 -1
- package/dist/member/index.js +9 -0
- package/dist/member/index.js.map +1 -1
- package/dist/member/types.js.map +1 -1
- package/dist/member/util.js +39 -28
- package/dist/member/util.js.map +1 -1
- package/dist/metrics/constants.js +3 -2
- package/dist/metrics/constants.js.map +1 -1
- package/dist/multistream/remoteMedia.js +30 -15
- package/dist/multistream/remoteMedia.js.map +1 -1
- package/dist/multistream/sendSlotManager.js +24 -0
- package/dist/multistream/sendSlotManager.js.map +1 -1
- package/dist/reachability/index.js +31 -3
- package/dist/reachability/index.js.map +1 -1
- package/dist/roap/index.js +10 -8
- package/dist/roap/index.js.map +1 -1
- package/dist/types/annotation/index.d.ts +5 -0
- package/dist/types/common/errors/join-forbidden-error.d.ts +15 -0
- package/dist/types/common/errors/{webinar-registration-error.d.ts → join-webinar-error.d.ts} +2 -2
- package/dist/types/common/errors/multistream-not-supported-error.d.ts +17 -0
- package/dist/types/constants.d.ts +38 -1
- package/dist/types/index.d.ts +3 -3
- package/dist/types/locus-info/index.d.ts +2 -1
- package/dist/types/meeting/brbState.d.ts +54 -0
- package/dist/types/meeting/in-meeting-actions.d.ts +2 -0
- package/dist/types/meeting/index.d.ts +21 -12
- package/dist/types/meeting/locusMediaRequest.d.ts +4 -0
- package/dist/types/meeting/request.d.ts +12 -1
- package/dist/types/meeting/request.type.d.ts +6 -0
- package/dist/types/meeting/util.d.ts +1 -1
- package/dist/types/meeting-info/meeting-info-v2.d.ts +27 -4
- package/dist/types/meetings/index.d.ts +19 -1
- package/dist/types/meetings/meetings.types.d.ts +8 -0
- package/dist/types/member/index.d.ts +1 -0
- package/dist/types/member/types.d.ts +7 -0
- package/dist/types/metrics/constants.d.ts +2 -1
- package/dist/types/multistream/sendSlotManager.d.ts +8 -1
- package/dist/types/reachability/index.d.ts +9 -1
- package/dist/webinar/index.js +354 -3
- package/dist/webinar/index.js.map +1 -1
- package/package.json +23 -22
- package/src/annotation/index.ts +16 -0
- package/src/common/errors/join-forbidden-error.ts +26 -0
- package/src/common/errors/join-webinar-error.ts +24 -0
- package/src/common/errors/multistream-not-supported-error.ts +30 -0
- package/src/config.ts +1 -1
- package/src/constants.ts +43 -3
- package/src/index.ts +5 -3
- package/src/locus-info/index.ts +20 -3
- package/src/locus-info/selfUtils.ts +24 -6
- package/src/meeting/brbState.ts +169 -0
- package/src/meeting/in-meeting-actions.ts +4 -0
- package/src/meeting/index.ts +256 -82
- package/src/meeting/locusMediaRequest.ts +7 -0
- package/src/meeting/muteState.ts +1 -6
- package/src/meeting/request.ts +26 -1
- package/src/meeting/request.type.ts +7 -0
- package/src/meeting/util.ts +8 -10
- package/src/meeting-info/meeting-info-v2.ts +74 -11
- package/src/meeting-info/utilv2.ts +3 -1
- package/src/meetings/index.ts +79 -20
- package/src/meetings/meetings.types.ts +10 -0
- package/src/meetings/util.ts +2 -1
- package/src/member/index.ts +9 -0
- package/src/member/types.ts +8 -0
- package/src/member/util.ts +34 -24
- package/src/metrics/constants.ts +2 -1
- package/src/multistream/remoteMedia.ts +28 -15
- package/src/multistream/sendSlotManager.ts +31 -0
- package/src/reachability/index.ts +29 -1
- package/src/roap/index.ts +10 -8
- package/src/webinar/index.ts +197 -3
- package/test/unit/spec/annotation/index.ts +46 -1
- package/test/unit/spec/locus-info/index.js +292 -60
- package/test/unit/spec/locus-info/selfConstant.js +7 -0
- package/test/unit/spec/locus-info/selfUtils.js +101 -1
- package/test/unit/spec/meeting/brbState.ts +114 -0
- package/test/unit/spec/meeting/in-meeting-actions.ts +2 -0
- package/test/unit/spec/meeting/index.js +733 -106
- package/test/unit/spec/meeting/muteState.js +0 -24
- package/test/unit/spec/meeting/utils.js +22 -19
- package/test/unit/spec/meeting-info/meetinginfov2.js +46 -4
- package/test/unit/spec/meeting-info/utilv2.js +17 -0
- package/test/unit/spec/meetings/index.js +159 -18
- package/test/unit/spec/meetings/utils.js +10 -0
- package/test/unit/spec/member/util.js +52 -11
- package/test/unit/spec/multistream/remoteMedia.ts +11 -7
- package/test/unit/spec/reachability/index.ts +120 -10
- package/test/unit/spec/roap/index.ts +47 -0
- package/test/unit/spec/webinar/index.ts +457 -0
- package/dist/common/errors/webinar-registration-error.js.map +0 -1
- package/src/common/errors/webinar-registration-error.ts +0 -27
package/src/meeting/index.ts
CHANGED
|
@@ -31,7 +31,6 @@ import {
|
|
|
31
31
|
} from '@webex/internal-media-core';
|
|
32
32
|
|
|
33
33
|
import {
|
|
34
|
-
getDevices,
|
|
35
34
|
LocalStream,
|
|
36
35
|
LocalCameraStream,
|
|
37
36
|
LocalDisplayStream,
|
|
@@ -122,6 +121,9 @@ import {
|
|
|
122
121
|
MEETING_PERMISSION_TOKEN_REFRESH_REASON,
|
|
123
122
|
ROAP_OFFER_ANSWER_EXCHANGE_TIMEOUT,
|
|
124
123
|
NAMED_MEDIA_GROUP_TYPE_AUDIO,
|
|
124
|
+
WEBINAR_ERROR_WEBCAST,
|
|
125
|
+
WEBINAR_ERROR_REGISTRATIONID,
|
|
126
|
+
JOIN_BEFORE_HOST,
|
|
125
127
|
} from '../constants';
|
|
126
128
|
import BEHAVIORAL_METRICS from '../metrics/constants';
|
|
127
129
|
import ParameterError from '../common/errors/parameter';
|
|
@@ -129,7 +131,8 @@ import {
|
|
|
129
131
|
MeetingInfoV2PasswordError,
|
|
130
132
|
MeetingInfoV2CaptchaError,
|
|
131
133
|
MeetingInfoV2PolicyError,
|
|
132
|
-
|
|
134
|
+
MeetingInfoV2JoinWebinarError,
|
|
135
|
+
MeetingInfoV2JoinForbiddenError,
|
|
133
136
|
} from '../meeting-info/meeting-info-v2';
|
|
134
137
|
import {CSI, ReceiveSlotManager} from '../multistream/receiveSlotManager';
|
|
135
138
|
import SendSlotManager from '../multistream/sendSlotManager';
|
|
@@ -158,7 +161,11 @@ import ControlsOptionsManager from '../controls-options-manager';
|
|
|
158
161
|
import PermissionError from '../common/errors/permission';
|
|
159
162
|
import {LocusMediaRequest} from './locusMediaRequest';
|
|
160
163
|
import {ConnectionStateHandler, ConnectionStateEvent} from './connectionStateHandler';
|
|
161
|
-
import
|
|
164
|
+
import JoinWebinarError from '../common/errors/join-webinar-error';
|
|
165
|
+
import Member from '../member';
|
|
166
|
+
import {BrbState, createBrbState} from './brbState';
|
|
167
|
+
import MultistreamNotSupportedError from '../common/errors/multistream-not-supported-error';
|
|
168
|
+
import JoinForbiddenError from '../common/errors/join-forbidden-error';
|
|
162
169
|
|
|
163
170
|
// default callback so we don't call an undefined function, but in practice it should never be used
|
|
164
171
|
const DEFAULT_ICE_PHASE_CALLBACK = () => 'JOIN_MEETING_FINAL';
|
|
@@ -643,6 +650,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
643
650
|
turnServerUsed: boolean;
|
|
644
651
|
areVoiceaEventsSetup = false;
|
|
645
652
|
isMoveToInProgress = false;
|
|
653
|
+
brbState: BrbState;
|
|
646
654
|
|
|
647
655
|
voiceaListenerCallbacks: object = {
|
|
648
656
|
[VOICEAEVENTS.VOICEA_ANNOUNCEMENT]: (payload: Transcription['languageOptions']) => {
|
|
@@ -848,7 +856,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
848
856
|
* @memberof Meeting
|
|
849
857
|
*/
|
|
850
858
|
// @ts-ignore
|
|
851
|
-
this.webinar = new Webinar({}, {parent: this.webex});
|
|
859
|
+
this.webinar = new Webinar({meetingId: this.id}, {parent: this.webex});
|
|
852
860
|
/**
|
|
853
861
|
* helper class for managing receive slots (for multistream media connections)
|
|
854
862
|
*/
|
|
@@ -1767,15 +1775,34 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1767
1775
|
this.meetingInfo = err.meetingInfo;
|
|
1768
1776
|
}
|
|
1769
1777
|
throw new PermissionError();
|
|
1770
|
-
} else if (err instanceof
|
|
1778
|
+
} else if (err instanceof MeetingInfoV2JoinWebinarError) {
|
|
1771
1779
|
this.meetingInfoFailureReason = MEETING_INFO_FAILURE_REASON.WEBINAR_REGISTRATION;
|
|
1780
|
+
if (WEBINAR_ERROR_WEBCAST.includes(err.wbxAppApiCode)) {
|
|
1781
|
+
this.meetingInfoFailureReason = MEETING_INFO_FAILURE_REASON.NEED_JOIN_WITH_WEBCAST;
|
|
1782
|
+
} else if (WEBINAR_ERROR_REGISTRATIONID.includes(err.wbxAppApiCode)) {
|
|
1783
|
+
this.meetingInfoFailureReason = MEETING_INFO_FAILURE_REASON.WEBINAR_NEED_REGISTRATIONID;
|
|
1784
|
+
}
|
|
1785
|
+
this.meetingInfoFailureCode = err.wbxAppApiCode;
|
|
1786
|
+
|
|
1787
|
+
if (err.meetingInfo) {
|
|
1788
|
+
this.meetingInfo = err.meetingInfo;
|
|
1789
|
+
}
|
|
1790
|
+
|
|
1791
|
+
throw new JoinWebinarError();
|
|
1792
|
+
} else if (err instanceof MeetingInfoV2JoinForbiddenError) {
|
|
1793
|
+
this.meetingInfoFailureReason = MEETING_INFO_FAILURE_REASON.JOIN_FORBIDDEN;
|
|
1772
1794
|
this.meetingInfoFailureCode = err.wbxAppApiCode;
|
|
1773
1795
|
|
|
1774
1796
|
if (err.meetingInfo) {
|
|
1775
1797
|
this.meetingInfo = err.meetingInfo;
|
|
1776
1798
|
}
|
|
1777
1799
|
|
|
1778
|
-
|
|
1800
|
+
// Handle the case where user hasn't reached Join Before Host (JBH) time (error code 403003)
|
|
1801
|
+
if (JOIN_BEFORE_HOST === err.wbxAppApiCode) {
|
|
1802
|
+
this.meetingInfoFailureReason = MEETING_INFO_FAILURE_REASON.NOT_REACH_JBH;
|
|
1803
|
+
}
|
|
1804
|
+
|
|
1805
|
+
throw new JoinForbiddenError(this.meetingInfoFailureReason, err);
|
|
1779
1806
|
} else if (err instanceof MeetingInfoV2PasswordError) {
|
|
1780
1807
|
LoggerProxy.logger.info(
|
|
1781
1808
|
// @ts-ignore
|
|
@@ -2734,6 +2761,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2734
2761
|
this.triggerAnnotationInfoEvent(contentShare, previousContentShare);
|
|
2735
2762
|
|
|
2736
2763
|
if (
|
|
2764
|
+
!payload.forceUpdate &&
|
|
2737
2765
|
contentShare.beneficiaryId === previousContentShare?.beneficiaryId &&
|
|
2738
2766
|
contentShare.disposition === previousContentShare?.disposition &&
|
|
2739
2767
|
contentShare.deviceUrlSharing === previousContentShare.deviceUrlSharing &&
|
|
@@ -2780,7 +2808,11 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2780
2808
|
// It does not matter who requested to share the whiteboard, everyone gets the same view
|
|
2781
2809
|
else if (whiteboardShare.disposition === FLOOR_ACTION.GRANTED) {
|
|
2782
2810
|
// WHITEBOARD - sharing whiteboard
|
|
2783
|
-
|
|
2811
|
+
// Webinar attendee should receive whiteboard as remote share
|
|
2812
|
+
newShareStatus =
|
|
2813
|
+
this.locusInfo?.info?.isWebinar && this.webinar?.selfIsAttendee
|
|
2814
|
+
? SHARE_STATUS.REMOTE_SHARE_ACTIVE
|
|
2815
|
+
: SHARE_STATUS.WHITEBOARD_SHARE_ACTIVE;
|
|
2784
2816
|
}
|
|
2785
2817
|
// or if content share is either released or null and whiteboard share is either released or null, no one is sharing
|
|
2786
2818
|
else if (
|
|
@@ -2795,6 +2827,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2795
2827
|
LoggerProxy.logger.info(
|
|
2796
2828
|
`Meeting:index#setUpLocusInfoMediaInactiveListener --> this.shareStatus=${this.shareStatus} newShareStatus=${newShareStatus}`
|
|
2797
2829
|
);
|
|
2830
|
+
|
|
2798
2831
|
if (newShareStatus !== this.shareStatus) {
|
|
2799
2832
|
const oldShareStatus = this.shareStatus;
|
|
2800
2833
|
|
|
@@ -3052,7 +3085,20 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3052
3085
|
*/
|
|
3053
3086
|
private setUpLocusResourcesListener() {
|
|
3054
3087
|
this.locusInfo.on(LOCUSINFO.EVENTS.LINKS_RESOURCES, (payload) => {
|
|
3055
|
-
|
|
3088
|
+
if (payload) {
|
|
3089
|
+
this.webinar.updateWebcastUrl(payload);
|
|
3090
|
+
Trigger.trigger(
|
|
3091
|
+
this,
|
|
3092
|
+
{
|
|
3093
|
+
file: 'meeting/index',
|
|
3094
|
+
function: 'setUpLocusInfoMeetingInfoListener',
|
|
3095
|
+
},
|
|
3096
|
+
EVENT_TRIGGERS.MEETING_RESOURCE_LINKS_UPDATE,
|
|
3097
|
+
{
|
|
3098
|
+
payload,
|
|
3099
|
+
}
|
|
3100
|
+
);
|
|
3101
|
+
}
|
|
3056
3102
|
});
|
|
3057
3103
|
}
|
|
3058
3104
|
|
|
@@ -3362,6 +3408,21 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3362
3408
|
}
|
|
3363
3409
|
});
|
|
3364
3410
|
|
|
3411
|
+
this.locusInfo.on(LOCUSINFO.EVENTS.SELF_MEETING_BRB_CHANGED, (payload) => {
|
|
3412
|
+
this.brbState?.handleServerBrbUpdate(payload?.brb?.enabled);
|
|
3413
|
+
Trigger.trigger(
|
|
3414
|
+
this,
|
|
3415
|
+
{
|
|
3416
|
+
file: 'meeting/index',
|
|
3417
|
+
function: 'setUpLocusInfoSelfListener',
|
|
3418
|
+
},
|
|
3419
|
+
EVENT_TRIGGERS.MEETING_SELF_BRB_UPDATE,
|
|
3420
|
+
{
|
|
3421
|
+
payload,
|
|
3422
|
+
}
|
|
3423
|
+
);
|
|
3424
|
+
});
|
|
3425
|
+
|
|
3365
3426
|
this.locusInfo.on(LOCUSINFO.EVENTS.SELF_ROLES_CHANGED, (payload) => {
|
|
3366
3427
|
const isModeratorOrCohost =
|
|
3367
3428
|
payload.newRoles?.includes(SELF_ROLES.MODERATOR) ||
|
|
@@ -3371,6 +3432,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3371
3432
|
payload.newRoles?.includes(SELF_ROLES.MODERATOR)
|
|
3372
3433
|
);
|
|
3373
3434
|
this.webinar.updateRoleChanged(payload);
|
|
3435
|
+
|
|
3374
3436
|
Trigger.trigger(
|
|
3375
3437
|
this,
|
|
3376
3438
|
{
|
|
@@ -3565,6 +3627,35 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3565
3627
|
return this.members.admitMembers(memberIds, locusUrls);
|
|
3566
3628
|
}
|
|
3567
3629
|
|
|
3630
|
+
/**
|
|
3631
|
+
* Manages be right back status updates for the current participant.
|
|
3632
|
+
*
|
|
3633
|
+
* @param {boolean} enabled - Indicates whether the user enabled brb or not.
|
|
3634
|
+
* @returns {Promise<void>} resolves when the brb status is updated or does nothing if not in a multistream meeting.
|
|
3635
|
+
* @throws {Error} - Throws an error if the request fails.
|
|
3636
|
+
*/
|
|
3637
|
+
public async beRightBack(enabled: boolean): Promise<void> {
|
|
3638
|
+
if (!this.isMultistream) {
|
|
3639
|
+
const errorMessage = 'Meeting:index#beRightBack --> Not a multistream meeting';
|
|
3640
|
+
const error = new Error(errorMessage);
|
|
3641
|
+
|
|
3642
|
+
LoggerProxy.logger.error(error);
|
|
3643
|
+
|
|
3644
|
+
return Promise.reject(error);
|
|
3645
|
+
}
|
|
3646
|
+
|
|
3647
|
+
if (!this.mediaProperties.webrtcMediaConnection) {
|
|
3648
|
+
const errorMessage = 'Meeting:index#beRightBack --> WebRTC media connection is not defined';
|
|
3649
|
+
const error = new Error(errorMessage);
|
|
3650
|
+
|
|
3651
|
+
LoggerProxy.logger.error(error);
|
|
3652
|
+
|
|
3653
|
+
return Promise.reject(error);
|
|
3654
|
+
}
|
|
3655
|
+
|
|
3656
|
+
return this.brbState.enable(enabled, this.sendSlotManager);
|
|
3657
|
+
}
|
|
3658
|
+
|
|
3568
3659
|
/**
|
|
3569
3660
|
* Remove the member from the meeting, boot them
|
|
3570
3661
|
* @param {String} memberId
|
|
@@ -3804,6 +3895,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3804
3895
|
this.userDisplayHints
|
|
3805
3896
|
),
|
|
3806
3897
|
canManageBreakout: MeetingUtil.canManageBreakout(this.userDisplayHints),
|
|
3898
|
+
canStartBreakout: MeetingUtil.canStartBreakout(this.userDisplayHints),
|
|
3807
3899
|
canBroadcastMessageToBreakout: MeetingUtil.canBroadcastMessageToBreakout(
|
|
3808
3900
|
this.userDisplayHints,
|
|
3809
3901
|
this.selfUserPolicies
|
|
@@ -4099,10 +4191,11 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4099
4191
|
*/
|
|
4100
4192
|
private setLogUploadTimer() {
|
|
4101
4193
|
// start with short timeouts and increase them later on so in case users have very long multi-hour meetings we don't get too fragmented logs
|
|
4102
|
-
const LOG_UPLOAD_INTERVALS = [0.1,
|
|
4194
|
+
const LOG_UPLOAD_INTERVALS = [0.1, 15, 30, 60]; // in minutes
|
|
4103
4195
|
|
|
4104
4196
|
const delay =
|
|
4105
4197
|
1000 *
|
|
4198
|
+
60 *
|
|
4106
4199
|
// @ts-ignore - config coming from registerPlugin
|
|
4107
4200
|
this.config.logUploadIntervalMultiplicationFactor *
|
|
4108
4201
|
LOG_UPLOAD_INTERVALS[this.logUploadIntervalIndex];
|
|
@@ -4541,11 +4634,12 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4541
4634
|
* Close the peer connections and remove them from the class.
|
|
4542
4635
|
* Cleanup any media connection related things.
|
|
4543
4636
|
*
|
|
4637
|
+
* @param {boolean} resetMuteStates whether to also reset the audio/video mute state information
|
|
4544
4638
|
* @returns {Promise}
|
|
4545
4639
|
* @public
|
|
4546
4640
|
* @memberof Meeting
|
|
4547
4641
|
*/
|
|
4548
|
-
public closePeerConnections() {
|
|
4642
|
+
public closePeerConnections(resetMuteStates = true) {
|
|
4549
4643
|
if (this.mediaProperties.webrtcMediaConnection) {
|
|
4550
4644
|
if (this.remoteMediaManager) {
|
|
4551
4645
|
this.remoteMediaManager.stop();
|
|
@@ -4558,12 +4652,15 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4558
4652
|
|
|
4559
4653
|
this.receiveSlotManager.reset();
|
|
4560
4654
|
this.mediaProperties.webrtcMediaConnection.close();
|
|
4655
|
+
this.mediaProperties.unsetPeerConnection();
|
|
4561
4656
|
this.sendSlotManager.reset();
|
|
4562
4657
|
this.setNetworkStatus(undefined);
|
|
4563
4658
|
}
|
|
4564
4659
|
|
|
4565
|
-
|
|
4566
|
-
|
|
4660
|
+
if (resetMuteStates) {
|
|
4661
|
+
this.audio = null;
|
|
4662
|
+
this.video = null;
|
|
4663
|
+
}
|
|
4567
4664
|
|
|
4568
4665
|
return Promise.resolve();
|
|
4569
4666
|
}
|
|
@@ -4823,7 +4920,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4823
4920
|
* @param {Object} options - options to join with media
|
|
4824
4921
|
* @param {JoinOptions} [options.joinOptions] - see #join()
|
|
4825
4922
|
* @param {AddMediaOptions} [options.mediaOptions] - see #addMedia()
|
|
4826
|
-
* @returns {Promise} -- {join: see join(), media: see addMedia()}
|
|
4923
|
+
* @returns {Promise} -- {join: see join(), media: see addMedia(), multistreamEnabled: flag to indicate if we managed to join in multistream mode}
|
|
4827
4924
|
* @public
|
|
4828
4925
|
* @memberof Meeting
|
|
4829
4926
|
* @example
|
|
@@ -4913,6 +5010,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4913
5010
|
return {
|
|
4914
5011
|
join: joinResponse,
|
|
4915
5012
|
media: mediaResponse,
|
|
5013
|
+
multistreamEnabled: this.isMultistream,
|
|
4916
5014
|
};
|
|
4917
5015
|
} catch (error) {
|
|
4918
5016
|
LoggerProxy.logger.error('Meeting:index#joinWithMedia --> ', error);
|
|
@@ -4921,7 +5019,17 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4921
5019
|
|
|
4922
5020
|
this.roap.abortTurnDiscovery();
|
|
4923
5021
|
|
|
4924
|
-
if
|
|
5022
|
+
// if this was the first attempt, let's do a retry
|
|
5023
|
+
let shouldRetry = !isRetry;
|
|
5024
|
+
|
|
5025
|
+
if (CallDiagnosticUtils.isSdpOfferCreationError(error)) {
|
|
5026
|
+
// errors related to offer creation (for example missing H264 codec) will happen again no matter how many times we try,
|
|
5027
|
+
// so there is no point doing a retry
|
|
5028
|
+
shouldRetry = false;
|
|
5029
|
+
}
|
|
5030
|
+
|
|
5031
|
+
// we only want to call leave if join was successful and this was a retry or we won't be doing any more retries
|
|
5032
|
+
if (joined && (isRetry || !shouldRetry)) {
|
|
4925
5033
|
try {
|
|
4926
5034
|
await this.leave({resourceId: joinOptions?.resourceId, reason: 'joinWithMedia failure'});
|
|
4927
5035
|
} catch (e) {
|
|
@@ -4945,15 +5053,6 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4945
5053
|
}
|
|
4946
5054
|
);
|
|
4947
5055
|
|
|
4948
|
-
// if this was the first attempt, let's do a retry
|
|
4949
|
-
let shouldRetry = !isRetry;
|
|
4950
|
-
|
|
4951
|
-
if (CallDiagnosticUtils.isSdpOfferCreationError(error)) {
|
|
4952
|
-
// errors related to offer creation (for example missing H264 codec) will happen again no matter how many times we try,
|
|
4953
|
-
// so there is no point doing a retry
|
|
4954
|
-
shouldRetry = false;
|
|
4955
|
-
}
|
|
4956
|
-
|
|
4957
5056
|
if (shouldRetry) {
|
|
4958
5057
|
LoggerProxy.logger.warn('Meeting:index#joinWithMedia --> retrying call to joinWithMedia');
|
|
4959
5058
|
this.joinWithMediaRetryInfo.isRetry = true;
|
|
@@ -5209,7 +5308,16 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5209
5308
|
(this.config.receiveReactions || options.receiveReactions) &&
|
|
5210
5309
|
this.isReactionsSupported()
|
|
5211
5310
|
) {
|
|
5212
|
-
const
|
|
5311
|
+
const member = this.members.membersCollection.get(e.data.sender.participantId);
|
|
5312
|
+
if (!member) {
|
|
5313
|
+
// @ts-ignore -- fix type
|
|
5314
|
+
LoggerProxy.logger.warn(
|
|
5315
|
+
`Meeting:index#processRelayEvent --> Skipping handling of ${REACTION_RELAY_TYPES.REACTION} for ${this.id}. participantId ${e.data.sender.participantId} does not exist in membersCollection.`
|
|
5316
|
+
);
|
|
5317
|
+
break;
|
|
5318
|
+
}
|
|
5319
|
+
|
|
5320
|
+
const {name} = member;
|
|
5213
5321
|
const processedReaction: ProcessedReaction = {
|
|
5214
5322
|
reaction: e.data.reaction,
|
|
5215
5323
|
sender: {
|
|
@@ -5263,6 +5371,9 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5263
5371
|
this.voiceaListenerCallbacks[VOICEAEVENTS.NEW_CAPTION]
|
|
5264
5372
|
);
|
|
5265
5373
|
|
|
5374
|
+
// @ts-ignore
|
|
5375
|
+
this.webex.internal.voicea.deregisterEvents();
|
|
5376
|
+
|
|
5266
5377
|
this.areVoiceaEventsSetup = false;
|
|
5267
5378
|
this.triggerStopReceivingTranscriptionEvent();
|
|
5268
5379
|
}
|
|
@@ -5373,16 +5484,19 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5373
5484
|
this.meetingFiniteStateMachine.reset();
|
|
5374
5485
|
}
|
|
5375
5486
|
|
|
5376
|
-
//
|
|
5377
|
-
|
|
5378
|
-
|
|
5379
|
-
|
|
5380
|
-
|
|
5381
|
-
|
|
5382
|
-
|
|
5383
|
-
|
|
5384
|
-
|
|
5385
|
-
|
|
5487
|
+
// send client.call.initiated unless told not to
|
|
5488
|
+
if (options.sendCallInitiated !== false) {
|
|
5489
|
+
// @ts-ignore
|
|
5490
|
+
this.webex.internal.newMetrics.submitClientEvent({
|
|
5491
|
+
name: 'client.call.initiated',
|
|
5492
|
+
payload: {
|
|
5493
|
+
trigger: this.callStateForMetrics.joinTrigger || 'user-interaction',
|
|
5494
|
+
isRoapCallEnabled: true,
|
|
5495
|
+
pstnAudioType: options?.pstnAudioType,
|
|
5496
|
+
},
|
|
5497
|
+
options: {meetingId: this.id},
|
|
5498
|
+
});
|
|
5499
|
+
}
|
|
5386
5500
|
|
|
5387
5501
|
LoggerProxy.logger.log('Meeting:index#join --> Joining a meeting');
|
|
5388
5502
|
|
|
@@ -5570,17 +5684,23 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5570
5684
|
*/
|
|
5571
5685
|
async updateLLMConnection() {
|
|
5572
5686
|
// @ts-ignore - Fix type
|
|
5573
|
-
const {url, info: {datachannelUrl} = {}} = this.locusInfo;
|
|
5687
|
+
const {url, info: {datachannelUrl, practiceSessionDatachannelUrl} = {}} = this.locusInfo;
|
|
5574
5688
|
|
|
5575
5689
|
const isJoined = this.isJoined();
|
|
5576
5690
|
|
|
5691
|
+
// webinar panelist should use new data channel in practice session
|
|
5692
|
+
const dataChannelUrl =
|
|
5693
|
+
this.webinar.isJoinPracticeSessionDataChannel() && practiceSessionDatachannelUrl
|
|
5694
|
+
? practiceSessionDatachannelUrl
|
|
5695
|
+
: datachannelUrl;
|
|
5696
|
+
|
|
5577
5697
|
// @ts-ignore - Fix type
|
|
5578
5698
|
if (this.webex.internal.llm.isConnected()) {
|
|
5579
5699
|
if (
|
|
5580
5700
|
// @ts-ignore - Fix type
|
|
5581
5701
|
url === this.webex.internal.llm.getLocusUrl() &&
|
|
5582
5702
|
// @ts-ignore - Fix type
|
|
5583
|
-
|
|
5703
|
+
dataChannelUrl === this.webex.internal.llm.getDatachannelUrl() &&
|
|
5584
5704
|
isJoined
|
|
5585
5705
|
) {
|
|
5586
5706
|
return undefined;
|
|
@@ -5597,7 +5717,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5597
5717
|
|
|
5598
5718
|
// @ts-ignore - Fix type
|
|
5599
5719
|
return this.webex.internal.llm
|
|
5600
|
-
.registerAndConnect(url,
|
|
5720
|
+
.registerAndConnect(url, dataChannelUrl)
|
|
5601
5721
|
.then((registerAndConnectResult) => {
|
|
5602
5722
|
// @ts-ignore - Fix type
|
|
5603
5723
|
this.webex.internal.llm.off('event:relay.event', this.processRelayEvent);
|
|
@@ -5967,8 +6087,16 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5967
6087
|
* @returns {undefined}
|
|
5968
6088
|
*/
|
|
5969
6089
|
public roapMessageReceived = (roapMessage: RoapMessage) => {
|
|
5970
|
-
const mediaServer =
|
|
5971
|
-
|
|
6090
|
+
const mediaServer =
|
|
6091
|
+
roapMessage.messageType === 'ANSWER'
|
|
6092
|
+
? MeetingsUtil.getMediaServer(roapMessage.sdp)
|
|
6093
|
+
: undefined;
|
|
6094
|
+
|
|
6095
|
+
if (this.isMultistream && mediaServer && mediaServer !== 'homer') {
|
|
6096
|
+
throw new MultistreamNotSupportedError(
|
|
6097
|
+
`Client asked for multistream backend (Homer), but got ${mediaServer} instead`
|
|
6098
|
+
);
|
|
6099
|
+
}
|
|
5972
6100
|
this.mediaProperties.webrtcMediaConnection.roapMessageReceived(roapMessage);
|
|
5973
6101
|
|
|
5974
6102
|
if (mediaServer) {
|
|
@@ -6091,16 +6219,20 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
6091
6219
|
logText: `${LOG_HEADER} Roap Offer`,
|
|
6092
6220
|
}
|
|
6093
6221
|
).catch((error) => {
|
|
6222
|
+
const multistreamNotSupported = error instanceof MultistreamNotSupportedError;
|
|
6223
|
+
|
|
6094
6224
|
// @ts-ignore
|
|
6095
6225
|
this.webex.internal.newMetrics.submitClientEvent({
|
|
6096
6226
|
name: 'client.media-engine.remote-sdp-received',
|
|
6097
6227
|
payload: {
|
|
6098
|
-
canProceed:
|
|
6228
|
+
canProceed: multistreamNotSupported,
|
|
6099
6229
|
errors: [
|
|
6100
6230
|
// @ts-ignore
|
|
6101
6231
|
this.webex.internal.newMetrics.callDiagnosticMetrics.getErrorPayloadForClientErrorCode(
|
|
6102
6232
|
{
|
|
6103
|
-
clientErrorCode:
|
|
6233
|
+
clientErrorCode: multistreamNotSupported
|
|
6234
|
+
? CALL_DIAGNOSTIC_CONFIG.MULTISTREAM_NOT_AVAILABLE_CLIENT_CODE
|
|
6235
|
+
: CALL_DIAGNOSTIC_CONFIG.MISSING_ROAP_ANSWER_CLIENT_CODE,
|
|
6104
6236
|
}
|
|
6105
6237
|
),
|
|
6106
6238
|
],
|
|
@@ -6108,7 +6240,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
6108
6240
|
options: {meetingId: this.id, rawError: error},
|
|
6109
6241
|
});
|
|
6110
6242
|
|
|
6111
|
-
this.deferSDPAnswer.reject(
|
|
6243
|
+
this.deferSDPAnswer.reject(error);
|
|
6112
6244
|
clearTimeout(this.sdpResponseTimer);
|
|
6113
6245
|
this.sdpResponseTimer = undefined;
|
|
6114
6246
|
});
|
|
@@ -6436,6 +6568,14 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
6436
6568
|
this.webex.meetings.geoHintInfo?.clientAddress ||
|
|
6437
6569
|
options.data.intervalMetadata.peerReflexiveIP ||
|
|
6438
6570
|
MQA_STATS.DEFAULT_IP;
|
|
6571
|
+
|
|
6572
|
+
const {members} = this.getMembers().membersCollection;
|
|
6573
|
+
|
|
6574
|
+
// Count members that are in the meeting
|
|
6575
|
+
options.data.intervalMetadata.meetingUserCount = Object.values(members).filter(
|
|
6576
|
+
(member: Member) => member.isInMeeting
|
|
6577
|
+
).length;
|
|
6578
|
+
|
|
6439
6579
|
// @ts-ignore
|
|
6440
6580
|
this.webex.internal.newMetrics.submitMQE({
|
|
6441
6581
|
name: 'client.mediaquality.event',
|
|
@@ -6567,6 +6707,9 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
6567
6707
|
new RtcMetrics(this.webex, {meetingId: this.id}, this.correlationId)
|
|
6568
6708
|
: undefined;
|
|
6569
6709
|
|
|
6710
|
+
// ongoing reachability checks slow down new media connections especially on Firefox, so we stop them
|
|
6711
|
+
this.getWebexObject().meetings.reachability.stopReachability();
|
|
6712
|
+
|
|
6570
6713
|
const mc = Media.createMediaConnection(
|
|
6571
6714
|
this.isMultistream,
|
|
6572
6715
|
this.getMediaConnectionDebugId(),
|
|
@@ -6767,32 +6910,6 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
6767
6910
|
}
|
|
6768
6911
|
}
|
|
6769
6912
|
|
|
6770
|
-
/**
|
|
6771
|
-
* Handles device logging
|
|
6772
|
-
*
|
|
6773
|
-
* @private
|
|
6774
|
-
* @static
|
|
6775
|
-
* @param {boolean} isAudioEnabled
|
|
6776
|
-
* @param {boolean} isVideoEnabled
|
|
6777
|
-
* @returns {Promise<void>}
|
|
6778
|
-
*/
|
|
6779
|
-
|
|
6780
|
-
private static async handleDeviceLogging(isAudioEnabled, isVideoEnabled): Promise<void> {
|
|
6781
|
-
try {
|
|
6782
|
-
let devices = [];
|
|
6783
|
-
if (isVideoEnabled && isAudioEnabled) {
|
|
6784
|
-
devices = await getDevices();
|
|
6785
|
-
} else if (isVideoEnabled) {
|
|
6786
|
-
devices = await getDevices(Media.DeviceKind.VIDEO_INPUT);
|
|
6787
|
-
} else if (isAudioEnabled) {
|
|
6788
|
-
devices = await getDevices(Media.DeviceKind.AUDIO_INPUT);
|
|
6789
|
-
}
|
|
6790
|
-
MeetingUtil.handleDeviceLogging(devices);
|
|
6791
|
-
} catch {
|
|
6792
|
-
// getDevices may fail if we don't have browser permissions, that's ok, we still can have a media connection
|
|
6793
|
-
}
|
|
6794
|
-
}
|
|
6795
|
-
|
|
6796
6913
|
/**
|
|
6797
6914
|
* Returns a promise. This promise is created once the local sdp offer has been successfully created and is resolved
|
|
6798
6915
|
* once the remote sdp answer has been received.
|
|
@@ -7016,7 +7133,9 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
7016
7133
|
|
|
7017
7134
|
const mc = await this.createMediaConnection(turnServerInfo, bundlePolicy);
|
|
7018
7135
|
|
|
7019
|
-
LoggerProxy.logger.info(
|
|
7136
|
+
LoggerProxy.logger.info(
|
|
7137
|
+
`${LOG_HEADER} media connection created this.isMultistream=${this.isMultistream}`
|
|
7138
|
+
);
|
|
7020
7139
|
|
|
7021
7140
|
if (this.isMultistream) {
|
|
7022
7141
|
this.remoteMediaManager = new RemoteMediaManager(
|
|
@@ -7094,6 +7213,33 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
7094
7213
|
}
|
|
7095
7214
|
}
|
|
7096
7215
|
|
|
7216
|
+
/**
|
|
7217
|
+
* Cleans up stats analyzer, peer connection and other things before
|
|
7218
|
+
* we can create a new transcoded media connection
|
|
7219
|
+
*
|
|
7220
|
+
* @private
|
|
7221
|
+
* @returns {Promise<void>}
|
|
7222
|
+
*/
|
|
7223
|
+
private async downgradeFromMultistreamToTranscoded(): Promise<void> {
|
|
7224
|
+
if (this.statsAnalyzer) {
|
|
7225
|
+
await this.statsAnalyzer.stopAnalyzer();
|
|
7226
|
+
}
|
|
7227
|
+
this.statsAnalyzer = null;
|
|
7228
|
+
|
|
7229
|
+
this.isMultistream = false;
|
|
7230
|
+
|
|
7231
|
+
if (this.mediaProperties.webrtcMediaConnection) {
|
|
7232
|
+
// close peer connection, but don't reset mute state information, because we will want to use it on the retry
|
|
7233
|
+
this.closePeerConnections(false);
|
|
7234
|
+
|
|
7235
|
+
this.mediaProperties.unsetPeerConnection();
|
|
7236
|
+
}
|
|
7237
|
+
|
|
7238
|
+
this.locusMediaRequest?.downgradeFromMultistreamToTranscoded();
|
|
7239
|
+
|
|
7240
|
+
this.createStatsAnalyzer();
|
|
7241
|
+
}
|
|
7242
|
+
|
|
7097
7243
|
/**
|
|
7098
7244
|
* Sends stats report, closes peer connection and cleans up any media connection
|
|
7099
7245
|
* related things before trying to establish media connection again with turn server
|
|
@@ -7280,6 +7426,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
7280
7426
|
|
|
7281
7427
|
this.audio = createMuteState(AUDIO, this, audioEnabled);
|
|
7282
7428
|
this.video = createMuteState(VIDEO, this, videoEnabled);
|
|
7429
|
+
this.brbState = createBrbState(this, false);
|
|
7283
7430
|
|
|
7284
7431
|
try {
|
|
7285
7432
|
await this.setUpLocalStreamReferences(localStreams);
|
|
@@ -7288,19 +7435,33 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
7288
7435
|
|
|
7289
7436
|
this.createStatsAnalyzer();
|
|
7290
7437
|
|
|
7291
|
-
|
|
7292
|
-
|
|
7293
|
-
|
|
7294
|
-
|
|
7295
|
-
|
|
7296
|
-
|
|
7438
|
+
try {
|
|
7439
|
+
await this.establishMediaConnection(
|
|
7440
|
+
remoteMediaManagerConfig,
|
|
7441
|
+
bundlePolicy,
|
|
7442
|
+
forceTurnDiscovery,
|
|
7443
|
+
turnServerInfo
|
|
7444
|
+
);
|
|
7445
|
+
} catch (error) {
|
|
7446
|
+
if (error instanceof MultistreamNotSupportedError) {
|
|
7447
|
+
LoggerProxy.logger.warn(
|
|
7448
|
+
`${LOG_HEADER} we asked for multistream backend (Homer), but got transcoded backend, recreating media connection...`
|
|
7449
|
+
);
|
|
7297
7450
|
|
|
7298
|
-
|
|
7299
|
-
await Meeting.handleDeviceLogging(audioEnabled, videoEnabled);
|
|
7300
|
-
} else {
|
|
7301
|
-
LoggerProxy.logger.info(`${LOG_HEADER} device logging not required`);
|
|
7302
|
-
}
|
|
7451
|
+
await this.downgradeFromMultistreamToTranscoded();
|
|
7303
7452
|
|
|
7453
|
+
// Establish new media connection with forced TURN discovery
|
|
7454
|
+
// We need to do TURN discovery again, because backend will be creating a new confluence, so it might land on a different node or cluster
|
|
7455
|
+
await this.establishMediaConnection(
|
|
7456
|
+
remoteMediaManagerConfig,
|
|
7457
|
+
bundlePolicy,
|
|
7458
|
+
true,
|
|
7459
|
+
undefined
|
|
7460
|
+
);
|
|
7461
|
+
} else {
|
|
7462
|
+
throw error;
|
|
7463
|
+
}
|
|
7464
|
+
}
|
|
7304
7465
|
if (this.mediaProperties.hasLocalShareStream()) {
|
|
7305
7466
|
await this.enqueueScreenShareFloorRequest();
|
|
7306
7467
|
}
|
|
@@ -8270,7 +8431,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
8270
8431
|
if (layoutType) {
|
|
8271
8432
|
if (!LAYOUT_TYPES.includes(layoutType)) {
|
|
8272
8433
|
return this.rejectWithErrorLog(
|
|
8273
|
-
|
|
8434
|
+
`Meeting:index#changeVideoLayout --> cannot change video layout, invalid layoutType "${layoutType}" received.`
|
|
8274
8435
|
);
|
|
8275
8436
|
}
|
|
8276
8437
|
|
|
@@ -8426,6 +8587,12 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
8426
8587
|
correlationId: this.correlationId,
|
|
8427
8588
|
muted,
|
|
8428
8589
|
encoderImplementation: this.statsAnalyzer?.shareVideoEncoderImplementation,
|
|
8590
|
+
// TypeScript 4 does not recognize the `displaySurface` property. Instead of upgrading the
|
|
8591
|
+
// SDK to TypeScript 5, which may affect other packages, use bracket notation for now, since
|
|
8592
|
+
// all we're doing here is adding metrics.
|
|
8593
|
+
// eslint-disable-next-line dot-notation
|
|
8594
|
+
displaySurface: this.mediaProperties?.shareVideoStream?.getSettings()['displaySurface'],
|
|
8595
|
+
isMultistream: this.isMultistream,
|
|
8429
8596
|
});
|
|
8430
8597
|
};
|
|
8431
8598
|
|
|
@@ -8628,6 +8795,11 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
8628
8795
|
this.stopTranscription();
|
|
8629
8796
|
this.transcription = undefined;
|
|
8630
8797
|
}
|
|
8798
|
+
|
|
8799
|
+
this.annotation.deregisterEvents();
|
|
8800
|
+
|
|
8801
|
+
// @ts-ignore - fix types
|
|
8802
|
+
this.webex.internal.llm.off('event:relay.event', this.processRelayEvent);
|
|
8631
8803
|
};
|
|
8632
8804
|
|
|
8633
8805
|
/**
|
|
@@ -8665,10 +8837,12 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
8665
8837
|
|
|
8666
8838
|
return;
|
|
8667
8839
|
}
|
|
8668
|
-
|
|
8840
|
+
|
|
8669
8841
|
const keepAliveInterval = (this.joinedWith.keepAliveSecs - 1) * 750; // taken from UCF
|
|
8670
8842
|
|
|
8671
8843
|
this.keepAliveTimerId = setInterval(() => {
|
|
8844
|
+
const {keepAliveUrl} = this.joinedWith;
|
|
8845
|
+
|
|
8672
8846
|
this.meetingRequest.keepAlive({keepAliveUrl}).catch((error) => {
|
|
8673
8847
|
LoggerProxy.logger.warn(
|
|
8674
8848
|
`Meeting:index#startKeepAlive --> Stopping sending keepAlives to ${keepAliveUrl} after error ${error}`
|
|
@@ -342,4 +342,11 @@ export class LocusMediaRequest extends WebexPlugin {
|
|
|
342
342
|
public isConfluenceCreated() {
|
|
343
343
|
return this.confluenceState === 'created';
|
|
344
344
|
}
|
|
345
|
+
|
|
346
|
+
/**
|
|
347
|
+
* This method needs to be called when we downgrade from multistream to transcoded connection.
|
|
348
|
+
*/
|
|
349
|
+
public downgradeFromMultistreamToTranscoded() {
|
|
350
|
+
this.config.preferTranscoding = true;
|
|
351
|
+
}
|
|
345
352
|
}
|
package/src/meeting/muteState.ts
CHANGED
|
@@ -379,12 +379,7 @@ export class MuteState {
|
|
|
379
379
|
}
|
|
380
380
|
if (muted !== undefined) {
|
|
381
381
|
this.state.server.remoteMute = muted;
|
|
382
|
-
|
|
383
|
-
// We never want to unmute the local stream from a server remote mute update.
|
|
384
|
-
// Moderated unmute is handled by a different function.
|
|
385
|
-
if (muted) {
|
|
386
|
-
this.muteLocalStream(meeting, muted, 'remotelyMuted');
|
|
387
|
-
}
|
|
382
|
+
this.muteLocalStream(meeting, muted, 'remotelyMuted');
|
|
388
383
|
}
|
|
389
384
|
}
|
|
390
385
|
|