@webex/plugin-meetings 3.0.0-next.2 → 3.0.0-next.21

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 (94) hide show
  1. package/dist/breakouts/breakout.js +1 -1
  2. package/dist/breakouts/index.js +1 -1
  3. package/dist/constants.d.ts +3 -9
  4. package/dist/constants.js +4 -9
  5. package/dist/constants.js.map +1 -1
  6. package/dist/index.d.ts +1 -1
  7. package/dist/index.js +6 -0
  8. package/dist/index.js.map +1 -1
  9. package/dist/interpretation/index.js +3 -3
  10. package/dist/interpretation/index.js.map +1 -1
  11. package/dist/interpretation/siLanguage.js +1 -1
  12. package/dist/locus-info/mediaSharesUtils.js +15 -1
  13. package/dist/locus-info/mediaSharesUtils.js.map +1 -1
  14. package/dist/media/index.js +4 -1
  15. package/dist/media/index.js.map +1 -1
  16. package/dist/mediaQualityMetrics/config.d.ts +9 -1
  17. package/dist/mediaQualityMetrics/config.js +10 -1
  18. package/dist/mediaQualityMetrics/config.js.map +1 -1
  19. package/dist/meeting/index.d.ts +18 -7
  20. package/dist/meeting/index.js +745 -567
  21. package/dist/meeting/index.js.map +1 -1
  22. package/dist/meeting/muteState.d.ts +2 -8
  23. package/dist/meeting/muteState.js +37 -25
  24. package/dist/meeting/muteState.js.map +1 -1
  25. package/dist/meeting/request.d.ts +3 -0
  26. package/dist/meeting/request.js +32 -23
  27. package/dist/meeting/request.js.map +1 -1
  28. package/dist/meeting/util.js +1 -0
  29. package/dist/meeting/util.js.map +1 -1
  30. package/dist/multistream/mediaRequestManager.d.ts +1 -2
  31. package/dist/multistream/mediaRequestManager.js.map +1 -1
  32. package/dist/multistream/remoteMediaGroup.d.ts +1 -1
  33. package/dist/multistream/remoteMediaGroup.js.map +1 -1
  34. package/dist/multistream/remoteMediaManager.d.ts +1 -2
  35. package/dist/multistream/remoteMediaManager.js.map +1 -1
  36. package/dist/multistream/sendSlotManager.d.ts +1 -2
  37. package/dist/multistream/sendSlotManager.js.map +1 -1
  38. package/dist/reachability/request.js +12 -10
  39. package/dist/reachability/request.js.map +1 -1
  40. package/dist/reconnection-manager/index.js +2 -1
  41. package/dist/reconnection-manager/index.js.map +1 -1
  42. package/dist/roap/index.d.ts +10 -2
  43. package/dist/roap/index.js +15 -0
  44. package/dist/roap/index.js.map +1 -1
  45. package/dist/roap/request.js +3 -3
  46. package/dist/roap/request.js.map +1 -1
  47. package/dist/roap/turnDiscovery.d.ts +64 -17
  48. package/dist/roap/turnDiscovery.js +307 -126
  49. package/dist/roap/turnDiscovery.js.map +1 -1
  50. package/dist/statsAnalyzer/index.js +61 -41
  51. package/dist/statsAnalyzer/index.js.map +1 -1
  52. package/dist/webinar/index.js +1 -1
  53. package/package.json +22 -22
  54. package/src/constants.ts +3 -9
  55. package/src/index.ts +1 -0
  56. package/src/interpretation/index.ts +2 -2
  57. package/src/locus-info/mediaSharesUtils.ts +16 -0
  58. package/src/media/index.ts +3 -1
  59. package/src/mediaQualityMetrics/config.ts +11 -1
  60. package/src/meeting/index.ts +264 -90
  61. package/src/meeting/muteState.ts +34 -20
  62. package/src/meeting/request.ts +18 -2
  63. package/src/meeting/util.ts +1 -0
  64. package/src/multistream/mediaRequestManager.ts +1 -1
  65. package/src/multistream/remoteMediaGroup.ts +1 -1
  66. package/src/multistream/remoteMediaManager.ts +1 -2
  67. package/src/multistream/sendSlotManager.ts +1 -2
  68. package/src/reachability/request.ts +15 -11
  69. package/src/reconnection-manager/index.ts +1 -1
  70. package/src/roap/index.ts +25 -3
  71. package/src/roap/request.ts +3 -3
  72. package/src/roap/turnDiscovery.ts +244 -78
  73. package/src/statsAnalyzer/index.ts +72 -43
  74. package/test/integration/spec/journey.js +14 -14
  75. package/test/integration/spec/space-meeting.js +1 -1
  76. package/test/unit/spec/interpretation/index.ts +4 -1
  77. package/test/unit/spec/locus-info/mediaSharesUtils.ts +9 -0
  78. package/test/unit/spec/media/index.ts +89 -78
  79. package/test/unit/spec/meeting/index.js +611 -125
  80. package/test/unit/spec/meeting/muteState.js +219 -67
  81. package/test/unit/spec/meeting/request.js +21 -0
  82. package/test/unit/spec/meeting/utils.js +6 -1
  83. package/test/unit/spec/meetings/index.js +27 -20
  84. package/test/unit/spec/multistream/remoteMediaGroup.ts +0 -1
  85. package/test/unit/spec/multistream/remoteMediaManager.ts +0 -1
  86. package/test/unit/spec/reachability/request.js +15 -7
  87. package/test/unit/spec/reconnection-manager/index.js +28 -0
  88. package/test/unit/spec/roap/index.ts +61 -6
  89. package/test/unit/spec/roap/turnDiscovery.ts +298 -16
  90. package/test/unit/spec/stats-analyzer/index.js +183 -8
  91. package/dist/member/member.types.d.ts +0 -11
  92. package/dist/member/member.types.js +0 -17
  93. package/dist/member/member.types.js.map +0 -1
  94. package/src/member/member.types.ts +0 -13
