@webex/plugin-meetings 3.0.0-beta.42 → 3.0.0-beta.43

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.
@@ -615,6 +615,8 @@ export declare const DISPLAY_HINTS: {
615
615
  DISABLE_MUTE_ON_ENTRY: string;
616
616
  ENABLE_HARD_MUTE: string;
617
617
  DISABLE_HARD_MUTE: string;
618
+ MUTE_ALL: string;
619
+ UNMUTE_ALL: string;
618
620
  };
619
621
  export declare const SELF_ROLES: {
620
622
  COHOST: string;
@@ -1,5 +1,6 @@
1
1
  declare enum Setting {
2
2
  disallowUnmute = "DisallowUnmute",
3
- muteOnEntry = "MuteOnEntry"
3
+ muteOnEntry = "MuteOnEntry",
4
+ muted = "Muted"
4
5
  }
5
6
  export default Setting;
@@ -97,7 +97,6 @@ export default class ControlsOptionsManager {
97
97
  private extract;
98
98
  /**
99
99
  * @param {Setting} setting
100
- * @param {boolean} enabled
101
100
  * @private
102
101
  * @memberof ControlsOptionsManager
103
102
  * @returns {Promise}
@@ -117,4 +116,13 @@ export default class ControlsOptionsManager {
117
116
  * @returns {Promise}
118
117
  */
119
118
  setDisallowUnmute(enabled: boolean): Promise<any>;
119
+ /**
120
+ * @public
121
+ * @param {boolean} mutedEnabled
122
+ * @param {boolean} disallowUnmuteEnabled
123
+ * @param {boolean} muteOnEntryEnabled
124
+ * @memberof ControlsOptionsManager
125
+ * @returns {Promise}
126
+ */
127
+ setMuteAll(mutedEnabled: boolean, disallowUnmuteEnabled: boolean, muteOnEntryEnabled: boolean): Promise<any>;
120
128
  }
@@ -1,7 +1,9 @@
1
1
  declare const _default: {
2
2
  canSetMuteOnEntry: (displayHints: string[]) => boolean;
3
3
  canSetDisallowUnmute: (displayHints: string[]) => boolean;
4
+ canSetMuted: (displayHints: string[]) => boolean;
4
5
  canUnsetMuteOnEntry: (displayHints: string[]) => boolean;
5
6
  canUnsetDisallowUnmute: (displayHints: string[]) => boolean;
7
+ canUnsetMuted: (displayHints: string[]) => boolean;
6
8
  };
7
9
  export default _default;
@@ -14,6 +14,8 @@ interface IInMeetingActions {
14
14
  canUnsetMuteOnEntry?: boolean;
15
15
  canSetDisallowUnmute?: boolean;
16
16
  canUnsetDisallowUnmute?: boolean;
17
+ canSetMuted?: boolean;
18
+ canUnsetMuted?: boolean;
17
19
  canAssignHost?: boolean;
18
20
  canStartRecording?: boolean;
19
21
  canPauseRecording?: boolean;
@@ -53,6 +55,8 @@ export default class InMeetingActions implements IInMeetingActions {
53
55
  canUnsetMuteOnEntry: any;
54
56
  canSetDisallowUnmute: any;
55
57
  canUnsetDisallowUnmute: any;
58
+ canSetMuted: any;
59
+ canUnsetMuted: any;
56
60
  canRaiseHand: any;
57
61
  canLowerAllHands: any;
58
62
  canLowerSomeoneElsesHand: any;
@@ -1401,6 +1401,16 @@ export default class Meeting extends StatelessWebexPlugin {
1401
1401
  * @memberof Meeting
1402
1402
  */
1403
1403
  setDisallowUnmute(enabled: boolean): Promise<any>;
1404
+ /**
1405
+ * set the mute all flag for participants if you're the host
1406
+ * @returns {Promise}
1407
+ * @param {boolean} mutedEnabled
1408
+ * @param {boolean} disallowUnmuteEnabled
1409
+ * @param {boolean} muteOnEntryEnabled
1410
+ * @public
1411
+ * @memberof Meeting
1412
+ */
1413
+ setMuteAll(mutedEnabled: boolean, disallowUnmuteEnabled: boolean, muteOnEntryEnabled: boolean): Promise<any>;
1404
1414
  /**
1405
1415
  * End the recording of this meeting
1406
1416
  * @returns {Promise}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webex/plugin-meetings",
3
- "version": "3.0.0-beta.42",
3
+ "version": "3.0.0-beta.43",
4
4
  "description": "",
5
5
  "license": "Cisco EULA (https://www.cisco.com/c/en/us/products/end-user-license-agreement.html)",
6
6
  "contributors": [
@@ -32,12 +32,12 @@
32
32
  "build": "yarn run -T tsc --declaration true --declarationDir ./dist/types"
33
33
  },
34
34
  "devDependencies": {
35
- "@webex/plugin-meetings": "3.0.0-beta.42",
36
- "@webex/test-helper-chai": "3.0.0-beta.42",
37
- "@webex/test-helper-mocha": "3.0.0-beta.42",
38
- "@webex/test-helper-mock-webex": "3.0.0-beta.42",
39
- "@webex/test-helper-retry": "3.0.0-beta.42",
40
- "@webex/test-helper-test-users": "3.0.0-beta.42",
35
+ "@webex/plugin-meetings": "3.0.0-beta.43",
36
+ "@webex/test-helper-chai": "3.0.0-beta.43",
37
+ "@webex/test-helper-mocha": "3.0.0-beta.43",
38
+ "@webex/test-helper-mock-webex": "3.0.0-beta.43",
39
+ "@webex/test-helper-retry": "3.0.0-beta.43",
40
+ "@webex/test-helper-test-users": "3.0.0-beta.43",
41
41
  "chai": "^4.3.4",
42
42
  "chai-as-promised": "^7.1.1",
43
43
  "jsdom-global": "3.0.2",
@@ -46,18 +46,18 @@
46
46
  "typescript": "^4.7.4"
47
47
  },
48
48
  "dependencies": {
49
- "@webex/common": "3.0.0-beta.42",
49
+ "@webex/common": "3.0.0-beta.43",
50
50
  "@webex/internal-media-core": "1.35.2",
51
- "@webex/internal-plugin-conversation": "3.0.0-beta.42",
52
- "@webex/internal-plugin-device": "3.0.0-beta.42",
53
- "@webex/internal-plugin-llm": "3.0.0-beta.42",
54
- "@webex/internal-plugin-mercury": "3.0.0-beta.42",
55
- "@webex/internal-plugin-metrics": "3.0.0-beta.42",
56
- "@webex/internal-plugin-support": "3.0.0-beta.42",
57
- "@webex/internal-plugin-user": "3.0.0-beta.42",
58
- "@webex/plugin-people": "3.0.0-beta.42",
59
- "@webex/plugin-rooms": "3.0.0-beta.42",
60
- "@webex/webex-core": "3.0.0-beta.42",
51
+ "@webex/internal-plugin-conversation": "3.0.0-beta.43",
52
+ "@webex/internal-plugin-device": "3.0.0-beta.43",
53
+ "@webex/internal-plugin-llm": "3.0.0-beta.43",
54
+ "@webex/internal-plugin-mercury": "3.0.0-beta.43",
55
+ "@webex/internal-plugin-metrics": "3.0.0-beta.43",
56
+ "@webex/internal-plugin-support": "3.0.0-beta.43",
57
+ "@webex/internal-plugin-user": "3.0.0-beta.43",
58
+ "@webex/plugin-people": "3.0.0-beta.43",
59
+ "@webex/plugin-rooms": "3.0.0-beta.43",
60
+ "@webex/webex-core": "3.0.0-beta.43",
61
61
  "ampersand-collection": "^2.0.2",
62
62
  "bowser": "^2.11.0",
63
63
  "btoa": "^1.2.1",
package/src/constants.ts CHANGED
@@ -781,6 +781,8 @@ export const DISPLAY_HINTS = {
781
781
  DISABLE_MUTE_ON_ENTRY: 'DISABLE_MUTE_ON_ENTRY',
782
782
  ENABLE_HARD_MUTE: 'ENABLE_HARD_MUTE',
783
783
  DISABLE_HARD_MUTE: 'DISABLE_HARD_MUTE',
784
+ MUTE_ALL: 'MUTE_ALL',
785
+ UNMUTE_ALL: 'UNMUTE_ALL',
784
786
  };
785
787
 
786
788
  export const SELF_ROLES = {
@@ -1,6 +1,7 @@
1
1
  enum Setting {
2
2
  disallowUnmute = 'DisallowUnmute',
3
3
  muteOnEntry = 'MuteOnEntry',
4
+ muted = 'Muted',
4
5
  }
5
6
 
6
7
  export default Setting;
@@ -135,30 +135,45 @@ export default class ControlsOptionsManager {
135
135
 
136
136
  /**
137
137
  * @param {Setting} setting
138
- * @param {boolean} enabled
139
138
  * @private
140
139
  * @memberof ControlsOptionsManager
141
140
  * @returns {Promise}
142
141
  */
143
- private setControls(setting: Setting, enabled: boolean): Promise<any> {
144
- LoggerProxy.logger.log(`ControlsOptionsManager:index#setControls --> ${setting} [${enabled}]`);
145
-
146
- if (Util?.[`${enabled ? CAN_SET : CAN_UNSET}${setting}`](this.displayHints)) {
147
- // @ts-ignore
148
- return this.request.request({
149
- uri: `${this.locusUrl}/${CONTROLS}`,
150
- body: {
151
- [camelCase(setting)]: {
152
- [ENABLED]: enabled,
153
- },
154
- },
155
- method: HTTP_VERBS.PATCH,
156
- });
142
+ private setControls(setting: {[key in Setting]?: boolean}): Promise<any> {
143
+ const muteUnmuteAll = Object.keys(setting).includes(Setting.muted);
144
+
145
+ const body = muteUnmuteAll ? {audio: {}} : {};
146
+ for (const [key, value] of Object.entries(setting)) {
147
+ LoggerProxy.logger.log(`ControlsOptionsManager:index#setControls --> ${key} [${value}]`);
148
+ // mute unmute all has different body structure than toggling disable hard mute
149
+ // or mute on entry by themselves
150
+ if (muteUnmuteAll) {
151
+ if (Util?.[`${value ? CAN_SET : CAN_UNSET}${Setting.muted}`](this.displayHints)) {
152
+ body.audio[camelCase(key)] = value;
153
+ } else {
154
+ return Promise.reject(
155
+ new PermissionError(
156
+ `${Setting.muted} [${value}] not allowed, due to moderator property.`
157
+ )
158
+ );
159
+ }
160
+ } else if (Util?.[`${value ? CAN_SET : CAN_UNSET}${key}`](this.displayHints)) {
161
+ body[camelCase(key)] = {
162
+ [ENABLED]: value,
163
+ };
164
+ } else {
165
+ return Promise.reject(
166
+ new PermissionError(`${key} [${value}] not allowed, due to moderator property.`)
167
+ );
168
+ }
157
169
  }
158
170
 
159
- return Promise.reject(
160
- new PermissionError(`${setting} [${enabled}] not allowed, due to moderator property.`)
161
- );
171
+ // @ts-ignore
172
+ return this.request.request({
173
+ uri: `${this.locusUrl}/${CONTROLS}`,
174
+ body,
175
+ method: HTTP_VERBS.PATCH,
176
+ });
162
177
  }
163
178
 
164
179
  /**
@@ -168,7 +183,7 @@ export default class ControlsOptionsManager {
168
183
  * @returns {Promise}
169
184
  */
170
185
  public setMuteOnEntry(enabled: boolean): Promise<any> {
171
- return this.setControls(Setting.muteOnEntry, enabled);
186
+ return this.setControls({[Setting.muteOnEntry]: enabled});
172
187
  }
173
188
 
174
189
  /**
@@ -178,6 +193,26 @@ export default class ControlsOptionsManager {
178
193
  * @returns {Promise}
179
194
  */
180
195
  public setDisallowUnmute(enabled: boolean): Promise<any> {
181
- return this.setControls(Setting.disallowUnmute, enabled);
196
+ return this.setControls({[Setting.disallowUnmute]: enabled});
197
+ }
198
+
199
+ /**
200
+ * @public
201
+ * @param {boolean} mutedEnabled
202
+ * @param {boolean} disallowUnmuteEnabled
203
+ * @param {boolean} muteOnEntryEnabled
204
+ * @memberof ControlsOptionsManager
205
+ * @returns {Promise}
206
+ */
207
+ public setMuteAll(
208
+ mutedEnabled: boolean,
209
+ disallowUnmuteEnabled: boolean,
210
+ muteOnEntryEnabled: boolean
211
+ ): Promise<any> {
212
+ return this.setControls({
213
+ [Setting.muted]: mutedEnabled,
214
+ [Setting.disallowUnmute]: disallowUnmuteEnabled,
215
+ [Setting.muteOnEntry]: muteOnEntryEnabled,
216
+ });
182
217
  }
183
218
  }
@@ -12,9 +12,19 @@ const canUnsetMuteOnEntry = (displayHints: Array<string>): boolean =>
12
12
  const canUnsetDisallowUnmute = (displayHints: Array<string>): boolean =>
13
13
  displayHints.includes(DISPLAY_HINTS.DISABLE_HARD_MUTE);
14
14
 
15
+ // 'Muted' in the context of controls options manager refers to mute/unmute all.
16
+ // This was chosen because locus uses "muted" in the /controls API
17
+ const canSetMuted = (displayHints: Array<string>): boolean =>
18
+ displayHints.includes(DISPLAY_HINTS.MUTE_ALL);
19
+
20
+ const canUnsetMuted = (displayHints: Array<string>): boolean =>
21
+ displayHints.includes(DISPLAY_HINTS.UNMUTE_ALL);
22
+
15
23
  export default {
16
24
  canSetMuteOnEntry,
17
25
  canSetDisallowUnmute,
26
+ canSetMuted,
18
27
  canUnsetMuteOnEntry,
19
28
  canUnsetDisallowUnmute,
29
+ canUnsetMuted,
20
30
  };
@@ -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,
@@ -2290,6 +2290,8 @@ export default class Meeting extends StatelessWebexPlugin {
2290
2290
  canUnsetMuteOnEntry: ControlsOptionsUtil.canUnsetMuteOnEntry(
2291
2291
  payload.info.userDisplayHints
2292
2292
  ),
2293
+ canSetMuted: ControlsOptionsUtil.canSetMuted(payload.info.userDisplayHints),
2294
+ canUnsetMuted: ControlsOptionsUtil.canUnsetMuted(payload.info.userDisplayHints),
2293
2295
  canStartRecording: RecordingUtil.canUserStart(payload.info.userDisplayHints),
2294
2296
  canStopRecording: RecordingUtil.canUserStop(payload.info.userDisplayHints),
2295
2297
  canPauseRecording: RecordingUtil.canUserPause(payload.info.userDisplayHints),
@@ -6216,6 +6218,27 @@ export default class Meeting extends StatelessWebexPlugin {
6216
6218
  return this.controlsOptionsManager.setDisallowUnmute(enabled);
6217
6219
  }
6218
6220
 
6221
+ /**
6222
+ * set the mute all flag for participants if you're the host
6223
+ * @returns {Promise}
6224
+ * @param {boolean} mutedEnabled
6225
+ * @param {boolean} disallowUnmuteEnabled
6226
+ * @param {boolean} muteOnEntryEnabled
6227
+ * @public
6228
+ * @memberof Meeting
6229
+ */
6230
+ public setMuteAll(
6231
+ mutedEnabled: boolean,
6232
+ disallowUnmuteEnabled: boolean,
6233
+ muteOnEntryEnabled: boolean
6234
+ ) {
6235
+ return this.controlsOptionsManager.setMuteAll(
6236
+ mutedEnabled,
6237
+ disallowUnmuteEnabled,
6238
+ muteOnEntryEnabled
6239
+ );
6240
+ }
6241
+
6219
6242
  /**
6220
6243
  * End the recording of this meeting
6221
6244
  * @returns {Promise}
@@ -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
  });
@@ -17,6 +17,8 @@ describe('plugin-meetings', () => {
17
17
  canUnsetMuteOnEntry: null,
18
18
  canSetDisallowUnmute: null,
19
19
  canUnsetDisallowUnmute: null,
20
+ canSetMuted: null,
21
+ canUnsetMuted: null,
20
22
  canStopRecording: null,
21
23
  canRaiseHand: null,
22
24
  canLowerAllHands: null,