@webex/plugin-meetings 3.7.0-next.5 → 3.7.0-next.51
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/{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 +40 -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 +30 -17
- package/dist/locus-info/selfUtils.js.map +1 -1
- package/dist/meeting/in-meeting-actions.js +4 -0
- package/dist/meeting/in-meeting-actions.js.map +1 -1
- package/dist/meeting/index.js +944 -832
- 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/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 +29 -17
- 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 +106 -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 +1 -1
- 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/recording-controller/enums.js +8 -4
- package/dist/recording-controller/enums.js.map +1 -1
- package/dist/recording-controller/index.js +18 -9
- package/dist/recording-controller/index.js.map +1 -1
- package/dist/recording-controller/util.js +13 -9
- package/dist/recording-controller/util.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/{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 +34 -1
- package/dist/types/index.d.ts +3 -3
- package/dist/types/locus-info/index.d.ts +2 -1
- package/dist/types/meeting/in-meeting-actions.d.ts +4 -0
- package/dist/types/meeting/index.d.ts +19 -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 +4 -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 +1 -1
- package/dist/types/multistream/sendSlotManager.d.ts +8 -1
- package/dist/types/recording-controller/enums.d.ts +5 -2
- package/dist/types/recording-controller/index.d.ts +1 -0
- package/dist/types/recording-controller/util.d.ts +2 -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-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 +39 -3
- package/src/index.ts +5 -3
- package/src/locus-info/index.ts +20 -3
- package/src/locus-info/selfUtils.ts +19 -6
- package/src/meeting/in-meeting-actions.ts +8 -0
- package/src/meeting/index.ts +246 -80
- package/src/meeting/locusMediaRequest.ts +7 -0
- 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 +23 -11
- package/src/meeting-info/utilv2.ts +3 -1
- package/src/meetings/index.ts +77 -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 +1 -1
- package/src/multistream/remoteMedia.ts +28 -15
- package/src/multistream/sendSlotManager.ts +31 -0
- package/src/recording-controller/enums.ts +5 -2
- package/src/recording-controller/index.ts +17 -4
- package/src/recording-controller/util.ts +20 -5
- 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 +91 -1
- package/test/unit/spec/meeting/in-meeting-actions.ts +4 -0
- package/test/unit/spec/meeting/index.js +689 -105
- package/test/unit/spec/meeting/utils.js +22 -19
- package/test/unit/spec/meeting-info/meetinginfov2.js +9 -4
- package/test/unit/spec/meeting-info/utilv2.js +17 -0
- package/test/unit/spec/meetings/index.js +153 -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/recording-controller/index.js +61 -5
- package/test/unit/spec/recording-controller/util.js +39 -3
- 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,8 @@ 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,
|
|
125
126
|
} from '../constants';
|
|
126
127
|
import BEHAVIORAL_METRICS from '../metrics/constants';
|
|
127
128
|
import ParameterError from '../common/errors/parameter';
|
|
@@ -129,7 +130,7 @@ import {
|
|
|
129
130
|
MeetingInfoV2PasswordError,
|
|
130
131
|
MeetingInfoV2CaptchaError,
|
|
131
132
|
MeetingInfoV2PolicyError,
|
|
132
|
-
|
|
133
|
+
MeetingInfoV2JoinWebinarError,
|
|
133
134
|
} from '../meeting-info/meeting-info-v2';
|
|
134
135
|
import {CSI, ReceiveSlotManager} from '../multistream/receiveSlotManager';
|
|
135
136
|
import SendSlotManager from '../multistream/sendSlotManager';
|
|
@@ -158,7 +159,9 @@ import ControlsOptionsManager from '../controls-options-manager';
|
|
|
158
159
|
import PermissionError from '../common/errors/permission';
|
|
159
160
|
import {LocusMediaRequest} from './locusMediaRequest';
|
|
160
161
|
import {ConnectionStateHandler, ConnectionStateEvent} from './connectionStateHandler';
|
|
161
|
-
import
|
|
162
|
+
import JoinWebinarError from '../common/errors/join-webinar-error';
|
|
163
|
+
import Member from '../member';
|
|
164
|
+
import MultistreamNotSupportedError from '../common/errors/multistream-not-supported-error';
|
|
162
165
|
|
|
163
166
|
// default callback so we don't call an undefined function, but in practice it should never be used
|
|
164
167
|
const DEFAULT_ICE_PHASE_CALLBACK = () => 'JOIN_MEETING_FINAL';
|
|
@@ -848,7 +851,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
848
851
|
* @memberof Meeting
|
|
849
852
|
*/
|
|
850
853
|
// @ts-ignore
|
|
851
|
-
this.webinar = new Webinar({}, {parent: this.webex});
|
|
854
|
+
this.webinar = new Webinar({meetingId: this.id}, {parent: this.webex});
|
|
852
855
|
/**
|
|
853
856
|
* helper class for managing receive slots (for multistream media connections)
|
|
854
857
|
*/
|
|
@@ -1767,15 +1770,20 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1767
1770
|
this.meetingInfo = err.meetingInfo;
|
|
1768
1771
|
}
|
|
1769
1772
|
throw new PermissionError();
|
|
1770
|
-
} else if (err instanceof
|
|
1773
|
+
} else if (err instanceof MeetingInfoV2JoinWebinarError) {
|
|
1771
1774
|
this.meetingInfoFailureReason = MEETING_INFO_FAILURE_REASON.WEBINAR_REGISTRATION;
|
|
1775
|
+
if (WEBINAR_ERROR_WEBCAST.includes(err.wbxAppApiCode)) {
|
|
1776
|
+
this.meetingInfoFailureReason = MEETING_INFO_FAILURE_REASON.NEED_JOIN_WITH_WEBCAST;
|
|
1777
|
+
} else if (WEBINAR_ERROR_REGISTRATIONID.includes(err.wbxAppApiCode)) {
|
|
1778
|
+
this.meetingInfoFailureReason = MEETING_INFO_FAILURE_REASON.WEBINAR_NEED_REGISTRATIONID;
|
|
1779
|
+
}
|
|
1772
1780
|
this.meetingInfoFailureCode = err.wbxAppApiCode;
|
|
1773
1781
|
|
|
1774
1782
|
if (err.meetingInfo) {
|
|
1775
1783
|
this.meetingInfo = err.meetingInfo;
|
|
1776
1784
|
}
|
|
1777
1785
|
|
|
1778
|
-
throw new
|
|
1786
|
+
throw new JoinWebinarError();
|
|
1779
1787
|
} else if (err instanceof MeetingInfoV2PasswordError) {
|
|
1780
1788
|
LoggerProxy.logger.info(
|
|
1781
1789
|
// @ts-ignore
|
|
@@ -2734,6 +2742,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2734
2742
|
this.triggerAnnotationInfoEvent(contentShare, previousContentShare);
|
|
2735
2743
|
|
|
2736
2744
|
if (
|
|
2745
|
+
!payload.forceUpdate &&
|
|
2737
2746
|
contentShare.beneficiaryId === previousContentShare?.beneficiaryId &&
|
|
2738
2747
|
contentShare.disposition === previousContentShare?.disposition &&
|
|
2739
2748
|
contentShare.deviceUrlSharing === previousContentShare.deviceUrlSharing &&
|
|
@@ -2780,7 +2789,11 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2780
2789
|
// It does not matter who requested to share the whiteboard, everyone gets the same view
|
|
2781
2790
|
else if (whiteboardShare.disposition === FLOOR_ACTION.GRANTED) {
|
|
2782
2791
|
// WHITEBOARD - sharing whiteboard
|
|
2783
|
-
|
|
2792
|
+
// Webinar attendee should receive whiteboard as remote share
|
|
2793
|
+
newShareStatus =
|
|
2794
|
+
this.locusInfo?.info?.isWebinar && this.webinar?.selfIsAttendee
|
|
2795
|
+
? SHARE_STATUS.REMOTE_SHARE_ACTIVE
|
|
2796
|
+
: SHARE_STATUS.WHITEBOARD_SHARE_ACTIVE;
|
|
2784
2797
|
}
|
|
2785
2798
|
// or if content share is either released or null and whiteboard share is either released or null, no one is sharing
|
|
2786
2799
|
else if (
|
|
@@ -2795,6 +2808,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2795
2808
|
LoggerProxy.logger.info(
|
|
2796
2809
|
`Meeting:index#setUpLocusInfoMediaInactiveListener --> this.shareStatus=${this.shareStatus} newShareStatus=${newShareStatus}`
|
|
2797
2810
|
);
|
|
2811
|
+
|
|
2798
2812
|
if (newShareStatus !== this.shareStatus) {
|
|
2799
2813
|
const oldShareStatus = this.shareStatus;
|
|
2800
2814
|
|
|
@@ -3052,7 +3066,20 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3052
3066
|
*/
|
|
3053
3067
|
private setUpLocusResourcesListener() {
|
|
3054
3068
|
this.locusInfo.on(LOCUSINFO.EVENTS.LINKS_RESOURCES, (payload) => {
|
|
3055
|
-
|
|
3069
|
+
if (payload) {
|
|
3070
|
+
this.webinar.updateWebcastUrl(payload);
|
|
3071
|
+
Trigger.trigger(
|
|
3072
|
+
this,
|
|
3073
|
+
{
|
|
3074
|
+
file: 'meeting/index',
|
|
3075
|
+
function: 'setUpLocusInfoMeetingInfoListener',
|
|
3076
|
+
},
|
|
3077
|
+
EVENT_TRIGGERS.MEETING_RESOURCE_LINKS_UPDATE,
|
|
3078
|
+
{
|
|
3079
|
+
payload,
|
|
3080
|
+
}
|
|
3081
|
+
);
|
|
3082
|
+
}
|
|
3056
3083
|
});
|
|
3057
3084
|
}
|
|
3058
3085
|
|
|
@@ -3362,6 +3389,20 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3362
3389
|
}
|
|
3363
3390
|
});
|
|
3364
3391
|
|
|
3392
|
+
this.locusInfo.on(LOCUSINFO.EVENTS.SELF_MEETING_BRB_CHANGED, (payload) => {
|
|
3393
|
+
Trigger.trigger(
|
|
3394
|
+
this,
|
|
3395
|
+
{
|
|
3396
|
+
file: 'meeting/index',
|
|
3397
|
+
function: 'setUpLocusInfoSelfListener',
|
|
3398
|
+
},
|
|
3399
|
+
EVENT_TRIGGERS.MEETING_SELF_BRB_UPDATE,
|
|
3400
|
+
{
|
|
3401
|
+
payload,
|
|
3402
|
+
}
|
|
3403
|
+
);
|
|
3404
|
+
});
|
|
3405
|
+
|
|
3365
3406
|
this.locusInfo.on(LOCUSINFO.EVENTS.SELF_ROLES_CHANGED, (payload) => {
|
|
3366
3407
|
const isModeratorOrCohost =
|
|
3367
3408
|
payload.newRoles?.includes(SELF_ROLES.MODERATOR) ||
|
|
@@ -3371,6 +3412,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3371
3412
|
payload.newRoles?.includes(SELF_ROLES.MODERATOR)
|
|
3372
3413
|
);
|
|
3373
3414
|
this.webinar.updateRoleChanged(payload);
|
|
3415
|
+
|
|
3374
3416
|
Trigger.trigger(
|
|
3375
3417
|
this,
|
|
3376
3418
|
{
|
|
@@ -3565,6 +3607,50 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3565
3607
|
return this.members.admitMembers(memberIds, locusUrls);
|
|
3566
3608
|
}
|
|
3567
3609
|
|
|
3610
|
+
/**
|
|
3611
|
+
* Manages be right back status updates for the current participant.
|
|
3612
|
+
*
|
|
3613
|
+
* @param {boolean} enabled - Indicates whether the user enabled brb or not.
|
|
3614
|
+
* @returns {Promise<void>} resolves when the brb status is updated or does nothing if not in a multistream meeting.
|
|
3615
|
+
* @throws {Error} - Throws an error if the request fails.
|
|
3616
|
+
*/
|
|
3617
|
+
public async beRightBack(enabled: boolean): Promise<void> {
|
|
3618
|
+
if (!this.isMultistream) {
|
|
3619
|
+
const errorMessage = 'Meeting:index#beRightBack --> Not a multistream meeting';
|
|
3620
|
+
const error = new Error(errorMessage);
|
|
3621
|
+
|
|
3622
|
+
LoggerProxy.logger.error(error);
|
|
3623
|
+
|
|
3624
|
+
return Promise.reject(error);
|
|
3625
|
+
}
|
|
3626
|
+
|
|
3627
|
+
if (!this.mediaProperties.webrtcMediaConnection) {
|
|
3628
|
+
const errorMessage = 'Meeting:index#beRightBack --> WebRTC media connection is not defined';
|
|
3629
|
+
const error = new Error(errorMessage);
|
|
3630
|
+
|
|
3631
|
+
LoggerProxy.logger.error(error);
|
|
3632
|
+
|
|
3633
|
+
return Promise.reject(error);
|
|
3634
|
+
}
|
|
3635
|
+
|
|
3636
|
+
// this logic should be applied only to multistream meetings
|
|
3637
|
+
return this.meetingRequest
|
|
3638
|
+
.setBrb({
|
|
3639
|
+
enabled,
|
|
3640
|
+
locusUrl: this.locusUrl,
|
|
3641
|
+
deviceUrl: this.deviceUrl,
|
|
3642
|
+
selfId: this.selfId,
|
|
3643
|
+
})
|
|
3644
|
+
.then(() => {
|
|
3645
|
+
this.sendSlotManager.setSourceStateOverride(MediaType.VideoMain, enabled ? 'away' : null);
|
|
3646
|
+
})
|
|
3647
|
+
.catch((error) => {
|
|
3648
|
+
LoggerProxy.logger.error('Meeting:index#beRightBack --> Error ', error);
|
|
3649
|
+
|
|
3650
|
+
return Promise.reject(error);
|
|
3651
|
+
});
|
|
3652
|
+
}
|
|
3653
|
+
|
|
3568
3654
|
/**
|
|
3569
3655
|
* Remove the member from the meeting, boot them
|
|
3570
3656
|
* @param {String} memberId
|
|
@@ -3774,6 +3860,10 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3774
3860
|
this.userDisplayHints,
|
|
3775
3861
|
this.selfUserPolicies
|
|
3776
3862
|
),
|
|
3863
|
+
isPremiseRecordingEnabled: RecordingUtil.isPremiseRecordingEnabled(
|
|
3864
|
+
this.userDisplayHints,
|
|
3865
|
+
this.selfUserPolicies
|
|
3866
|
+
),
|
|
3777
3867
|
canRaiseHand: MeetingUtil.canUserRaiseHand(this.userDisplayHints),
|
|
3778
3868
|
canLowerAllHands: MeetingUtil.canUserLowerAllHands(this.userDisplayHints),
|
|
3779
3869
|
canLowerSomeoneElsesHand: MeetingUtil.canUserLowerSomeoneElsesHand(this.userDisplayHints),
|
|
@@ -3800,6 +3890,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3800
3890
|
this.userDisplayHints
|
|
3801
3891
|
),
|
|
3802
3892
|
canManageBreakout: MeetingUtil.canManageBreakout(this.userDisplayHints),
|
|
3893
|
+
canStartBreakout: MeetingUtil.canStartBreakout(this.userDisplayHints),
|
|
3803
3894
|
canBroadcastMessageToBreakout: MeetingUtil.canBroadcastMessageToBreakout(
|
|
3804
3895
|
this.userDisplayHints,
|
|
3805
3896
|
this.selfUserPolicies
|
|
@@ -4095,10 +4186,11 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4095
4186
|
*/
|
|
4096
4187
|
private setLogUploadTimer() {
|
|
4097
4188
|
// 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
|
|
4098
|
-
const LOG_UPLOAD_INTERVALS = [0.1,
|
|
4189
|
+
const LOG_UPLOAD_INTERVALS = [0.1, 15, 30, 60]; // in minutes
|
|
4099
4190
|
|
|
4100
4191
|
const delay =
|
|
4101
4192
|
1000 *
|
|
4193
|
+
60 *
|
|
4102
4194
|
// @ts-ignore - config coming from registerPlugin
|
|
4103
4195
|
this.config.logUploadIntervalMultiplicationFactor *
|
|
4104
4196
|
LOG_UPLOAD_INTERVALS[this.logUploadIntervalIndex];
|
|
@@ -4537,11 +4629,12 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4537
4629
|
* Close the peer connections and remove them from the class.
|
|
4538
4630
|
* Cleanup any media connection related things.
|
|
4539
4631
|
*
|
|
4632
|
+
* @param {boolean} resetMuteStates whether to also reset the audio/video mute state information
|
|
4540
4633
|
* @returns {Promise}
|
|
4541
4634
|
* @public
|
|
4542
4635
|
* @memberof Meeting
|
|
4543
4636
|
*/
|
|
4544
|
-
public closePeerConnections() {
|
|
4637
|
+
public closePeerConnections(resetMuteStates = true) {
|
|
4545
4638
|
if (this.mediaProperties.webrtcMediaConnection) {
|
|
4546
4639
|
if (this.remoteMediaManager) {
|
|
4547
4640
|
this.remoteMediaManager.stop();
|
|
@@ -4554,12 +4647,15 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4554
4647
|
|
|
4555
4648
|
this.receiveSlotManager.reset();
|
|
4556
4649
|
this.mediaProperties.webrtcMediaConnection.close();
|
|
4650
|
+
this.mediaProperties.unsetPeerConnection();
|
|
4557
4651
|
this.sendSlotManager.reset();
|
|
4558
4652
|
this.setNetworkStatus(undefined);
|
|
4559
4653
|
}
|
|
4560
4654
|
|
|
4561
|
-
|
|
4562
|
-
|
|
4655
|
+
if (resetMuteStates) {
|
|
4656
|
+
this.audio = null;
|
|
4657
|
+
this.video = null;
|
|
4658
|
+
}
|
|
4563
4659
|
|
|
4564
4660
|
return Promise.resolve();
|
|
4565
4661
|
}
|
|
@@ -4819,7 +4915,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4819
4915
|
* @param {Object} options - options to join with media
|
|
4820
4916
|
* @param {JoinOptions} [options.joinOptions] - see #join()
|
|
4821
4917
|
* @param {AddMediaOptions} [options.mediaOptions] - see #addMedia()
|
|
4822
|
-
* @returns {Promise} -- {join: see join(), media: see addMedia()}
|
|
4918
|
+
* @returns {Promise} -- {join: see join(), media: see addMedia(), multistreamEnabled: flag to indicate if we managed to join in multistream mode}
|
|
4823
4919
|
* @public
|
|
4824
4920
|
* @memberof Meeting
|
|
4825
4921
|
* @example
|
|
@@ -4909,6 +5005,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4909
5005
|
return {
|
|
4910
5006
|
join: joinResponse,
|
|
4911
5007
|
media: mediaResponse,
|
|
5008
|
+
multistreamEnabled: this.isMultistream,
|
|
4912
5009
|
};
|
|
4913
5010
|
} catch (error) {
|
|
4914
5011
|
LoggerProxy.logger.error('Meeting:index#joinWithMedia --> ', error);
|
|
@@ -4917,7 +5014,17 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4917
5014
|
|
|
4918
5015
|
this.roap.abortTurnDiscovery();
|
|
4919
5016
|
|
|
4920
|
-
if
|
|
5017
|
+
// if this was the first attempt, let's do a retry
|
|
5018
|
+
let shouldRetry = !isRetry;
|
|
5019
|
+
|
|
5020
|
+
if (CallDiagnosticUtils.isSdpOfferCreationError(error)) {
|
|
5021
|
+
// errors related to offer creation (for example missing H264 codec) will happen again no matter how many times we try,
|
|
5022
|
+
// so there is no point doing a retry
|
|
5023
|
+
shouldRetry = false;
|
|
5024
|
+
}
|
|
5025
|
+
|
|
5026
|
+
// we only want to call leave if join was successful and this was a retry or we won't be doing any more retries
|
|
5027
|
+
if (joined && (isRetry || !shouldRetry)) {
|
|
4921
5028
|
try {
|
|
4922
5029
|
await this.leave({resourceId: joinOptions?.resourceId, reason: 'joinWithMedia failure'});
|
|
4923
5030
|
} catch (e) {
|
|
@@ -4941,15 +5048,6 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4941
5048
|
}
|
|
4942
5049
|
);
|
|
4943
5050
|
|
|
4944
|
-
// if this was the first attempt, let's do a retry
|
|
4945
|
-
let shouldRetry = !isRetry;
|
|
4946
|
-
|
|
4947
|
-
if (CallDiagnosticUtils.isSdpOfferCreationError(error)) {
|
|
4948
|
-
// errors related to offer creation (for example missing H264 codec) will happen again no matter how many times we try,
|
|
4949
|
-
// so there is no point doing a retry
|
|
4950
|
-
shouldRetry = false;
|
|
4951
|
-
}
|
|
4952
|
-
|
|
4953
5051
|
if (shouldRetry) {
|
|
4954
5052
|
LoggerProxy.logger.warn('Meeting:index#joinWithMedia --> retrying call to joinWithMedia');
|
|
4955
5053
|
this.joinWithMediaRetryInfo.isRetry = true;
|
|
@@ -5205,7 +5303,16 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5205
5303
|
(this.config.receiveReactions || options.receiveReactions) &&
|
|
5206
5304
|
this.isReactionsSupported()
|
|
5207
5305
|
) {
|
|
5208
|
-
const
|
|
5306
|
+
const member = this.members.membersCollection.get(e.data.sender.participantId);
|
|
5307
|
+
if (!member) {
|
|
5308
|
+
// @ts-ignore -- fix type
|
|
5309
|
+
LoggerProxy.logger.warn(
|
|
5310
|
+
`Meeting:index#processRelayEvent --> Skipping handling of ${REACTION_RELAY_TYPES.REACTION} for ${this.id}. participantId ${e.data.sender.participantId} does not exist in membersCollection.`
|
|
5311
|
+
);
|
|
5312
|
+
break;
|
|
5313
|
+
}
|
|
5314
|
+
|
|
5315
|
+
const {name} = member;
|
|
5209
5316
|
const processedReaction: ProcessedReaction = {
|
|
5210
5317
|
reaction: e.data.reaction,
|
|
5211
5318
|
sender: {
|
|
@@ -5259,6 +5366,9 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5259
5366
|
this.voiceaListenerCallbacks[VOICEAEVENTS.NEW_CAPTION]
|
|
5260
5367
|
);
|
|
5261
5368
|
|
|
5369
|
+
// @ts-ignore
|
|
5370
|
+
this.webex.internal.voicea.deregisterEvents();
|
|
5371
|
+
|
|
5262
5372
|
this.areVoiceaEventsSetup = false;
|
|
5263
5373
|
this.triggerStopReceivingTranscriptionEvent();
|
|
5264
5374
|
}
|
|
@@ -5369,16 +5479,19 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5369
5479
|
this.meetingFiniteStateMachine.reset();
|
|
5370
5480
|
}
|
|
5371
5481
|
|
|
5372
|
-
//
|
|
5373
|
-
|
|
5374
|
-
|
|
5375
|
-
|
|
5376
|
-
|
|
5377
|
-
|
|
5378
|
-
|
|
5379
|
-
|
|
5380
|
-
|
|
5381
|
-
|
|
5482
|
+
// send client.call.initiated unless told not to
|
|
5483
|
+
if (options.sendCallInitiated !== false) {
|
|
5484
|
+
// @ts-ignore
|
|
5485
|
+
this.webex.internal.newMetrics.submitClientEvent({
|
|
5486
|
+
name: 'client.call.initiated',
|
|
5487
|
+
payload: {
|
|
5488
|
+
trigger: this.callStateForMetrics.joinTrigger || 'user-interaction',
|
|
5489
|
+
isRoapCallEnabled: true,
|
|
5490
|
+
pstnAudioType: options?.pstnAudioType,
|
|
5491
|
+
},
|
|
5492
|
+
options: {meetingId: this.id},
|
|
5493
|
+
});
|
|
5494
|
+
}
|
|
5382
5495
|
|
|
5383
5496
|
LoggerProxy.logger.log('Meeting:index#join --> Joining a meeting');
|
|
5384
5497
|
|
|
@@ -5566,17 +5679,23 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5566
5679
|
*/
|
|
5567
5680
|
async updateLLMConnection() {
|
|
5568
5681
|
// @ts-ignore - Fix type
|
|
5569
|
-
const {url, info: {datachannelUrl} = {}} = this.locusInfo;
|
|
5682
|
+
const {url, info: {datachannelUrl, practiceSessionDatachannelUrl} = {}} = this.locusInfo;
|
|
5570
5683
|
|
|
5571
5684
|
const isJoined = this.isJoined();
|
|
5572
5685
|
|
|
5686
|
+
// webinar panelist should use new data channel in practice session
|
|
5687
|
+
const dataChannelUrl =
|
|
5688
|
+
this.webinar.isJoinPracticeSessionDataChannel() && practiceSessionDatachannelUrl
|
|
5689
|
+
? practiceSessionDatachannelUrl
|
|
5690
|
+
: datachannelUrl;
|
|
5691
|
+
|
|
5573
5692
|
// @ts-ignore - Fix type
|
|
5574
5693
|
if (this.webex.internal.llm.isConnected()) {
|
|
5575
5694
|
if (
|
|
5576
5695
|
// @ts-ignore - Fix type
|
|
5577
5696
|
url === this.webex.internal.llm.getLocusUrl() &&
|
|
5578
5697
|
// @ts-ignore - Fix type
|
|
5579
|
-
|
|
5698
|
+
dataChannelUrl === this.webex.internal.llm.getDatachannelUrl() &&
|
|
5580
5699
|
isJoined
|
|
5581
5700
|
) {
|
|
5582
5701
|
return undefined;
|
|
@@ -5593,7 +5712,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5593
5712
|
|
|
5594
5713
|
// @ts-ignore - Fix type
|
|
5595
5714
|
return this.webex.internal.llm
|
|
5596
|
-
.registerAndConnect(url,
|
|
5715
|
+
.registerAndConnect(url, dataChannelUrl)
|
|
5597
5716
|
.then((registerAndConnectResult) => {
|
|
5598
5717
|
// @ts-ignore - Fix type
|
|
5599
5718
|
this.webex.internal.llm.off('event:relay.event', this.processRelayEvent);
|
|
@@ -5965,6 +6084,11 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5965
6084
|
public roapMessageReceived = (roapMessage: RoapMessage) => {
|
|
5966
6085
|
const mediaServer = MeetingsUtil.getMediaServer(roapMessage.sdp);
|
|
5967
6086
|
|
|
6087
|
+
if (this.isMultistream && mediaServer !== 'homer') {
|
|
6088
|
+
throw new MultistreamNotSupportedError(
|
|
6089
|
+
`Client asked for multistream backend (Homer), but got ${mediaServer} instead`
|
|
6090
|
+
);
|
|
6091
|
+
}
|
|
5968
6092
|
this.mediaProperties.webrtcMediaConnection.roapMessageReceived(roapMessage);
|
|
5969
6093
|
|
|
5970
6094
|
if (mediaServer) {
|
|
@@ -6087,16 +6211,20 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
6087
6211
|
logText: `${LOG_HEADER} Roap Offer`,
|
|
6088
6212
|
}
|
|
6089
6213
|
).catch((error) => {
|
|
6214
|
+
const multistreamNotSupported = error instanceof MultistreamNotSupportedError;
|
|
6215
|
+
|
|
6090
6216
|
// @ts-ignore
|
|
6091
6217
|
this.webex.internal.newMetrics.submitClientEvent({
|
|
6092
6218
|
name: 'client.media-engine.remote-sdp-received',
|
|
6093
6219
|
payload: {
|
|
6094
|
-
canProceed:
|
|
6220
|
+
canProceed: multistreamNotSupported,
|
|
6095
6221
|
errors: [
|
|
6096
6222
|
// @ts-ignore
|
|
6097
6223
|
this.webex.internal.newMetrics.callDiagnosticMetrics.getErrorPayloadForClientErrorCode(
|
|
6098
6224
|
{
|
|
6099
|
-
clientErrorCode:
|
|
6225
|
+
clientErrorCode: multistreamNotSupported
|
|
6226
|
+
? CALL_DIAGNOSTIC_CONFIG.MULTISTREAM_NOT_AVAILABLE_CLIENT_CODE
|
|
6227
|
+
: CALL_DIAGNOSTIC_CONFIG.MISSING_ROAP_ANSWER_CLIENT_CODE,
|
|
6100
6228
|
}
|
|
6101
6229
|
),
|
|
6102
6230
|
],
|
|
@@ -6104,7 +6232,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
6104
6232
|
options: {meetingId: this.id, rawError: error},
|
|
6105
6233
|
});
|
|
6106
6234
|
|
|
6107
|
-
this.deferSDPAnswer.reject(
|
|
6235
|
+
this.deferSDPAnswer.reject(error);
|
|
6108
6236
|
clearTimeout(this.sdpResponseTimer);
|
|
6109
6237
|
this.sdpResponseTimer = undefined;
|
|
6110
6238
|
});
|
|
@@ -6432,6 +6560,14 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
6432
6560
|
this.webex.meetings.geoHintInfo?.clientAddress ||
|
|
6433
6561
|
options.data.intervalMetadata.peerReflexiveIP ||
|
|
6434
6562
|
MQA_STATS.DEFAULT_IP;
|
|
6563
|
+
|
|
6564
|
+
const {members} = this.getMembers().membersCollection;
|
|
6565
|
+
|
|
6566
|
+
// Count members that are in the meeting
|
|
6567
|
+
options.data.intervalMetadata.meetingUserCount = Object.values(members).filter(
|
|
6568
|
+
(member: Member) => member.isInMeeting
|
|
6569
|
+
).length;
|
|
6570
|
+
|
|
6435
6571
|
// @ts-ignore
|
|
6436
6572
|
this.webex.internal.newMetrics.submitMQE({
|
|
6437
6573
|
name: 'client.mediaquality.event',
|
|
@@ -6763,32 +6899,6 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
6763
6899
|
}
|
|
6764
6900
|
}
|
|
6765
6901
|
|
|
6766
|
-
/**
|
|
6767
|
-
* Handles device logging
|
|
6768
|
-
*
|
|
6769
|
-
* @private
|
|
6770
|
-
* @static
|
|
6771
|
-
* @param {boolean} isAudioEnabled
|
|
6772
|
-
* @param {boolean} isVideoEnabled
|
|
6773
|
-
* @returns {Promise<void>}
|
|
6774
|
-
*/
|
|
6775
|
-
|
|
6776
|
-
private static async handleDeviceLogging(isAudioEnabled, isVideoEnabled): Promise<void> {
|
|
6777
|
-
try {
|
|
6778
|
-
let devices = [];
|
|
6779
|
-
if (isVideoEnabled && isAudioEnabled) {
|
|
6780
|
-
devices = await getDevices();
|
|
6781
|
-
} else if (isVideoEnabled) {
|
|
6782
|
-
devices = await getDevices(Media.DeviceKind.VIDEO_INPUT);
|
|
6783
|
-
} else if (isAudioEnabled) {
|
|
6784
|
-
devices = await getDevices(Media.DeviceKind.AUDIO_INPUT);
|
|
6785
|
-
}
|
|
6786
|
-
MeetingUtil.handleDeviceLogging(devices);
|
|
6787
|
-
} catch {
|
|
6788
|
-
// getDevices may fail if we don't have browser permissions, that's ok, we still can have a media connection
|
|
6789
|
-
}
|
|
6790
|
-
}
|
|
6791
|
-
|
|
6792
6902
|
/**
|
|
6793
6903
|
* Returns a promise. This promise is created once the local sdp offer has been successfully created and is resolved
|
|
6794
6904
|
* once the remote sdp answer has been received.
|
|
@@ -7012,7 +7122,9 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
7012
7122
|
|
|
7013
7123
|
const mc = await this.createMediaConnection(turnServerInfo, bundlePolicy);
|
|
7014
7124
|
|
|
7015
|
-
LoggerProxy.logger.info(
|
|
7125
|
+
LoggerProxy.logger.info(
|
|
7126
|
+
`${LOG_HEADER} media connection created this.isMultistream=${this.isMultistream}`
|
|
7127
|
+
);
|
|
7016
7128
|
|
|
7017
7129
|
if (this.isMultistream) {
|
|
7018
7130
|
this.remoteMediaManager = new RemoteMediaManager(
|
|
@@ -7090,6 +7202,33 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
7090
7202
|
}
|
|
7091
7203
|
}
|
|
7092
7204
|
|
|
7205
|
+
/**
|
|
7206
|
+
* Cleans up stats analyzer, peer connection and other things before
|
|
7207
|
+
* we can create a new transcoded media connection
|
|
7208
|
+
*
|
|
7209
|
+
* @private
|
|
7210
|
+
* @returns {Promise<void>}
|
|
7211
|
+
*/
|
|
7212
|
+
private async downgradeFromMultistreamToTranscoded(): Promise<void> {
|
|
7213
|
+
if (this.statsAnalyzer) {
|
|
7214
|
+
await this.statsAnalyzer.stopAnalyzer();
|
|
7215
|
+
}
|
|
7216
|
+
this.statsAnalyzer = null;
|
|
7217
|
+
|
|
7218
|
+
this.isMultistream = false;
|
|
7219
|
+
|
|
7220
|
+
if (this.mediaProperties.webrtcMediaConnection) {
|
|
7221
|
+
// close peer connection, but don't reset mute state information, because we will want to use it on the retry
|
|
7222
|
+
this.closePeerConnections(false);
|
|
7223
|
+
|
|
7224
|
+
this.mediaProperties.unsetPeerConnection();
|
|
7225
|
+
}
|
|
7226
|
+
|
|
7227
|
+
this.locusMediaRequest?.downgradeFromMultistreamToTranscoded();
|
|
7228
|
+
|
|
7229
|
+
this.createStatsAnalyzer();
|
|
7230
|
+
}
|
|
7231
|
+
|
|
7093
7232
|
/**
|
|
7094
7233
|
* Sends stats report, closes peer connection and cleans up any media connection
|
|
7095
7234
|
* related things before trying to establish media connection again with turn server
|
|
@@ -7284,19 +7423,33 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
7284
7423
|
|
|
7285
7424
|
this.createStatsAnalyzer();
|
|
7286
7425
|
|
|
7287
|
-
|
|
7288
|
-
|
|
7289
|
-
|
|
7290
|
-
|
|
7291
|
-
|
|
7292
|
-
|
|
7426
|
+
try {
|
|
7427
|
+
await this.establishMediaConnection(
|
|
7428
|
+
remoteMediaManagerConfig,
|
|
7429
|
+
bundlePolicy,
|
|
7430
|
+
forceTurnDiscovery,
|
|
7431
|
+
turnServerInfo
|
|
7432
|
+
);
|
|
7433
|
+
} catch (error) {
|
|
7434
|
+
if (error instanceof MultistreamNotSupportedError) {
|
|
7435
|
+
LoggerProxy.logger.warn(
|
|
7436
|
+
`${LOG_HEADER} we asked for multistream backend (Homer), but got transcoded backend, recreating media connection...`
|
|
7437
|
+
);
|
|
7293
7438
|
|
|
7294
|
-
|
|
7295
|
-
await Meeting.handleDeviceLogging(audioEnabled, videoEnabled);
|
|
7296
|
-
} else {
|
|
7297
|
-
LoggerProxy.logger.info(`${LOG_HEADER} device logging not required`);
|
|
7298
|
-
}
|
|
7439
|
+
await this.downgradeFromMultistreamToTranscoded();
|
|
7299
7440
|
|
|
7441
|
+
// Establish new media connection with forced TURN discovery
|
|
7442
|
+
// 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
|
|
7443
|
+
await this.establishMediaConnection(
|
|
7444
|
+
remoteMediaManagerConfig,
|
|
7445
|
+
bundlePolicy,
|
|
7446
|
+
true,
|
|
7447
|
+
undefined
|
|
7448
|
+
);
|
|
7449
|
+
} else {
|
|
7450
|
+
throw error;
|
|
7451
|
+
}
|
|
7452
|
+
}
|
|
7300
7453
|
if (this.mediaProperties.hasLocalShareStream()) {
|
|
7301
7454
|
await this.enqueueScreenShareFloorRequest();
|
|
7302
7455
|
}
|
|
@@ -8266,7 +8419,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
8266
8419
|
if (layoutType) {
|
|
8267
8420
|
if (!LAYOUT_TYPES.includes(layoutType)) {
|
|
8268
8421
|
return this.rejectWithErrorLog(
|
|
8269
|
-
|
|
8422
|
+
`Meeting:index#changeVideoLayout --> cannot change video layout, invalid layoutType "${layoutType}" received.`
|
|
8270
8423
|
);
|
|
8271
8424
|
}
|
|
8272
8425
|
|
|
@@ -8422,6 +8575,12 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
8422
8575
|
correlationId: this.correlationId,
|
|
8423
8576
|
muted,
|
|
8424
8577
|
encoderImplementation: this.statsAnalyzer?.shareVideoEncoderImplementation,
|
|
8578
|
+
// TypeScript 4 does not recognize the `displaySurface` property. Instead of upgrading the
|
|
8579
|
+
// SDK to TypeScript 5, which may affect other packages, use bracket notation for now, since
|
|
8580
|
+
// all we're doing here is adding metrics.
|
|
8581
|
+
// eslint-disable-next-line dot-notation
|
|
8582
|
+
displaySurface: this.mediaProperties?.shareVideoStream?.getSettings()['displaySurface'],
|
|
8583
|
+
isMultistream: this.isMultistream,
|
|
8425
8584
|
});
|
|
8426
8585
|
};
|
|
8427
8586
|
|
|
@@ -8624,6 +8783,11 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
8624
8783
|
this.stopTranscription();
|
|
8625
8784
|
this.transcription = undefined;
|
|
8626
8785
|
}
|
|
8786
|
+
|
|
8787
|
+
this.annotation.deregisterEvents();
|
|
8788
|
+
|
|
8789
|
+
// @ts-ignore - fix types
|
|
8790
|
+
this.webex.internal.llm.off('event:relay.event', this.processRelayEvent);
|
|
8627
8791
|
};
|
|
8628
8792
|
|
|
8629
8793
|
/**
|
|
@@ -8661,10 +8825,12 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
8661
8825
|
|
|
8662
8826
|
return;
|
|
8663
8827
|
}
|
|
8664
|
-
|
|
8828
|
+
|
|
8665
8829
|
const keepAliveInterval = (this.joinedWith.keepAliveSecs - 1) * 750; // taken from UCF
|
|
8666
8830
|
|
|
8667
8831
|
this.keepAliveTimerId = setInterval(() => {
|
|
8832
|
+
const {keepAliveUrl} = this.joinedWith;
|
|
8833
|
+
|
|
8668
8834
|
this.meetingRequest.keepAlive({keepAliveUrl}).catch((error) => {
|
|
8669
8835
|
LoggerProxy.logger.warn(
|
|
8670
8836
|
`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/request.ts
CHANGED
|
@@ -27,7 +27,7 @@ import {
|
|
|
27
27
|
_SLIDES_,
|
|
28
28
|
ANNOTATION,
|
|
29
29
|
} from '../constants';
|
|
30
|
-
import {SendReactionOptions, ToggleReactionsOptions} from './request.type';
|
|
30
|
+
import {SendReactionOptions, BrbOptions, ToggleReactionsOptions} from './request.type';
|
|
31
31
|
import MeetingUtil from './util';
|
|
32
32
|
import {AnnotationInfo} from '../annotation/annotation.types';
|
|
33
33
|
import {ClientMediaPreferences} from '../reachability/reachability.types';
|
|
@@ -909,4 +909,29 @@ export default class MeetingRequest extends StatelessWebexPlugin {
|
|
|
909
909
|
uri: locusUrl,
|
|
910
910
|
});
|
|
911
911
|
}
|
|
912
|
+
|
|
913
|
+
/**
|
|
914
|
+
* Sends a request to set be right back status.
|
|
915
|
+
*
|
|
916
|
+
* @param {Object} options - The options for brb request.
|
|
917
|
+
* @param {boolean} options.enabled - Whether brb status is enabled.
|
|
918
|
+
* @param {string} options.locusUrl - The URL of the locus.
|
|
919
|
+
* @param {string} options.deviceUrl - The URL of the device.
|
|
920
|
+
* @param {string} options.selfId - The ID of the participant.
|
|
921
|
+
* @returns {Promise}
|
|
922
|
+
*/
|
|
923
|
+
setBrb({enabled, locusUrl, deviceUrl, selfId}: BrbOptions) {
|
|
924
|
+
const uri = `${locusUrl}/${PARTICIPANT}/${selfId}/${CONTROLS}`;
|
|
925
|
+
|
|
926
|
+
return this.locusDeltaRequest({
|
|
927
|
+
method: HTTP_VERBS.PATCH,
|
|
928
|
+
uri,
|
|
929
|
+
body: {
|
|
930
|
+
brb: {
|
|
931
|
+
enabled,
|
|
932
|
+
deviceUrl,
|
|
933
|
+
},
|
|
934
|
+
},
|
|
935
|
+
});
|
|
936
|
+
}
|
|
912
937
|
}
|