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

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 (38) 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/types/constants.d.ts +1 -0
  20. package/dist/types/locus-info/index.d.ts +37 -0
  21. package/dist/types/meeting/request.d.ts +1 -0
  22. package/package.json +18 -18
  23. package/src/breakouts/breakout.ts +1 -0
  24. package/src/breakouts/index.ts +7 -3
  25. package/src/constants.ts +1 -0
  26. package/src/locus-info/controlsUtils.ts +28 -0
  27. package/src/locus-info/index.ts +110 -6
  28. package/src/meeting/index.ts +10 -0
  29. package/src/meeting/request.ts +8 -0
  30. package/src/meetings/index.ts +12 -4
  31. package/src/meetings/util.ts +23 -12
  32. package/test/unit/spec/breakouts/index.ts +3 -3
  33. package/test/unit/spec/locus-info/controlsUtils.js +47 -1
  34. package/test/unit/spec/locus-info/index.js +153 -2
  35. package/test/unit/spec/meeting/index.js +35 -0
  36. package/test/unit/spec/meeting/request.js +12 -0
  37. package/test/unit/spec/meetings/index.js +29 -21
  38. package/test/unit/spec/meetings/utils.js +49 -9
@@ -8,7 +8,6 @@ _Object$defineProperty(exports, "__esModule", {
8
8
  exports.default = void 0;
9
9
  var _now = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/date/now"));
10
10
  var _regenerator = _interopRequireDefault(require("@babel/runtime-corejs2/regenerator"));
11
- var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/slicedToArray"));
12
11
  var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/asyncToGenerator"));
13
12
  var _constants = require("../constants");
14
13
  var _loggerProxy = _interopRequireDefault(require("../common/logs/logger-proxy"));
@@ -238,14 +237,15 @@ MeetingsUtil.checkH264Support = /*#__PURE__*/function () {
238
237
  /**
239
238
  * get device from locus data
240
239
  * @param {Object} newLocus new locus data
240
+ * @param {String} deviceUrl current device url
241
241
  * @returns {Object}
242
242
  */
243
- MeetingsUtil.getThisDevice = function (newLocus) {
243
+ MeetingsUtil.getThisDevice = function (newLocus, deviceUrl) {
244
244
  var _newLocus$self, _newLocus$self$device;
245
245
  if ((newLocus === null || newLocus === void 0 ? void 0 : (_newLocus$self = newLocus.self) === null || _newLocus$self === void 0 ? void 0 : (_newLocus$self$device = _newLocus$self.devices) === null || _newLocus$self$device === void 0 ? void 0 : _newLocus$self$device.length) > 0) {
246
- var _newLocus$self$device2 = (0, _slicedToArray2.default)(newLocus.self.devices, 1),
247
- thisDevice = _newLocus$self$device2[0];
248
- return thisDevice;
246
+ return newLocus.self.devices.find(function (device) {
247
+ return device.url === deviceUrl;
248
+ });
249
249
  }
250
250
  return null;
251
251
  };
@@ -254,10 +254,11 @@ MeetingsUtil.getThisDevice = function (newLocus) {
254
254
  * get self device joined status from locus data
255
255
  * @param {Object} meeting current meeting data
256
256
  * @param {Object} newLocus new locus data
257
+ * @param {String} deviceUrl current device url
257
258
  * @returns {Object}
258
259
  */
259
- MeetingsUtil.joinedOnThisDevice = function (meeting, newLocus) {
260
- var thisDevice = MeetingsUtil.getThisDevice(newLocus);
260
+ MeetingsUtil.joinedOnThisDevice = function (meeting, newLocus, deviceUrl) {
261
+ var thisDevice = MeetingsUtil.getThisDevice(newLocus, deviceUrl);
261
262
  if (thisDevice) {
262
263
  if (!thisDevice.correlationId || (meeting === null || meeting === void 0 ? void 0 : meeting.correlationId) === thisDevice.correlationId) {
263
264
  return thisDevice.state === _constants._JOINED_ || thisDevice.state === _constants._LEFT_ && thisDevice.reason === _constants._MOVED_;
@@ -265,6 +266,18 @@ MeetingsUtil.joinedOnThisDevice = function (meeting, newLocus) {
265
266
  }
266
267
  return false;
267
268
  };
269
+
270
+ /**
271
+ * check the new locus is breakout session's one or not
272
+ * @param {Object} newLocus new locus data
273
+ * @returns {boolean}
274
+ * @private
275
+ * @memberof Meetings
276
+ */
277
+ MeetingsUtil.isBreakoutLocusDTO = function (newLocus) {
278
+ var _newLocus$controls, _newLocus$controls$br;
279
+ return (newLocus === null || newLocus === void 0 ? void 0 : (_newLocus$controls = newLocus.controls) === null || _newLocus$controls === void 0 ? void 0 : (_newLocus$controls$br = _newLocus$controls.breakout) === null || _newLocus$controls$br === void 0 ? void 0 : _newLocus$controls$br.sessionType) === _constants.BREAKOUTS.SESSION_TYPES.BREAKOUT;
280
+ };
268
281
  var _default = MeetingsUtil;
269
282
  exports.default = _default;
270
283
  //# sourceMappingURL=util.js.map
@@ -1 +1 @@
1
- {"version":3,"names":["MeetingsUtil","getMeetingAddedType","type","_LOCUS_ID_","_INCOMING_","_CREATED_","handleRoapMercury","envelope","meetingCollection","data","eventType","LOCUSEVENT","MESSAGE_ROAP","meeting","getByKey","CORRELATION_ID","correlationId","message","seq","messageType","tieBreaker","errorType","errorCause","ROAP","ROAP_TYPES","TURN_DISCOVERY_RESPONSE","roap","turnDiscovery","handleTurnDiscoveryResponse","roapMessage","sdp","sdps","length","undefined","mediaServer","getMediaServer","mediaProperties","webrtcMediaConnection","roapMessageReceived","split","find","line","startsWith","shift","replace","checkForCorrelationId","deviceUrl","locus","devices","self","foundDevice","device","url","parseDefaultSiteFromMeetingPreferences","userPreferences","result","sites","defaultSite","site","default","siteUrl","hasH264Codec","hasCodec","pc","window","RTCPeerConnection","createOffer","offerToReceiveVideo","offer","match","close","LoggerProxy","logger","warn","checkH264Support","options","firstChecked","disableNotifications","delay","maxDuration","shouldTrigger","shouldStopChecking","Trigger","trigger","file","function","EVENT_TRIGGERS","MEDIA_CODEC_LOADED","log","error","MEDIA_CODEC_MISSING","setTimeout","timestamp","call","getThisDevice","newLocus","thisDevice","joinedOnThisDevice","state","_JOINED_","_LEFT_","reason","_MOVED_"],"sources":["util.ts"],"sourcesContent":["/* globals window */\n\nimport {\n _LOCUS_ID_,\n _INCOMING_,\n _CREATED_,\n LOCUSEVENT,\n CORRELATION_ID,\n EVENT_TRIGGERS,\n ROAP,\n _LEFT_,\n _MOVED_,\n _JOINED_,\n} from '../constants';\nimport LoggerProxy from '../common/logs/logger-proxy';\nimport Trigger from '../common/events/trigger-proxy';\n\n/**\n * Meetings Media Codec Missing Event\n * Emitted when H.264 codec is not\n * found in the browser.\n * @event media:codec:missing\n * @instance\n * @memberof MeetingsUtil\n */\n\n/**\n * Meetings Media Codec Loaded Event\n * Emitted when H.264 codec has been\n * loaded in the browser.\n * @event media:codec:loaded\n * @instance\n * @memberof MeetingsUtil\n */\n\nconst MeetingsUtil: any = {};\n\nMeetingsUtil.getMeetingAddedType = (type) => (type === _LOCUS_ID_ ? _INCOMING_ : _CREATED_);\n\nMeetingsUtil.handleRoapMercury = (envelope, meetingCollection) => {\n const {data} = envelope;\n const {eventType} = data;\n\n if (eventType === LOCUSEVENT.MESSAGE_ROAP) {\n const meeting = meetingCollection.getByKey(CORRELATION_ID, data.correlationId);\n\n if (meeting) {\n const {seq, messageType, tieBreaker, errorType, errorCause} = data.message;\n\n if (messageType === ROAP.ROAP_TYPES.TURN_DISCOVERY_RESPONSE) {\n // turn discovery is not part of normal roap protocol and so we are not handling it\n // through the usual roap state machine\n meeting.roap.turnDiscovery.handleTurnDiscoveryResponse(data.message);\n } else {\n const roapMessage = {\n seq,\n messageType,\n sdp: data.message.sdps?.length > 0 ? data.message.sdps[0] : undefined,\n tieBreaker,\n errorType,\n errorCause,\n };\n\n const mediaServer = MeetingsUtil.getMediaServer(roapMessage.sdp);\n\n meeting.mediaProperties.webrtcMediaConnection.roapMessageReceived(roapMessage);\n\n if (mediaServer) {\n meeting.mediaProperties.webrtcMediaConnection.mediaServer = mediaServer;\n }\n }\n }\n }\n};\n\nMeetingsUtil.getMediaServer = (sdp) => {\n let mediaServer;\n\n // Attempt to collect the media server from the roap message.\n try {\n mediaServer = sdp\n .split('\\r\\n')\n .find((line) => line.startsWith('o='))\n .split(' ')\n .shift()\n .replace('o=', '');\n } catch {\n mediaServer = undefined;\n }\n\n return mediaServer;\n};\n\nMeetingsUtil.checkForCorrelationId = (deviceUrl, locus) => {\n let devices = [];\n\n if (locus) {\n if (locus && locus.self && locus.self.devices) {\n devices = locus.self.devices;\n }\n\n const foundDevice = devices.find((device) => device.url === deviceUrl);\n\n if (foundDevice && foundDevice.correlationId) {\n return foundDevice.correlationId;\n }\n }\n\n return false;\n};\n\nMeetingsUtil.parseDefaultSiteFromMeetingPreferences = (userPreferences) => {\n let result = '';\n\n if (userPreferences?.sites?.length) {\n const defaultSite = userPreferences.sites.find((site) => site.default);\n\n if (defaultSite) {\n result = defaultSite.siteUrl;\n } else {\n result = userPreferences.sites[0].siteUrl;\n }\n }\n\n return result;\n};\n\n/**\n * Will check to see if the H.264 media codec is supported.\n * @async\n * @private\n * @returns {Promise<boolean>}\n */\nMeetingsUtil.hasH264Codec = async () => {\n let hasCodec = false;\n\n try {\n const pc = new window.RTCPeerConnection();\n const offer = await pc.createOffer({offerToReceiveVideo: true});\n\n if (offer.sdp.match(/^a=rtpmap:\\d+\\s+H264\\/\\d+/m)) {\n hasCodec = true;\n }\n pc.close();\n } catch (error) {\n LoggerProxy.logger.warn(\n 'Meetings:util#hasH264Codec --> Error creating peerConnection for H.264 test.'\n );\n }\n\n return hasCodec;\n};\n\n/**\n * Notifies the user whether or not the H.264\n * codec is present. Will continuously check\n * until max duration.\n * @async\n * @private\n * @param {object} options\n * @param {Number} options.firstChecked Timestamp in milliseconds\n * @param {boolean} options.disableNotifications Default is false. Boolean to enable/disable notification and events\n * @returns {undefined}\n */\nMeetingsUtil.checkH264Support = async function checkH264Support(options: {\n firstChecked: number;\n disableNotifications: boolean;\n}) {\n const {hasH264Codec} = MeetingsUtil;\n const {firstChecked, disableNotifications} = options || {};\n const delay = 5e3; // ms\n const maxDuration = 3e5; // ms\n const shouldTrigger = firstChecked === undefined;\n const shouldStopChecking = firstChecked && Date.now() - firstChecked >= maxDuration;\n\n // Disable notifications and start H.264 download only\n if (disableNotifications) {\n hasH264Codec();\n\n return;\n }\n\n // Codec loaded trigger event notification\n if (await hasH264Codec()) {\n Trigger.trigger(\n this,\n {\n file: 'meetings/util',\n function: 'checkH264Support',\n },\n EVENT_TRIGGERS.MEDIA_CODEC_LOADED\n );\n LoggerProxy.logger.log('Meetings:util#checkH264Support --> H264 codec loaded successfully.');\n\n return;\n }\n\n // Stop checking if past the timelimit\n if (shouldStopChecking) {\n LoggerProxy.logger.error(\n 'Meetings:util#checkH264Support --> Timed out waiting for H264 codec to load.'\n );\n\n return;\n }\n\n // Trigger only once\n if (shouldTrigger) {\n Trigger.trigger(\n this,\n {\n file: 'meetings/util',\n function: 'checkH264Support',\n },\n EVENT_TRIGGERS.MEDIA_CODEC_MISSING\n );\n LoggerProxy.logger.log('Meetings:util#checkH264Support --> H264 codec is missing.');\n }\n\n // Keep checking in intervals to see if codec loaded\n window.setTimeout(() => {\n const timestamp = firstChecked || Date.now();\n\n MeetingsUtil.checkH264Support.call(this, {firstChecked: timestamp});\n }, delay);\n};\n\n/**\n * get device from locus data\n * @param {Object} newLocus new locus data\n * @returns {Object}\n */\nMeetingsUtil.getThisDevice = (newLocus: any) => {\n if (newLocus?.self?.devices?.length > 0) {\n const [thisDevice] = newLocus.self.devices;\n\n return thisDevice;\n }\n\n return null;\n};\n\n/**\n * get self device joined status from locus data\n * @param {Object} meeting current meeting data\n * @param {Object} newLocus new locus data\n * @returns {Object}\n */\nMeetingsUtil.joinedOnThisDevice = (meeting: any, newLocus: any) => {\n const thisDevice = MeetingsUtil.getThisDevice(newLocus);\n if (thisDevice) {\n if (!thisDevice.correlationId || meeting?.correlationId === thisDevice.correlationId) {\n return (\n thisDevice.state === _JOINED_ ||\n (thisDevice.state === _LEFT_ && thisDevice.reason === _MOVED_)\n );\n }\n }\n\n return false;\n};\n\nexport default MeetingsUtil;\n"],"mappings":"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"}
1
+ {"version":3,"names":["MeetingsUtil","getMeetingAddedType","type","_LOCUS_ID_","_INCOMING_","_CREATED_","handleRoapMercury","envelope","meetingCollection","data","eventType","LOCUSEVENT","MESSAGE_ROAP","meeting","getByKey","CORRELATION_ID","correlationId","message","seq","messageType","tieBreaker","errorType","errorCause","ROAP","ROAP_TYPES","TURN_DISCOVERY_RESPONSE","roap","turnDiscovery","handleTurnDiscoveryResponse","roapMessage","sdp","sdps","length","undefined","mediaServer","getMediaServer","mediaProperties","webrtcMediaConnection","roapMessageReceived","split","find","line","startsWith","shift","replace","checkForCorrelationId","deviceUrl","locus","devices","self","foundDevice","device","url","parseDefaultSiteFromMeetingPreferences","userPreferences","result","sites","defaultSite","site","default","siteUrl","hasH264Codec","hasCodec","pc","window","RTCPeerConnection","createOffer","offerToReceiveVideo","offer","match","close","LoggerProxy","logger","warn","checkH264Support","options","firstChecked","disableNotifications","delay","maxDuration","shouldTrigger","shouldStopChecking","Trigger","trigger","file","function","EVENT_TRIGGERS","MEDIA_CODEC_LOADED","log","error","MEDIA_CODEC_MISSING","setTimeout","timestamp","call","getThisDevice","newLocus","joinedOnThisDevice","thisDevice","state","_JOINED_","_LEFT_","reason","_MOVED_","isBreakoutLocusDTO","controls","breakout","sessionType","BREAKOUTS","SESSION_TYPES","BREAKOUT"],"sources":["util.ts"],"sourcesContent":["/* globals window */\n\nimport {\n _CREATED_,\n _INCOMING_,\n _JOINED_,\n _LEFT_,\n _LOCUS_ID_,\n _MOVED_,\n BREAKOUTS,\n CORRELATION_ID,\n EVENT_TRIGGERS,\n LOCUSEVENT,\n ROAP,\n} from '../constants';\nimport LoggerProxy from '../common/logs/logger-proxy';\nimport Trigger from '../common/events/trigger-proxy';\n\n/**\n * Meetings Media Codec Missing Event\n * Emitted when H.264 codec is not\n * found in the browser.\n * @event media:codec:missing\n * @instance\n * @memberof MeetingsUtil\n */\n\n/**\n * Meetings Media Codec Loaded Event\n * Emitted when H.264 codec has been\n * loaded in the browser.\n * @event media:codec:loaded\n * @instance\n * @memberof MeetingsUtil\n */\n\nconst MeetingsUtil: any = {};\n\nMeetingsUtil.getMeetingAddedType = (type) => (type === _LOCUS_ID_ ? _INCOMING_ : _CREATED_);\n\nMeetingsUtil.handleRoapMercury = (envelope, meetingCollection) => {\n const {data} = envelope;\n const {eventType} = data;\n\n if (eventType === LOCUSEVENT.MESSAGE_ROAP) {\n const meeting = meetingCollection.getByKey(CORRELATION_ID, data.correlationId);\n\n if (meeting) {\n const {seq, messageType, tieBreaker, errorType, errorCause} = data.message;\n\n if (messageType === ROAP.ROAP_TYPES.TURN_DISCOVERY_RESPONSE) {\n // turn discovery is not part of normal roap protocol and so we are not handling it\n // through the usual roap state machine\n meeting.roap.turnDiscovery.handleTurnDiscoveryResponse(data.message);\n } else {\n const roapMessage = {\n seq,\n messageType,\n sdp: data.message.sdps?.length > 0 ? data.message.sdps[0] : undefined,\n tieBreaker,\n errorType,\n errorCause,\n };\n\n const mediaServer = MeetingsUtil.getMediaServer(roapMessage.sdp);\n\n meeting.mediaProperties.webrtcMediaConnection.roapMessageReceived(roapMessage);\n\n if (mediaServer) {\n meeting.mediaProperties.webrtcMediaConnection.mediaServer = mediaServer;\n }\n }\n }\n }\n};\n\nMeetingsUtil.getMediaServer = (sdp) => {\n let mediaServer;\n\n // Attempt to collect the media server from the roap message.\n try {\n mediaServer = sdp\n .split('\\r\\n')\n .find((line) => line.startsWith('o='))\n .split(' ')\n .shift()\n .replace('o=', '');\n } catch {\n mediaServer = undefined;\n }\n\n return mediaServer;\n};\n\nMeetingsUtil.checkForCorrelationId = (deviceUrl, locus) => {\n let devices = [];\n\n if (locus) {\n if (locus && locus.self && locus.self.devices) {\n devices = locus.self.devices;\n }\n\n const foundDevice = devices.find((device) => device.url === deviceUrl);\n\n if (foundDevice && foundDevice.correlationId) {\n return foundDevice.correlationId;\n }\n }\n\n return false;\n};\n\nMeetingsUtil.parseDefaultSiteFromMeetingPreferences = (userPreferences) => {\n let result = '';\n\n if (userPreferences?.sites?.length) {\n const defaultSite = userPreferences.sites.find((site) => site.default);\n\n if (defaultSite) {\n result = defaultSite.siteUrl;\n } else {\n result = userPreferences.sites[0].siteUrl;\n }\n }\n\n return result;\n};\n\n/**\n * Will check to see if the H.264 media codec is supported.\n * @async\n * @private\n * @returns {Promise<boolean>}\n */\nMeetingsUtil.hasH264Codec = async () => {\n let hasCodec = false;\n\n try {\n const pc = new window.RTCPeerConnection();\n const offer = await pc.createOffer({offerToReceiveVideo: true});\n\n if (offer.sdp.match(/^a=rtpmap:\\d+\\s+H264\\/\\d+/m)) {\n hasCodec = true;\n }\n pc.close();\n } catch (error) {\n LoggerProxy.logger.warn(\n 'Meetings:util#hasH264Codec --> Error creating peerConnection for H.264 test.'\n );\n }\n\n return hasCodec;\n};\n\n/**\n * Notifies the user whether or not the H.264\n * codec is present. Will continuously check\n * until max duration.\n * @async\n * @private\n * @param {object} options\n * @param {Number} options.firstChecked Timestamp in milliseconds\n * @param {boolean} options.disableNotifications Default is false. Boolean to enable/disable notification and events\n * @returns {undefined}\n */\nMeetingsUtil.checkH264Support = async function checkH264Support(options: {\n firstChecked: number;\n disableNotifications: boolean;\n}) {\n const {hasH264Codec} = MeetingsUtil;\n const {firstChecked, disableNotifications} = options || {};\n const delay = 5e3; // ms\n const maxDuration = 3e5; // ms\n const shouldTrigger = firstChecked === undefined;\n const shouldStopChecking = firstChecked && Date.now() - firstChecked >= maxDuration;\n\n // Disable notifications and start H.264 download only\n if (disableNotifications) {\n hasH264Codec();\n\n return;\n }\n\n // Codec loaded trigger event notification\n if (await hasH264Codec()) {\n Trigger.trigger(\n this,\n {\n file: 'meetings/util',\n function: 'checkH264Support',\n },\n EVENT_TRIGGERS.MEDIA_CODEC_LOADED\n );\n LoggerProxy.logger.log('Meetings:util#checkH264Support --> H264 codec loaded successfully.');\n\n return;\n }\n\n // Stop checking if past the timelimit\n if (shouldStopChecking) {\n LoggerProxy.logger.error(\n 'Meetings:util#checkH264Support --> Timed out waiting for H264 codec to load.'\n );\n\n return;\n }\n\n // Trigger only once\n if (shouldTrigger) {\n Trigger.trigger(\n this,\n {\n file: 'meetings/util',\n function: 'checkH264Support',\n },\n EVENT_TRIGGERS.MEDIA_CODEC_MISSING\n );\n LoggerProxy.logger.log('Meetings:util#checkH264Support --> H264 codec is missing.');\n }\n\n // Keep checking in intervals to see if codec loaded\n window.setTimeout(() => {\n const timestamp = firstChecked || Date.now();\n\n MeetingsUtil.checkH264Support.call(this, {firstChecked: timestamp});\n }, delay);\n};\n\n/**\n * get device from locus data\n * @param {Object} newLocus new locus data\n * @param {String} deviceUrl current device url\n * @returns {Object}\n */\nMeetingsUtil.getThisDevice = (newLocus: any, deviceUrl: string) => {\n if (newLocus?.self?.devices?.length > 0) {\n return newLocus.self.devices.find((device) => device.url === deviceUrl);\n }\n\n return null;\n};\n\n/**\n * get self device joined status from locus data\n * @param {Object} meeting current meeting data\n * @param {Object} newLocus new locus data\n * @param {String} deviceUrl current device url\n * @returns {Object}\n */\nMeetingsUtil.joinedOnThisDevice = (meeting: any, newLocus: any, deviceUrl: string) => {\n const thisDevice = MeetingsUtil.getThisDevice(newLocus, deviceUrl);\n if (thisDevice) {\n if (!thisDevice.correlationId || meeting?.correlationId === thisDevice.correlationId) {\n return (\n thisDevice.state === _JOINED_ ||\n (thisDevice.state === _LEFT_ && thisDevice.reason === _MOVED_)\n );\n }\n }\n\n return false;\n};\n\n/**\n * check the new locus is breakout session's one or not\n * @param {Object} newLocus new locus data\n * @returns {boolean}\n * @private\n * @memberof Meetings\n */\nMeetingsUtil.isBreakoutLocusDTO = (newLocus: any) => {\n return newLocus?.controls?.breakout?.sessionType === BREAKOUTS.SESSION_TYPES.BREAKOUT;\n};\nexport default MeetingsUtil;\n"],"mappings":"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"}
@@ -449,6 +449,7 @@ export declare const LOCUSINFO: {
449
449
  CONTROLS_MEETING_BREAKOUT_UPDATED: string;
450
450
  CONTROLS_MEETING_CONTAINER_UPDATED: string;
451
451
  CONTROLS_ENTRY_EXIT_TONE_UPDATED: string;
452
+ CONTROLS_JOIN_BREAKOUT_FROM_MAIN: string;
452
453
  SELF_UNADMITTED_GUEST: string;
453
454
  SELF_ADMITTED_GUEST: string;
454
455
  SELF_REMOTE_VIDEO_MUTE_STATUS_UPDATED: string;
@@ -35,6 +35,7 @@ export default class LocusInfo extends EventsScope {
35
35
  replace: any;
36
36
  url: any;
37
37
  services: any;
38
+ mainSessionLocusCache: any;
38
39
  /**
39
40
  * Constructor
40
41
  * @param {boolean} updateMeeting true if the meeting should be updated
@@ -274,4 +275,40 @@ export default class LocusInfo extends EventsScope {
274
275
  * @memberof LocusInfo
275
276
  */
276
277
  updateIdentifiers(identities: Array<any>): void;
278
+ /**
279
+ * check the locus is main session's one or not, if is main session's, update main session cache
280
+ * @param {Object} locus
281
+ * @returns {undefined}
282
+ * @memberof LocusInfo
283
+ */
284
+ updateLocusCache(locus: any): void;
285
+ /**
286
+ * if return from breakout to main session, need to use cached main session DTO since locus won't send the full locus (participants)
287
+ * if join breakout from main session, need to query main locus url (if response with 403 means no privilege, need to clear the cache)
288
+ * @param {Object} newLocus
289
+ * @returns {Object}
290
+ * @memberof LocusInfo
291
+ */
292
+ getTheLocusToUpdate(newLocus: any): any;
293
+ /**
294
+ * merge participants by participant id
295
+ * @param {Array} participants
296
+ * @param {Array} sourceParticipants
297
+ * @returns {Array} merged participants
298
+ * @memberof LocusInfo
299
+ */
300
+ mergeParticipants(participants: any, sourceParticipants: any): any;
301
+ /**
302
+ * need cache main sessions' participants since locus will not send the full list when cohost/host leave breakout
303
+ * @param {Object} mainLocus
304
+ * @returns {undefined}
305
+ * @memberof LocusInfo
306
+ */
307
+ updateMainSessionLocusCache(mainLocus: any): void;
308
+ /**
309
+ * clear main session cache
310
+ * @returns {undefined}
311
+ * @memberof LocusInfo
312
+ */
313
+ clearMainSessionLocusCache(): void;
277
314
  }
@@ -268,4 +268,5 @@ export default class MeetingRequest extends StatelessWebexPlugin {
268
268
  * @returns {Promise}
269
269
  */
270
270
  toggleReactions({ enable, locusUrl, requestingParticipantId }: ToggleReactionsOptions): any;
271
+ getLocusStatusByUrl(locusUrl: string): any;
271
272
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webex/plugin-meetings",
3
- "version": "3.0.0-beta.83",
3
+ "version": "3.0.0-beta.84",
4
4
  "description": "",
5
5
  "license": "Cisco EULA (https://www.cisco.com/c/en/us/products/end-user-license-agreement.html)",
6
6
  "contributors": [
@@ -32,12 +32,12 @@
32
32
  "build": "yarn run -T tsc --declaration true --declarationDir ./dist/types"
33
33
  },
34
34
  "devDependencies": {
35
- "@webex/plugin-meetings": "3.0.0-beta.83",
36
- "@webex/test-helper-chai": "3.0.0-beta.83",
37
- "@webex/test-helper-mocha": "3.0.0-beta.83",
38
- "@webex/test-helper-mock-webex": "3.0.0-beta.83",
39
- "@webex/test-helper-retry": "3.0.0-beta.83",
40
- "@webex/test-helper-test-users": "3.0.0-beta.83",
35
+ "@webex/plugin-meetings": "3.0.0-beta.84",
36
+ "@webex/test-helper-chai": "3.0.0-beta.84",
37
+ "@webex/test-helper-mocha": "3.0.0-beta.84",
38
+ "@webex/test-helper-mock-webex": "3.0.0-beta.84",
39
+ "@webex/test-helper-retry": "3.0.0-beta.84",
40
+ "@webex/test-helper-test-users": "3.0.0-beta.84",
41
41
  "chai": "^4.3.4",
42
42
  "chai-as-promised": "^7.1.1",
43
43
  "jsdom-global": "3.0.2",
@@ -46,18 +46,18 @@
46
46
  "typescript": "^4.7.4"
47
47
  },
48
48
  "dependencies": {
49
- "@webex/common": "3.0.0-beta.83",
49
+ "@webex/common": "3.0.0-beta.84",
50
50
  "@webex/internal-media-core": "1.36.0",
51
- "@webex/internal-plugin-conversation": "3.0.0-beta.83",
52
- "@webex/internal-plugin-device": "3.0.0-beta.83",
53
- "@webex/internal-plugin-llm": "3.0.0-beta.83",
54
- "@webex/internal-plugin-mercury": "3.0.0-beta.83",
55
- "@webex/internal-plugin-metrics": "3.0.0-beta.83",
56
- "@webex/internal-plugin-support": "3.0.0-beta.83",
57
- "@webex/internal-plugin-user": "3.0.0-beta.83",
58
- "@webex/plugin-people": "3.0.0-beta.83",
59
- "@webex/plugin-rooms": "3.0.0-beta.83",
60
- "@webex/webex-core": "3.0.0-beta.83",
51
+ "@webex/internal-plugin-conversation": "3.0.0-beta.84",
52
+ "@webex/internal-plugin-device": "3.0.0-beta.84",
53
+ "@webex/internal-plugin-llm": "3.0.0-beta.84",
54
+ "@webex/internal-plugin-mercury": "3.0.0-beta.84",
55
+ "@webex/internal-plugin-metrics": "3.0.0-beta.84",
56
+ "@webex/internal-plugin-support": "3.0.0-beta.84",
57
+ "@webex/internal-plugin-user": "3.0.0-beta.84",
58
+ "@webex/plugin-people": "3.0.0-beta.84",
59
+ "@webex/plugin-rooms": "3.0.0-beta.84",
60
+ "@webex/webex-core": "3.0.0-beta.84",
61
61
  "ampersand-collection": "^2.0.2",
62
62
  "bowser": "^2.11.0",
63
63
  "btoa": "^1.2.1",
@@ -36,6 +36,7 @@ const Breakout = WebexPlugin.extend({
36
36
 
37
37
  derived: {
38
38
  isMain: {
39
+ cache: false, // fix issue: sometimes the derived will not change even if the deps changed
39
40
  deps: ['sessionType'],
40
41
  /**
41
42
  * If the breakout has no name, assume it is the main session
@@ -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;