@webex/plugin-meetings 3.0.0-beta.42 → 3.0.0-beta.44
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 +10 -2
- package/dist/breakouts/index.js.map +1 -1
- package/dist/constants.js +9 -2
- package/dist/constants.js.map +1 -1
- package/dist/controls-options-manager/enums.js +1 -0
- package/dist/controls-options-manager/enums.js.map +1 -1
- package/dist/controls-options-manager/index.js +51 -14
- package/dist/controls-options-manager/index.js.map +1 -1
- package/dist/controls-options-manager/util.js +12 -1
- package/dist/controls-options-manager/util.js.map +1 -1
- package/dist/locus-info/controlsUtils.js +6 -2
- package/dist/locus-info/controlsUtils.js.map +1 -1
- package/dist/locus-info/index.js +35 -1
- package/dist/locus-info/index.js.map +1 -1
- package/dist/locus-info/selfUtils.js +28 -0
- 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 +55 -3
- package/dist/meeting/index.js.map +1 -1
- package/dist/meeting/muteState.js +45 -20
- package/dist/meeting/muteState.js.map +1 -1
- package/dist/members/index.js +15 -3
- package/dist/members/index.js.map +1 -1
- package/dist/members/util.js +33 -12
- package/dist/members/util.js.map +1 -1
- package/dist/types/constants.d.ts +7 -0
- package/dist/types/controls-options-manager/enums.d.ts +2 -1
- package/dist/types/controls-options-manager/index.d.ts +9 -1
- package/dist/types/controls-options-manager/util.d.ts +2 -0
- package/dist/types/locus-info/index.d.ts +7 -0
- package/dist/types/meeting/in-meeting-actions.d.ts +4 -0
- package/dist/types/meeting/index.d.ts +22 -2
- package/dist/types/meeting/muteState.d.ts +16 -0
- package/dist/types/members/index.d.ts +7 -2
- package/package.json +18 -18
- package/src/breakouts/index.ts +6 -0
- package/src/constants.ts +7 -0
- package/src/controls-options-manager/enums.ts +1 -0
- package/src/controls-options-manager/index.ts +55 -20
- package/src/controls-options-manager/util.ts +10 -0
- package/src/locus-info/controlsUtils.ts +8 -0
- package/src/locus-info/index.ts +42 -1
- package/src/locus-info/selfUtils.ts +34 -0
- package/src/meeting/in-meeting-actions.ts +8 -0
- package/src/meeting/index.ts +68 -4
- package/src/meeting/muteState.ts +49 -30
- package/src/members/index.ts +12 -4
- package/src/members/util.ts +21 -8
- package/test/unit/spec/breakouts/index.ts +2 -2
- package/test/unit/spec/controls-options-manager/index.js +56 -0
- package/test/unit/spec/controls-options-manager/util.js +20 -0
- package/test/unit/spec/locus-info/controlsUtils.js +104 -46
- package/test/unit/spec/locus-info/index.js +131 -16
- package/test/unit/spec/locus-info/selfConstant.js +9 -5
- package/test/unit/spec/locus-info/selfUtils.js +39 -16
- package/test/unit/spec/meeting/in-meeting-actions.ts +2 -0
- package/test/unit/spec/meeting/index.js +208 -79
- package/test/unit/spec/meeting/muteState.js +72 -6
- package/test/unit/spec/members/index.js +75 -0
- package/test/unit/spec/members/utils.js +112 -0
|
@@ -32,6 +32,7 @@ SelfUtils.parse = (self: any, deviceId: string) => {
|
|
|
32
32
|
const pstnDevices = self.devices.filter((device) => PSTN_DEVICE_TYPE === device.deviceType);
|
|
33
33
|
|
|
34
34
|
return {
|
|
35
|
+
remoteVideoMuted: SelfUtils.getRemoteVideoMuted(self),
|
|
35
36
|
remoteMuted: SelfUtils.getRemoteMuted(self),
|
|
36
37
|
unmuteAllowed: SelfUtils.getUnmuteAllowed(self),
|
|
37
38
|
localAudioUnmuteRequested: SelfUtils.getLocalAudioUnmuteRequested(self),
|
|
@@ -93,6 +94,7 @@ SelfUtils.getSelves = (oldSelf, newSelf, deviceId) => {
|
|
|
93
94
|
|
|
94
95
|
updates.isUserUnadmitted = SelfUtils.isUserUnadmitted(current);
|
|
95
96
|
updates.isUserAdmitted = SelfUtils.isUserAdmitted(previous, current);
|
|
97
|
+
updates.isVideoMutedByOthersChanged = SelfUtils.videoMutedByOthersChanged(previous, current);
|
|
96
98
|
updates.isMutedByOthersChanged = SelfUtils.mutedByOthersChanged(previous, current);
|
|
97
99
|
updates.localAudioUnmuteRequestedByServer = SelfUtils.localAudioUnmuteRequestedByServer(
|
|
98
100
|
previous,
|
|
@@ -236,6 +238,19 @@ SelfUtils.getSelfIdentity = (self: any) => {
|
|
|
236
238
|
return self.person.id;
|
|
237
239
|
};
|
|
238
240
|
|
|
241
|
+
/**
|
|
242
|
+
* get the "remote video mute" property from the self object
|
|
243
|
+
* @param {Object} self
|
|
244
|
+
* @returns {Boolean}
|
|
245
|
+
*/
|
|
246
|
+
SelfUtils.getRemoteVideoMuted = (self: any) => {
|
|
247
|
+
if (!self || !self.controls || !self.controls.video) {
|
|
248
|
+
return null;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
return self.controls.video.muted;
|
|
252
|
+
};
|
|
253
|
+
|
|
239
254
|
/**
|
|
240
255
|
* get the "remote mute" property from the self object
|
|
241
256
|
* @param {Object} self
|
|
@@ -351,6 +366,25 @@ SelfUtils.isUserAdmitted = (oldSelf: object, changedSelf: object) => {
|
|
|
351
366
|
return SelfUtils.isLocusUserUnadmitted(oldSelf) && SelfUtils.isLocusUserAdmitted(changedSelf);
|
|
352
367
|
};
|
|
353
368
|
|
|
369
|
+
SelfUtils.videoMutedByOthersChanged = (oldSelf, changedSelf) => {
|
|
370
|
+
if (!changedSelf) {
|
|
371
|
+
throw new ParameterError(
|
|
372
|
+
'New self must be defined to determine if self was video muted by others.'
|
|
373
|
+
);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
if (!oldSelf || oldSelf.remoteVideoMuted === null) {
|
|
377
|
+
if (changedSelf.remoteVideoMuted) {
|
|
378
|
+
return true; // this happens when host disables "Allow start video"
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
// we don't want to be sending the 'meeting:self:videoUnmutedByOthers' notification on meeting join
|
|
382
|
+
return false;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
return oldSelf.remoteVideoMuted !== changedSelf.remoteVideoMuted;
|
|
386
|
+
};
|
|
387
|
+
|
|
354
388
|
SelfUtils.mutedByOthersChanged = (oldSelf, changedSelf) => {
|
|
355
389
|
if (!changedSelf) {
|
|
356
390
|
throw new ParameterError('New self must be defined to determine if self was muted by others.');
|
|
@@ -17,6 +17,8 @@ interface IInMeetingActions {
|
|
|
17
17
|
canUnsetMuteOnEntry?: boolean;
|
|
18
18
|
canSetDisallowUnmute?: boolean;
|
|
19
19
|
canUnsetDisallowUnmute?: boolean;
|
|
20
|
+
canSetMuted?: boolean;
|
|
21
|
+
canUnsetMuted?: boolean;
|
|
20
22
|
canAssignHost?: boolean;
|
|
21
23
|
canStartRecording?: boolean;
|
|
22
24
|
canPauseRecording?: boolean;
|
|
@@ -71,6 +73,10 @@ export default class InMeetingActions implements IInMeetingActions {
|
|
|
71
73
|
|
|
72
74
|
canUnsetDisallowUnmute = null;
|
|
73
75
|
|
|
76
|
+
canSetMuted = null;
|
|
77
|
+
|
|
78
|
+
canUnsetMuted = null;
|
|
79
|
+
|
|
74
80
|
canRaiseHand = null;
|
|
75
81
|
|
|
76
82
|
canLowerAllHands = null;
|
|
@@ -114,6 +120,8 @@ export default class InMeetingActions implements IInMeetingActions {
|
|
|
114
120
|
canSetMuteOnEntry: this.canSetMuteOnEntry,
|
|
115
121
|
canUnsetMuteOnEntry: this.canUnsetMuteOnEntry,
|
|
116
122
|
canSetDisallowUnmute: this.canSetDisallowUnmute,
|
|
123
|
+
canSetMuted: this.canSetMuted,
|
|
124
|
+
canUnsetMuted: this.canUnsetMuted,
|
|
117
125
|
canUnsetDisallowUnmute: this.canUnsetDisallowUnmute,
|
|
118
126
|
canStartRecording: this.canStartRecording,
|
|
119
127
|
canPauseRecording: this.canPauseRecording,
|
package/src/meeting/index.ts
CHANGED
|
@@ -17,7 +17,6 @@ import {
|
|
|
17
17
|
|
|
18
18
|
import {
|
|
19
19
|
MeetingNotActiveError,
|
|
20
|
-
createMeetingsError,
|
|
21
20
|
UserInLobbyError,
|
|
22
21
|
NoMediaEstablishedYetError,
|
|
23
22
|
UserNotJoinedError,
|
|
@@ -2290,6 +2289,8 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2290
2289
|
canUnsetMuteOnEntry: ControlsOptionsUtil.canUnsetMuteOnEntry(
|
|
2291
2290
|
payload.info.userDisplayHints
|
|
2292
2291
|
),
|
|
2292
|
+
canSetMuted: ControlsOptionsUtil.canSetMuted(payload.info.userDisplayHints),
|
|
2293
|
+
canUnsetMuted: ControlsOptionsUtil.canUnsetMuted(payload.info.userDisplayHints),
|
|
2293
2294
|
canStartRecording: RecordingUtil.canUserStart(payload.info.userDisplayHints),
|
|
2294
2295
|
canStopRecording: RecordingUtil.canUserStop(payload.info.userDisplayHints),
|
|
2295
2296
|
canPauseRecording: RecordingUtil.canUserPause(payload.info.userDisplayHints),
|
|
@@ -2406,6 +2407,30 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2406
2407
|
);
|
|
2407
2408
|
}
|
|
2408
2409
|
});
|
|
2410
|
+
|
|
2411
|
+
this.locusInfo.on(LOCUSINFO.EVENTS.SELF_REMOTE_VIDEO_MUTE_STATUS_UPDATED, (payload) => {
|
|
2412
|
+
if (payload) {
|
|
2413
|
+
if (this.video) {
|
|
2414
|
+
payload.muted = payload.muted ?? this.video.isRemotelyMuted();
|
|
2415
|
+
payload.unmuteAllowed = payload.unmuteAllowed ?? this.video.isUnmuteAllowed();
|
|
2416
|
+
this.video.handleServerRemoteMuteUpdate(payload.muted, payload.unmuteAllowed);
|
|
2417
|
+
}
|
|
2418
|
+
Trigger.trigger(
|
|
2419
|
+
this,
|
|
2420
|
+
{
|
|
2421
|
+
file: 'meeting/index',
|
|
2422
|
+
function: 'setUpLocusInfoSelfListener',
|
|
2423
|
+
},
|
|
2424
|
+
payload.muted
|
|
2425
|
+
? EVENT_TRIGGERS.MEETING_SELF_VIDEO_MUTED_BY_OTHERS
|
|
2426
|
+
: EVENT_TRIGGERS.MEETING_SELF_VIDEO_UNMUTED_BY_OTHERS,
|
|
2427
|
+
{
|
|
2428
|
+
payload,
|
|
2429
|
+
}
|
|
2430
|
+
);
|
|
2431
|
+
}
|
|
2432
|
+
});
|
|
2433
|
+
|
|
2409
2434
|
this.locusInfo.on(LOCUSINFO.EVENTS.SELF_REMOTE_MUTE_STATUS_UPDATED, (payload) => {
|
|
2410
2435
|
if (payload) {
|
|
2411
2436
|
if (this.audio) {
|
|
@@ -2693,14 +2718,32 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2693
2718
|
}
|
|
2694
2719
|
|
|
2695
2720
|
/**
|
|
2696
|
-
* Admit the guest(s) to the call once they are waiting
|
|
2721
|
+
* Admit the guest(s) to the call once they are waiting.
|
|
2722
|
+
* If the host/cohost is in a breakout session, the locus url
|
|
2723
|
+
* of the session must be provided as the authorizingLocusUrl.
|
|
2724
|
+
* Regardless of host/cohost location, the locus Id (lid) in
|
|
2725
|
+
* the path should be the locus Id of the main, which means the
|
|
2726
|
+
* locus url of the api call must be from the main session.
|
|
2727
|
+
* If these loucs urls are not provided, the function will do the check.
|
|
2697
2728
|
* @param {Array} memberIds
|
|
2729
|
+
* @param {Object} sessionLocusUrls: {authorizingLocusUrl, mainLocusUrl}
|
|
2698
2730
|
* @returns {Promise} see #members.admitMembers
|
|
2699
2731
|
* @public
|
|
2700
2732
|
* @memberof Meeting
|
|
2701
2733
|
*/
|
|
2702
|
-
public admit(
|
|
2703
|
-
|
|
2734
|
+
public admit(
|
|
2735
|
+
memberIds: Array<any>,
|
|
2736
|
+
sessionLocusUrls?: {authorizingLocusUrl: string; mainLocusUrl: string}
|
|
2737
|
+
) {
|
|
2738
|
+
let locusUrls = sessionLocusUrls;
|
|
2739
|
+
if (!locusUrls) {
|
|
2740
|
+
const {locusUrl, mainLocusUrl} = this.breakouts;
|
|
2741
|
+
if (locusUrl && mainLocusUrl) {
|
|
2742
|
+
locusUrls = {authorizingLocusUrl: locusUrl, mainLocusUrl};
|
|
2743
|
+
}
|
|
2744
|
+
}
|
|
2745
|
+
|
|
2746
|
+
return this.members.admitMembers(memberIds, locusUrls);
|
|
2704
2747
|
}
|
|
2705
2748
|
|
|
2706
2749
|
/**
|
|
@@ -6216,6 +6259,27 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
6216
6259
|
return this.controlsOptionsManager.setDisallowUnmute(enabled);
|
|
6217
6260
|
}
|
|
6218
6261
|
|
|
6262
|
+
/**
|
|
6263
|
+
* set the mute all flag for participants if you're the host
|
|
6264
|
+
* @returns {Promise}
|
|
6265
|
+
* @param {boolean} mutedEnabled
|
|
6266
|
+
* @param {boolean} disallowUnmuteEnabled
|
|
6267
|
+
* @param {boolean} muteOnEntryEnabled
|
|
6268
|
+
* @public
|
|
6269
|
+
* @memberof Meeting
|
|
6270
|
+
*/
|
|
6271
|
+
public setMuteAll(
|
|
6272
|
+
mutedEnabled: boolean,
|
|
6273
|
+
disallowUnmuteEnabled: boolean,
|
|
6274
|
+
muteOnEntryEnabled: boolean
|
|
6275
|
+
) {
|
|
6276
|
+
return this.controlsOptionsManager.setMuteAll(
|
|
6277
|
+
mutedEnabled,
|
|
6278
|
+
disallowUnmuteEnabled,
|
|
6279
|
+
muteOnEntryEnabled
|
|
6280
|
+
);
|
|
6281
|
+
}
|
|
6282
|
+
|
|
6219
6283
|
/**
|
|
6220
6284
|
* End the recording of this meeting
|
|
6221
6285
|
* @returns {Promise}
|
package/src/meeting/muteState.ts
CHANGED
|
@@ -52,9 +52,9 @@ class MuteState {
|
|
|
52
52
|
},
|
|
53
53
|
server: {
|
|
54
54
|
localMute: false,
|
|
55
|
-
//
|
|
56
|
-
remoteMute: type === AUDIO ? meeting.remoteMuted : false,
|
|
57
|
-
unmuteAllowed: type === AUDIO ? meeting.unmuteAllowed : true,
|
|
55
|
+
// because remoteVideoMuted and unmuteVideoAllowed are updated seperately, they might be undefined
|
|
56
|
+
remoteMute: type === AUDIO ? meeting.remoteMuted : meeting.remoteVideoMuted ?? false,
|
|
57
|
+
unmuteAllowed: type === AUDIO ? meeting.unmuteAllowed : meeting.unmuteVideoAllowed ?? true,
|
|
58
58
|
},
|
|
59
59
|
syncToServerInProgress: false,
|
|
60
60
|
};
|
|
@@ -241,35 +241,28 @@ class MuteState {
|
|
|
241
241
|
* @returns {Promise}
|
|
242
242
|
*/
|
|
243
243
|
private sendRemoteMuteRequestToServer(meeting?: any) {
|
|
244
|
-
|
|
245
|
-
const remoteMute = this.state.client.localMute;
|
|
244
|
+
const remoteMute = this.state.client.localMute;
|
|
246
245
|
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
246
|
+
LoggerProxy.logger.info(
|
|
247
|
+
`Meeting:muteState#sendRemoteMuteRequestToServer --> ${this.type}: sending remote mute:${remoteMute} to server`
|
|
248
|
+
);
|
|
250
249
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
this.state.server.remoteMute = remoteMute;
|
|
259
|
-
})
|
|
260
|
-
.catch((remoteUpdateError) => {
|
|
261
|
-
LoggerProxy.logger.warn(
|
|
262
|
-
`Meeting:muteState#sendRemoteMuteRequestToServer --> ${this.type}: failed to apply remote mute ${remoteMute} to server: ${remoteUpdateError}`
|
|
263
|
-
);
|
|
264
|
-
|
|
265
|
-
return Promise.reject(remoteUpdateError);
|
|
266
|
-
});
|
|
267
|
-
}
|
|
250
|
+
return meeting.members
|
|
251
|
+
.muteMember(meeting.members.selfId, remoteMute, this.type === AUDIO)
|
|
252
|
+
.then(() => {
|
|
253
|
+
LoggerProxy.logger.info(
|
|
254
|
+
`Meeting:muteState#sendRemoteMuteRequestToServer --> ${this.type}: remote mute:${remoteMute} applied to server`
|
|
255
|
+
);
|
|
268
256
|
|
|
269
|
-
|
|
270
|
-
|
|
257
|
+
this.state.server.remoteMute = remoteMute;
|
|
258
|
+
})
|
|
259
|
+
.catch((remoteUpdateError) => {
|
|
260
|
+
LoggerProxy.logger.warn(
|
|
261
|
+
`Meeting:muteState#sendRemoteMuteRequestToServer --> ${this.type}: failed to apply remote mute ${remoteMute} to server: ${remoteUpdateError}`
|
|
262
|
+
);
|
|
271
263
|
|
|
272
|
-
|
|
264
|
+
return Promise.reject(remoteUpdateError);
|
|
265
|
+
});
|
|
273
266
|
}
|
|
274
267
|
|
|
275
268
|
/**
|
|
@@ -285,8 +278,12 @@ class MuteState {
|
|
|
285
278
|
LoggerProxy.logger.info(
|
|
286
279
|
`Meeting:muteState#handleServerRemoteMuteUpdate --> ${this.type}: updating server remoteMute to (${muted})`
|
|
287
280
|
);
|
|
288
|
-
|
|
289
|
-
|
|
281
|
+
if (muted !== undefined) {
|
|
282
|
+
this.state.server.remoteMute = muted;
|
|
283
|
+
}
|
|
284
|
+
if (unmuteAllowed !== undefined) {
|
|
285
|
+
this.state.server.unmuteAllowed = unmuteAllowed;
|
|
286
|
+
}
|
|
290
287
|
}
|
|
291
288
|
|
|
292
289
|
/**
|
|
@@ -330,6 +327,28 @@ class MuteState {
|
|
|
330
327
|
);
|
|
331
328
|
}
|
|
332
329
|
|
|
330
|
+
/**
|
|
331
|
+
* Returns true if the user is remotely muted
|
|
332
|
+
*
|
|
333
|
+
* @public
|
|
334
|
+
* @memberof MuteState
|
|
335
|
+
* @returns {Boolean}
|
|
336
|
+
*/
|
|
337
|
+
public isRemotelyMuted() {
|
|
338
|
+
return this.state.server.remoteMute;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* Returns true if unmute is allowed
|
|
343
|
+
*
|
|
344
|
+
* @public
|
|
345
|
+
* @memberof MuteState
|
|
346
|
+
* @returns {Boolean}
|
|
347
|
+
*/
|
|
348
|
+
public isUnmuteAllowed() {
|
|
349
|
+
return this.state.server.unmuteAllowed;
|
|
350
|
+
}
|
|
351
|
+
|
|
333
352
|
/**
|
|
334
353
|
* Returns true if the user is locally muted
|
|
335
354
|
*
|
package/src/members/index.ts
CHANGED
|
@@ -733,15 +733,22 @@ export default class Members extends StatelessWebexPlugin {
|
|
|
733
733
|
/**
|
|
734
734
|
* Admits waiting members (invited guests to meeting)
|
|
735
735
|
* @param {Array} memberIds
|
|
736
|
+
* @param {Object} sessionLocusUrls: {authorizingLocusUrl, mainLocusUrl}
|
|
736
737
|
* @returns {Promise}
|
|
737
738
|
* @public
|
|
738
739
|
* @memberof Members
|
|
739
740
|
*/
|
|
740
|
-
public admitMembers(
|
|
741
|
+
public admitMembers(
|
|
742
|
+
memberIds: Array<any>,
|
|
743
|
+
sessionLocusUrls?: {authorizingLocusUrl: string; mainLocusUrl: string}
|
|
744
|
+
) {
|
|
741
745
|
if (isEmpty(memberIds)) {
|
|
742
746
|
return Promise.reject(new ParameterError('No member ids provided to admit.'));
|
|
743
747
|
}
|
|
744
|
-
const options =
|
|
748
|
+
const options = {
|
|
749
|
+
sessionLocusUrls,
|
|
750
|
+
...MembersUtil.generateAdmitMemberOptions(memberIds, this.locusUrl),
|
|
751
|
+
};
|
|
745
752
|
|
|
746
753
|
return this.membersRequest.admitMember(options);
|
|
747
754
|
}
|
|
@@ -773,11 +780,12 @@ export default class Members extends StatelessWebexPlugin {
|
|
|
773
780
|
* Audio mutes another member in a meeting
|
|
774
781
|
* @param {String} memberId
|
|
775
782
|
* @param {boolean} [mute] default true
|
|
783
|
+
* @param {boolean} [isAudio] default true
|
|
776
784
|
* @returns {Promise}
|
|
777
785
|
* @public
|
|
778
786
|
* @memberof Members
|
|
779
787
|
*/
|
|
780
|
-
public muteMember(memberId: string, mute = true) {
|
|
788
|
+
public muteMember(memberId: string, mute = true, isAudio = true) {
|
|
781
789
|
if (!this.locusUrl) {
|
|
782
790
|
return Promise.reject(
|
|
783
791
|
new ParameterError(
|
|
@@ -790,7 +798,7 @@ export default class Members extends StatelessWebexPlugin {
|
|
|
790
798
|
new ParameterError('The member id must be defined to mute the member.')
|
|
791
799
|
);
|
|
792
800
|
}
|
|
793
|
-
const options = MembersUtil.generateMuteMemberOptions(memberId, mute, this.locusUrl);
|
|
801
|
+
const options = MembersUtil.generateMuteMemberOptions(memberId, mute, this.locusUrl, isAudio);
|
|
794
802
|
|
|
795
803
|
return this.membersRequest.muteMember(options);
|
|
796
804
|
}
|
package/src/members/util.ts
CHANGED
|
@@ -54,20 +54,31 @@ MembersUtil.getAddMemberBody = (options: any) => ({
|
|
|
54
54
|
});
|
|
55
55
|
|
|
56
56
|
/**
|
|
57
|
-
* @param {Object} options with {memberIds}
|
|
57
|
+
* @param {Object} options with {memberIds, authorizingLocusUrl}
|
|
58
58
|
* @returns {Object} admit with {memberIds}
|
|
59
59
|
*/
|
|
60
|
-
MembersUtil.getAdmitMemberRequestBody = (options: any) =>
|
|
61
|
-
|
|
62
|
-
}
|
|
60
|
+
MembersUtil.getAdmitMemberRequestBody = (options: any) => {
|
|
61
|
+
const {memberIds, sessionLocusUrls} = options;
|
|
62
|
+
const body: any = {admit: {participantIds: memberIds}};
|
|
63
|
+
if (sessionLocusUrls) {
|
|
64
|
+
const {authorizingLocusUrl} = sessionLocusUrls;
|
|
65
|
+
|
|
66
|
+
return {authorizingLocusUrl, ...body};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return body;
|
|
70
|
+
};
|
|
63
71
|
|
|
64
72
|
/**
|
|
65
|
-
* @param {Object} format with {memberIds, locusUrl}
|
|
73
|
+
* @param {Object} format with {memberIds, locusUrl, sessionLocusUrls}
|
|
66
74
|
* @returns {Object} the request parameters (method, uri, body) needed to make a admitMember request
|
|
75
|
+
* if a host/cohost is in a breakout session, the locus url should be the main session locus url
|
|
67
76
|
*/
|
|
68
77
|
MembersUtil.getAdmitMemberRequestParams = (format: any) => {
|
|
69
78
|
const body = MembersUtil.getAdmitMemberRequestBody(format);
|
|
70
|
-
const
|
|
79
|
+
const {locusUrl, sessionLocusUrls} = format;
|
|
80
|
+
const baseUrl = sessionLocusUrls?.mainLocusUrl || locusUrl;
|
|
81
|
+
const uri = `${baseUrl}/${CONTROLS}`;
|
|
71
82
|
|
|
72
83
|
return {
|
|
73
84
|
method: HTTP_VERBS.PUT,
|
|
@@ -128,10 +139,11 @@ MembersUtil.generateRemoveMemberOptions = (removal, locusUrl) => ({
|
|
|
128
139
|
locusUrl,
|
|
129
140
|
});
|
|
130
141
|
|
|
131
|
-
MembersUtil.generateMuteMemberOptions = (memberId, status, locusUrl) => ({
|
|
142
|
+
MembersUtil.generateMuteMemberOptions = (memberId, status, locusUrl, isAudio) => ({
|
|
132
143
|
memberId,
|
|
133
144
|
muted: status,
|
|
134
145
|
locusUrl,
|
|
146
|
+
isAudio,
|
|
135
147
|
});
|
|
136
148
|
|
|
137
149
|
MembersUtil.generateRaiseHandMemberOptions = (memberId, status, locusUrl) => ({
|
|
@@ -146,8 +158,9 @@ MembersUtil.generateLowerAllHandsMemberOptions = (requestingParticipantId, locus
|
|
|
146
158
|
});
|
|
147
159
|
|
|
148
160
|
MembersUtil.getMuteMemberRequestParams = (options) => {
|
|
161
|
+
const property = options.isAudio === false ? 'video' : 'audio';
|
|
149
162
|
const body = {
|
|
150
|
-
|
|
163
|
+
[property]: {
|
|
151
164
|
muted: options.muted,
|
|
152
165
|
},
|
|
153
166
|
};
|
|
@@ -511,8 +511,8 @@ describe('plugin-meetings', () => {
|
|
|
511
511
|
|
|
512
512
|
assert.equal(arg.uri, 'url');
|
|
513
513
|
assert.equal(arg.method, 'PUT');
|
|
514
|
-
assert.deepEqual(argObj1, {id:'groupId', action: 'START', allowBackToMain: false, allowToJoinLater: false});
|
|
515
|
-
assert.deepEqual(argObj2, {id:'id', action: 'START', allowBackToMain: false, allowToJoinLater: false, someOtherParam: 'someOtherParam'});
|
|
514
|
+
assert.deepEqual(argObj1, {id:'groupId', action: 'START', allowBackToMain: false, allowToJoinLater: false, duration: BREAKOUTS.DEFAULT_DURATION});
|
|
515
|
+
assert.deepEqual(argObj2, {id:'id', action: 'START', allowBackToMain: false, allowToJoinLater: false, someOtherParam: 'someOtherParam', duration: BREAKOUTS.DEFAULT_DURATION});
|
|
516
516
|
assert.deepEqual(result, {body: getBOResponse('OPEN')});
|
|
517
517
|
});
|
|
518
518
|
|
|
@@ -119,6 +119,62 @@ describe('plugin-meetings', () => {
|
|
|
119
119
|
});
|
|
120
120
|
});
|
|
121
121
|
});
|
|
122
|
+
|
|
123
|
+
describe('Mute/Unmute All', () => {
|
|
124
|
+
let manager;
|
|
125
|
+
beforeEach(() => {
|
|
126
|
+
request = {
|
|
127
|
+
request: sinon.stub().returns(Promise.resolve()),
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
manager = new ControlsOptionsManager(request);
|
|
131
|
+
|
|
132
|
+
manager.set({
|
|
133
|
+
locusUrl: 'test/id',
|
|
134
|
+
displayHints: [],
|
|
135
|
+
})
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it('rejects when correct display hint is not present mutedEnabled=false', () => {
|
|
139
|
+
const result = manager.setMuteAll(false, false, false);
|
|
140
|
+
|
|
141
|
+
assert.notCalled(request.request);
|
|
142
|
+
|
|
143
|
+
assert.isRejected(result);
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
it('rejects when correct display hint is not present mutedEnabled=true', () => {
|
|
147
|
+
const result = manager.setMuteAll(true, false, false);
|
|
148
|
+
|
|
149
|
+
assert.notCalled(request.request);
|
|
150
|
+
|
|
151
|
+
assert.isRejected(result);
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it('can set mute all when the display hint is available mutedEnabled=true', () => {
|
|
155
|
+
manager.setDisplayHints(['MUTE_ALL', 'ENABLE_HARD_MUTE', 'ENABLE_MUTE_ON_ENTRY']);
|
|
156
|
+
|
|
157
|
+
const result = manager.setMuteAll(true, true, true);
|
|
158
|
+
|
|
159
|
+
assert.calledWith(request.request, { uri: 'test/id/controls',
|
|
160
|
+
body: { audio: { muted: true, disallowUnmute: true, muteOnEntry: true } },
|
|
161
|
+
method: HTTP_VERBS.PATCH});
|
|
162
|
+
|
|
163
|
+
assert.deepEqual(result, request.request.firstCall.returnValue);
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
it('can set mute all when the display hint is available mutedEnabled=false', () => {
|
|
167
|
+
manager.setDisplayHints(['UNMUTE_ALL', 'DISABLE_HARD_MUTE', 'DISABLE_MUTE_ON_ENTRY']);
|
|
168
|
+
|
|
169
|
+
const result = manager.setMuteAll(false, false, false);
|
|
170
|
+
|
|
171
|
+
assert.calledWith(request.request, { uri: 'test/id/controls',
|
|
172
|
+
body: { audio: { muted: false, disallowUnmute: false, muteOnEntry: false } },
|
|
173
|
+
method: HTTP_VERBS.PATCH});
|
|
174
|
+
|
|
175
|
+
assert.deepEqual(result, request.request.firstCall.returnValue);
|
|
176
|
+
});
|
|
177
|
+
});
|
|
122
178
|
});
|
|
123
179
|
});
|
|
124
180
|
});
|
|
@@ -61,6 +61,26 @@ describe('plugin-meetings', () => {
|
|
|
61
61
|
});
|
|
62
62
|
});
|
|
63
63
|
|
|
64
|
+
describe('canSetMuteAll', () => {
|
|
65
|
+
it('can mute all', () => {
|
|
66
|
+
locusInfo.parsedLocus.info.userDisplayHints.push('MUTE_ALL');
|
|
67
|
+
|
|
68
|
+
assert.equal(ControlsOptionsUtil.canSetMuted(locusInfo.parsedLocus.info.userDisplayHints), true);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('can unmute all', () => {
|
|
72
|
+
locusInfo.parsedLocus.info.userDisplayHints.push('UNMUTE_ALL');
|
|
73
|
+
|
|
74
|
+
assert.equal(ControlsOptionsUtil.canUnsetMuted(locusInfo.parsedLocus.info.userDisplayHints), true);
|
|
75
|
+
});
|
|
76
|
+
it('rejects when correct display hint is not present', () => {
|
|
77
|
+
assert.equal(ControlsOptionsUtil.canSetMuted(locusInfo.parsedLocus.info.userDisplayHints), false);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('rejects when correct display hint is not present', () => {
|
|
81
|
+
assert.equal(ControlsOptionsUtil.canUnsetMuted(locusInfo.parsedLocus.info.userDisplayHints), false);
|
|
82
|
+
});
|
|
83
|
+
});
|
|
64
84
|
});
|
|
65
85
|
});
|
|
66
86
|
});
|