@webex/plugin-meetings 3.0.0-beta.146 → 3.0.0-beta.147

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.
Files changed (56) hide show
  1. package/dist/breakouts/breakout.js +1 -1
  2. package/dist/breakouts/index.js +1 -1
  3. package/dist/common/errors/webex-errors.js +3 -2
  4. package/dist/common/errors/webex-errors.js.map +1 -1
  5. package/dist/config.js +1 -7
  6. package/dist/config.js.map +1 -1
  7. package/dist/constants.js +7 -15
  8. package/dist/constants.js.map +1 -1
  9. package/dist/index.js +6 -0
  10. package/dist/index.js.map +1 -1
  11. package/dist/media/index.js +5 -56
  12. package/dist/media/index.js.map +1 -1
  13. package/dist/media/properties.js +15 -93
  14. package/dist/media/properties.js.map +1 -1
  15. package/dist/meeting/index.js +1092 -1865
  16. package/dist/meeting/index.js.map +1 -1
  17. package/dist/meeting/muteState.js +88 -184
  18. package/dist/meeting/muteState.js.map +1 -1
  19. package/dist/meeting/util.js +1 -23
  20. package/dist/meeting/util.js.map +1 -1
  21. package/dist/meetings/index.js +1 -2
  22. package/dist/meetings/index.js.map +1 -1
  23. package/dist/reconnection-manager/index.js +153 -134
  24. package/dist/reconnection-manager/index.js.map +1 -1
  25. package/dist/roap/index.js +8 -7
  26. package/dist/roap/index.js.map +1 -1
  27. package/dist/types/common/errors/webex-errors.d.ts +1 -1
  28. package/dist/types/config.d.ts +0 -6
  29. package/dist/types/constants.d.ts +1 -18
  30. package/dist/types/index.d.ts +1 -1
  31. package/dist/types/media/properties.d.ts +16 -38
  32. package/dist/types/meeting/index.d.ts +90 -353
  33. package/dist/types/meeting/muteState.d.ts +36 -38
  34. package/dist/types/meeting/util.d.ts +2 -4
  35. package/package.json +19 -19
  36. package/src/common/errors/webex-errors.ts +6 -2
  37. package/src/config.ts +0 -6
  38. package/src/constants.ts +1 -14
  39. package/src/index.ts +1 -0
  40. package/src/media/index.ts +10 -53
  41. package/src/media/properties.ts +32 -92
  42. package/src/meeting/index.ts +530 -1566
  43. package/src/meeting/muteState.ts +87 -178
  44. package/src/meeting/util.ts +3 -24
  45. package/src/meetings/index.ts +0 -1
  46. package/src/reconnection-manager/index.ts +4 -9
  47. package/src/roap/index.ts +13 -14
  48. package/test/integration/spec/converged-space-meetings.js +59 -3
  49. package/test/integration/spec/journey.js +330 -256
  50. package/test/integration/spec/space-meeting.js +75 -3
  51. package/test/unit/spec/meeting/index.js +767 -1344
  52. package/test/unit/spec/meeting/muteState.js +238 -394
  53. package/test/unit/spec/meeting/utils.js +2 -9
  54. package/test/unit/spec/multistream/receiveSlot.ts +1 -1
  55. package/test/unit/spec/roap/index.ts +2 -2
  56. package/test/utils/integrationTestUtils.js +5 -23
@@ -12,26 +12,14 @@ var _createClass2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpe
12
12
  var _defineProperty2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/defineProperty"));
13
13
  var _loggerProxy = _interopRequireDefault(require("../common/logs/logger-proxy"));
14
14
  var _parameter = _interopRequireDefault(require("../common/errors/parameter"));
15
- var _permission = _interopRequireDefault(require("../common/errors/permission"));
16
15
  var _util = _interopRequireDefault(require("./util"));
17
16
  var _constants = require("../constants");
18
- /* Certain aspects of server interaction for video muting are not implemented as we currently don't support remote muting of video.
19
- If we ever need to support it, search for REMOTE_MUTE_VIDEO_MISSING_IMPLEMENTATION string to find the places that need updating
20
- */
21
-
22
17
  // eslint-disable-next-line import/prefer-default-export
