@webex/plugin-meetings 3.0.0-bnr.5 → 3.0.0-stream-classes.1

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 (303) hide show
  1. package/README.md +46 -8
  2. package/dist/annotation/annotation.types.js +7 -0
  3. package/dist/annotation/annotation.types.js.map +1 -0
  4. package/dist/annotation/constants.js +49 -0
  5. package/dist/annotation/constants.js.map +1 -0
  6. package/dist/annotation/index.js +342 -0
  7. package/dist/annotation/index.js.map +1 -0
  8. package/dist/breakouts/breakout.js +70 -32
  9. package/dist/breakouts/breakout.js.map +1 -1
  10. package/dist/breakouts/events.js +45 -0
  11. package/dist/breakouts/events.js.map +1 -0
  12. package/dist/breakouts/index.js +422 -217
  13. package/dist/breakouts/index.js.map +1 -1
  14. package/dist/breakouts/utils.js +12 -1
  15. package/dist/breakouts/utils.js.map +1 -1
  16. package/dist/common/errors/webex-errors.js +3 -2
  17. package/dist/common/errors/webex-errors.js.map +1 -1
  18. package/dist/common/logs/logger-proxy.js +1 -1
  19. package/dist/common/logs/logger-proxy.js.map +1 -1
  20. package/dist/common/logs/request.d.ts +1 -1
  21. package/dist/common/queue.js +24 -9
  22. package/dist/common/queue.js.map +1 -1
  23. package/dist/config.js +1 -7
  24. package/dist/config.js.map +1 -1
  25. package/dist/constants.js +118 -24
  26. package/dist/constants.js.map +1 -1
  27. package/dist/controls-options-manager/enums.js +2 -0
  28. package/dist/controls-options-manager/enums.js.map +1 -1
  29. package/dist/controls-options-manager/index.js +19 -14
  30. package/dist/controls-options-manager/index.js.map +1 -1
  31. package/dist/controls-options-manager/types.js.map +1 -1
  32. package/dist/controls-options-manager/util.js +80 -11
  33. package/dist/controls-options-manager/util.js.map +1 -1
  34. package/dist/index.js +62 -20
  35. package/dist/index.js.map +1 -1
  36. package/dist/interpretation/collection.js +23 -0
  37. package/dist/interpretation/collection.js.map +1 -0
  38. package/dist/interpretation/index.js +366 -0
  39. package/dist/interpretation/index.js.map +1 -0
  40. package/dist/interpretation/siLanguage.js +25 -0
  41. package/dist/interpretation/siLanguage.js.map +1 -0
  42. package/dist/locus-info/controlsUtils.js +71 -1
  43. package/dist/locus-info/controlsUtils.js.map +1 -1
  44. package/dist/locus-info/index.js +305 -57
  45. package/dist/locus-info/index.js.map +1 -1
  46. package/dist/locus-info/infoUtils.js +7 -1
  47. package/dist/locus-info/infoUtils.js.map +1 -1
  48. package/dist/locus-info/mediaSharesUtils.js +43 -1
  49. package/dist/locus-info/mediaSharesUtils.js.map +1 -1
  50. package/dist/locus-info/parser.js +219 -63
  51. package/dist/locus-info/parser.js.map +1 -1
  52. package/dist/locus-info/selfUtils.js +44 -22
  53. package/dist/locus-info/selfUtils.js.map +1 -1
  54. package/dist/media/index.js +57 -104
  55. package/dist/media/index.js.map +1 -1
  56. package/dist/media/properties.js +60 -121
  57. package/dist/media/properties.js.map +1 -1
  58. package/dist/meeting/in-meeting-actions.js +61 -3
  59. package/dist/meeting/in-meeting-actions.js.map +1 -1
  60. package/dist/meeting/index.js +2530 -2534
  61. package/dist/meeting/index.js.map +1 -1
  62. package/dist/meeting/locusMediaRequest.js +292 -0
  63. package/dist/meeting/locusMediaRequest.js.map +1 -0
  64. package/dist/meeting/muteState.js +125 -205
  65. package/dist/meeting/muteState.js.map +1 -1
  66. package/dist/meeting/request.js +150 -150
  67. package/dist/meeting/request.js.map +1 -1
  68. package/dist/meeting/util.js +568 -438
  69. package/dist/meeting/util.js.map +1 -1
  70. package/dist/meeting-info/index.js +48 -7
  71. package/dist/meeting-info/index.js.map +1 -1
  72. package/dist/meeting-info/meeting-info-v2.js +94 -38
  73. package/dist/meeting-info/meeting-info-v2.js.map +1 -1
  74. package/dist/meeting-info/utilv2.js +4 -2
  75. package/dist/meeting-info/utilv2.js.map +1 -1
  76. package/dist/meetings/index.d.ts +0 -2
  77. package/dist/meetings/index.js +260 -85
  78. package/dist/meetings/index.js.map +1 -1
  79. package/dist/meetings/meetings.types.js +7 -0
  80. package/dist/meetings/meetings.types.js.map +1 -0
  81. package/dist/meetings/util.js +42 -7
  82. package/dist/meetings/util.js.map +1 -1
  83. package/dist/member/index.d.ts +2 -0
  84. package/dist/member/index.js +26 -0
  85. package/dist/member/index.js.map +1 -1
  86. package/dist/member/member.types.d.ts +11 -0
  87. package/dist/member/member.types.js +18 -0
  88. package/dist/member/member.types.js.map +1 -0
  89. package/dist/member/types.js +11 -1
  90. package/dist/member/types.js.map +1 -1
  91. package/dist/member/util.js +60 -23
  92. package/dist/member/util.js.map +1 -1
  93. package/dist/members/index.js +4 -1
  94. package/dist/members/index.js.map +1 -1
  95. package/dist/members/request.js +75 -45
  96. package/dist/members/request.js.map +1 -1
  97. package/dist/members/util.js +308 -317
  98. package/dist/members/util.js.map +1 -1
  99. package/dist/metrics/config.js +1 -3
  100. package/dist/metrics/config.js.map +1 -1
  101. package/dist/metrics/constants.js +1 -0
  102. package/dist/metrics/constants.js.map +1 -1
  103. package/dist/metrics/index.d.ts +1 -1
  104. package/dist/metrics/index.js +1 -451
  105. package/dist/metrics/index.js.map +1 -1
  106. package/dist/multistream/mediaRequestManager.js +136 -40
  107. package/dist/multistream/mediaRequestManager.js.map +1 -1
  108. package/dist/multistream/receiveSlot.js.map +1 -1
  109. package/dist/multistream/receiveSlotManager.js +4 -4
  110. package/dist/multistream/receiveSlotManager.js.map +1 -1
  111. package/dist/multistream/remoteMedia.js.map +1 -1
  112. package/dist/multistream/remoteMediaGroup.js +60 -3
  113. package/dist/multistream/remoteMediaGroup.js.map +1 -1
  114. package/dist/multistream/remoteMediaManager.js +36 -0
  115. package/dist/multistream/remoteMediaManager.js.map +1 -1
  116. package/dist/multistream/sendSlotManager.js +233 -0
  117. package/dist/multistream/sendSlotManager.js.map +1 -0
  118. package/dist/reachability/index.js +18 -3
  119. package/dist/reachability/index.js.map +1 -1
  120. package/dist/reachability/request.js +5 -3
  121. package/dist/reachability/request.js.map +1 -1
  122. package/dist/reconnection-manager/index.js +181 -153
  123. package/dist/reconnection-manager/index.js.map +1 -1
  124. package/dist/recording-controller/index.js +21 -2
  125. package/dist/recording-controller/index.js.map +1 -1
  126. package/dist/recording-controller/util.js +9 -8
  127. package/dist/recording-controller/util.js.map +1 -1
  128. package/dist/roap/index.js +25 -32
  129. package/dist/roap/index.js.map +1 -1
  130. package/dist/roap/request.js +42 -51
  131. package/dist/roap/request.js.map +1 -1
  132. package/dist/roap/turnDiscovery.js +97 -38
  133. package/dist/roap/turnDiscovery.js.map +1 -1
  134. package/dist/rtcMetrics/constants.js +12 -0
  135. package/dist/rtcMetrics/constants.js.map +1 -0
  136. package/dist/rtcMetrics/index.js +117 -0
  137. package/dist/rtcMetrics/index.js.map +1 -0
  138. package/dist/statsAnalyzer/index.js +0 -1
  139. package/dist/statsAnalyzer/index.js.map +1 -1
  140. package/dist/types/annotation/annotation.types.d.ts +43 -0
  141. package/dist/types/annotation/constants.d.ts +31 -0
  142. package/dist/types/annotation/index.d.ts +124 -0
  143. package/dist/types/breakouts/events.d.ts +2 -0
  144. package/dist/types/breakouts/utils.d.ts +7 -0
  145. package/dist/types/common/errors/webex-errors.d.ts +1 -1
  146. package/dist/types/config.d.ts +0 -6
  147. package/dist/types/constants.d.ts +51 -21
  148. package/dist/types/controls-options-manager/enums.d.ts +2 -0
  149. package/dist/types/controls-options-manager/index.d.ts +1 -1
  150. package/dist/types/controls-options-manager/types.d.ts +7 -1
  151. package/dist/types/index.d.ts +1 -1
  152. package/dist/types/interpretation/collection.d.ts +5 -0
  153. package/dist/types/interpretation/index.d.ts +5 -0
  154. package/dist/types/interpretation/siLanguage.d.ts +5 -0
  155. package/dist/types/locus-info/index.d.ts +39 -1
  156. package/dist/types/media/index.d.ts +2 -0
  157. package/dist/types/media/properties.d.ts +16 -38
  158. package/dist/types/meeting/in-meeting-actions.d.ts +46 -2
  159. package/dist/types/meeting/index.d.ts +179 -379
  160. package/dist/types/meeting/locusMediaRequest.d.ts +70 -0
  161. package/dist/types/meeting/muteState.d.ts +39 -40
  162. package/dist/types/meeting/request.d.ts +25 -26
  163. package/dist/types/meeting/util.d.ts +74 -1
  164. package/dist/types/meeting-info/meeting-info-v2.d.ts +14 -3
  165. package/dist/types/meetings/index.d.ts +49 -1
  166. package/dist/types/meetings/meetings.types.d.ts +4 -0
  167. package/dist/types/member/index.d.ts +2 -0
  168. package/dist/types/members/request.d.ts +56 -11
  169. package/dist/types/members/util.d.ts +209 -1
  170. package/dist/types/metrics/config.d.ts +26 -2
  171. package/dist/types/metrics/constants.d.ts +1 -0
  172. package/dist/types/metrics/index.d.ts +17 -0
  173. package/dist/types/multistream/mediaRequestManager.d.ts +27 -10
  174. package/dist/types/multistream/receiveSlot.d.ts +3 -3
  175. package/dist/types/multistream/remoteMedia.d.ts +2 -2
  176. package/dist/types/multistream/remoteMediaManager.d.ts +14 -0
  177. package/dist/types/roap/request.d.ts +6 -8
  178. package/dist/types/roap/turnDiscovery.d.ts +18 -1
  179. package/package.json +21 -20
  180. package/src/annotation/annotation.types.ts +50 -0
  181. package/src/annotation/constants.ts +36 -0
  182. package/src/annotation/index.ts +328 -0
  183. package/src/breakouts/README.md +3 -2
  184. package/src/breakouts/breakout.ts +62 -27
  185. package/src/breakouts/events.ts +56 -0
  186. package/src/breakouts/index.ts +244 -64
  187. package/src/breakouts/utils.ts +13 -0
  188. package/src/common/errors/webex-errors.ts +6 -2
  189. package/src/common/logs/logger-proxy.ts +1 -1
  190. package/src/common/queue.ts +22 -8
  191. package/src/config.ts +0 -6
  192. package/src/constants.ts +111 -19
  193. package/src/controls-options-manager/enums.ts +2 -0
  194. package/src/controls-options-manager/index.ts +13 -10
  195. package/src/controls-options-manager/types.ts +10 -0
  196. package/src/controls-options-manager/util.ts +82 -11
  197. package/src/index.ts +18 -11
  198. package/src/interpretation/README.md +60 -0
  199. package/src/interpretation/collection.ts +19 -0
  200. package/src/interpretation/index.ts +332 -0
  201. package/src/interpretation/siLanguage.ts +18 -0
  202. package/src/locus-info/controlsUtils.ts +81 -0
  203. package/src/locus-info/index.ts +318 -57
  204. package/src/locus-info/infoUtils.ts +10 -2
  205. package/src/locus-info/mediaSharesUtils.ts +48 -0
  206. package/src/locus-info/parser.ts +224 -39
  207. package/src/locus-info/selfUtils.ts +32 -20
  208. package/src/media/index.ts +94 -108
  209. package/src/media/properties.ts +69 -109
  210. package/src/meeting/in-meeting-actions.ts +120 -4
  211. package/src/meeting/index.ts +1967 -2120
  212. package/src/meeting/locusMediaRequest.ts +314 -0
  213. package/src/meeting/muteState.ts +119 -194
  214. package/src/meeting/request.ts +122 -115
  215. package/src/meeting/util.ts +549 -413
  216. package/src/meeting-info/index.ts +54 -8
  217. package/src/meeting-info/meeting-info-v2.ts +89 -24
  218. package/src/meeting-info/utilv2.ts +6 -2
  219. package/src/meetings/index.ts +247 -87
  220. package/src/meetings/meetings.types.ts +12 -0
  221. package/src/meetings/util.ts +47 -12
  222. package/src/member/index.ts +28 -1
  223. package/src/member/types.ts +14 -0
  224. package/src/member/util.ts +75 -26
  225. package/src/members/index.ts +7 -1
  226. package/src/members/request.ts +61 -21
  227. package/src/members/util.ts +316 -326
  228. package/src/metrics/constants.ts +1 -0
  229. package/src/metrics/index.ts +1 -474
  230. package/src/multistream/mediaRequestManager.ts +183 -67
  231. package/src/multistream/receiveSlot.ts +4 -4
  232. package/src/multistream/receiveSlotManager.ts +4 -4
  233. package/src/multistream/remoteMedia.ts +2 -2
  234. package/src/multistream/remoteMediaGroup.ts +59 -0
  235. package/src/multistream/remoteMediaManager.ts +33 -0
  236. package/src/multistream/sendSlotManager.ts +170 -0
  237. package/src/reachability/index.ts +15 -4
  238. package/src/reachability/request.ts +7 -3
  239. package/src/reconnection-manager/index.ts +36 -29
  240. package/src/recording-controller/index.ts +20 -3
  241. package/src/recording-controller/util.ts +26 -9
  242. package/src/roap/index.ts +25 -30
  243. package/src/roap/request.ts +44 -51
  244. package/src/roap/turnDiscovery.ts +51 -25
  245. package/src/rtcMetrics/constants.ts +3 -0
  246. package/src/rtcMetrics/index.ts +100 -0
  247. package/src/statsAnalyzer/index.ts +0 -1
  248. package/test/integration/spec/converged-space-meetings.js +60 -3
  249. package/test/integration/spec/journey.js +336 -259
  250. package/test/integration/spec/space-meeting.js +76 -3
  251. package/test/unit/spec/annotation/index.ts +418 -0
  252. package/test/unit/spec/breakouts/breakout.ts +85 -26
  253. package/test/unit/spec/breakouts/events.ts +89 -0
  254. package/test/unit/spec/breakouts/index.ts +636 -98
  255. package/test/unit/spec/breakouts/utils.js +19 -1
  256. package/test/unit/spec/common/queue.js +31 -2
  257. package/test/unit/spec/controls-options-manager/index.js +8 -1
  258. package/test/unit/spec/controls-options-manager/util.js +576 -397
  259. package/test/unit/spec/fixture/locus.js +1 -0
  260. package/test/unit/spec/interpretation/collection.ts +15 -0
  261. package/test/unit/spec/interpretation/index.ts +589 -0
  262. package/test/unit/spec/interpretation/siLanguage.ts +28 -0
  263. package/test/unit/spec/locus-info/controlsUtils.js +195 -1
  264. package/test/unit/spec/locus-info/index.js +950 -45
  265. package/test/unit/spec/locus-info/infoUtils.js +37 -15
  266. package/test/unit/spec/locus-info/mediaSharesUtils.ts +22 -0
  267. package/test/unit/spec/locus-info/parser.js +62 -22
  268. package/test/unit/spec/locus-info/selfConstant.js +19 -0
  269. package/test/unit/spec/locus-info/selfUtils.js +131 -26
  270. package/test/unit/spec/media/index.ts +82 -79
  271. package/test/unit/spec/meeting/in-meeting-actions.ts +60 -2
  272. package/test/unit/spec/meeting/index.js +3208 -1734
  273. package/test/unit/spec/meeting/locusMediaRequest.ts +443 -0
  274. package/test/unit/spec/meeting/muteState.js +328 -417
  275. package/test/unit/spec/meeting/request.js +393 -48
  276. package/test/unit/spec/meeting/utils.js +552 -76
  277. package/test/unit/spec/meeting-info/index.js +181 -0
  278. package/test/unit/spec/meeting-info/meetinginfov2.js +258 -20
  279. package/test/unit/spec/meeting-info/utilv2.js +21 -0
  280. package/test/unit/spec/meetings/index.js +631 -145
  281. package/test/unit/spec/meetings/utils.js +164 -9
  282. package/test/unit/spec/member/index.js +44 -14
  283. package/test/unit/spec/member/util.js +296 -155
  284. package/test/unit/spec/members/index.js +23 -3
  285. package/test/unit/spec/members/request.js +167 -35
  286. package/test/unit/spec/metrics/index.js +1 -50
  287. package/test/unit/spec/multistream/mediaRequestManager.ts +366 -8
  288. package/test/unit/spec/multistream/receiveSlot.ts +1 -1
  289. package/test/unit/spec/multistream/remoteMediaGroup.ts +266 -0
  290. package/test/unit/spec/multistream/remoteMediaManager.ts +123 -0
  291. package/test/unit/spec/multistream/sendSlotManager.ts +242 -0
  292. package/test/unit/spec/reachability/index.ts +66 -5
  293. package/test/unit/spec/reachability/request.js +3 -1
  294. package/test/unit/spec/reconnection-manager/index.js +55 -5
  295. package/test/unit/spec/recording-controller/index.js +294 -218
  296. package/test/unit/spec/recording-controller/util.js +223 -96
  297. package/test/unit/spec/roap/index.ts +21 -48
  298. package/test/unit/spec/roap/request.ts +74 -60
  299. package/test/unit/spec/roap/turnDiscovery.ts +30 -6
  300. package/test/unit/spec/rtcMetrics/index.ts +68 -0
  301. package/test/utils/integrationTestUtils.js +46 -0
  302. package/test/utils/testUtils.js +0 -60
  303. package/src/metrics/config.ts +0 -487
