@webex/plugin-meetings 3.0.0-beta.83 → 3.0.0-beta.85

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 (47) hide show
  1. package/dist/breakouts/breakout.js +3 -1
  2. package/dist/breakouts/breakout.js.map +1 -1
  3. package/dist/breakouts/index.js +13 -10
  4. package/dist/breakouts/index.js.map +1 -1
  5. package/dist/constants.js +1 -0
  6. package/dist/constants.js.map +1 -1
  7. package/dist/locus-info/controlsUtils.js +25 -0
  8. package/dist/locus-info/controlsUtils.js.map +1 -1
  9. package/dist/locus-info/index.js +118 -4
  10. package/dist/locus-info/index.js.map +1 -1
  11. package/dist/meeting/index.js +26 -16
  12. package/dist/meeting/index.js.map +1 -1
  13. package/dist/meeting/request.js +9 -0
  14. package/dist/meeting/request.js.map +1 -1
  15. package/dist/meetings/index.js +10 -4
  16. package/dist/meetings/index.js.map +1 -1
  17. package/dist/meetings/util.js +20 -7
  18. package/dist/meetings/util.js.map +1 -1
  19. package/dist/roap/index.js +14 -11
  20. package/dist/roap/index.js.map +1 -1
  21. package/dist/roap/turnDiscovery.js +91 -28
  22. package/dist/roap/turnDiscovery.js.map +1 -1
  23. package/dist/types/constants.d.ts +1 -0
  24. package/dist/types/locus-info/index.d.ts +37 -0
  25. package/dist/types/meeting/request.d.ts +1 -0
  26. package/dist/types/roap/turnDiscovery.d.ts +14 -0
  27. package/package.json +18 -18
  28. package/src/breakouts/breakout.ts +1 -0
  29. package/src/breakouts/index.ts +7 -3
  30. package/src/constants.ts +1 -0
  31. package/src/locus-info/controlsUtils.ts +28 -0
  32. package/src/locus-info/index.ts +110 -6
  33. package/src/meeting/index.ts +10 -0
  34. package/src/meeting/request.ts +8 -0
  35. package/src/meetings/index.ts +12 -4
  36. package/src/meetings/util.ts +23 -12
  37. package/src/roap/index.ts +15 -11
  38. package/src/roap/turnDiscovery.ts +45 -17
  39. package/test/unit/spec/breakouts/index.ts +3 -3
  40. package/test/unit/spec/locus-info/controlsUtils.js +47 -1
  41. package/test/unit/spec/locus-info/index.js +153 -2
  42. package/test/unit/spec/meeting/index.js +35 -0
  43. package/test/unit/spec/meeting/request.js +12 -0
  44. package/test/unit/spec/meetings/index.js +29 -21
  45. package/test/unit/spec/meetings/utils.js +49 -9
  46. package/test/unit/spec/roap/index.ts +9 -8
  47. package/test/unit/spec/roap/turnDiscovery.ts +21 -0