@@ -150,15 +150,30 @@ export class MuteState {
150
150
  * @param {Boolean} [mute] true for muting, false for unmuting request
151
151
  * @returns {void}
152
152
  */
153
- public handleLocalStreamMuteStateChange(meeting?: object, mute?: boolean) {
153
+ public handleLocalStreamMuteStateChange(meeting?: any) {
154
154
  if (this.ignoreMuteStateChange) {
155
155
  return;
156
156
  }
157
+
158
+ // either user or system may have triggered a mute state change, but localMute should reflect both
159
+ let newMuteState: boolean;
160
+ let userMuteState: boolean;
161
+ let systemMuteState: boolean;
162
+ if (this.type === AUDIO) {
163
+ newMuteState = meeting.mediaProperties.audioStream?.muted;
164
+ userMuteState = meeting.mediaProperties.audioStream?.userMuted;
165
+ systemMuteState = meeting.mediaProperties.audioStream?.systemMuted;
166
+ } else {
167
+ newMuteState = meeting.mediaProperties.videoStream?.muted;
168
+ userMuteState = meeting.mediaProperties.videoStream?.userMuted;
169
+ systemMuteState = meeting.mediaProperties.videoStream?.systemMuted;
170
+ }
171
+
157
172
  LoggerProxy.logger.info(
158
- `Meeting:muteState#handleLocalStreamMuteStateChange --> ${this.type}: local stream new mute state: ${mute}`
173
+ `Meeting:muteState#handleLocalStreamMuteStateChange --> ${this.type}: local stream new mute state: ${newMuteState} (user mute: ${userMuteState}, system mute: ${systemMuteState})`
159
174
  );
160
175
 
161
- this.state.client.localMute = mute;
176
+ this.state.client.localMute = newMuteState;
162
177
 
163
178
  this.applyClientStateToServer(meeting);
164
179
  }
@@ -249,7 +264,12 @@ export class MuteState {
249
264
  `Meeting:muteState#applyClientStateToServer --> ${this.type}: error: ${e}`
250
265
  );
251
266
 
252
- this.applyServerMuteToLocalStream(meeting, 'clientRequestFailed');
267
+ // failed to apply client state to server, so revert stream mute state to server state
268
+ this.muteLocalStream(
269
+ meeting,
270
+ this.state.server.localMute || this.state.server.remoteMute,
271
+ 'clientRequestFailed'
272
+ );
253
273
  });
254
274
  }
255
275
 
@@ -325,18 +345,6 @@ export class MuteState {
325
345
  });
326
346
  }
327
347
 