@@ -2,6 +2,7 @@
2
2
 
3
3
  import '@webex/internal-plugin-mercury';
4
4
  import '@webex/internal-plugin-conversation';
5
+ import '@webex/internal-plugin-metrics';
5
6
  // @ts-ignore
6
7
  import {WebexPlugin} from '@webex/webex-core';
7
8
  import {setLogger} from '@webex/internal-media-core';
@@ -11,7 +12,6 @@ import * as mediaHelpersModule from '@webex/media-helpers';
11
12
  import 'webrtc-adapter';
12
13
 
13
14
  import Metrics from '../metrics';
14
- import {trigger, eventType} from '../metrics/config';
15
15
  import LoggerConfig from '../common/logs/logger-config';
16
16
  import StaticConfig from '../common/config';
17
17
  import LoggerProxy from '../common/logs/logger-proxy';
@@ -43,7 +43,6 @@ import {
43
43
  _CONVERSATION_URL_,
44
44
  CONVERSATION_URL,
45
45
  MEETINGNUMBER,
46
- BREAKOUTS,
47
46
  _JOINED_,
48
47
  _MOVED_,
49
48
  } from '../constants';
@@ -60,6 +59,7 @@ import CaptchaError from '../common/errors/captcha-error';
60
59
  import MeetingCollection from './collection';