23
- var createMuteState = function createMuteState(type, meeting, mediaDirection, sdkOwnsLocalTrack) {
24
- // todo: remove mediaDirection argument (SPARK-399695)
18
+ var createMuteState = function createMuteState(type, meeting, enabled) {
25
19
  // todo: remove the meeting argument (SPARK-399695)
26
- if (type === _constants.AUDIO && !mediaDirection.sendAudio) {
27
- return null;
28
- }
29
- if (type === _constants.VIDEO && !mediaDirection.sendVideo) {
30
- return null;
31
- }
20
+
32
21
  _loggerProxy.default.logger.info("Meeting:muteState#createMuteState --> ".concat(type, ": creating MuteState for meeting id ").concat(meeting === null || meeting === void 0 ? void 0 : meeting.id));
33
- var muteState = new MuteState(type, meeting, sdkOwnsLocalTrack);
34
- muteState.init(meeting);
22
+ var muteState = new MuteState(type, meeting, enabled);
35
23
  return muteState;
36
24
  };
37
25
 
@@ -44,33 +32,28 @@ var createMuteState = function createMuteState(type, meeting, mediaDirection, sd
44
32
  */
45
33
  exports.createMuteState = createMuteState;
46
34
  var MuteState = /*#__PURE__*/function () {
47
- // todo: remove this when doing SPARK-399695
48
-
49
35
  /**
50
36
  * Constructor
51
37
  *
52
38
  * @param {String} type - audio or video
53
39
  * @param {Object} meeting - the meeting object (used for reading current remote mute status)
54
- * @param {boolean} sdkOwnsLocalTrack - if false, then client app owns the local track (for now that's the case only for multistream meetings)
40
+ * @param {boolean} enabled - whether the client audio/video is enabled at all
55
41
  */
56
- function MuteState(type, meeting, sdkOwnsLocalTrack) {
42
+ function MuteState(type, meeting, enabled) {
57
43
  var _meeting$remoteVideoM, _meeting$unmuteVideoA;
58
44
  (0, _classCallCheck2.default)(this, MuteState);
59
- (0, _defineProperty2.default)(this, "pendingPromiseReject", void 0);
60
- (0, _defineProperty2.default)(this, "pendingPromiseResolve", void 0);
61
45
  (0, _defineProperty2.default)(this, "state", void 0);
62
46
  (0, _defineProperty2.default)(this, "type", void 0);
63
- (0, _defineProperty2.default)(this, "sdkOwnsLocalTrack", void 0);
64
47
  (0, _defineProperty2.default)(this, "ignoreMuteStateChange", void 0);
65
48
  if (type !== _constants.AUDIO && type !== _constants.VIDEO) {
66
49
  throw new _parameter.default('Mute state is designed for handling audio or video only');
67
50
  }
68
51
  this.type = type;
69
- this.sdkOwnsLocalTrack = sdkOwnsLocalTrack;
70
52
  this.ignoreMuteStateChange = false;
71
53
  this.state = {
72
54
  client: {
73
- localMute: false
55
+ enabled: enabled,
56
+ localMute: true
74
57
  },
75
58
  server: {
76
59
  localMute: true,
@@ -80,9 +63,6 @@ var MuteState = /*#__PURE__*/function () {
80
63
  },
81
64
  syncToServerInProgress: false
82
65
  };
83
- // these 2 hold the resolve, reject methods for the promise we returned to the client in last handleClientRequest() call
84
- this.pendingPromiseResolve = null;
85
- this.pendingPromiseReject = null;
86
66
  }
87
67
 
88
68
  /**
@@ -94,33 +74,23 @@ var MuteState = /*#__PURE__*/function () {
94
74
  (0, _createClass2.default)(MuteState, [{
95
75
  key: "init",
96
76
  value: function init(meeting) {
97
- var _this = this;
98
- if (!this.sdkOwnsLocalTrack) {
99
- var _meeting$mediaPropert, _meeting$mediaPropert2;
100
- this.applyUnmuteAllowedToTrack(meeting);
77
+ var _meeting$mediaPropert, _meeting$mediaPropert2;
78
+ this.applyUnmuteAllowedToTrack(meeting);
101
79
 
102
- // if we are remotely muted, we need to apply that to the local track now (mute on-entry)
103
- if (this.state.server.remoteMute) {
104
- this.muteLocalTrack(meeting, this.state.server.remoteMute, 'remotelyMuted');
105
- }
106
- var initialMute = this.type === _constants.AUDIO ? (_meeting$mediaPropert = meeting.mediaProperties.audioTrack) === null || _meeting$mediaPropert === void 0 ? void 0 : _meeting$mediaPropert.muted : (_meeting$mediaPropert2 = meeting.mediaProperties.videoTrack) === null || _meeting$mediaPropert2 === void 0 ? void 0 : _meeting$mediaPropert2.muted;
107
- _loggerProxy.default.logger.info("Meeting:muteState#init --> ".concat(this.type, ": local track initial mute state: ").concat(initialMute));
108
- if (initialMute !== undefined) {
109
- this.state.client.localMute = initialMute;
110
- this.applyClientStateToServer(meeting);
111
- }
80
+ // if we are remotely muted, we need to apply that to the local track now (mute on-entry)
81
+ if (this.state.server.remoteMute) {
82
+ this.muteLocalTrack(meeting, this.state.server.remoteMute, 'remotelyMuted');
83
+ }
84
+ var initialMute = this.type === _constants.AUDIO ? (_meeting$mediaPropert = meeting.mediaProperties.audioTrack) === null || _meeting$mediaPropert === void 0 ? void 0 : _meeting$mediaPropert.muted : (_meeting$mediaPropert2 = meeting.mediaProperties.videoTrack) === null || _meeting$mediaPropert2 === void 0 ? void 0 : _meeting$mediaPropert2.muted;
85
+ _loggerProxy.default.logger.info("Meeting:muteState#init --> ".concat(this.type, ": local track initial mute state: ").concat(initialMute));
86
+ if (initialMute !== undefined) {
87
+ this.state.client.localMute = initialMute;
112
88
  } else {
113
- // in the mode where sdkOwnsLocalTrack is false (transcoded meetings),
114
- // SDK API currently doesn't allow to start with audio/video muted,
115
- // so we need to apply the initial local mute state (false) to server
116
- this.state.syncToServerInProgress = true;
117
- this.sendLocalMuteRequestToServer(meeting).then(function () {
118
- _this.state.syncToServerInProgress = false;
119
- }).catch(function () {
120
- _this.state.syncToServerInProgress = false;
121
- // not much we can do here...
122
- });
89
+ // there is no track, so it's like we are locally muted
90
+ // (this is important especially for transcoded meetings, in which the SDP m-line direction always stays "sendrecv")
91
+ this.state.client.localMute = true;
123
92
  }
93
+ this.applyClientStateToServer(meeting);
124
94
  }
125
95
 
126
96
  /**
@@ -138,6 +108,20 @@ var MuteState = /*#__PURE__*/function () {
138
108
  return this.init(meeting);
139
109
  }
140
110
 
111
+ /**
112
+ * Enables/disables audio/video
113
+ *
114
+ * @param {Object} meeting - the meeting object
115
+ * @param {boolean} enable
116
+ * @returns {void}
117
+ */
118
+ }, {
119
+ key: "enable",
120
+ value: function enable(meeting, _enable) {
121
+ this.state.client.enabled = _enable;
122
+ this.applyClientStateToServer(meeting);
123
+ }
124
+
141
125
  /**
142
126
  * Mutes/unmutes local track
143
127
  *
@@ -160,45 +144,6 @@ var MuteState = /*#__PURE__*/function () {
160
144
  this.ignoreMuteStateChange = false;
161
145
  }
162
146
 
163
- /**
164
- * Handles mute/unmute request from the client/user. Returns a promise that's resolved once the server update is completed or
165
- * at the point that this request becomese superseded by another client request.
166
- *
167
- * The client doesn't have to wait for the returned promise to resolve before calling handleClientRequest() again. If
168
- * handleClientRequest() is called again before the previous one resolved, the MuteState class will make sure that eventually
169
- * the server state will match the last requested state from the client.
170
- *
171
- * @public
172
- * @memberof MuteState
173
- * @param {Object} [meeting] the meeting object
174
- * @param {Boolean} [mute] true for muting, false for unmuting request
175
- * @returns {Promise}
176
- */
177
- }, {
178
- key: "handleClientRequest",
179
- value: function handleClientRequest(meeting, mute) {
180
- var _this2 = this;
181
- // todo: this whole method will be removed in SPARK-399695
182
- _loggerProxy.default.logger.info("Meeting:muteState#handleClientRequest --> ".concat(this.type, ": user requesting new mute state: ").concat(mute));
183
- if (!mute && !this.state.server.unmuteAllowed) {
184
- return _promise.default.reject(new _permission.default('User is not allowed to unmute self (hard mute feature is being used)'));
185
- }
186
-
187
- // we don't check if we're already in the same state, because even if we were, we would still have to apply the mute state locally,
188
- // because the client may have changed the audio/video tracks
189
- this.state.client.localMute = mute;
190
- this.applyClientStateLocally(meeting);
191
- return new _promise.default(function (resolve, reject) {
192
- if (_this2.pendingPromiseResolve) {
193
- // resolve the last promise we returned to the client as the client has issued a new request that has superseded the previous one
194
- _this2.pendingPromiseResolve();
195
- }
196
- _this2.pendingPromiseResolve = resolve;
197
- _this2.pendingPromiseReject = reject;
198
- _this2.applyClientStateToServer(meeting);
199
- });
200
- }
201
-
202
147
  /**
203
148
  * This method should be called when the local track mute state is changed
204
149
  * @public
@@ -214,9 +159,6 @@ var MuteState = /*#__PURE__*/function () {
214
159
  return;
215
160
  }
216
161
  _loggerProxy.default.logger.info("Meeting:muteState#handleLocalTrackMuteStateChange --> ".concat(this.type, ": local track new mute state: ").concat(mute));
217
- if (this.pendingPromiseReject) {
218
- _loggerProxy.default.logger.error("Meeting:muteState#handleLocalTrackMuteStateChange --> ".concat(this.type, ": Local track mute state change handler called while a client request is handled - this should never happen!, mute state: ").concat(mute));
219
- }
220
162
  this.state.client.localMute = mute;
221
163
  this.applyClientStateToServer(meeting);
222
164
  }
@@ -233,17 +175,18 @@ var MuteState = /*#__PURE__*/function () {
233
175
  }, {
234
176
  key: "applyClientStateLocally",
235
177
  value: function applyClientStateLocally(meeting, reason) {
236
- if (this.sdkOwnsLocalTrack) {
237
- if (this.type === _constants.AUDIO) {
238
- var _meeting$mediaPropert5;
239
- (_meeting$mediaPropert5 = meeting.mediaProperties.audioTrack) === null || _meeting$mediaPropert5 === void 0 ? void 0 : _meeting$mediaPropert5.setMuted(this.state.client.localMute);
240
- } else {
241
- var _meeting$mediaPropert6;
242
- (_meeting$mediaPropert6 = meeting.mediaProperties.videoTrack) === null || _meeting$mediaPropert6 === void 0 ? void 0 : _meeting$mediaPropert6.setMuted(this.state.client.localMute);
243
- }
244
- } else {
245
- this.muteLocalTrack(meeting, this.state.client.localMute, reason);
246
- }
178
+ this.muteLocalTrack(meeting, this.state.client.localMute, reason);
179
+ }
180
+
181
+ /** Returns true if client is locally muted - it takes into account not just the client local mute state,
182
+ * but also whether audio/video is enabled at all
183
+ *
184
+ * @returns {boolean}
185
+ */
186
+ }, {
187
+ key: "getClientLocalMuteState",
188
+ value: function getClientLocalMuteState() {
189
+ return this.state.client.enabled ? this.state.client.localMute : true;
247
190
  }
248
191
 
249
192
  /**
@@ -257,22 +200,18 @@ var MuteState = /*#__PURE__*/function () {
257
200
  }, {
258
201
  key: "applyClientStateToServer",
259
202
  value: function applyClientStateToServer(meeting) {
260
- var _this3 = this;
203
+ var _this = this;
261
204
  if (this.state.syncToServerInProgress) {
262
205
  _loggerProxy.default.logger.info("Meeting:muteState#applyClientStateToServer --> ".concat(this.type, ": request to server in progress, we need to wait for it to complete"));
263
206
  return;
264
207
  }
265
- var localMuteRequiresSync = this.state.client.localMute !== this.state.server.localMute;
266
- var remoteMuteRequiresSync = !this.state.client.localMute && this.state.server.remoteMute;
267
- _loggerProxy.default.logger.info("Meeting:muteState#applyClientStateToServer --> ".concat(this.type, ": localMuteRequiresSync: ").concat(localMuteRequiresSync, " (").concat(this.state.client.localMute, " ?= ").concat(this.state.server.localMute, ")"));
208
+ var localMuteState = this.getClientLocalMuteState();
209
+ var localMuteRequiresSync = localMuteState !== this.state.server.localMute;
210
+ var remoteMuteRequiresSync = !localMuteState && this.state.server.remoteMute;
211
+ _loggerProxy.default.logger.info("Meeting:muteState#applyClientStateToServer --> ".concat(this.type, ": localMuteRequiresSync: ").concat(localMuteRequiresSync, " (").concat(localMuteState, " ?= ").concat(this.state.server.localMute, ")"));
268
212
  _loggerProxy.default.logger.info("Meeting:muteState#applyClientStateToServer --> ".concat(this.type, ": remoteMuteRequiresSync: ").concat(remoteMuteRequiresSync));
269
213
  if (!localMuteRequiresSync && !remoteMuteRequiresSync) {
270
214
  _loggerProxy.default.logger.info("Meeting:muteState#applyClientStateToServer --> ".concat(this.type, ": client state already matching server state, nothing to do"));
271
- if (this.pendingPromiseResolve) {
272
- this.pendingPromiseResolve();
273
- }
274
- this.pendingPromiseResolve = null;
275
- this.pendingPromiseReject = null;
276
215
  return;
277
216
  }
278
217
  this.state.syncToServerInProgress = true;
@@ -282,22 +221,18 @@ var MuteState = /*#__PURE__*/function () {
282
221
  localMuteSyncPromise.then(function () {
283
222
  return (
284
223
  // then follow it up with remote mute sync
285
- remoteMuteRequiresSync ? _this3.sendRemoteMuteRequestToServer(meeting) : _promise.default.resolve()
224
+ remoteMuteRequiresSync ? _this.sendRemoteMuteRequestToServer(meeting) : _promise.default.resolve()
286
225
  );
287
226
  }).then(function () {
288
- _this3.state.syncToServerInProgress = false;
289
- _loggerProxy.default.logger.info("Meeting:muteState#applyClientStateToServer --> ".concat(_this3.type, ": sync with server completed"));
227
+ _this.state.syncToServerInProgress = false;
228
+ _loggerProxy.default.logger.info("Meeting:muteState#applyClientStateToServer --> ".concat(_this.type, ": sync with server completed"));
290
229
 
291
230
  // need to check if a new sync is required, because this.state.client may have changed while we were doing the current sync
292
- _this3.applyClientStateToServer(meeting);
231
+ _this.applyClientStateToServer(meeting);
293
232
  }).catch(function (e) {
294
- _this3.state.syncToServerInProgress = false;
295
- if (_this3.pendingPromiseReject) {
296
- _this3.pendingPromiseReject(e);
297
- }
298
- _this3.pendingPromiseResolve = null;
299
- _this3.pendingPromiseReject = null;
300
- _this3.applyServerMuteToLocalTrack(meeting, 'clientRequestFailed');
233
+ _this.state.syncToServerInProgress = false;
234
+ _loggerProxy.default.logger.warn("Meeting:muteState#applyClientStateToServer --> ".concat(_this.type, ": error: ").concat(e));
235
+ _this.applyServerMuteToLocalTrack(meeting, 'clientRequestFailed');
301
236
  });
302
237
  }
303
238
 
@@ -312,19 +247,19 @@ var MuteState = /*#__PURE__*/function () {
312
247
  }, {
313
248
  key: "sendLocalMuteRequestToServer",
314
249
  value: function sendLocalMuteRequestToServer(meeting) {
315
- var _this4 = this;
316
- var audioMuted = this.type === _constants.AUDIO ? this.state.client.localMute : undefined;
317
- var videoMuted = this.type === _constants.VIDEO ? this.state.client.localMute : undefined;
250
+ var _this2 = this;
251
+ var audioMuted = this.type === _constants.AUDIO ? this.getClientLocalMuteState() : undefined;
252
+ var videoMuted = this.type === _constants.VIDEO ? this.getClientLocalMuteState() : undefined;
318
253
  _loggerProxy.default.logger.info("Meeting:muteState#sendLocalMuteRequestToServer --> ".concat(this.type, ": sending local mute (audio=").concat(audioMuted, ", video=").concat(videoMuted, ") to server"));
319
254
  return _util.default.remoteUpdateAudioVideo(meeting, audioMuted, videoMuted).then(function (locus) {
320
- _loggerProxy.default.logger.info("Meeting:muteState#sendLocalMuteRequestToServer --> ".concat(_this4.type, ": local mute (audio=").concat(audioMuted, ", video=").concat(videoMuted, ") applied to server"));
321
- _this4.state.server.localMute = _this4.type === _constants.AUDIO ? audioMuted : videoMuted;
255
+ _loggerProxy.default.logger.info("Meeting:muteState#sendLocalMuteRequestToServer --> ".concat(_this2.type, ": local mute (audio=").concat(audioMuted, ", video=").concat(videoMuted, ") applied to server"));
256
+ _this2.state.server.localMute = _this2.type === _constants.AUDIO ? audioMuted : videoMuted;
322
257
  if (locus) {
323
258
  meeting.locusInfo.onDeltaLocus(locus);
324
259
  }
325
260
  return locus;
326
261
  }).catch(function (remoteUpdateError) {
327
- _loggerProxy.default.logger.warn("Meeting:muteState#sendLocalMuteRequestToServer --> ".concat(_this4.type, ": failed to apply local mute (audio=").concat(audioMuted, ", video=").concat(videoMuted, ") to server: ").concat(remoteUpdateError));
262
+ _loggerProxy.default.logger.warn("Meeting:muteState#sendLocalMuteRequestToServer --> ".concat(_this2.type, ": failed to apply local mute (audio=").concat(audioMuted, ", video=").concat(videoMuted, ") to server: ").concat(remoteUpdateError));
328
263
  return _promise.default.reject(remoteUpdateError);
329
264
  });
330
265
  }
@@ -340,14 +275,14 @@ var MuteState = /*#__PURE__*/function () {
340
275
  }, {
341
276
  key: "sendRemoteMuteRequestToServer",
342
277
  value: function sendRemoteMuteRequestToServer(meeting) {
343
- var _this5 = this;
344
- var remoteMute = this.state.client.localMute;
278
+ var _this3 = this;
279
+ var remoteMute = this.getClientLocalMuteState();
345
280
  _loggerProxy.default.logger.info("Meeting:muteState#sendRemoteMuteRequestToServer --> ".concat(this.type, ": sending remote mute:").concat(remoteMute, " to server"));
346
281
  return meeting.members.muteMember(meeting.members.selfId, remoteMute, this.type === _constants.AUDIO).then(function () {
347
- _loggerProxy.default.logger.info("Meeting:muteState#sendRemoteMuteRequestToServer --> ".concat(_this5.type, ": remote mute:").concat(remoteMute, " applied to server"));
348
- _this5.state.server.remoteMute = remoteMute;
282
+ _loggerProxy.default.logger.info("Meeting:muteState#sendRemoteMuteRequestToServer --> ".concat(_this3.type, ": remote mute:").concat(remoteMute, " applied to server"));
283
+ _this3.state.server.remoteMute = remoteMute;
349
284
  }).catch(function (remoteUpdateError) {
350
- _loggerProxy.default.logger.warn("Meeting:muteState#sendRemoteMuteRequestToServer --> ".concat(_this5.type, ": failed to apply remote mute ").concat(remoteMute, " to server: ").concat(remoteUpdateError));
285
+ _loggerProxy.default.logger.warn("Meeting:muteState#sendRemoteMuteRequestToServer --> ".concat(_this3.type, ": failed to apply remote mute ").concat(remoteMute, " to server: ").concat(remoteUpdateError));
351
286
  return _promise.default.reject(remoteUpdateError);
352
287
  });
353
288
  }
@@ -360,12 +295,10 @@ var MuteState = /*#__PURE__*/function () {
360
295
  }, {
361
296
  key: "applyServerMuteToLocalTrack",
362
297
  value: function applyServerMuteToLocalTrack(meeting, serverMuteReason) {
363
- if (!this.sdkOwnsLocalTrack) {
364
- var muted = this.state.server.localMute || this.state.server.remoteMute;
298
+ var muted = this.state.server.localMute || this.state.server.remoteMute;
365
299
 
366
- // update the local track mute state, but not this.state.client.localMute
367
- this.muteLocalTrack(meeting, muted, serverMuteReason);
368
- }
300
+ // update the local track mute state, but not this.state.client.localMute
301
+ this.muteLocalTrack(meeting, muted, serverMuteReason);
369
302
  }
370
303
 
371
304
  /** Applies the current value for unmute allowed to the underlying track
@@ -376,14 +309,12 @@ var MuteState = /*#__PURE__*/function () {
376
309
  }, {
377
310
  key: "applyUnmuteAllowedToTrack",
378
311
  value: function applyUnmuteAllowedToTrack(meeting) {
379
- if (!this.sdkOwnsLocalTrack) {
380
- if (this.type === _constants.AUDIO) {
381
- var _meeting$mediaPropert7;
382
- (_meeting$mediaPropert7 = meeting.mediaProperties.audioTrack) === null || _meeting$mediaPropert7 === void 0 ? void 0 : _meeting$mediaPropert7.setUnmuteAllowed(this.state.server.unmuteAllowed);
383
- } else {
384
- var _meeting$mediaPropert8;
385
- (_meeting$mediaPropert8 = meeting.mediaProperties.videoTrack) === null || _meeting$mediaPropert8 === void 0 ? void 0 : _meeting$mediaPropert8.setUnmuteAllowed(this.state.server.unmuteAllowed);
386
- }
312
+ if (this.type === _constants.AUDIO) {
313
+ var _meeting$mediaPropert5;
314
+ (_meeting$mediaPropert5 = meeting.mediaProperties.audioTrack) === null || _meeting$mediaPropert5 === void 0 ? void 0 : _meeting$mediaPropert5.setUnmuteAllowed(this.state.server.unmuteAllowed);
315
+ } else {
316
+ var _meeting$mediaPropert6;
317
+ (_meeting$mediaPropert6 = meeting.mediaProperties.videoTrack) === null || _meeting$mediaPropert6 === void 0 ? void 0 : _meeting$mediaPropert6.setUnmuteAllowed(this.state.server.unmuteAllowed);
387
318
  }
388
319
  }
389
320
 
@@ -422,22 +353,22 @@ var MuteState = /*#__PURE__*/function () {
422
353
  }, {
423
354
  key: "handleServerLocalUnmuteRequired",
424
355
  value: function handleServerLocalUnmuteRequired(meeting) {
425
- _loggerProxy.default.logger.info("Meeting:muteState#handleServerLocalUnmuteRequired --> ".concat(this.type, ": localAudioUnmuteRequired received -> doing local unmute"));
356
+ if (!this.state.client.enabled) {
357
+ _loggerProxy.default.logger.warn("Meeting:muteState#handleServerLocalUnmuteRequired --> ".concat(this.type, ": localAudioUnmuteRequired received while ").concat(this.type, " is disabled -> local unmute will not result in ").concat(this.type, " being sent"));
358
+ } else {
359
+ _loggerProxy.default.logger.info("Meeting:muteState#handleServerLocalUnmuteRequired --> ".concat(this.type, ": localAudioUnmuteRequired received -> doing local unmute"));
360
+ }
426
361
 
427
362
  // todo: I'm seeing "you can now unmute yourself " popup when this happens - but same thing happens on web.w.c so we can ignore for now
428
363
  this.state.server.remoteMute = false;
429
364
  this.state.client.localMute = false;
430
- if (this.pendingPromiseReject) {
431
- this.pendingPromiseReject(new Error('Server requested local unmute - this overrides any client request in progress'));
432
- this.pendingPromiseResolve = null;
433
- this.pendingPromiseReject = null;
434
- }
435
365
  this.applyClientStateLocally(meeting, 'localUnmuteRequired');
436
366
  this.applyClientStateToServer(meeting);
437
367
  }
438
368
 
439
369
  /**
440
- * Returns true if the user is locally or remotely muted
370
+ * Returns true if the user is locally or remotely muted.
371
+ * It only checks the mute status, ignoring the fact whether audio/video is enabled.
441
372
  *
442
373
  * @public
443
374
  * @memberof MuteState
@@ -476,7 +407,7 @@ var MuteState = /*#__PURE__*/function () {
476
407
  }
477
408
 
478
409
  /**
479
- * Returns true if the user is locally muted
410
+ * Returns true if the user is locally muted or audio/video is disabled
480
411
  *
481
412
  * @public
482
413
  * @memberof MuteState
@@ -485,34 +416,7 @@ var MuteState = /*#__PURE__*/function () {
485
416
  }, {
486
417
  key: "isLocallyMuted",
487
418
  value: function isLocallyMuted() {
488
- return this.state.client.localMute || this.state.server.localMute;
489
- }
490
-
491
- /**
492
- * Returns true if the user is muted as a result of the client request (and not remotely muted)
493
- *
494
- * @public
495
- * @memberof MuteState
496
- * @returns {Boolean}
497
- */
498
- }, {
499
- key: "isSelf",
500
- value: function isSelf() {
501
- return this.state.client.localMute && !this.state.server.remoteMute;
502
- }
503
-
504
- // defined for backwards compatibility with the old AudioStateMachine/VideoStateMachine classes
505
- }, {
506
- key: "muted",
507
- get: function get() {
508
- return this.isMuted();
509
- }
510
-
511
- // defined for backwards compatibility with the old AudioStateMachine/VideoStateMachine classes
512
- }, {
513
- key: "self",
514
- get: function get() {
515
- return this.isSelf();
419
+ return this.getClientLocalMuteState();
516
420
  }
517
421
  }]);
518
422
  return MuteState;
@@ -1 +1 @@
1
- {"version":3,"names":["createMuteState","type","meeting","mediaDirection","sdkOwnsLocalTrack","AUDIO","sendAudio","VIDEO","sendVideo","LoggerProxy","logger","info","id","muteState","MuteState","init","ParameterError","ignoreMuteStateChange","state","client","localMute","server","remoteMute","remoteMuted","remoteVideoMuted","unmuteAllowed","unmuteVideoAllowed","syncToServerInProgress","pendingPromiseResolve","pendingPromiseReject","applyUnmuteAllowedToTrack","muteLocalTrack","initialMute","mediaProperties","audioTrack","muted","videoTrack","undefined","applyClientStateToServer","sendLocalMuteRequestToServer","then","catch","mute","reason","setServerMuted","reject","PermissionError","applyClientStateLocally","resolve","error","setMuted","localMuteRequiresSync","remoteMuteRequiresSync","localMuteSyncPromise","sendRemoteMuteRequestToServer","e","applyServerMuteToLocalTrack","audioMuted","videoMuted","MeetingUtil","remoteUpdateAudioVideo","locus","locusInfo","onDeltaLocus","remoteUpdateError","warn","members","muteMember","selfId","serverMuteReason","setUnmuteAllowed","Error","isMuted","isSelf"],"sources":["muteState.ts"],"sourcesContent":["import {ServerMuteReason} from '@webex/media-helpers';\nimport LoggerProxy from '../common/logs/logger-proxy';\nimport ParameterError from '../common/errors/parameter';\nimport PermissionError from '../common/errors/permission';\nimport MeetingUtil from './util';\nimport {AUDIO, VIDEO} from '../constants';\n/* Certain aspects of server interaction for video muting are not implemented as we currently don't support remote muting of video.\n If we ever need to support it, search for REMOTE_MUTE_VIDEO_MISSING_IMPLEMENTATION string to find the places that need updating\n*/\n\n// eslint-disable-next-line import/prefer-default-export\nexport const createMuteState = (type, meeting, mediaDirection, sdkOwnsLocalTrack: boolean) => {\n // todo: remove mediaDirection argument (SPARK-399695)\n // todo: remove the meeting argument (SPARK-399695)\n if (type === AUDIO && !mediaDirection.sendAudio) {\n return null;\n }\n if (type === VIDEO && !mediaDirection.sendVideo) {\n return null;\n }\n\n LoggerProxy.logger.info(\n `Meeting:muteState#createMuteState --> ${type}: creating MuteState for meeting id ${meeting?.id}`\n );\n\n const muteState = new MuteState(type, meeting, sdkOwnsLocalTrack);\n\n muteState.init(meeting);\n\n return muteState;\n};\n\n/** The purpose of this class is to manage the local and remote mute state and make sure that the server state always matches\n the last requested state by the client.\n\n More info about Locus muting API: https://sqbu-github.cisco.com/pages/WebExSquared/locus/guides/mute.html#\n\n This class is exported only for unit tests. It should never be instantiated directly with new MuteState(), instead createMuteState() should be called\n*/\nexport class MuteState {\n pendingPromiseReject: any;\n pendingPromiseResolve: any;\n state: any;\n type: any;\n sdkOwnsLocalTrack: boolean; // todo: remove this when doing SPARK-399695\n ignoreMuteStateChange: boolean;\n\n /**\n * Constructor\n *\n * @param {String} type - audio or video\n * @param {Object} meeting - the meeting object (used for reading current remote mute status)\n * @param {boolean} sdkOwnsLocalTrack - if false, then client app owns the local track (for now that's the case only for multistream meetings)\n */\n constructor(type: string, meeting: any, sdkOwnsLocalTrack: boolean) {\n if (type !== AUDIO && type !== VIDEO) {\n throw new ParameterError('Mute state is designed for handling audio or video only');\n }\n this.type = type;\n this.sdkOwnsLocalTrack = sdkOwnsLocalTrack;\n this.ignoreMuteStateChange = false;\n this.state = {\n client: {\n localMute: false,\n },\n server: {\n localMute: true,\n // because remoteVideoMuted and unmuteVideoAllowed are updated seperately, they might be undefined\n remoteMute: type === AUDIO ? meeting.remoteMuted : meeting.remoteVideoMuted ?? false,\n unmuteAllowed: type === AUDIO ? meeting.unmuteAllowed : meeting.unmuteVideoAllowed ?? true,\n },\n syncToServerInProgress: false,\n };\n // these 2 hold the resolve, reject methods for the promise we returned to the client in last handleClientRequest() call\n this.pendingPromiseResolve = null;\n this.pendingPromiseReject = null;\n }\n\n /**\n * Starts the mute state machine. Needs to be called after a new MuteState instance is created.\n *\n * @param {Object} meeting - the meeting object\n * @returns {void}\n */\n public init(meeting: any) {\n if (!this.sdkOwnsLocalTrack) {\n this.applyUnmuteAllowedToTrack(meeting);\n\n // if we are remotely muted, we need to apply that to the local track now (mute on-entry)\n if (this.state.server.remoteMute) {\n this.muteLocalTrack(meeting, this.state.server.remoteMute, 'remotelyMuted');\n }\n\n const initialMute =\n this.type === AUDIO\n ? meeting.mediaProperties.audioTrack?.muted\n : meeting.mediaProperties.videoTrack?.muted;\n\n LoggerProxy.logger.info(\n `Meeting:muteState#init --> ${this.type}: local track initial mute state: ${initialMute}`\n );\n\n if (initialMute !== undefined) {\n this.state.client.localMute = initialMute;\n\n this.applyClientStateToServer(meeting);\n }\n } else {\n // in the mode where sdkOwnsLocalTrack is false (transcoded meetings),\n // SDK API currently doesn't allow to start with audio/video muted,\n // so we need to apply the initial local mute state (false) to server\n this.state.syncToServerInProgress = true;\n this.sendLocalMuteRequestToServer(meeting)\n .then(() => {\n this.state.syncToServerInProgress = false;\n })\n .catch(() => {\n this.state.syncToServerInProgress = false;\n // not much we can do here...\n });\n }\n }\n\n /**\n * This method needs to be called whenever the local audio/video track has changed.\n * It reapplies the remote mute state onto the new track and also reads the current\n * local mute state from the track and updates the internal state machine and sends\n * any required requests to the server.\n *\n * @param {Object} meeting - the meeting object\n * @returns {void}\n */\n public handleLocalTrackChange(meeting: any) {\n return this.init(meeting);\n }\n\n /**\n * Mutes/unmutes local track\n *\n * @param {Object} meeting - the meeting object\n * @param {Boolean} mute - true to mute the track, false to unmute it\n * @param {ServerMuteReason} reason - reason for muting/unmuting\n * @returns {void}\n */\n private muteLocalTrack(meeting: any, mute: boolean, reason: ServerMuteReason) {\n this.ignoreMuteStateChange = true;\n if (this.type === AUDIO) {\n meeting.mediaProperties.audioTrack?.setServerMuted(mute, reason);\n } else {\n meeting.mediaProperties.videoTrack?.setServerMuted(mute, reason);\n }\n this.ignoreMuteStateChange = false;\n }\n\n /**\n * Handles mute/unmute request from the client/user. Returns a promise that's resolved once the server update is completed or\n * at the point that this request becomese superseded by another client request.\n *\n * The client doesn't have to wait for the returned promise to resolve before calling handleClientRequest() again. If\n * handleClientRequest() is called again before the previous one resolved, the MuteState class will make sure that eventually\n * the server state will match the last requested state from the client.\n *\n * @public\n * @memberof MuteState\n * @param {Object} [meeting] the meeting object\n * @param {Boolean} [mute] true for muting, false for unmuting request\n * @returns {Promise}\n */\n public handleClientRequest(meeting: object, mute?: boolean) {\n // todo: this whole method will be removed in SPARK-399695\n LoggerProxy.logger.info(\n `Meeting:muteState#handleClientRequest --> ${this.type}: user requesting new mute state: ${mute}`\n );\n\n if (!mute && !this.state.server.unmuteAllowed) {\n return Promise.reject(\n new PermissionError('User is not allowed to unmute self (hard mute feature is being used)')\n );\n }\n\n // we don't check if we're already in the same state, because even if we were, we would still have to apply the mute state locally,\n // because the client may have changed the audio/video tracks\n this.state.client.localMute = mute;\n\n this.applyClientStateLocally(meeting);\n\n return new Promise((resolve, reject) => {\n if (this.pendingPromiseResolve) {\n // resolve the last promise we returned to the client as the client has issued a new request that has superseded the previous one\n this.pendingPromiseResolve();\n }\n this.pendingPromiseResolve = resolve;\n this.pendingPromiseReject = reject;\n this.applyClientStateToServer(meeting);\n });\n }\n\n /**\n * This method should be called when the local track mute state is changed\n * @public\n * @memberof MuteState\n * @param {Object} [meeting] the meeting object\n * @param {Boolean} [mute] true for muting, false for unmuting request\n * @returns {void}\n */\n public handleLocalTrackMuteStateChange(meeting?: object, mute?: boolean) {\n if (this.ignoreMuteStateChange) {\n return;\n }\n LoggerProxy.logger.info(\n `Meeting:muteState#handleLocalTrackMuteStateChange --> ${this.type}: local track new mute state: ${mute}`\n );\n\n if (this.pendingPromiseReject) {\n LoggerProxy.logger.error(\n `Meeting:muteState#handleLocalTrackMuteStateChange --> ${this.type}: Local track mute state change handler called while a client request is handled - this should never happen!, mute state: ${mute}`\n );\n }\n\n this.state.client.localMute = mute;\n\n this.applyClientStateToServer(meeting);\n }\n\n /**\n * Applies the current mute state to the local track (by enabling or disabling it accordingly)\n *\n * @public\n * @param {Object} [meeting] the meeting object\n * @param {ServerMuteReason} reason - reason why we're applying our client state to the local track\n * @memberof MuteState\n * @returns {void}\n */\n public applyClientStateLocally(meeting?: any, reason?: ServerMuteReason) {\n if (this.sdkOwnsLocalTrack) {\n if (this.type === AUDIO) {\n meeting.mediaProperties.audioTrack?.setMuted(this.state.client.localMute);\n } else {\n meeting.mediaProperties.videoTrack?.setMuted(this.state.client.localMute);\n }\n } else {\n this.muteLocalTrack(meeting, this.state.client.localMute, reason);\n }\n }\n\n /**\n * Updates the server local and remote mute values so that they match the current client desired state.\n *\n * @private\n * @param {Object} [meeting] the meeting object\n * @memberof MuteState\n * @returns {void}\n */\n private applyClientStateToServer(meeting?: object) {\n if (this.state.syncToServerInProgress) {\n LoggerProxy.logger.info(\n `Meeting:muteState#applyClientStateToServer --> ${this.type}: request to server in progress, we need to wait for it to complete`\n );\n\n return;\n }\n\n const localMuteRequiresSync = this.state.client.localMute !== this.state.server.localMute;\n const remoteMuteRequiresSync = !this.state.client.localMute && this.state.server.remoteMute;\n\n LoggerProxy.logger.info(\n `Meeting:muteState#applyClientStateToServer --> ${this.type}: localMuteRequiresSync: ${localMuteRequiresSync} (${this.state.client.localMute} ?= ${this.state.server.localMute})`\n );\n LoggerProxy.logger.info(\n `Meeting:muteState#applyClientStateToServer --> ${this.type}: remoteMuteRequiresSync: ${remoteMuteRequiresSync}`\n );\n\n if (!localMuteRequiresSync && !remoteMuteRequiresSync) {\n LoggerProxy.logger.info(\n `Meeting:muteState#applyClientStateToServer --> ${this.type}: client state already matching server state, nothing to do`\n );\n\n if (this.pendingPromiseResolve) {\n this.pendingPromiseResolve();\n }\n this.pendingPromiseResolve = null;\n this.pendingPromiseReject = null;\n\n return;\n }\n\n this.state.syncToServerInProgress = true;\n\n // first sync local mute with server\n const localMuteSyncPromise = localMuteRequiresSync\n ? this.sendLocalMuteRequestToServer(meeting)\n : Promise.resolve();\n\n localMuteSyncPromise\n .then(() =>\n // then follow it up with remote mute sync\n remoteMuteRequiresSync ? this.sendRemoteMuteRequestToServer(meeting) : Promise.resolve()\n )\n .then(() => {\n this.state.syncToServerInProgress = false;\n LoggerProxy.logger.info(\n `Meeting:muteState#applyClientStateToServer --> ${this.type}: sync with server completed`\n );\n\n // need to check if a new sync is required, because this.state.client may have changed while we were doing the current sync\n this.applyClientStateToServer(meeting);\n })\n .catch((e) => {\n this.state.syncToServerInProgress = false;\n\n if (this.pendingPromiseReject) {\n this.pendingPromiseReject(e);\n }\n this.pendingPromiseResolve = null;\n this.pendingPromiseReject = null;\n\n this.applyServerMuteToLocalTrack(meeting, 'clientRequestFailed');\n });\n }\n\n /**\n * Sets the local mute value in the server\n *\n * @private\n * @param {Object} [meeting] the meeting object\n * @memberof MuteState\n * @returns {Promise}\n */\n private sendLocalMuteRequestToServer(meeting?: any) {\n const audioMuted = this.type === AUDIO ? this.state.client.localMute : undefined;\n const videoMuted = this.type === VIDEO ? this.state.client.localMute : undefined;\n\n LoggerProxy.logger.info(\n `Meeting:muteState#sendLocalMuteRequestToServer --> ${this.type}: sending local mute (audio=${audioMuted}, video=${videoMuted}) to server`\n );\n\n return MeetingUtil.remoteUpdateAudioVideo(meeting, audioMuted, videoMuted)\n .then((locus) => {\n LoggerProxy.logger.info(\n `Meeting:muteState#sendLocalMuteRequestToServer --> ${this.type}: local mute (audio=${audioMuted}, video=${videoMuted}) applied to server`\n );\n\n this.state.server.localMute = this.type === AUDIO ? audioMuted : videoMuted;\n\n if (locus) {\n meeting.locusInfo.onDeltaLocus(locus);\n }\n\n return locus;\n })\n .catch((remoteUpdateError) => {\n LoggerProxy.logger.warn(\n `Meeting:muteState#sendLocalMuteRequestToServer --> ${this.type}: failed to apply local mute (audio=${audioMuted}, video=${videoMuted}) to server: ${remoteUpdateError}`\n );\n\n return Promise.reject(remoteUpdateError);\n });\n }\n\n /**\n * Sets the remote mute value in the server\n *\n * @private\n * @param {Object} [meeting] the meeting object\n * @memberof MuteState\n * @returns {Promise}\n */\n private sendRemoteMuteRequestToServer(meeting?: any) {\n const remoteMute = this.state.client.localMute;\n\n LoggerProxy.logger.info(\n `Meeting:muteState#sendRemoteMuteRequestToServer --> ${this.type}: sending remote mute:${remoteMute} to server`\n );\n\n return meeting.members\n .muteMember(meeting.members.selfId, remoteMute, this.type === AUDIO)\n .then(() => {\n LoggerProxy.logger.info(\n `Meeting:muteState#sendRemoteMuteRequestToServer --> ${this.type}: remote mute:${remoteMute} applied to server`\n );\n\n this.state.server.remoteMute = remoteMute;\n })\n .catch((remoteUpdateError) => {\n LoggerProxy.logger.warn(\n `Meeting:muteState#sendRemoteMuteRequestToServer --> ${this.type}: failed to apply remote mute ${remoteMute} to server: ${remoteUpdateError}`\n );\n\n return Promise.reject(remoteUpdateError);\n });\n }\n\n /** Sets the mute state of the local track according to what server thinks is our state\n * @param {Object} meeting - the meeting object\n * @param {ServerMuteReason} serverMuteReason - reason why we're applying server mute to the local track\n * @returns {void}\n */\n private applyServerMuteToLocalTrack(meeting: any, serverMuteReason: ServerMuteReason) {\n if (!this.sdkOwnsLocalTrack) {\n const muted = this.state.server.localMute || this.state.server.remoteMute;\n\n // update the local track mute state, but not this.state.client.localMute\n this.muteLocalTrack(meeting, muted, serverMuteReason);\n }\n }\n\n /** Applies the current value for unmute allowed to the underlying track\n *\n * @param {Meeting} meeting\n * @returns {void}\n */\n private applyUnmuteAllowedToTrack(meeting: any) {\n if (!this.sdkOwnsLocalTrack) {\n if (this.type === AUDIO) {\n meeting.mediaProperties.audioTrack?.setUnmuteAllowed(this.state.server.unmuteAllowed);\n } else {\n meeting.mediaProperties.videoTrack?.setUnmuteAllowed(this.state.server.unmuteAllowed);\n }\n }\n }\n\n /**\n * This method should be called whenever the server remote mute state is changed\n *\n * @public\n * @memberof MuteState\n * @param {Meeting} meeting\n * @param {Boolean} [muted] true if user is remotely muted, false otherwise\n * @param {Boolean} [unmuteAllowed] indicates if user is allowed to unmute self (false when \"hard mute\" feature is used)\n * @returns {undefined}\n */\n public handleServerRemoteMuteUpdate(meeting: any, muted?: boolean, unmuteAllowed?: boolean) {\n LoggerProxy.logger.info(\n `Meeting:muteState#handleServerRemoteMuteUpdate --> ${this.type}: updating server remoteMute to (${muted})`\n );\n if (unmuteAllowed !== undefined) {\n this.state.server.unmuteAllowed = unmuteAllowed;\n this.applyUnmuteAllowedToTrack(meeting);\n }\n if (muted !== undefined) {\n this.state.server.remoteMute = muted;\n this.applyServerMuteToLocalTrack(meeting, 'remotelyMuted');\n }\n }\n\n /**\n * This method should be called whenever we receive from the server a requirement to locally unmute\n *\n * @public\n * @memberof MuteState\n * @param {Object} [meeting] the meeting object\n * @returns {undefined}\n */\n public handleServerLocalUnmuteRequired(meeting?: object) {\n LoggerProxy.logger.info(\n `Meeting:muteState#handleServerLocalUnmuteRequired --> ${this.type}: localAudioUnmuteRequired received -> doing local unmute`\n );\n\n // todo: I'm seeing \"you can now unmute yourself \" popup when this happens - but same thing happens on web.w.c so we can ignore for now\n this.state.server.remoteMute = false;\n this.state.client.localMute = false;\n\n if (this.pendingPromiseReject) {\n this.pendingPromiseReject(\n new Error('Server requested local unmute - this overrides any client request in progress')\n );\n this.pendingPromiseResolve = null;\n this.pendingPromiseReject = null;\n }\n\n this.applyClientStateLocally(meeting, 'localUnmuteRequired');\n this.applyClientStateToServer(meeting);\n }\n\n /**\n * Returns true if the user is locally or remotely muted\n *\n * @public\n * @memberof MuteState\n * @returns {Boolean}\n */\n public isMuted() {\n return (\n this.state.client.localMute || this.state.server.localMute || this.state.server.remoteMute\n );\n }\n\n /**\n * Returns true if the user is remotely muted\n *\n * @public\n * @memberof MuteState\n * @returns {Boolean}\n */\n public isRemotelyMuted() {\n return this.state.server.remoteMute;\n }\n\n /**\n * Returns true if unmute is allowed\n *\n * @public\n * @memberof MuteState\n * @returns {Boolean}\n */\n public isUnmuteAllowed() {\n return this.state.server.unmuteAllowed;\n }\n\n /**\n * Returns true if the user is locally muted\n *\n * @public\n * @memberof MuteState\n * @returns {Boolean}\n */\n public isLocallyMuted() {\n return this.state.client.localMute || this.state.server.localMute;\n }\n\n /**\n * Returns true if the user is muted as a result of the client request (and not remotely muted)\n *\n * @public\n * @memberof MuteState\n * @returns {Boolean}\n */\n public isSelf() {\n return this.state.client.localMute && !this.state.server.remoteMute;\n }\n\n // defined for backwards compatibility with the old AudioStateMachine/VideoStateMachine classes\n get muted() {\n return this.isMuted();\n }\n\n // defined for backwards compatibility with the old AudioStateMachine/VideoStateMachine classes\n get self() {\n return this.isSelf();\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"names":["createMuteState","type","meeting","enabled","LoggerProxy","logger","info","id","muteState","MuteState","AUDIO","VIDEO","ParameterError","ignoreMuteStateChange","state","client","localMute","server","remoteMute","remoteMuted","remoteVideoMuted","unmuteAllowed","unmuteVideoAllowed","syncToServerInProgress","applyUnmuteAllowedToTrack","muteLocalTrack","initialMute","mediaProperties","audioTrack","muted","videoTrack","undefined","applyClientStateToServer","init","enable","mute","reason","setServerMuted","localMuteState","getClientLocalMuteState","localMuteRequiresSync","remoteMuteRequiresSync","localMuteSyncPromise","sendLocalMuteRequestToServer","resolve","then","sendRemoteMuteRequestToServer","catch","e","warn","applyServerMuteToLocalTrack","audioMuted","videoMuted","MeetingUtil","remoteUpdateAudioVideo","locus","locusInfo","onDeltaLocus","remoteUpdateError","reject","members","muteMember","selfId","serverMuteReason","setUnmuteAllowed","applyClientStateLocally"],"sources":["muteState.ts"],"sourcesContent":["import {ServerMuteReason} from '@webex/media-helpers';\nimport LoggerProxy from '../common/logs/logger-proxy';\nimport ParameterError from '../common/errors/parameter';\nimport MeetingUtil from './util';\nimport {AUDIO, VIDEO} from '../constants';\n\n// eslint-disable-next-line import/prefer-default-export\nexport const createMuteState = (type, meeting, enabled: boolean) => {\n // todo: remove the meeting argument (SPARK-399695)\n\n LoggerProxy.logger.info(\n `Meeting:muteState#createMuteState --> ${type}: creating MuteState for meeting id ${meeting?.id}`\n );\n\n const muteState = new MuteState(type, meeting, enabled);\n\n return muteState;\n};\n\n/** The purpose of this class is to manage the local and remote mute state and make sure that the server state always matches\n the last requested state by the client.\n\n More info about Locus muting API: https://sqbu-github.cisco.com/pages/WebExSquared/locus/guides/mute.html#\n\n This class is exported only for unit tests. It should never be instantiated directly with new MuteState(), instead createMuteState() should be called\n*/\nexport class MuteState {\n state: {\n client: {\n enabled: boolean; // indicates if audio/video is enabled at all or not\n localMute: boolean;\n };\n server: {localMute: boolean; remoteMute: boolean; unmuteAllowed: boolean};\n syncToServerInProgress: boolean;\n };\n\n type: any;\n ignoreMuteStateChange: boolean;\n\n /**\n * Constructor\n *\n * @param {String} type - audio or video\n * @param {Object} meeting - the meeting object (used for reading current remote mute status)\n * @param {boolean} enabled - whether the client audio/video is enabled at all\n */\n constructor(type: string, meeting: any, enabled: boolean) {\n if (type !== AUDIO && type !== VIDEO) {\n throw new ParameterError('Mute state is designed for handling audio or video only');\n }\n this.type = type;\n this.ignoreMuteStateChange = false;\n this.state = {\n client: {\n enabled,\n localMute: true,\n },\n server: {\n localMute: true,\n // because remoteVideoMuted and unmuteVideoAllowed are updated seperately, they might be undefined\n remoteMute: type === AUDIO ? meeting.remoteMuted : meeting.remoteVideoMuted ?? false,\n unmuteAllowed: type === AUDIO ? meeting.unmuteAllowed : meeting.unmuteVideoAllowed ?? true,\n },\n syncToServerInProgress: false,\n };\n }\n\n /**\n * Starts the mute state machine. Needs to be called after a new MuteState instance is created.\n *\n * @param {Object} meeting - the meeting object\n * @returns {void}\n */\n public init(meeting: any) {\n this.applyUnmuteAllowedToTrack(meeting);\n\n // if we are remotely muted, we need to apply that to the local track now (mute on-entry)\n if (this.state.server.remoteMute) {\n this.muteLocalTrack(meeting, this.state.server.remoteMute, 'remotelyMuted');\n }\n\n const initialMute =\n this.type === AUDIO\n ? meeting.mediaProperties.audioTrack?.muted\n : meeting.mediaProperties.videoTrack?.muted;\n\n LoggerProxy.logger.info(\n `Meeting:muteState#init --> ${this.type}: local track initial mute state: ${initialMute}`\n );\n\n if (initialMute !== undefined) {\n this.state.client.localMute = initialMute;\n } else {\n // there is no track, so it's like we are locally muted\n // (this is important especially for transcoded meetings, in which the SDP m-line direction always stays \"sendrecv\")\n this.state.client.localMute = true;\n }\n this.applyClientStateToServer(meeting);\n }\n\n /**\n * This method needs to be called whenever the local audio/video track has changed.\n * It reapplies the remote mute state onto the new track and also reads the current\n * local mute state from the track and updates the internal state machine and sends\n * any required requests to the server.\n *\n * @param {Object} meeting - the meeting object\n * @returns {void}\n */\n public handleLocalTrackChange(meeting: any) {\n return this.init(meeting);\n }\n\n /**\n * Enables/disables audio/video\n *\n * @param {Object} meeting - the meeting object\n * @param {boolean} enable\n * @returns {void}\n */\n public enable(meeting: any, enable: boolean) {\n this.state.client.enabled = enable;\n\n this.applyClientStateToServer(meeting);\n }\n\n /**\n * Mutes/unmutes local track\n *\n * @param {Object} meeting - the meeting object\n * @param {Boolean} mute - true to mute the track, false to unmute it\n * @param {ServerMuteReason} reason - reason for muting/unmuting\n * @returns {void}\n */\n private muteLocalTrack(meeting: any, mute: boolean, reason: ServerMuteReason) {\n this.ignoreMuteStateChange = true;\n if (this.type === AUDIO) {\n meeting.mediaProperties.audioTrack?.setServerMuted(mute, reason);\n } else {\n meeting.mediaProperties.videoTrack?.setServerMuted(mute, reason);\n }\n this.ignoreMuteStateChange = false;\n }\n\n /**\n * This method should be called when the local track mute state is changed\n * @public\n * @memberof MuteState\n * @param {Object} [meeting] the meeting object\n * @param {Boolean} [mute] true for muting, false for unmuting request\n * @returns {void}\n */\n public handleLocalTrackMuteStateChange(meeting?: object, mute?: boolean) {\n if (this.ignoreMuteStateChange) {\n return;\n }\n LoggerProxy.logger.info(\n `Meeting:muteState#handleLocalTrackMuteStateChange --> ${this.type}: local track new mute state: ${mute}`\n );\n\n this.state.client.localMute = mute;\n\n this.applyClientStateToServer(meeting);\n }\n\n /**\n * Applies the current mute state to the local track (by enabling or disabling it accordingly)\n *\n * @public\n * @param {Object} [meeting] the meeting object\n * @param {ServerMuteReason} reason - reason why we're applying our client state to the local track\n * @memberof MuteState\n * @returns {void}\n */\n public applyClientStateLocally(meeting?: any, reason?: ServerMuteReason) {\n this.muteLocalTrack(meeting, this.state.client.localMute, reason);\n }\n\n /** Returns true if client is locally muted - it takes into account not just the client local mute state,\n * but also whether audio/video is enabled at all\n *\n * @returns {boolean}\n */\n private getClientLocalMuteState() {\n return this.state.client.enabled ? this.state.client.localMute : true;\n }\n\n /**\n * Updates the server local and remote mute values so that they match the current client desired state.\n *\n * @private\n * @param {Object} [meeting] the meeting object\n * @memberof MuteState\n * @returns {void}\n */\n private applyClientStateToServer(meeting?: any) {\n if (this.state.syncToServerInProgress) {\n LoggerProxy.logger.info(\n `Meeting:muteState#applyClientStateToServer --> ${this.type}: request to server in progress, we need to wait for it to complete`\n );\n\n return;\n }\n\n const localMuteState = this.getClientLocalMuteState();\n const localMuteRequiresSync = localMuteState !== this.state.server.localMute;\n const remoteMuteRequiresSync = !localMuteState && this.state.server.remoteMute;\n\n LoggerProxy.logger.info(\n `Meeting:muteState#applyClientStateToServer --> ${this.type}: localMuteRequiresSync: ${localMuteRequiresSync} (${localMuteState} ?= ${this.state.server.localMute})`\n );\n LoggerProxy.logger.info(\n `Meeting:muteState#applyClientStateToServer --> ${this.type}: remoteMuteRequiresSync: ${remoteMuteRequiresSync}`\n );\n\n if (!localMuteRequiresSync && !remoteMuteRequiresSync) {\n LoggerProxy.logger.info(\n `Meeting:muteState#applyClientStateToServer --> ${this.type}: client state already matching server state, nothing to do`\n );\n\n return;\n }\n\n this.state.syncToServerInProgress = true;\n\n // first sync local mute with server\n const localMuteSyncPromise = localMuteRequiresSync\n ? this.sendLocalMuteRequestToServer(meeting)\n : Promise.resolve();\n\n localMuteSyncPromise\n .then(() =>\n // then follow it up with remote mute sync\n remoteMuteRequiresSync ? this.sendRemoteMuteRequestToServer(meeting) : Promise.resolve()\n )\n .then(() => {\n this.state.syncToServerInProgress = false;\n LoggerProxy.logger.info(\n `Meeting:muteState#applyClientStateToServer --> ${this.type}: sync with server completed`\n );\n\n // need to check if a new sync is required, because this.state.client may have changed while we were doing the current sync\n this.applyClientStateToServer(meeting);\n })\n .catch((e) => {\n this.state.syncToServerInProgress = false;\n\n LoggerProxy.logger.warn(\n `Meeting:muteState#applyClientStateToServer --> ${this.type}: error: ${e}`\n );\n\n this.applyServerMuteToLocalTrack(meeting, 'clientRequestFailed');\n });\n }\n\n /**\n * Sets the local mute value in the server\n *\n * @private\n * @param {Object} [meeting] the meeting object\n * @memberof MuteState\n * @returns {Promise}\n */\n private sendLocalMuteRequestToServer(meeting?: any) {\n const audioMuted = this.type === AUDIO ? this.getClientLocalMuteState() : undefined;\n const videoMuted = this.type === VIDEO ? this.getClientLocalMuteState() : undefined;\n\n LoggerProxy.logger.info(\n `Meeting:muteState#sendLocalMuteRequestToServer --> ${this.type}: sending local mute (audio=${audioMuted}, video=${videoMuted}) to server`\n );\n\n return MeetingUtil.remoteUpdateAudioVideo(meeting, audioMuted, videoMuted)\n .then((locus) => {\n LoggerProxy.logger.info(\n `Meeting:muteState#sendLocalMuteRequestToServer --> ${this.type}: local mute (audio=${audioMuted}, video=${videoMuted}) applied to server`\n );\n\n this.state.server.localMute = this.type === AUDIO ? audioMuted : videoMuted;\n\n if (locus) {\n meeting.locusInfo.onDeltaLocus(locus);\n }\n\n return locus;\n })\n .catch((remoteUpdateError) => {\n LoggerProxy.logger.warn(\n `Meeting:muteState#sendLocalMuteRequestToServer --> ${this.type}: failed to apply local mute (audio=${audioMuted}, video=${videoMuted}) to server: ${remoteUpdateError}`\n );\n\n return Promise.reject(remoteUpdateError);\n });\n }\n\n /**\n * Sets the remote mute value in the server\n *\n * @private\n * @param {Object} [meeting] the meeting object\n * @memberof MuteState\n * @returns {Promise}\n */\n private sendRemoteMuteRequestToServer(meeting?: any) {\n const remoteMute = this.getClientLocalMuteState();\n\n LoggerProxy.logger.info(\n `Meeting:muteState#sendRemoteMuteRequestToServer --> ${this.type}: sending remote mute:${remoteMute} to server`\n );\n\n return meeting.members\n .muteMember(meeting.members.selfId, remoteMute, this.type === AUDIO)\n .then(() => {\n LoggerProxy.logger.info(\n `Meeting:muteState#sendRemoteMuteRequestToServer --> ${this.type}: remote mute:${remoteMute} applied to server`\n );\n\n this.state.server.remoteMute = remoteMute;\n })\n .catch((remoteUpdateError) => {\n LoggerProxy.logger.warn(\n `Meeting:muteState#sendRemoteMuteRequestToServer --> ${this.type}: failed to apply remote mute ${remoteMute} to server: ${remoteUpdateError}`\n );\n\n return Promise.reject(remoteUpdateError);\n });\n }\n\n /** Sets the mute state of the local track according to what server thinks is our state\n * @param {Object} meeting - the meeting object\n * @param {ServerMuteReason} serverMuteReason - reason why we're applying server mute to the local track\n * @returns {void}\n */\n private applyServerMuteToLocalTrack(meeting: any, serverMuteReason: ServerMuteReason) {\n const muted = this.state.server.localMute || this.state.server.remoteMute;\n\n // update the local track mute state, but not this.state.client.localMute\n this.muteLocalTrack(meeting, muted, serverMuteReason);\n }\n\n /** Applies the current value for unmute allowed to the underlying track\n *\n * @param {Meeting} meeting\n * @returns {void}\n */\n private applyUnmuteAllowedToTrack(meeting: any) {\n if (this.type === AUDIO) {\n meeting.mediaProperties.audioTrack?.setUnmuteAllowed(this.state.server.unmuteAllowed);\n } else {\n meeting.mediaProperties.videoTrack?.setUnmuteAllowed(this.state.server.unmuteAllowed);\n }\n }\n\n /**\n * This method should be called whenever the server remote mute state is changed\n *\n * @public\n * @memberof MuteState\n * @param {Meeting} meeting\n * @param {Boolean} [muted] true if user is remotely muted, false otherwise\n * @param {Boolean} [unmuteAllowed] indicates if user is allowed to unmute self (false when \"hard mute\" feature is used)\n * @returns {undefined}\n */\n public handleServerRemoteMuteUpdate(meeting: any, muted?: boolean, unmuteAllowed?: boolean) {\n LoggerProxy.logger.info(\n `Meeting:muteState#handleServerRemoteMuteUpdate --> ${this.type}: updating server remoteMute to (${muted})`\n );\n if (unmuteAllowed !== undefined) {\n this.state.server.unmuteAllowed = unmuteAllowed;\n this.applyUnmuteAllowedToTrack(meeting);\n }\n if (muted !== undefined) {\n this.state.server.remoteMute = muted;\n this.applyServerMuteToLocalTrack(meeting, 'remotelyMuted');\n }\n }\n\n /**\n * This method should be called whenever we receive from the server a requirement to locally unmute\n *\n * @public\n * @memberof MuteState\n * @param {Object} [meeting] the meeting object\n * @returns {undefined}\n */\n public handleServerLocalUnmuteRequired(meeting?: object) {\n if (!this.state.client.enabled) {\n LoggerProxy.logger.warn(\n `Meeting:muteState#handleServerLocalUnmuteRequired --> ${this.type}: localAudioUnmuteRequired received while ${this.type} is disabled -> local unmute will not result in ${this.type} being sent`\n );\n } else {\n LoggerProxy.logger.info(\n `Meeting:muteState#handleServerLocalUnmuteRequired --> ${this.type}: localAudioUnmuteRequired received -> doing local unmute`\n );\n }\n\n // todo: I'm seeing \"you can now unmute yourself \" popup when this happens - but same thing happens on web.w.c so we can ignore for now\n this.state.server.remoteMute = false;\n this.state.client.localMute = false;\n\n this.applyClientStateLocally(meeting, 'localUnmuteRequired');\n this.applyClientStateToServer(meeting);\n }\n\n /**\n * Returns true if the user is locally or remotely muted.\n * It only checks the mute status, ignoring the fact whether audio/video is enabled.\n *\n * @public\n * @memberof MuteState\n * @returns {Boolean}\n */\n public isMuted() {\n return (\n this.state.client.localMute || this.state.server.localMute || this.state.server.remoteMute\n );\n }\n\n /**\n * Returns true if the user is remotely muted\n *\n * @public\n * @memberof MuteState\n * @returns {Boolean}\n */\n public isRemotelyMuted() {\n return this.state.server.remoteMute;\n }\n\n /**\n * Returns true if unmute is allowed\n *\n * @public\n * @memberof MuteState\n * @returns {Boolean}\n */\n public isUnmuteAllowed() {\n return this.state.server.unmuteAllowed;\n }\n\n /**\n * Returns true if the user is locally muted or audio/video is disabled\n *\n * @public\n * @memberof MuteState\n * @returns {Boolean}\n */\n public isLocallyMuted() {\n return this.getClientLocalMuteState();\n }\n}\n"],"mappings":"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"}
@@ -137,16 +137,11 @@ var MeetingUtil = {
137
137
  // make sure we send last metrics before we close the peerconnection
138
138
  var stopStatsAnalyzer = meeting.statsAnalyzer ? meeting.statsAnalyzer.stopAnalyzer() : _promise.default.resolve();
139
139
  return stopStatsAnalyzer.then(function () {
140
- return meeting.closeLocalStream();
141
- }).then(function () {
142
- return meeting.closeLocalShare();
143
- }).then(function () {
144
140
  return meeting.closeRemoteTracks();
145
141
  }).then(function () {
146
142
  return meeting.closePeerConnections();
147
143
  }).then(function () {
148
- meeting.unsetLocalVideoTrack();
149
- meeting.unsetLocalShareTrack();
144
+ meeting.cleanupLocalTracks();
150
145
  meeting.unsetRemoteTracks();
151
146
  meeting.unsetPeerConnections();
152
147
  meeting.reconnectionManager.cleanUp();
@@ -263,23 +258,6 @@ var MeetingUtil = {
263
258
  return _promise.default.reject(new _joinMeeting.default(options, 'Error Joining Meeting', err));
264
259
  });
265
260
  },
266
- validateOptions: function validateOptions(options) {
267
- var sendVideo = options.sendVideo,
268
- sendAudio = options.sendAudio,
269
- sendShare = options.sendShare,
270
- localStream = options.localStream,
271
- localShare = options.localShare;
272
- if (sendVideo && !MeetingUtil.getTrack(localStream).videoTrack) {
273
- return _promise.default.reject(new _parameter.default('please pass valid video streams'));
274
- }
275
- if (sendAudio && !MeetingUtil.getTrack(localStream).audioTrack) {
276
- return _promise.default.reject(new _parameter.default('please pass valid audio streams'));
277
- }
278
- if (sendShare && !MeetingUtil.getTrack(localShare).videoTrack) {
279
- return _promise.default.reject(new _parameter.default('please pass valid share streams'));
280
- }
281
- return _promise.default.resolve();
282
- },
283
261
  getTrack: function getTrack(stream) {
284
262
  var audioTrack = null;
285
263
  var videoTrack = null;