@@ -49,6 +49,7 @@ const Breakouts = WebexPlugin.extend({
49
49
 
50
50
  derived: {
51
51
  isInMainSession: {
52
+ cache: false,
52
53
  deps: ['sessionType'],
53
54
  /**
54
55
  * Returns true if the user is in the main session
@@ -59,6 +60,7 @@ const Breakouts = WebexPlugin.extend({
59
60
  },
60
61
  },
61
62
  isActiveBreakout: {
63
+ cache: false, // fix issue: sometimes the derived will not change even if the deps changed
62
64
  deps: ['sessionType', 'status'],
63
65
  /**
64
66
  * Returns true if the breakout status is active
@@ -72,6 +74,7 @@ const Breakouts = WebexPlugin.extend({
72
74
  },
73
75
  },
74
76
  breakoutGroupId: {
77
+ cache: false,
75
78
  deps: ['groups'],
76
79
  /**
77
80
  * Returns the actived group id
@@ -399,13 +402,14 @@ const Breakouts = WebexPlugin.extend({
399
402
 
400
403
  /**
401
404
  * Create new breakout sessions
402
- * @param {object} sessions -- breakout session group
405
+ * @param {object} params -- breakout session group
403
406
  * @returns {Promise}
404
407
  */
405
- async create(sessions) {
408
+ async create(params) {
409
+ const payload = {...params};
406
410
  const body = {
407
411
  ...(this.editLock && !!this.editLock.token ? {editlock: {token: this.editLock.token}} : {}),
408
- ...{groups: [{sessions}]},
412
+ ...{groups: [payload]},
409
413
  };
410
414
  // @ts-ignore
411
415
  const breakInfo = await this.webex
package/src/constants.ts CHANGED
@@ -581,6 +581,7 @@ export const LOCUSINFO = {
581
581
  CONTROLS_MEETING_BREAKOUT_UPDATED: 'CONTROLS_MEETING_BREAKOUT_UPDATED',
582
582
  CONTROLS_MEETING_CONTAINER_UPDATED: 'CONTROLS_MEETING_CONTAINER_UPDATED',
583
583
  CONTROLS_ENTRY_EXIT_TONE_UPDATED: 'CONTROLS_ENTRY_EXIT_TONE_UPDATED',
584
+ CONTROLS_JOIN_BREAKOUT_FROM_MAIN: 'CONTROLS_JOIN_BREAKOUT_FROM_MAIN',
584
585
  SELF_UNADMITTED_GUEST: 'SELF_UNADMITTED_GUEST',
585
586
  SELF_ADMITTED_GUEST: 'SELF_ADMITTED_GUEST',
586
587
  SELF_REMOTE_VIDEO_MUTE_STATUS_UPDATED: 'SELF_REMOTE_VIDEO_MUTE_STATUS_UPDATED',
@@ -1,4 +1,5 @@
1
1
  import {isEqual} from 'lodash';
2
+ import {BREAKOUTS} from '../constants';
2
3
 
3
4
  const ControlsUtils: any = {};
4
5
 
@@ -138,4 +139,31 @@ ControlsUtils.isNeedReplaceMembers = (oldControls: any, controls: any) => {
138
139
  );
139
140
  };
140
141
 
142
+ /**
143
+ * determine the switch status between breakout session and main session.
144
+ * @param {LocusControls} oldControls
145
+ * @param {LocusControls} controls
146
+ * @returns {Object}
147
+ */
148
+ ControlsUtils.getSessionSwitchStatus = (oldControls: any, controls: any) => {
149
+ const status = {isReturnToMain: false, isJoinToBreakout: false};
150
+ // no breakout case
151
+ if (!oldControls?.breakout || !controls?.breakout) {
152
+ return status;
153
+ }
154
+
155
+ status.isReturnToMain =
156
+ oldControls.breakout.sessionType === BREAKOUTS.SESSION_TYPES.BREAKOUT &&
157
+ controls.breakout.sessionType === BREAKOUTS.SESSION_TYPES.MAIN;
158
+ status.isJoinToBreakout =
159
+ oldControls.breakout.sessionType === BREAKOUTS.SESSION_TYPES.MAIN &&
160
+ controls.breakout.sessionType === BREAKOUTS.SESSION_TYPES.BREAKOUT;
161
+
162
+ return status;
163
+ };
164
+
165
+ ControlsUtils.isMainSessionDTO = (locus: any) => {
166
+ return locus?.controls?.breakout?.sessionType !== BREAKOUTS.SESSION_TYPES.BREAKOUT;
167
+ };
168
+
141
169
  export default ControlsUtils;
@@ -1,4 +1,4 @@
1
- import {isEqual} from 'lodash';
1
+ import {isArray, isEqual, mergeWith, cloneDeep} from 'lodash';
2
2
 
3
3
  import LoggerProxy from '../common/logs/logger-proxy';
4
4
  import EventsScope from '../common/events/events-scope';
@@ -64,7 +64,7 @@ export default class LocusInfo extends EventsScope {
64
64
  replace: any;
65
65
  url: any;
66
66
  services: any;
67
-
67
+ mainSessionLocusCache: any;
68
68
  /**
69
69
  * Constructor
70
70
  * @param {boolean} updateMeeting true if the meeting should be updated
@@ -180,6 +180,7 @@ export default class LocusInfo extends EventsScope {
180
180
  */
181
181
  this.deltaParticipants = [];
182
182
 
183
+ this.updateLocusCache(locus);
183
184
  // above section only updates the locusInfo object
184
185
  // The below section makes sure it updates the locusInfo as well as updates the meeting object
185
186
  this.updateParticipants(locus.participants);
@@ -203,6 +204,7 @@ export default class LocusInfo extends EventsScope {
203
204
  * @memberof LocusInfo
204
205
  */
205
206
  initialSetup(locus: object) {
207
+ this.updateLocusCache(locus);
206
208
  this.onFullLocus(locus);
207
209
 
208
210
  // Change it to true after it receives it first locus object
@@ -218,7 +220,7 @@ export default class LocusInfo extends EventsScope {
218
220
  parse(meeting: any, data: any) {
219
221
  // eslint-disable-next-line @typescript-eslint/no-shadow
220
222
  const {eventType} = data;
221
-
223
+ const locus = this.getTheLocusToUpdate(data.locus);
222
224
  LoggerProxy.logger.info(`Locus-info:index#parse --> received locus data: ${eventType}`);
223
225
 
224
226
  switch (eventType) {
@@ -236,16 +238,16 @@ export default class LocusInfo extends EventsScope {
236
238
  case LOCUSEVENT.PARTICIPANT_DECLINED:
237
239
  case LOCUSEVENT.FLOOR_GRANTED:
238
240
  case LOCUSEVENT.FLOOR_RELEASED:
239
- this.onFullLocus(data.locus, eventType);
241
+ this.onFullLocus(locus, eventType);
240
242
  break;
241
243
  case LOCUSEVENT.DIFFERENCE:
242
- this.handleLocusDelta(data.locus, meeting);
244
+ this.handleLocusDelta(locus, meeting);
243
245
  break;
244
246
 
245
247
  default:
246
248
  // Why will there be a event with no eventType ????
247
249
  // we may not need this, we can get full locus
248
- this.handleLocusDelta(data.locus, meeting);
250
+ this.handleLocusDelta(locus, meeting);
249
251
  }
250
252
  }
251
253
 
@@ -1395,4 +1397,106 @@ export default class LocusInfo extends EventsScope {
1395
1397
  this.identities = identities;
1396
1398
  }
1397
1399
  }
1400
+
1401
+ /**
1402
+ * check the locus is main session's one or not, if is main session's, update main session cache
1403
+ * @param {Object} locus
1404
+ * @returns {undefined}
1405
+ * @memberof LocusInfo
1406
+ */
1407
+ updateLocusCache(locus: any) {
1408
+ const isMainSessionDTO = ControlsUtils.isMainSessionDTO(locus);
1409
+ if (isMainSessionDTO) {
1410
+ this.updateMainSessionLocusCache(locus);
1411
+ }
1412
+ }
1413
+
1414
+ /**
1415
+ * if return from breakout to main session, need to use cached main session DTO since locus won't send the full locus (participants)
1416
+ * if join breakout from main session, need to query main locus url (if response with 403 means no privilege, need to clear the cache)
1417
+ * @param {Object} newLocus
1418
+ * @returns {Object}
1419
+ * @memberof LocusInfo
1420
+ */
1421
+ getTheLocusToUpdate(newLocus: any) {
1422
+ const switchStatus = ControlsUtils.getSessionSwitchStatus(this.controls, newLocus.controls);
1423
+ if (switchStatus.isReturnToMain && this.mainSessionLocusCache) {
1424
+ return cloneDeep(this.mainSessionLocusCache);
1425
+ }
1426
+ if (switchStatus.isJoinToBreakout) {
1427
+ this.emitScoped(
1428
+ {
1429
+ file: 'locus-info',
1430
+ function: 'updateControls',
1431
+ },
1432
+ LOCUSINFO.EVENTS.CONTROLS_JOIN_BREAKOUT_FROM_MAIN,
1433
+ {
1434
+ mainLocusUrl: this.url,
1435
+ }
1436
+ );
1437
+ }
1438
+
1439
+ return newLocus;
1440
+ }
1441
+
1442
+ /**
1443
+ * merge participants by participant id
1444
+ * @param {Array} participants
1445
+ * @param {Array} sourceParticipants
1446
+ * @returns {Array} merged participants
1447
+ * @memberof LocusInfo
1448
+ */
1449
+ // eslint-disable-next-line class-methods-use-this
1450
+ mergeParticipants(participants, sourceParticipants) {
1451
+ if (!sourceParticipants || !sourceParticipants.length) return participants;
1452
+ if (!participants || !participants.length) {
1453
+ return sourceParticipants;
1454
+ }
1455
+ sourceParticipants.forEach((participant) => {
1456
+ const existIndex = participants.findIndex((p) => p.id === participant.id);
1457
+ if (existIndex > -1) {
1458
+ participants.splice(existIndex, 1, participant);
1459
+ } else {
1460
+ participants.push(participant);
1461
+ }
1462
+ });
1463
+
1464
+ return participants;
1465
+ }
1466
+
1467
+ /**
1468
+ * need cache main sessions' participants since locus will not send the full list when cohost/host leave breakout
1469
+ * @param {Object} mainLocus
1470
+ * @returns {undefined}
1471
+ * @memberof LocusInfo
1472
+ */
1473
+ updateMainSessionLocusCache(mainLocus: any) {
1474
+ if (!mainLocus) {
1475
+ return;
1476
+ }
1477
+ const locusClone = cloneDeep(mainLocus);
1478
+ if (this.mainSessionLocusCache) {
1479
+ // eslint-disable-next-line consistent-return
1480
+ mergeWith(this.mainSessionLocusCache, locusClone, (objValue, srcValue, key) => {
1481
+ if (isArray(objValue)) {
1482
+ if (key === 'participants') {
1483
+ return this.mergeParticipants(objValue, srcValue);
1484
+ }
1485
+
1486
+ return srcValue; // just replace the old ones
1487
+ }
1488
+ });
1489
+ } else {
1490
+ this.mainSessionLocusCache = locusClone;
1491
+ }
1492
+ }
1493
+
1494
+ /**
1495
+ * clear main session cache
1496
+ * @returns {undefined}
1497
+ * @memberof LocusInfo
1498
+ */
1499
+ clearMainSessionLocusCache() {
1500
+ this.mainSessionLocusCache = null;
1501
+ }
1398
1502
  }
@@ -1991,6 +1991,16 @@ export default class Meeting extends StatelessWebexPlugin {
1991
1991
  );
1992
1992
  });
1993
1993
 
1994
+ this.locusInfo.on(LOCUSINFO.EVENTS.CONTROLS_JOIN_BREAKOUT_FROM_MAIN, ({mainLocusUrl}) => {
1995
+ this.meetingRequest.getLocusStatusByUrl(mainLocusUrl).catch((error) => {
1996
+ // clear main session cache when attendee join into breakout and forbidden to get locus from main locus url,
1997
+ // which means main session is not active for the attendee
1998
+ if (error?.statusCode === 403) {
1999
+ this.locusInfo.clearMainSessionLocusCache();
2000
+ }
2001
+ });
2002
+ });
2003
+
1994
2004
  this.locusInfo.on(LOCUSINFO.EVENTS.CONTROLS_ENTRY_EXIT_TONE_UPDATED, ({entryExitTone}) => {
1995
2005
  Trigger.trigger(
1996
2006
  this,
@@ -865,4 +865,12 @@ export default class MeetingRequest extends StatelessWebexPlugin {
865
865
  },
866
866
  });
867
867
  }
868
+
869
+ getLocusStatusByUrl(locusUrl: string) {
870
+ // @ts-ignore
871
+ return this.request({
872
+ method: HTTP_VERBS.GET,
873
+ uri: locusUrl,
874
+ });
875
+ }
868
876
  }
@@ -246,8 +246,14 @@ export default class Meetings extends WebexPlugin {
246
246
 
247
247
  const isSelfJoined = newLocus?.self?.state === _JOINED_;
248
248
  const isSelfMoved = newLocus?.self?.state === _LEFT_ && newLocus?.self?.reason === _MOVED_;
249
- const deviceFromNewLocus = MeetingsUtil.getThisDevice(newLocus);
250
- const isNewLocusJoinThisDevice = MeetingsUtil.joinedOnThisDevice(meeting, newLocus);
249
+ // @ts-ignore
250
+ const deviceFromNewLocus = MeetingsUtil.getThisDevice(newLocus, this.webex.internal.device.url);
251
+ const isNewLocusJoinThisDevice = MeetingsUtil.joinedOnThisDevice(
252
+ meeting,
253
+ newLocus,
254
+ // @ts-ignore
255
+ this.webex.internal.device.url
256
+ );
251
257
  const isBreakoutLocusJoinThisDevice =
252
258
  breakoutLocus?.joinedWith?.correlationId &&
253
259
  breakoutLocus.joinedWith.correlationId === meeting?.correlationId;
@@ -305,8 +311,7 @@ export default class Meetings extends WebexPlugin {
305
311
  */
306
312
  private isNeedHandleLocusDTO(meeting: any, newLocus: any) {
307
313
  if (newLocus) {
308
- const isNewLocusAsBreakout =
309
- newLocus.controls?.breakout?.sessionType === BREAKOUTS.SESSION_TYPES.BREAKOUT;
314
+ const isNewLocusAsBreakout = MeetingsUtil.isBreakoutLocusDTO(newLocus);
310
315
  const isSelfMoved = newLocus?.self?.state === _LEFT_ && newLocus?.self?.reason === _MOVED_;
311
316
  if (!meeting) {
312
317
  if (isNewLocusAsBreakout) {
@@ -375,6 +380,9 @@ export default class Meetings extends WebexPlugin {
375
380
  );
376
381
  }
377
382
 
383
+ if (meeting && !MeetingsUtil.isBreakoutLocusDTO(data.locus)) {
384
+ meeting.locusInfo.updateMainSessionLocusCache(data.locus);
385
+ }
378
386
  if (!this.isNeedHandleLocusDTO(meeting, data.locus)) {
379
387
  LoggerProxy.logger.log(
380
388
  `Meetings:index#handleLocusEvent --> doesn't need to process locus event`
@@ -1,16 +1,17 @@
1
1
  /* globals window */
2
2
 
3
3
  import {
4
- _LOCUS_ID_,
5
- _INCOMING_,
6
4
  _CREATED_,
7
- LOCUSEVENT,
5
+ _INCOMING_,
6
+ _JOINED_,
7
+ _LEFT_,
8
+ _LOCUS_ID_,
9
+ _MOVED_,
10
+ BREAKOUTS,
8
11
  CORRELATION_ID,
9
12
  EVENT_TRIGGERS,
13
+ LOCUSEVENT,
10
14
  ROAP,
11
- _LEFT_,
12
- _MOVED_,
13
- _JOINED_,
14
15
  } from '../constants';
15
16
  import LoggerProxy from '../common/logs/logger-proxy';
16
17
  import Trigger from '../common/events/trigger-proxy';
@@ -228,13 +229,12 @@ MeetingsUtil.checkH264Support = async function checkH264Support(options: {
228
229
  /**
229
230
  * get device from locus data
230
231
  * @param {Object} newLocus new locus data
232
+ * @param {String} deviceUrl current device url
231
233
  * @returns {Object}
232
234
  */
233
- MeetingsUtil.getThisDevice = (newLocus: any) => {
235
+ MeetingsUtil.getThisDevice = (newLocus: any, deviceUrl: string) => {
234
236
  if (newLocus?.self?.devices?.length > 0) {
235
- const [thisDevice] = newLocus.self.devices;
236
-
237
- return thisDevice;
237
+ return newLocus.self.devices.find((device) => device.url === deviceUrl);
238
238
  }
239
239
 
240
240
  return null;
@@ -244,10 +244,11 @@ MeetingsUtil.getThisDevice = (newLocus: any) => {
244
244
  * get self device joined status from locus data
245
245
  * @param {Object} meeting current meeting data
246
246
  * @param {Object} newLocus new locus data
247
+ * @param {String} deviceUrl current device url
247
248
  * @returns {Object}
248
249
  */
249
- MeetingsUtil.joinedOnThisDevice = (meeting: any, newLocus: any) => {
250
- const thisDevice = MeetingsUtil.getThisDevice(newLocus);
250
+ MeetingsUtil.joinedOnThisDevice = (meeting: any, newLocus: any, deviceUrl: string) => {
251
+ const thisDevice = MeetingsUtil.getThisDevice(newLocus, deviceUrl);
251
252
  if (thisDevice) {
252
253
  if (!thisDevice.correlationId || meeting?.correlationId === thisDevice.correlationId) {
253
254
  return (
@@ -260,4 +261,14 @@ MeetingsUtil.joinedOnThisDevice = (meeting: any, newLocus: any) => {
260
261
  return false;
261
262
  };
262
263
 
264
+ /**
265
+ * check the new locus is breakout session's one or not
266
+ * @param {Object} newLocus new locus data
267
+ * @returns {boolean}
268
+ * @private
269
+ * @memberof Meetings
270
+ */
271
+ MeetingsUtil.isBreakoutLocusDTO = (newLocus: any) => {
272
+ return newLocus?.controls?.breakout?.sessionType === BREAKOUTS.SESSION_TYPES.BREAKOUT;
273
+ };
263
274
  export default MeetingsUtil;
package/src/roap/index.ts CHANGED
@@ -199,19 +199,23 @@ export default class Roap extends StatelessWebexPlugin {
199
199
  // When reconnecting, it's important that the first roap message being sent out has empty media id.
200
200
  // Normally this is the roap offer, but when TURN discovery is enabled,
201
201
  // then this is the TURN discovery request message
202
- const sendEmptyMediaId = reconnect && !meeting.config.experimental.enableTurnDiscovery;
202
+ return this.turnDiscovery
203
+ .isSkipped(meeting)
204
+ .then((isTurnDiscoverySkipped) => {
205
+ const sendEmptyMediaId = reconnect && isTurnDiscoverySkipped;
203
206
 
204
- return this.roapRequest
205
- .sendRoap({
206
- roapMessage,
207
- correlationId: meeting.correlationId,
208
- locusSelfUrl: meeting.selfUrl,
209
- mediaId: sendEmptyMediaId ? '' : meeting.mediaId,
210
- audioMuted: meeting.audio?.isLocallyMuted(),
211
- videoMuted: meeting.video?.isLocallyMuted(),
212
- meetingId: meeting.id,
213
- preferTranscoding: !meeting.isMultistream,
207
+ return this.roapRequest.sendRoap({
208
+ roapMessage,
209
+ correlationId: meeting.correlationId,
210
+ locusSelfUrl: meeting.selfUrl,
211
+ mediaId: sendEmptyMediaId ? '' : meeting.mediaId,
212
+ audioMuted: meeting.audio?.isLocallyMuted(),
213
+ videoMuted: meeting.video?.isLocallyMuted(),
214
+ meetingId: meeting.id,
215
+ preferTranscoding: !meeting.isMultistream,
216
+ });
214
217
  })
218
+
215
219
  .then(({locus, mediaConnections}) => {
216
220
  if (mediaConnections) {
217
221
  meeting.updateMediaConnections(mediaConnections);
@@ -221,6 +221,48 @@ export default class TurnDiscovery {
221
221
  });
222
222
  }
223
223
 
224
+ /**
225
+ * Gets the reason why reachability is skipped.
226
+ *
227
+ * @param {Meeting} meeting
228
+ * @returns {Promise<string>} Promise with empty string if reachability is not skipped or a reason if it is skipped
229
+ */
230
+ private async getSkipReason(meeting: Meeting): Promise<string> {
231
+ // @ts-ignore - fix type
232
+ const isAnyClusterReachable = await meeting.webex.meetings.reachability.isAnyClusterReachable();
233
+
234
+ if (isAnyClusterReachable) {
235
+ LoggerProxy.logger.info(
236
+ 'Roap:turnDiscovery#getSkipReason --> reachability has not failed, skipping TURN discovery'
237
+ );
238
+
239
+ return 'reachability';
240
+ }
241
+
242
+ // @ts-ignore - fix type
243
+ if (!meeting.config.experimental.enableTurnDiscovery) {
244
+ LoggerProxy.logger.info(
245
+ 'Roap:turnDiscovery#getSkipReason --> TURN discovery disabled in config, skipping it'
246
+ );
247
+
248
+ return 'config';
249
+ }
250
+
251
+ return '';
252
+ }
253
+
254
+ /**
255
+ * Checks if TURN discovery is skipped.
256
+ *
257
+ * @param {Meeting} meeting
258
+ * @returns {Boolean} true if TURN discovery is being skipped, false if it is being done
259
+ */
260
+ async isSkipped(meeting) {
261
+ const skipReason = await this.getSkipReason(meeting);
262
+
263
+ return !!skipReason;
264
+ }
265
+
224
266
  /**
225
267
  * Retrieves TURN server information from the backend by doing
226
268
  * a roap message exchange:
@@ -239,29 +281,15 @@ export default class TurnDiscovery {
239
281
  * @returns {Promise}
240
282
  */
241
283
  async doTurnDiscovery(meeting: Meeting, isReconnecting?: boolean) {
242
- // @ts-ignore - fix type
243
- const isAnyClusterReachable = await meeting.webex.meetings.reachability.isAnyClusterReachable();
244
-
245
- if (isAnyClusterReachable) {
246
- LoggerProxy.logger.info(
247
- 'Roap:turnDiscovery#doTurnDiscovery --> reachability has not failed, skipping TURN discovery'
248
- );
284
+ const turnDiscoverySkippedReason = await this.getSkipReason(meeting);
249
285
 
286
+ if (turnDiscoverySkippedReason) {
250
287
  return {
251
288
  turnServerInfo: undefined,
252
- turnDiscoverySkippedReason: 'reachability',
289
+ turnDiscoverySkippedReason,
253
290
  };
254
291
  }
255
292
 
256
- // @ts-ignore - fix type
257
- if (!meeting.config.experimental.enableTurnDiscovery) {
258
- LoggerProxy.logger.info(
259
- 'Roap:turnDiscovery#doTurnDiscovery --> TURN discovery disabled in config, skipping it'
260
- );
261
-
262
- return {turnServerInfo: undefined, turnDiscoverySkippedReason: 'config'};
263
- }
264
-
265
293
  return this.sendRoapTurnDiscoveryRequest(meeting, isReconnecting)
266
294
  .then(() => this.waitForTurnDiscoveryResponse())
267
295
  .then(() => this.sendRoapOK(meeting))
@@ -868,7 +868,7 @@ describe('plugin-meetings', () => {
868
868
  describe('create', () => {
869
869
  it('response not include groups info', async () => {
870
870
  const sessions = [{name: 'session1', anyoneCanJoin: true}];
871
- const result = await breakouts.create(sessions);
871
+ const result = await breakouts.create({sessions});
872
872
 
873
873
  assert.equal(result, 'REQUEST_RETURN_VALUE');
874
874
  });
@@ -890,7 +890,7 @@ describe('plugin-meetings', () => {
890
890
  })
891
891
  );
892
892
 
893
- const result = await breakouts.create(sessions);
893
+ const result = await breakouts.create({sessions});
894
894
 
895
895
  assert.equal(breakouts.groups[0].id, '455556a4-37cd-4baa-89bc-8730581a1cc0');
896
896
  });
@@ -908,7 +908,7 @@ describe('plugin-meetings', () => {
908
908
  );
909
909
 
910
910
  await assert.isRejected(
911
- breakouts.create(sessions),
911
+ breakouts.create({sessions}),
912
912
  BreakoutEditLockedError,
913
913
  'Edit lock token mismatch'
914
914
  );
@@ -176,6 +176,52 @@ describe('plugin-meetings', () => {
176
176
  const newControls = {breakout: {sessionId: 'sessionId1', groupId: 'groupId'}};
177
177
  assert.equal(controlsUtils.isNeedReplaceMembers(oldControls, newControls), false);
178
178
  });
179
- })
179
+ });
180
+
181
+ describe('getSessionSwitchStatus', () => {
182
+ it('if no breakout control, return switch status both false', () => {
183
+ const oldControls = {};
184
+ const newControls = {};
185
+ assert.deepEqual(controlsUtils.getSessionSwitchStatus(oldControls, newControls), {
186
+ isReturnToMain: false, isJoinToBreakout: false
187
+ });
188
+ });
189
+
190
+ it('if switch session from breakout to main, return isReturnToMain as true', () => {
191
+ const oldControls = {breakout: {sessionType: 'BREAKOUT'}};
192
+ const newControls = {breakout: {sessionType: 'MAIN'}};
193
+ assert.deepEqual(controlsUtils.getSessionSwitchStatus(oldControls, newControls), {
194
+ isReturnToMain: true, isJoinToBreakout: false
195
+ });
196
+ });
197
+
198
+ it('if switch session from main to breakout, return isJoinToBreakout as true', () => {
199
+ const oldControls = {breakout: {sessionType: 'MAIN'}};
200
+ const newControls = {breakout: {sessionType: 'BREAKOUT'}};
201
+ assert.deepEqual(controlsUtils.getSessionSwitchStatus(oldControls, newControls), {
202
+ isReturnToMain: false, isJoinToBreakout: true
203
+ });
204
+ });
205
+ });
206
+
207
+ describe('#isMainSessionDTO', () => {
208
+ it('return false is sessionType is BREAKOUT', () => {
209
+ const locus = {
210
+ controls: {breakout: {sessionType: 'BREAKOUT'}}
211
+ };
212
+
213
+ assert.equal(controlsUtils.isMainSessionDTO(locus), false);
214
+ });
215
+
216
+ it('return true is sessionType is not BREAKOUT', () => {
217
+ const locus = {
218
+ controls: {breakout: {sessionType: 'MAIN'}}
219
+ };
220
+
221
+ assert.equal(controlsUtils.isMainSessionDTO(locus), true);
222
+
223
+ assert.equal(controlsUtils.isMainSessionDTO({}), true);
224
+ });
225
+ });
180
226
  });
181
227
  });