328
- /** Sets the mute state of the local stream according to what server thinks is our state
329
- * @param {Object} meeting - the meeting object
330
- * @param {ServerMuteReason} serverMuteReason - reason why we're applying server mute to the local stream
331
- * @returns {void}
332
- */
333
- private applyServerMuteToLocalStream(meeting: any, serverMuteReason: ServerMuteReason) {
334
- const muted = this.state.server.localMute || this.state.server.remoteMute;
335
-
336
- // update the local stream mute state, but not this.state.client.localMute
337
- this.muteLocalStream(meeting, muted, serverMuteReason);
338
- }
339
-
340
348
  /** Applies the current value for unmute allowed to the underlying stream
341
349
  *
342
350
  * @param {Meeting} meeting
@@ -371,7 +379,7 @@ export class MuteState {
371
379
  }
372
380
  if (muted !== undefined) {
373
381
  this.state.server.remoteMute = muted;
374
- this.applyServerMuteToLocalStream(meeting, 'remotelyMuted');
382
+ this.muteLocalStream(meeting, muted, 'remotelyMuted');
375
383
  }
376
384
  }
377
385
 
@@ -383,7 +391,7 @@ export class MuteState {
383
391
  * @param {Object} [meeting] the meeting object
384
392
  * @returns {undefined}
385
393
  */