61
60
  import MeetingsUtil from './util';
62
61
  import PermissionError from '../common/errors/permission';
62
+ import {INoiseReductionEffect, IVirtualBackgroundEffect} from './meetings.types';
63
63
 
64
64
  let mediaLogger;
65
65
 
@@ -146,13 +146,13 @@ export default class Meetings extends WebexPlugin {
146
146
  meetingCollection: any;
147
147
  personalMeetingRoom: any;
148
148
  preferredWebexSite: any;
149
- reachability: any;
149
+ reachability: Reachability;
150
150
  registered: any;
151
151
  request: any;
152
152
  geoHintInfo: any;
153
153
  meetingInfo: any;
154
154
  mediaHelpers: any;
155
-
155
+ breakoutLocusForHandleLater: any;
156
156
  namespace = MEETINGS;
157
157
 
158
158
  /**
@@ -202,15 +202,17 @@ export default class Meetings extends WebexPlugin {
202
202
  * @memberof Meetings
203
203
  */
204
204
  this.personalMeetingRoom = null;
205
+
205
206
  /**
206
- * The Reachability object to interact with server, starts as null until {@link Meeting#setReachability} is called
207
+ * The Reachability object to interact with server
207
208
  * starts as null
208
209
  * @instance
209
210
  * @type {Object}
210
211
  * @private
211
212
  * @memberof Meetings
212
213
  */
213
- this.reachability = null;
214
+ // @ts-ignore
215
+ this.reachability = new Reachability(this.webex);
214
216
 
215
217
  /**
216
218
  * If the meetings plugin has been registered and listening via {@link Meetings#register}
@@ -240,7 +242,6 @@ export default class Meetings extends WebexPlugin {
240
242
  */
241
243
  this.media = {
242
244
  getUserMedia: Media.getUserMedia,
243
- getSupportedDevice: Media.getSupportedDevice,
244
245
  };
245
246
 
246
247
  this.onReady();
@@ -260,8 +261,17 @@ export default class Meetings extends WebexPlugin {
260
261
 
261
262
  const isSelfJoined = newLocus?.self?.state === _JOINED_;
262
263
  const isSelfMoved = newLocus?.self?.state === _LEFT_ && newLocus?.self?.reason === _MOVED_;
263
- const deviceFromNewLocus = MeetingsUtil.getThisDevice(newLocus);
264
- const isNewLocusJoinThisDevice = MeetingsUtil.joinedOnThisDevice(meeting, newLocus);
264
+ // @ts-ignore
265
+ const deviceFromNewLocus = MeetingsUtil.getThisDevice(newLocus, this.webex.internal.device.url);
266
+ const isResourceMovedOnThisDevice =
267
+ deviceFromNewLocus?.state === _LEFT_ && deviceFromNewLocus?.reason === _MOVED_;
268
+
269
+ const isNewLocusJoinThisDevice = MeetingsUtil.joinedOnThisDevice(
270
+ meeting,
271
+ newLocus,
272
+ // @ts-ignore
273
+ this.webex.internal.device.url
274
+ );
265
275
  const isBreakoutLocusJoinThisDevice =
266
276
  breakoutLocus?.joinedWith?.correlationId &&
267
277
  breakoutLocus.joinedWith.correlationId === meeting?.correlationId;
@@ -295,9 +305,16 @@ export default class Meetings extends WebexPlugin {
295
305
 
296
306
  return false;
297
307
  }
298
- if (isSelfMoved && newLocus?.self?.removed) {
308
+ if (isSelfMoved && (newLocus?.self?.removed || isResourceMovedOnThisDevice)) {
299
309
  LoggerProxy.logger.log(
300
- 'Meetings:index#isNeedHandleMainLocus --> self moved main locus with self removed status, not need to handle'
310
+ 'Meetings:index#isNeedHandleMainLocus --> self moved main locus with self removed status or with device resource moved, not need to handle'
311
+ );
312
+
313
+ return false;
314
+ }
315
+ if (isSelfJoined && isResourceMovedOnThisDevice) {
316
+ LoggerProxy.logger.log(
317
+ 'Meetings:index#isNeedHandleMainLocus --> self device left&moved in main locus with self joined status, not need to handle'
301
318
  );
302
319
 
303
320
  return false;
@@ -319,8 +336,7 @@ export default class Meetings extends WebexPlugin {
319
336
  */
320
337
  private isNeedHandleLocusDTO(meeting: any, newLocus: any) {
321
338
  if (newLocus) {
322
- const isNewLocusAsBreakout =
323
- newLocus.controls?.breakout?.sessionType === BREAKOUTS.SESSION_TYPES.BREAKOUT;
339
+ const isNewLocusAsBreakout = MeetingsUtil.isBreakoutLocusDTO(newLocus);
324
340
  const isSelfMoved = newLocus?.self?.state === _LEFT_ && newLocus?.self?.reason === _MOVED_;
325
341
  if (!meeting) {
326
342
  if (isNewLocusAsBreakout) {
@@ -344,22 +360,19 @@ export default class Meetings extends WebexPlugin {
344
360
  }
345
361
 
346
362
  /**
347
- * handle locus events and takes meeting actions with them as they come in
363
+ * get corresponding meeting object by locus data
348
364
  * @param {Object} data a locus event
349
365
  * @param {String} data.locusUrl
350
366
  * @param {Object} data.locus
351
- * @param {Boolean} useRandomDelayForInfo whether a random delay should be added to fetching meeting info
352
- * @param {String} data.eventType
353
- * @returns {undefined}
367
+ * @returns {Object}
354
368
  * @private
355
369
  * @memberof Meetings
356
370
  */
357
- private handleLocusEvent(data: {locusUrl: string; locus: any}, useRandomDelayForInfo = false) {
358
- let meeting = null;
371
+ getCorrespondingMeetingByLocus(data) {
359
372
  // getting meeting by correlationId. This will happen for the new event
360
373
  // Either the locus
361
374
  // TODO : Add check for the callBack Address
362
- meeting =
375
+ return (
363
376
  this.meetingCollection.getByKey(LOCUS_URL, data.locusUrl) ||
364
377
  // @ts-ignore
365
378
  this.meetingCollection.getByKey(
@@ -376,7 +389,23 @@ export default class Meetings extends WebexPlugin {
376
389
  (data.locus.info?.isUnifiedSpaceMeeting
377
390
  ? undefined
378
391
  : this.meetingCollection.getByKey(CONVERSATION_URL, data.locus.conversationUrl)) ||
379
- this.meetingCollection.getByKey(MEETINGNUMBER, data.locus?.info?.webExMeetingId);
392
+ this.meetingCollection.getByKey(MEETINGNUMBER, data.locus?.info?.webExMeetingId)
393
+ );
394
+ }
395
+
396
+ /**
397
+ * handle locus events and takes meeting actions with them as they come in
398
+ * @param {Object} data a locus event
399
+ * @param {String} data.locusUrl
400
+ * @param {Object} data.locus
401
+ * @param {Boolean} useRandomDelayForInfo whether a random delay should be added to fetching meeting info
402
+ * @param {String} data.eventType
403
+ * @returns {undefined}
404
+ * @private
405
+ * @memberof Meetings
406
+ */
407
+ private handleLocusEvent(data: {locusUrl: string; locus: any}, useRandomDelayForInfo = false) {
408
+ let meeting = this.getCorrespondingMeetingByLocus(data);
380
409
 
381
410
  // Special case when locus has got replaced, This only happend once if a replace locus exists
382
411
  // https://sqbu-github.cisco.com/WebExSquared/locus/wiki/Locus-changing-mid-call
@@ -389,6 +418,9 @@ export default class Meetings extends WebexPlugin {
389
418
  );
390
419
  }
391
420
 
421
+ if (meeting && !MeetingsUtil.isBreakoutLocusDTO(data.locus)) {
422
+ meeting.locusInfo.updateMainSessionLocusCache(data.locus);
423
+ }
392
424
  if (!this.isNeedHandleLocusDTO(meeting, data.locus)) {
393
425
  LoggerProxy.logger.log(
394
426
  `Meetings:index#handleLocusEvent --> doesn't need to process locus event`
@@ -452,6 +484,7 @@ export default class Meetings extends WebexPlugin {
452
484
 
453
485
  // It's a new meeting so initialize the locus data
454
486
  meeting.locusInfo.initialSetup(data.locus);
487
+ this.checkHandleBreakoutLocus(data.locus);
455
488
  })
456
489
  .catch((e) => {
457
490
  LoggerProxy.logger.error(e);
@@ -461,10 +494,15 @@ export default class Meetings extends WebexPlugin {
461
494
  // because the other user left so before sending 'added' event make sure it exists in the collection
462
495
 
463
496
  if (this.getMeetingByType(_ID_, meeting.id)) {
464
- Metrics.postEvent({
465
- event: eventType.REMOTE_STARTED,
466
- meeting,
467
- data: {trigger: trigger.MERCURY_EVENT},
497
+ // @ts-ignore
498
+ this.webex.internal.newMetrics.submitClientEvent({
499
+ name: 'client.call.remote-started',
500
+ payload: {
501
+ trigger: 'mercury-event',
502
+ },
503
+ options: {
504
+ meetingId: meeting.id,
505
+ },
468
506
  });
469
507
  Trigger.trigger(
470
508
  this,
@@ -617,7 +655,7 @@ export default class Meetings extends WebexPlugin {
617
655
 
618
656
  MeetingsUtil.checkH264Support({disableNotifications: true});
619
657
  // @ts-ignore
620
- Metrics.initialSetup(this.meetingCollection, this.webex);
658
+ Metrics.initialSetup(this.webex);
621
659
  });
622
660
  }
623
661
 
@@ -786,6 +824,36 @@ export default class Meetings extends WebexPlugin {
786
824
  );
787
825
  }
788
826
 
827
+ /**
828
+ * Creates a noise reduction effect
829
+ *
830
+ * @param {INoiseReductionEffect} options optional custom effect options
831
+ * @returns {Promise<effect>} noise reduction effect.
832
+ * @public
833
+ * @memberof Meetings
834
+ */
835
+ createNoiseReductionEffect = async (options?: INoiseReductionEffect) => {
836
+ // @ts-ignore
837
+ const authToken = this.webex.credentials.supertoken.access_token;
838
+
839
+ return new mediaHelpersModule.NoiseReductionEffect({authToken, ...options});
840
+ };
841
+
842
+ /**
843
+ * Creates a virtual background effect
844
+ *
845
+ * @param {IVirtualBackgroundEffect} options optional custom effect options
846
+ * @returns {Promise<effect>} virtual background effect.
847
+ * @public
848
+ * @memberof Meetings
849
+ */
850
+ createVirtualBackgroundEffect = async (options?: IVirtualBackgroundEffect) => {
851
+ // @ts-ignore
852
+ const authToken = this.webex.credentials.supertoken.access_token;
853
+
854
+ return new mediaHelpersModule.VirtualBackgroundEffect({authToken, ...options});
855
+ };
856
+
789
857
  /**
790
858
  * Uploads logs to the webex services for tracking
791
859
  * @param {Object} [options={}]
@@ -861,17 +929,6 @@ export default class Meetings extends WebexPlugin {
861
929
  });
862
930
  }
863
931
 
864
- /**
865
- * initializes the reachability instance for Meetings
866
- * @returns {undefined}
867
- * @public
868
- * @memberof Meetings
869
- */
870
- setReachability() {
871
- // @ts-ignore
872
- this.reachability = new Reachability(this.webex);
873
- }
874
-
875
932
  /**
876
933
  * gets the reachability instance for Meetings
877
934
  * @returns {Reachability}
@@ -889,10 +946,6 @@ export default class Meetings extends WebexPlugin {
889
946
  * @memberof Meetings
890
947
  */
891
948
  startReachability() {
892
- if (!this.reachability) {
893
- this.setReachability();
894
- }
895
-
896
949
  return this.getReachability().gatherReachability();
897
950
  }
898
951
 
@@ -920,6 +973,29 @@ export default class Meetings extends WebexPlugin {
920
973
  if (res) {
921
974
  this.preferredWebexSite = MeetingsUtil.parseDefaultSiteFromMeetingPreferences(res);
922
975
  }
976
+
977
+ // fall back to getting the preferred site from the user information
978
+ if (!this.preferredWebexSite) {
979
+ // @ts-ignore
980
+ return this.webex.internal.user
981
+ .get()
982
+ .then((user) => {
983
+ const preferredWebexSite =
984
+ user?.userPreferences?.userPreferencesItems?.preferredWebExSite;
985
+ if (preferredWebexSite) {
986
+ this.preferredWebexSite = preferredWebexSite;
987
+ } else {
988
+ throw new Error('site not found');
989
+ }
990
+ })
991
+ .catch(() => {
992
+ LoggerProxy.logger.error(
993
+ 'Failed to fetch preferred site from user - no site will be set'
994
+ );
995
+ });
996
+ }
997
+
998
+ return Promise.resolve();
923
999
  });
924
1000
  }
925
1001
 
@@ -964,11 +1040,19 @@ export default class Meetings extends WebexPlugin {
964
1040
  * @param {string} destination - sipURL, spaceId, phonenumber, or locus object}
965
1041
  * @param {string} [type] - the optional specified type, such as locusId
966
1042
  * @param {Boolean} useRandomDelayForInfo - whether a random delay should be added to fetching meeting info
1043
+ * @param {Object} infoExtraParams extra parameters to be provided when fetching meeting info
1044
+ * @param {string} correlationId - the optional specified correlationId
967
1045
  * @returns {Promise<Meeting>} A new Meeting.
968
1046
  * @public
969
1047
  * @memberof Meetings
970
1048
  */
971
- public create(destination: string, type: string = null, useRandomDelayForInfo = false) {
1049
+ public create(
1050
+ destination: string,
1051
+ type: string = null,
1052
+ useRandomDelayForInfo = false,
1053
+ infoExtraParams = {},
1054
+ correlationId: string = undefined
1055
+ ) {
972
1056
  // TODO: type should be from a dictionary
973
1057
 
974
1058
  // Validate meeting information based on the provided destination and
@@ -1013,48 +1097,52 @@ export default class Meetings extends WebexPlugin {
1013
1097
  // Validate if a meeting was found.
1014
1098
  if (!meeting) {
1015
1099
  // Create a meeting based on the normalized destination and type.
1016
- return this.createMeeting(targetDest, type, useRandomDelayForInfo).then(
1017
- (createdMeeting: any) => {
1018
- // If the meeting was successfully created.
1019
- if (createdMeeting && createdMeeting.on) {
1020
- // Create a destruction event for the meeting.
1021
- createdMeeting.on(EVENTS.DESTROY_MEETING, (payload) => {
1022
- // @ts-ignore
1023
- if (this.config.autoUploadLogs) {
1024
- this.uploadLogs({
1025
- callStart: createdMeeting.locusInfo?.fullState?.lastActive,
1026
- correlationId: createdMeeting.correlationId,
1027
- feedbackId: createdMeeting.correlationId,
1028
- locusId: createdMeeting.locusId,
1029
- meetingId: createdMeeting.locusInfo?.info?.webExMeetingId,
1030
- }).then(() => this.destroy(createdMeeting, payload.reason));
1031
- } else {
1032
- this.destroy(createdMeeting, payload.reason);
1033
- }
1034
- });
1035
-
1036
- createdMeeting.on(EVENTS.REQUEST_UPLOAD_LOGS, (meetingInstance) => {
1037
- // @ts-ignore
1038
- if (this.config.autoUploadLogs) {
1039
- this.uploadLogs({
1040
- callStart: meetingInstance?.locusInfo?.fullState?.lastActive,
1041
- correlationId: meetingInstance.correlationId,
1042
- feedbackId: meetingInstance.correlationId,
1043
- locusId: meetingInstance.locusId,
1044
- meetingId: meetingInstance.locusInfo?.info?.webExMeetingId,
1045
- });
1046
- }
1047
- });
1048
- } else {
1049
- LoggerProxy.logger.error(
1050
- `Meetings:index#create --> ERROR, meeting does not have on method, will not be destroyed, meeting cleanup impossible for meeting: ${meeting}`
1051
- );
1052
- }
1053
-
1054
- // Return the newly created meeting.
1055
- return Promise.resolve(createdMeeting);
1100
+ return this.createMeeting(
1101
+ targetDest,
1102
+ type,
1103
+ useRandomDelayForInfo,
1104
+ infoExtraParams,
1105
+ correlationId
1106
+ ).then((createdMeeting: any) => {
1107
+ // If the meeting was successfully created.
1108
+ if (createdMeeting && createdMeeting.on) {
1109
+ // Create a destruction event for the meeting.
1110
+ createdMeeting.on(EVENTS.DESTROY_MEETING, (payload) => {
1111
+ // @ts-ignore
1112
+ if (this.config.autoUploadLogs) {
1113
+ this.uploadLogs({
1114
+ callStart: createdMeeting.locusInfo?.fullState?.lastActive,
1115
+ correlationId: createdMeeting.correlationId,
1116
+ feedbackId: createdMeeting.correlationId,
1117
+ locusId: createdMeeting.locusId,
1118
+ meetingId: createdMeeting.locusInfo?.info?.webExMeetingId,
1119
+ }).then(() => this.destroy(createdMeeting, payload.reason));
1120
+ } else {
1121
+ this.destroy(createdMeeting, payload.reason);
1122
+ }
1123
+ });
1124
+
1125
+ createdMeeting.on(EVENTS.REQUEST_UPLOAD_LOGS, (meetingInstance) => {
1126
+ // @ts-ignore
1127
+ if (this.config.autoUploadLogs) {
1128
+ this.uploadLogs({
1129
+ callStart: meetingInstance?.locusInfo?.fullState?.lastActive,
1130
+ correlationId: meetingInstance.correlationId,
1131
+ feedbackId: meetingInstance.correlationId,
1132
+ locusId: meetingInstance.locusId,
1133
+ meetingId: meetingInstance.locusInfo?.info?.webExMeetingId,
1134
+ });
1135
+ }
1136
+ });
1137
+ } else {
1138
+ LoggerProxy.logger.error(
1139
+ `Meetings:index#create --> ERROR, meeting does not have on method, will not be destroyed, meeting cleanup impossible for meeting: ${meeting}`
1140
+ );
1056
1141
  }
1057
- );
1142
+
1143
+ // Return the newly created meeting.
1144
+ return Promise.resolve(createdMeeting);
1145
+ });
1058
1146
  }
1059
1147
 
1060
1148
  // Return the existing meeting.
@@ -1067,6 +1155,8 @@ export default class Meetings extends WebexPlugin {
1067
1155
  * @param {String} destination see create()
1068
1156
  * @param {String} type see create()
1069
1157
  * @param {Boolean} useRandomDelayForInfo whether a random delay should be added to fetching meeting info
1158
+ * @param {Object} infoExtraParams extra parameters to be provided when fetching meeting info
1159
+ * @param {String} correlationId the optional specified correlationId
1070
1160
  * @returns {Promise} a new meeting instance complete with meeting info and destination
1071
1161
  * @private
1072
1162
  * @memberof Meetings
@@ -1074,7 +1164,9 @@ export default class Meetings extends WebexPlugin {
1074
1164
  private async createMeeting(
1075
1165
  destination: any,
1076
1166
  type: string = null,
1077
- useRandomDelayForInfo = false
1167
+ useRandomDelayForInfo = false,
1168
+ infoExtraParams = {},
1169
+ correlationId: string = undefined
1078
1170
  ) {
1079
1171
  const meeting = new Meeting(
1080
1172
  {
@@ -1088,6 +1180,7 @@ export default class Meetings extends WebexPlugin {
1088
1180
  meetingInfoProvider: this.meetingInfo,
1089
1181
  destination,
1090
1182
  destinationType: type,
1183
+ correlationId,
1091
1184
  },
1092
1185
  {
1093
1186
  // @ts-ignore
@@ -1122,12 +1215,12 @@ export default class Meetings extends WebexPlugin {
1122
1215
 
1123
1216
  if (enableUnifiedMeetings && !isMeetingActive && useRandomDelayForInfo && waitingTime > 0) {
1124
1217
  meeting.fetchMeetingInfoTimeoutId = setTimeout(
1125
- () => meeting.fetchMeetingInfo({}),
1218
+ () => meeting.fetchMeetingInfo({extraParams: infoExtraParams}),
1126
1219
  waitingTime
1127
1220
  );
1128
1221
  meeting.parseMeetingInfo(undefined, destination);
1129
1222
  } else {
1130
- await meeting.fetchMeetingInfo({});
1223
+ await meeting.fetchMeetingInfo({extraParams: infoExtraParams});
1131
1224
  }
1132
1225
  } catch (err) {
1133
1226
  if (
@@ -1241,7 +1334,8 @@ export default class Meetings extends WebexPlugin {
1241
1334
  const activeLocusUrl = [];
1242
1335
 
1243
1336
  if (locusArray?.loci && locusArray.loci.length > 0) {
1244
- locusArray.loci.forEach((locus) => {
1337
+ const lociToUpdate = this.sortLocusArrayToUpdate(locusArray.loci);
1338
+ lociToUpdate.forEach((locus) => {
1245
1339
  activeLocusUrl.push(locus.url);
1246
1340
  this.handleLocusEvent({
1247
1341
  locus,
@@ -1272,6 +1366,72 @@ export default class Meetings extends WebexPlugin {
1272
1366
  });
1273
1367
  }
1274
1368
 
1369
+ /**
1370
+ * sort out locus array for initial creating
1371
+ * @param {Array} loci original locus array
1372
+ * @returns {undefined}
1373
+ * @public
1374
+ * @memberof Meetings
1375
+ */
1376
+ sortLocusArrayToUpdate(loci: any[]) {
1377
+ const mainLoci = loci.filter((locus) => !MeetingsUtil.isBreakoutLocusDTO(locus));
1378
+ const breakoutLoci = loci.filter((locus) => MeetingsUtil.isValidBreakoutLocus(locus));
1379
+ this.breakoutLocusForHandleLater = [];
1380
+ const lociToUpdate = [...mainLoci];
1381
+ breakoutLoci.forEach((breakoutLocus) => {
1382
+ const associateMainLocus = mainLoci.find(
1383
+ (mainLocus) => mainLocus.controls?.breakout?.url === breakoutLocus.controls?.breakout?.url
1384
+ );
1385
+ const existCorrespondingMeeting = this.getCorrespondingMeetingByLocus({
1386
+ locus: breakoutLocus,
1387
+ locusUrl: breakoutLocus.url,
1388
+ });
1389
+
1390
+ if (associateMainLocus && !existCorrespondingMeeting) {
1391
+ // if exists both main session and breakout session locus of the same non-exist meeting, handle main locus first,
1392
+ // after meeting create with main locus, then handle the associate breakout locus.
1393
+ // if only handle breakout locus, will miss some date
1394
+ this.breakoutLocusForHandleLater.push(breakoutLocus);
1395
+ } else {
1396
+ lociToUpdate.push(breakoutLocus);
1397
+ }
1398
+ });
1399
+
1400
+ return lociToUpdate;
1401
+ }
1402
+
1403
+ /**
1404
+ * check breakout locus which waiting for main locus's meeting to be created, then handle the breakout locus
1405
+ * @param {Object} newCreatedLocus the locus which just create meeting object of it
1406
+ * @returns {undefined}
1407
+ * @public
1408
+ * @memberof Meetings
1409
+ */
1410
+ checkHandleBreakoutLocus(newCreatedLocus) {
1411
+ if (
1412
+ !newCreatedLocus ||
1413
+ !this.breakoutLocusForHandleLater ||
1414
+ !this.breakoutLocusForHandleLater.length
1415
+ ) {
1416
+ return;
1417
+ }
1418
+ if (MeetingsUtil.isBreakoutLocusDTO(newCreatedLocus)) {
1419
+ return;
1420
+ }
1421
+ const existIndex = this.breakoutLocusForHandleLater.findIndex(
1422
+ (breakoutLocus) =>
1423
+ breakoutLocus.controls?.breakout?.url === newCreatedLocus.controls?.breakout?.url
1424
+ );
1425
+
1426
+ if (existIndex < 0) {
1427
+ return;
1428
+ }
1429
+
1430
+ const associateBreakoutLocus = this.breakoutLocusForHandleLater[existIndex];
1431
+ this.handleLocusEvent({locus: associateBreakoutLocus, locusUrl: associateBreakoutLocus.url});
1432
+ this.breakoutLocusForHandleLater.splice(existIndex, 1);
1433
+ }
1434
+
1275
1435
  /**
1276
1436
  * Get all scheduled meetings.
1277
1437
  * @param {object} options
@@ -0,0 +1,12 @@
1
+ import type {
2
+ NoiseReductionEffectOptions,
3
+ VirtualBackgroundEffectOptions,
4
+ } from '@webex/media-helpers';
5
+
6
+ type INoiseReductionEffect = Omit<
7
+ NoiseReductionEffectOptions,
8
+ 'authToken' | 'workletProcessorUrl' | 'legacyProcessorUrl'
9
+ >;
10
+ type IVirtualBackgroundEffect = Omit<VirtualBackgroundEffectOptions, 'authToken'>;
11
+
12
+ export type {INoiseReductionEffect, IVirtualBackgroundEffect};
@@ -1,19 +1,23 @@
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
+ LOCUS,
14
+ LOCUSEVENT,
10
15
  ROAP,
11
- _LEFT_,
12
- _MOVED_,
13
- _JOINED_,
14
16
  } from '../constants';
15
17
  import LoggerProxy from '../common/logs/logger-proxy';
16
18
  import Trigger from '../common/events/trigger-proxy';
19
+ import BEHAVIORAL_METRICS from '../metrics/constants';
20
+ import Metrics from '../metrics';
17
21
 
18
22
  /**
19
23
  * Meetings Media Codec Missing Event
@@ -47,6 +51,14 @@ MeetingsUtil.handleRoapMercury = (envelope, meetingCollection) => {
47
51
  if (meeting) {
48
52
  const {seq, messageType, tieBreaker, errorType, errorCause} = data.message;
49
53
 
54
+ Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.ROAP_MERCURY_EVENT_RECEIVED, {
55
+ correlation_id: data.correlationId,
56
+ seq,
57
+ message_type: messageType,
58
+ error_type: errorType,
59
+ error_cause: errorCause,
60
+ });
61
+
50
62
  if (messageType === ROAP.ROAP_TYPES.TURN_DISCOVERY_RESPONSE) {
51
63
  // turn discovery is not part of normal roap protocol and so we are not handling it
52
64
  // through the usual roap state machine
@@ -228,13 +240,12 @@ MeetingsUtil.checkH264Support = async function checkH264Support(options: {
228
240
  /**
229
241
  * get device from locus data
230
242
  * @param {Object} newLocus new locus data
243
+ * @param {String} deviceUrl current device url
231
244
  * @returns {Object}
232
245
  */
233
- MeetingsUtil.getThisDevice = (newLocus: any) => {
246
+ MeetingsUtil.getThisDevice = (newLocus: any, deviceUrl: string) => {
234
247
  if (newLocus?.self?.devices?.length > 0) {
235
- const [thisDevice] = newLocus.self.devices;
236
-
237
- return thisDevice;
248
+ return newLocus.self.devices.find((device) => device.url === deviceUrl);
238
249
  }
239
250
 
240
251
  return null;
@@ -244,10 +255,11 @@ MeetingsUtil.getThisDevice = (newLocus: any) => {
244
255
  * get self device joined status from locus data
245
256
  * @param {Object} meeting current meeting data
246
257
  * @param {Object} newLocus new locus data
258
+ * @param {String} deviceUrl current device url
247
259
  * @returns {Object}
248
260
  */
249
- MeetingsUtil.joinedOnThisDevice = (meeting: any, newLocus: any) => {
250
- const thisDevice = MeetingsUtil.getThisDevice(newLocus);
261
+ MeetingsUtil.joinedOnThisDevice = (meeting: any, newLocus: any, deviceUrl: string) => {
262
+ const thisDevice = MeetingsUtil.getThisDevice(newLocus, deviceUrl);
251
263
  if (thisDevice) {
252
264
  if (!thisDevice.correlationId || meeting?.correlationId === thisDevice.correlationId) {
253
265
  return (
@@ -260,4 +272,27 @@ MeetingsUtil.joinedOnThisDevice = (meeting: any, newLocus: any) => {
260
272
  return false;
261
273
  };
262
274
 
275
+ /**
276
+ * check the new locus is breakout session's one or not
277
+ * @param {Object} newLocus new locus data
278
+ * @returns {boolean}
279
+ * @private
280
+ */
281
+ MeetingsUtil.isBreakoutLocusDTO = (newLocus: any) => {
282
+ return newLocus?.controls?.breakout?.sessionType === BREAKOUTS.SESSION_TYPES.BREAKOUT;
283
+ };
284
+
285
+ /**
286
+ * check the locus is valid breakout locus or not
287
+ * @param {Object} locus
288
+ * @returns {boolean}
289
+ * @private
290
+ */
291
+ MeetingsUtil.isValidBreakoutLocus = (locus: any) => {
292
+ const inActiveStatus = locus?.fullState?.state === LOCUS.STATE.INACTIVE;
293
+ const isLocusAsBreakout = MeetingsUtil.isBreakoutLocusDTO(locus);
294
+ const selfJoined = locus.self?.state === _JOINED_;
295
+
296
+ return isLocusAsBreakout && !inActiveStatus && selfJoined;
297
+ };
263
298
  export default MeetingsUtil;