386
- public handleServerLocalUnmuteRequired(meeting?: object) {
394
+ public handleServerLocalUnmuteRequired(meeting?: any) {
387
395
  if (!this.state.client.enabled) {
388
396
  LoggerProxy.logger.warn(
389
397
  `Meeting:muteState#handleServerLocalUnmuteRequired --> ${this.type}: localAudioUnmuteRequired received while ${this.type} is disabled -> local unmute will not result in ${this.type} being sent`
@@ -396,9 +404,15 @@ export class MuteState {
396
404
 
397
405
  // 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
398
406
  this.state.server.remoteMute = false;
399
- this.state.client.localMute = false;
400
407
 
401
- this.applyClientStateLocally(meeting, 'localUnmuteRequired');
408
+ // change user mute state to false, but keep localMute true if overall mute state is still true
409
+ this.muteLocalStream(meeting, false, 'localUnmuteRequired');
410
+ if (this.type === AUDIO) {
411
+ this.state.client.localMute = meeting.mediaProperties.audioStream?.muted;
412
+ } else {
413
+ this.state.client.localMute = meeting.mediaProperties.videoStream?.muted;
414
+ }
415
+
402
416
  this.applyClientStateToServer(meeting);
403
417
  }
404
418
 
@@ -103,6 +103,7 @@ export default class MeetingRequest extends StatelessWebexPlugin {
103
103
  * @param {String} options.locale,
104
104
  * @param {Array} options.deviceCapabilities
105
105
  * @param {boolean} options.liveAnnotationSupported
106
+ * @param {String} options.alias
106
107
  * @returns {Promise}
107
108
  */
108
109
  async joinMeeting(options: {
@@ -122,11 +123,13 @@ export default class MeetingRequest extends StatelessWebexPlugin {
122
123
  meetingNumber: any;
123
124
  permissionToken: any;
124
125
  preferTranscoding: any;
126
+ reachability: any;
125
127
  breakoutsSupported: boolean;
126
128
  locale?: string;
127
129
  deviceCapabilities?: Array<string>;
128
130
  liveAnnotationSupported: boolean;
129
131
  ipVersion?: IP_VERSION;
132
+ alias?: string;
130
133
  }) {
131
134
  const {
132
135
  asResourceOccupant,
@@ -143,12 +146,14 @@ export default class MeetingRequest extends StatelessWebexPlugin {
143
146
  pin,
144
147
  moveToResource,
145
148
  roapMessage,
149
+ reachability,
146
150
  preferTranscoding,
147
151
  breakoutsSupported,
148
152
  locale,
149
153
  deviceCapabilities = [],
150
154
  liveAnnotationSupported,
151
155
  ipVersion,
156
+ alias,
152
157
  } = options;
153
158
 
154
159
  LoggerProxy.logger.info('Meeting:request#joinMeeting --> Joining a meeting', correlationId);
@@ -178,6 +183,10 @@ export default class MeetingRequest extends StatelessWebexPlugin {
178
183
  },
179
184
  };
180
185
 
186
+ if (alias) {
187
+ body.alias = alias;
188
+ }
189
+
181
190
  if (breakoutsSupported) {
182
191
  deviceCapabilities.push(BREAKOUTS.BREAKOUTS_SUPPORTED);
183
192
  }
@@ -260,8 +269,15 @@ export default class MeetingRequest extends StatelessWebexPlugin {
260
269
  };
261
270
  }
262
271
 
263
- if (roapMessage) {
264
- body.localMedias = roapMessage.localMedias;
272
+ if (roapMessage || reachability) {
273
+ body.localMedias = [
274
+ {
275
+ localSdp: JSON.stringify({
276
+ roapMessage,
277
+ reachability,
278
+ }),
279
+ },
280
+ ];
265
281
  }
266
282
 
267
283
  /// @ts-ignore
@@ -149,6 +149,7 @@ const MeetingUtil = {
149
149
  locusUrl: meeting.locusUrl,
150
150
  locusClusterUrl: meeting.meetingInfo?.locusClusterUrl,
151
151
  correlationId: meeting.correlationId,
152
+ reachability: options.reachability,
152
153
  roapMessage: options.roapMessage,
153
154
  permissionToken: meeting.permissionToken,
154
155
  resourceId: options.resourceId || null,
@@ -8,10 +8,10 @@ import {
8
8
  H264Codec,
9
9
  getRecommendedMaxBitrateForFrameSize,
10
10
  RecommendedOpusBitrates,
11
+ NamedMediaGroup,
11
12
  } from '@webex/internal-media-core';
12
13
  import {cloneDeepWith, debounce, isEmpty} from 'lodash';
13
14
 
14
- import {NamedMediaGroup} from '@webex/json-multistream';
15
15
  import LoggerProxy from '../common/logs/logger-proxy';
16
16
 
17
17
  import {ReceiveSlot, ReceiveSlotEvents} from './receiveSlot';
@@ -2,7 +2,7 @@
2
2
  /* eslint-disable require-jsdoc */
3
3
  /* eslint-disable import/prefer-default-export */
4
4
  import {forEach} from 'lodash';
5
- import {NamedMediaGroup} from '@webex/json-multistream';
5
+ import {NamedMediaGroup} from '@webex/internal-media-core';
6
6
  import LoggerProxy from '../common/logs/logger-proxy';
7
7
 
8
8
  import {getMaxFs, RemoteMedia, RemoteVideoResolution} from './remoteMedia';
@@ -1,8 +1,7 @@
1
1
  /* eslint-disable valid-jsdoc */
2
2
  import {cloneDeep, forEach, remove} from 'lodash';
3
3
  import {EventMap} from 'typed-emitter';
4
- import {MediaType} from '@webex/internal-media-core';
5
- import {NamedMediaGroup} from '@webex/json-multistream';
4
+ import {MediaType, NamedMediaGroup} from '@webex/internal-media-core';
6
5
 
7
6
  import LoggerProxy from '../common/logs/logger-proxy';
8
7
  import EventsScope from '../common/events/events-scope';
@@ -3,10 +3,9 @@ import {
3
3
  MediaType,
4
4
  LocalStream,
5
5
  MultistreamRoapMediaConnection,
6
+ NamedMediaGroup,
6
7
  } from '@webex/internal-media-core';
7
8
 
8
- import {NamedMediaGroup} from '@webex/json-multistream';
9
-
10
9
  export default class SendSlotManager {
11
10
  private readonly slots: Map<MediaType, SendSlot> = new Map();
12
11
  private readonly LoggerProxy: any;
@@ -34,17 +34,21 @@ class ReachabilityRequest {
34
34
  * @returns {Promise}
35
35
  */
36
36
  getClusters = (ipVersion?: IP_VERSION): Promise<{clusters: ClusterList; joinCookie: any}> =>
37
- this.webex
38
- .request({
39
- method: HTTP_VERBS.GET,
40
- shouldRefreshAccessToken: false,
41
- api: API.CALLIOPEDISCOVERY,
42
- resource: RESOURCE.CLUSTERS,
43
- qs: {
44
- JCSupport: 1,
45
- ipver: ipVersion,
46
- },
47
- })
37
+ this.webex.internal.newMetrics.callDiagnosticLatencies
38
+ .measureLatency(
39
+ () =>
40
+ this.webex.request({
41
+ method: HTTP_VERBS.GET,
42
+ shouldRefreshAccessToken: false,
43
+ api: API.CALLIOPEDISCOVERY,
44
+ resource: RESOURCE.CLUSTERS,
45
+ qs: {
46
+ JCSupport: 1,
47
+ ipver: ipVersion,
48
+ },
49
+ }),
50
+ 'internal.get.cluster.time'
51
+ )
48
52
  .then((res) => {
49
53
  const {clusters, joinCookie} = res.body;
50
54
 
@@ -568,7 +568,7 @@ export default class ReconnectionManager {
568
568
 
569
569
  const iceServers = [];
570
570
 
571
- if (turnServerResult.turnServerInfo) {
571
+ if (turnServerResult.turnServerInfo?.url) {
572
572
  iceServers.push({
573
573
  urls: turnServerResult.turnServerInfo.url,
574
574
  username: turnServerResult.turnServerInfo.username || '',
package/src/roap/index.ts CHANGED
@@ -5,12 +5,18 @@ import {ROAP} from '../constants';
5
5
  import LoggerProxy from '../common/logs/logger-proxy';
6
6
 
7
7
  import RoapRequest from './request';
8
- import TurnDiscovery from './turnDiscovery';
8
+ import TurnDiscovery, {TurnDiscoveryResult} from './turnDiscovery';
9
9
  import Meeting from '../meeting';
10
10
  import MeetingUtil from '../meeting/util';
11
11
  import Metrics from '../metrics';
12
12
  import BEHAVIORAL_METRICS from '../metrics/constants';
13
13
 
14
+ export {
15
+ type TurnDiscoveryResult,
16
+ type TurnServerInfo,
17
+ type TurnDiscoverySkipReason,
18
+ } from './turnDiscovery';
19
+
14
20
  /**
15
21
  * Roap options
16
22
  * @typedef {Object} RoapOptions
@@ -39,7 +45,7 @@ export default class Roap extends StatelessWebexPlugin {
39
45
  options: any;
40
46
  roapHandler: any;
41
47
  roapRequest: any;
42
- turnDiscovery: any;
48
+ turnDiscovery: TurnDiscovery;
43
49
 
44
50
  /**
45
51
  *
@@ -260,7 +266,23 @@ export default class Roap extends StatelessWebexPlugin {
260
266
  * @param {Boolean} [isForced]
261
267
  * @returns {Promise}
262
268
  */
263
- doTurnDiscovery(meeting: Meeting, isReconnecting: boolean, isForced?: boolean) {
269
+ doTurnDiscovery(
270
+ meeting: Meeting,
271
+ isReconnecting: boolean,
272
+ isForced?: boolean
273
+ ): Promise<TurnDiscoveryResult> {
264
274
  return this.turnDiscovery.doTurnDiscovery(meeting, isReconnecting, isForced);
265
275
  }
276
+
277
+ generateTurnDiscoveryRequestMessage(meeting: Meeting, isForced: boolean) {
278
+ return this.turnDiscovery.generateTurnDiscoveryRequestMessage(meeting, isForced);
279
+ }
280
+
281
+ handleTurnDiscoveryHttpResponse(meeting: Meeting, httpResponse: object) {
282
+ return this.turnDiscovery.handleTurnDiscoveryHttpResponse(meeting, httpResponse);
283
+ }
284
+
285
+ abortTurnDiscovery() {
286
+ return this.turnDiscovery.abort();
287
+ }
266
288
  }
@@ -123,7 +123,7 @@ export default class RoapRequest extends StatelessWebexPlugin {
123
123
  );
124
124
  const {locus} = res.body;
125
125
 
126
- locus.roapSeq = roapMessage.seq;
126
+ locus.roapSeq = options.roapMessage.seq;
127
127
 
128
128
  return {
129
129
  locus,
@@ -139,9 +139,9 @@ export default class RoapRequest extends StatelessWebexPlugin {
139
139
  rawError: err,
140
140
  },
141
141
  });
142
- LoggerProxy.logger.error(`Roap:request#sendRoap --> Error:${JSON.stringify(err, null, 2)}`);
142
+ LoggerProxy.logger.error(`Roap:request#sendRoap --> Error:`, err);
143
143
  LoggerProxy.logger.error(
144
- `Roap:request#sendRoapRequest --> errorBody:${JSON.stringify(
144
+ `Roap:request#sendRoapRequest --> roapMessage that caused error:${JSON.stringify(
145
145
  roapMessage,
146
146
  null,
147
147
  2