@webex/plugin-meetings 3.0.0-beta.16 → 3.0.0-beta.18

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 (156) hide show
  1. package/dist/breakouts/breakout.js +116 -0
  2. package/dist/breakouts/breakout.js.map +1 -0
  3. package/dist/breakouts/collection.js +23 -0
  4. package/dist/breakouts/collection.js.map +1 -0
  5. package/dist/breakouts/index.js +226 -0
  6. package/dist/breakouts/index.js.map +1 -0
  7. package/dist/config.js +4 -1
  8. package/dist/config.js.map +1 -1
  9. package/dist/constants.js +43 -6
  10. package/dist/constants.js.map +1 -1
  11. package/dist/locus-info/controlsUtils.js +2 -1
  12. package/dist/locus-info/controlsUtils.js.map +1 -1
  13. package/dist/locus-info/index.js +48 -0
  14. package/dist/locus-info/index.js.map +1 -1
  15. package/dist/locus-info/parser.js +1 -0
  16. package/dist/locus-info/parser.js.map +1 -1
  17. package/dist/locus-info/selfUtils.js +19 -11
  18. package/dist/locus-info/selfUtils.js.map +1 -1
  19. package/dist/media/index.js +3 -3
  20. package/dist/media/index.js.map +1 -1
  21. package/dist/media/properties.js +4 -4
  22. package/dist/media/properties.js.map +1 -1
  23. package/dist/meeting/in-meeting-actions.js +5 -1
  24. package/dist/meeting/in-meeting-actions.js.map +1 -1
  25. package/dist/meeting/index.js +652 -459
  26. package/dist/meeting/index.js.map +1 -1
  27. package/dist/meeting/request.js +25 -44
  28. package/dist/meeting/request.js.map +1 -1
  29. package/dist/meeting/request.type.js.map +1 -1
  30. package/dist/meeting/util.js +22 -57
  31. package/dist/meeting/util.js.map +1 -1
  32. package/dist/meeting-info/meeting-info-v2.js +2 -0
  33. package/dist/meeting-info/meeting-info-v2.js.map +1 -1
  34. package/dist/meetings/index.js +28 -18
  35. package/dist/meetings/index.js.map +1 -1
  36. package/dist/meetings/request.js +14 -12
  37. package/dist/meetings/request.js.map +1 -1
  38. package/dist/member/index.js +9 -0
  39. package/dist/member/index.js.map +1 -1
  40. package/dist/member/util.js +14 -1
  41. package/dist/member/util.js.map +1 -1
  42. package/dist/members/index.js +8 -6
  43. package/dist/members/index.js.map +1 -1
  44. package/dist/members/request.js +3 -1
  45. package/dist/members/request.js.map +1 -1
  46. package/dist/multistream/mediaRequestManager.js +46 -6
  47. package/dist/multistream/mediaRequestManager.js.map +1 -1
  48. package/dist/multistream/multistreamMedia.js +4 -0
  49. package/dist/multistream/multistreamMedia.js.map +1 -1
  50. package/dist/multistream/receiveSlot.js +3 -3
  51. package/dist/multistream/receiveSlot.js.map +1 -1
  52. package/dist/multistream/receiveSlotManager.js +8 -6
  53. package/dist/multistream/receiveSlotManager.js.map +1 -1
  54. package/dist/multistream/remoteMedia.js.map +1 -1
  55. package/dist/multistream/remoteMediaGroup.js.map +1 -1
  56. package/dist/multistream/remoteMediaManager.js +168 -63
  57. package/dist/multistream/remoteMediaManager.js.map +1 -1
  58. package/dist/reachability/index.js +63 -51
  59. package/dist/reachability/index.js.map +1 -1
  60. package/dist/reactions/constants.js +13 -0
  61. package/dist/reactions/constants.js.map +1 -0
  62. package/dist/reactions/reactions.type.js.map +1 -1
  63. package/dist/reconnection-manager/index.js +25 -12
  64. package/dist/reconnection-manager/index.js.map +1 -1
  65. package/dist/recording-controller/enums.js +17 -0
  66. package/dist/recording-controller/enums.js.map +1 -0
  67. package/dist/recording-controller/index.js +343 -0
  68. package/dist/recording-controller/index.js.map +1 -0
  69. package/dist/recording-controller/util.js +63 -0
  70. package/dist/recording-controller/util.js.map +1 -0
  71. package/dist/roap/request.js +88 -68
  72. package/dist/roap/request.js.map +1 -1
  73. package/dist/roap/turnDiscovery.js +72 -47
  74. package/dist/roap/turnDiscovery.js.map +1 -1
  75. package/dist/statsAnalyzer/index.js +3 -3
  76. package/dist/statsAnalyzer/index.js.map +1 -1
  77. package/dist/statsAnalyzer/mqaUtil.js +18 -6
  78. package/dist/statsAnalyzer/mqaUtil.js.map +1 -1
  79. package/package.json +24 -19
  80. package/src/breakouts/README.md +190 -0
  81. package/src/breakouts/breakout.ts +110 -0
  82. package/src/breakouts/collection.ts +19 -0
  83. package/src/breakouts/index.ts +225 -0
  84. package/src/config.ts +4 -1
  85. package/src/constants.ts +39 -1
  86. package/src/locus-info/controlsUtils.ts +2 -0
  87. package/src/locus-info/index.ts +59 -1
  88. package/src/locus-info/parser.ts +1 -0
  89. package/src/locus-info/selfUtils.ts +8 -0
  90. package/src/media/index.ts +1 -2
  91. package/src/media/properties.ts +6 -9
  92. package/src/meeting/in-meeting-actions.ts +8 -0
  93. package/src/meeting/index.ts +360 -111
  94. package/src/meeting/request.ts +9 -31
  95. package/src/meeting/request.type.ts +2 -0
  96. package/src/meeting/util.ts +25 -60
  97. package/src/meeting-info/meeting-info-v2.ts +2 -0
  98. package/src/meetings/index.ts +10 -5
  99. package/src/meetings/request.ts +1 -1
  100. package/src/member/index.ts +9 -0
  101. package/src/member/util.ts +14 -1
  102. package/src/members/index.ts +1 -0
  103. package/src/members/request.ts +1 -0
  104. package/src/multistream/mediaRequestManager.ts +79 -15
  105. package/src/multistream/multistreamMedia.ts +4 -0
  106. package/src/multistream/receiveSlot.ts +17 -12
  107. package/src/multistream/receiveSlotManager.ts +22 -21
  108. package/src/multistream/remoteMedia.ts +1 -1
  109. package/src/multistream/remoteMediaGroup.ts +2 -2
  110. package/src/multistream/remoteMediaManager.ts +150 -37
  111. package/src/reachability/index.ts +16 -13
  112. package/src/reactions/constants.ts +4 -0
  113. package/src/reactions/reactions.type.ts +25 -0
  114. package/src/reconnection-manager/index.ts +18 -9
  115. package/src/recording-controller/enums.ts +8 -0
  116. package/src/recording-controller/index.ts +315 -0
  117. package/src/recording-controller/util.ts +58 -0
  118. package/src/roap/request.ts +78 -73
  119. package/src/roap/turnDiscovery.ts +8 -6
  120. package/src/statsAnalyzer/index.ts +4 -4
  121. package/src/statsAnalyzer/mqaUtil.ts +6 -0
  122. package/test/unit/spec/breakouts/breakout.ts +119 -0
  123. package/test/unit/spec/breakouts/collection.ts +15 -0
  124. package/test/unit/spec/breakouts/index.ts +293 -0
  125. package/test/unit/spec/locus-info/controlsUtils.js +20 -0
  126. package/test/unit/spec/locus-info/index.js +103 -0
  127. package/test/unit/spec/locus-info/selfConstant.js +25 -0
  128. package/test/unit/spec/locus-info/selfUtils.js +84 -0
  129. package/test/unit/spec/media/index.ts +1 -1
  130. package/test/unit/spec/media/properties.ts +9 -9
  131. package/test/unit/spec/meeting/effectsState.js +5 -1
  132. package/test/unit/spec/meeting/in-meeting-actions.ts +5 -1
  133. package/test/unit/spec/meeting/index.js +241 -50
  134. package/test/unit/spec/meeting/request.js +17 -0
  135. package/test/unit/spec/meeting/utils.js +28 -122
  136. package/test/unit/spec/meetings/index.js +1 -0
  137. package/test/unit/spec/member/util.js +26 -1
  138. package/test/unit/spec/multistream/mediaRequestManager.ts +312 -50
  139. package/test/unit/spec/multistream/receiveSlot.ts +6 -6
  140. package/test/unit/spec/multistream/receiveSlotManager.ts +13 -13
  141. package/test/unit/spec/multistream/remoteMedia.ts +2 -2
  142. package/test/unit/spec/multistream/remoteMediaGroup.ts +5 -5
  143. package/test/unit/spec/multistream/remoteMediaManager.ts +354 -65
  144. package/test/unit/spec/reachability/index.ts +58 -24
  145. package/test/unit/spec/reconnection-manager/index.js +42 -13
  146. package/test/unit/spec/recording-controller/index.js +231 -0
  147. package/test/unit/spec/recording-controller/util.js +102 -0
  148. package/test/unit/spec/roap/index.ts +2 -1
  149. package/test/unit/spec/roap/request.ts +114 -0
  150. package/test/unit/spec/roap/turnDiscovery.ts +45 -29
  151. package/test/unit/spec/stats-analyzer/index.js +2 -2
  152. package/test/utils/webex-test-users.js +1 -0
  153. package/tsconfig.json +6 -0
  154. package/dist/media/internal-media-core-wrapper.js +0 -18
  155. package/dist/media/internal-media-core-wrapper.js.map +0 -1
  156. package/src/media/internal-media-core-wrapper.ts +0 -9
@@ -2,7 +2,15 @@ import uuid from 'uuid';
2
2
  import {cloneDeep, isEqual, pick, isString, defer} from 'lodash';
3
3
  // @ts-ignore - Fix this
4
4
  import {StatelessWebexPlugin} from '@webex/webex-core';
5
- import {Media as WebRTCMedia, MediaConnection as MC} from '@webex/internal-media-core';
5
+ import {
6
+ ConnectionState,
7
+ Errors,
8
+ ErrorType,
9
+ Event,
10
+ Media as WebRTCMedia,
11
+ MediaType,
12
+ RemoteTrackType,
13
+ } from '@webex/internal-media-core';
6
14
 
7
15
  import {
8
16
  MeetingNotActiveError,
@@ -28,8 +36,10 @@ import ReconnectionManager from '../reconnection-manager';
28
36
  import MeetingRequest from './request';
29
37
  import Members from '../members/index';
30
38
  import MeetingUtil from './util';
39
+ import RecordingUtil from '../recording-controller/util';
31
40
  import MediaUtil from '../media/util';
32
41
  import Transcription from '../transcription';
42
+ import {Reactions, SkinTones} from '../reactions/reactions';
33
43
  import PasswordError from '../common/errors/password-error';
34
44
  import CaptchaError from '../common/errors/captcha-error';
35
45
  import ReconnectionError from '../common/errors/reconnection';
@@ -44,6 +54,7 @@ import {
44
54
  EVENT_TRIGGERS,
45
55
  EVENT_TYPES,
46
56
  EVENTS,
57
+ BREAKOUTS,
47
58
  FLOOR_ACTION,
48
59
  FULL_STATE,
49
60
  LAYOUT_TYPES,
@@ -84,10 +95,18 @@ import {
84
95
  Event as RemoteMediaManagerEvent,
85
96
  } from '../multistream/remoteMediaManager';
86
97
  import {MultistreamMedia} from '../multistream/multistreamMedia';
87
- import {SkinTones, Reactions} from '../reactions/reactions';
88
- import {Reaction, ReactionType, SkinToneType} from '../reactions/reactions.type';
98
+ import {
99
+ Reaction,
100
+ ReactionType,
101
+ SkinToneType,
102
+ ProcessedReaction,
103
+ RelayEvent,
104
+ } from '../reactions/reactions.type';
105
+ import Breakouts from '../breakouts';
89
106
 
90
107
  import InMeetingActions from './in-meeting-actions';
108
+ import {REACTION_RELAY_TYPES} from '../reactions/constants';
109
+ import RecordingController from '../recording-controller';
91
110
 
92
111
  const {isBrowser} = BrowserDetection();
93
112
 
@@ -403,6 +422,7 @@ export const MEDIA_UPDATE_TYPE = {
403
422
  export default class Meeting extends StatelessWebexPlugin {
404
423
  attrs: any;
405
424
  audio: any;
425
+ breakouts: any;
406
426
  conversationUrl: string;
407
427
  correlationId: string;
408
428
  destination: string;
@@ -454,6 +474,8 @@ export default class Meeting extends StatelessWebexPlugin {
454
474
  mediaRequestManagers: {
455
475
  audio: MediaRequestManager;
456
476
  video: MediaRequestManager;
477
+ screenShareAudio: MediaRequestManager;
478
+ screenShareVideo: MediaRequestManager;
457
479
  };
458
480
 
459
481
  meetingInfoFailureReason: string;
@@ -463,6 +485,7 @@ export default class Meeting extends StatelessWebexPlugin {
463
485
  queuedMediaUpdates: any[];
464
486
  recording: any;
465
487
  remoteMediaManager: RemoteMediaManager | null;
488
+ recordingController: RecordingController;
466
489
  requiredCaptcha: any;
467
490
  receiveSlotManager: ReceiveSlotManager;
468
491
  shareStatus: string;
@@ -573,16 +596,25 @@ export default class Meeting extends StatelessWebexPlugin {
573
596
  */
574
597
  // TODO: needs to be defined as a class
575
598
  this.meetingInfo = {};
599
+ /**
600
+ * @instance
601
+ * @type {Breakouts}
602
+ * @public
603
+ * @memberof Meeting
604
+ */
605
+ // @ts-ignore
606
+ this.breakouts = new Breakouts({}, {parent: this.webex});
576
607
  /**
577
608
  * helper class for managing receive slots (for multistream media connections)
578
609
  */
579
610
  this.receiveSlotManager = new ReceiveSlotManager(this);
580
611
  /**
581
- * Helper class for managing media requests for main video (for multistream media connections)
582
- * All media requests sent out for main video for this meeting have to go through it.
612
+ * Object containing helper classes for managing media requests for audio/video/screenshare (for multistream media connections)
613
+ * All multistream media requests sent out for this meeting have to go through them.
583
614
  */
584
615
  this.mediaRequestManagers = {
585
- audio: new MediaRequestManager((mediaRequests) => {
616
+ // @ts-ignore - config coming from registerPlugin
617
+ audio: new MediaRequestManager(this.config.degradationPreferences, (mediaRequests) => {
586
618
  if (!this.mediaProperties.webrtcMediaConnection) {
587
619
  LoggerProxy.logger.warn(
588
620
  'Meeting:index#mediaRequestManager --> trying to send audio media request before media connection was created'
@@ -590,12 +622,10 @@ export default class Meeting extends StatelessWebexPlugin {
590
622
 
591
623
  return;
592
624
  }
593
- this.mediaProperties.webrtcMediaConnection.requestMedia(
594
- MC.MediaType.AudioMain,
595
- mediaRequests
596
- );
625
+ this.mediaProperties.webrtcMediaConnection.requestMedia(MediaType.AudioMain, mediaRequests);
597
626
  }),
598
- video: new MediaRequestManager((mediaRequests) => {
627
+ // @ts-ignore - config coming from registerPlugin
628
+ video: new MediaRequestManager(this.config.degradationPreferences, (mediaRequests) => {
599
629
  if (!this.mediaProperties.webrtcMediaConnection) {
600
630
  LoggerProxy.logger.warn(
601
631
  'Meeting:index#mediaRequestManager --> trying to send video media request before media connection was created'
@@ -603,11 +633,42 @@ export default class Meeting extends StatelessWebexPlugin {
603
633
 
604
634
  return;
605
635
  }
606
- this.mediaProperties.webrtcMediaConnection.requestMedia(
607
- MC.MediaType.VideoMain,
608
- mediaRequests
609
- );
636
+ this.mediaProperties.webrtcMediaConnection.requestMedia(MediaType.VideoMain, mediaRequests);
610
637
  }),
638
+ screenShareAudio: new MediaRequestManager(
639
+ // @ts-ignore - config coming from registerPlugin
640
+ this.config.degradationPreferences,
641
+ (mediaRequests) => {
642
+ if (!this.mediaProperties.webrtcMediaConnection) {
643
+ LoggerProxy.logger.warn(
644
+ 'Meeting:index#mediaRequestManager --> trying to send screenshare audio media request before media connection was created'
645
+ );
646
+
647
+ return;
648
+ }
649
+ this.mediaProperties.webrtcMediaConnection.requestMedia(
650
+ MediaType.AudioSlides,
651
+ mediaRequests
652
+ );
653
+ }
654
+ ),
655
+ screenShareVideo: new MediaRequestManager(
656
+ // @ts-ignore - config coming from registerPlugin
657
+ this.config.degradationPreferences,
658
+ (mediaRequests) => {
659
+ if (!this.mediaProperties.webrtcMediaConnection) {
660
+ LoggerProxy.logger.warn(
661
+ 'Meeting:index#mediaRequestManager --> trying to send screenshare video media request before media connection was created'
662
+ );
663
+
664
+ return;
665
+ }
666
+ this.mediaProperties.webrtcMediaConnection.requestMedia(
667
+ MediaType.VideoSlides,
668
+ mediaRequests
669
+ );
670
+ }
671
+ ),
611
672
  };
612
673
  /**
613
674
  * @instance
@@ -620,8 +681,8 @@ export default class Meeting extends StatelessWebexPlugin {
620
681
  locusUrl: attrs.locus && attrs.locus.url,
621
682
  receiveSlotManager: this.receiveSlotManager,
622
683
  mediaRequestManagers: this.mediaRequestManagers,
623
- // @ts-ignore - Fix type
624
684
  },
685
+ // @ts-ignore - Fix type
625
686
  {parent: this.webex}
626
687
  );
627
688
  /**
@@ -924,6 +985,7 @@ export default class Meeting extends StatelessWebexPlugin {
924
985
  */
925
986
  // @ts-ignore - Fix type
926
987
  this.locusInfo = new LocusInfo(this.updateMeetingObject.bind(this), this.webex, this.id);
988
+
927
989
  // We had to add listeners first before setting up the locus instance
928
990
  /**
929
991
  * @instance
@@ -1023,6 +1085,20 @@ export default class Meeting extends StatelessWebexPlugin {
1023
1085
  */
1024
1086
  this.keepAliveTimerId = null;
1025
1087
 
1088
+ /**
1089
+ * The class that helps to control recording functions: start, stop, pause, resume, etc
1090
+ * @instance
1091
+ * @type {RecordingController}
1092
+ * @public
1093
+ * @memberof Meeting
1094
+ */
1095
+ this.recordingController = new RecordingController(this.meetingRequest, {
1096
+ serviceUrl: this.locusInfo?.links?.services?.record?.url,
1097
+ sessionId: this.locusInfo?.fullState?.sessionId,
1098
+ locusUrl: this.locusInfo?.url,
1099
+ displayHints: [],
1100
+ });
1101
+
1026
1102
  this.setUpLocusInfoListeners();
1027
1103
  this.locusInfo.init(attrs.locus ? attrs.locus : {});
1028
1104
  this.hasJoinedOnce = false;
@@ -1108,8 +1184,8 @@ export default class Meeting extends StatelessWebexPlugin {
1108
1184
  return Promise.resolve();
1109
1185
  } catch (err) {
1110
1186
  if (err instanceof MeetingInfoV2PasswordError) {
1111
- // @ts-ignore
1112
1187
  LoggerProxy.logger.info(
1188
+ // @ts-ignore
1113
1189
  `Meeting:index#fetchMeetingInfo --> Info Unable to fetch meeting info for ${this.destination} - password required (code=${err?.body?.code}).`
1114
1190
  );
1115
1191
 
@@ -1128,8 +1204,8 @@ export default class Meeting extends StatelessWebexPlugin {
1128
1204
 
1129
1205
  throw new PasswordError();
1130
1206
  } else if (err instanceof MeetingInfoV2CaptchaError) {
1131
- // @ts-ignore
1132
1207
  LoggerProxy.logger.info(
1208
+ // @ts-ignore
1133
1209
  `Meeting:index#fetchMeetingInfo --> Info Unable to fetch meeting info for ${this.destination} - captcha required (code=${err?.body?.code}).`
1134
1210
  );
1135
1211
 
@@ -1201,22 +1277,25 @@ export default class Meeting extends StatelessWebexPlugin {
1201
1277
  // we have to pass the wbxappapi hostname as the siteFullName parameter
1202
1278
  const {hostname} = new URL(this.requiredCaptcha.refreshURL);
1203
1279
 
1204
- return this.meetingRequest
1205
- .refreshCaptcha({
1206
- captchaRefreshUrl: `${this.requiredCaptcha.refreshURL}&siteFullName=${hostname}`,
1207
- captchaId: this.requiredCaptcha.captchaId,
1208
- })
1209
- .then((response) => {
1210
- this.requiredCaptcha.captchaId = response.body.captchaID;
1211
- this.requiredCaptcha.verificationImageURL = response.body.verificationImageURL;
1212
- this.requiredCaptcha.verificationAudioURL = response.body.verificationAudioURL;
1213
- })
1214
- .catch((error) => {
1215
- LoggerProxy.logger.error(
1216
- `Meeting:index#refreshCaptcha --> Error Unable to refresh captcha for ${this.destination} - ${error}`
1217
- );
1218
- throw error;
1219
- });
1280
+ return (
1281
+ this.meetingRequest
1282
+ // @ts-ignore
1283
+ .refreshCaptcha({
1284
+ captchaRefreshUrl: `${this.requiredCaptcha.refreshURL}&siteFullName=${hostname}`,
1285
+ captchaId: this.requiredCaptcha.captchaId,
1286
+ })
1287
+ .then((response) => {
1288
+ this.requiredCaptcha.captchaId = response.body.captchaID;
1289
+ this.requiredCaptcha.verificationImageURL = response.body.verificationImageURL;
1290
+ this.requiredCaptcha.verificationAudioURL = response.body.verificationAudioURL;
1291
+ })
1292
+ .catch((error) => {
1293
+ LoggerProxy.logger.error(
1294
+ `Meeting:index#refreshCaptcha --> Error Unable to refresh captcha for ${this.destination} - ${error}`
1295
+ );
1296
+ throw error;
1297
+ })
1298
+ );
1220
1299
  }
1221
1300
 
1222
1301
  /**
@@ -1229,6 +1308,7 @@ export default class Meeting extends StatelessWebexPlugin {
1229
1308
  // meeting update listeners
1230
1309
  this.setUpLocusInfoSelfListener();
1231
1310
  this.setUpLocusInfoMeetingListener();
1311
+ this.setUpLocusServicesListener();
1232
1312
  // members update listeners
1233
1313
  this.setUpLocusFullStateListener();
1234
1314
  this.setUpLocusUrlListener();
@@ -1241,6 +1321,49 @@ export default class Meeting extends StatelessWebexPlugin {
1241
1321
  this.setUpLocusInfoMeetingInfoListener();
1242
1322
  this.setUpLocusInfoAssignHostListener();
1243
1323
  this.setUpLocusInfoMediaInactiveListener();
1324
+ this.setUpBreakoutsListener();
1325
+ }
1326
+
1327
+ /**
1328
+ * Set up the listeners for breakouts
1329
+ * @returns {undefined}
1330
+ * @private
1331
+ * @memberof Meeting
1332
+ */
1333
+ setUpBreakoutsListener() {
1334
+ this.breakouts.on(BREAKOUTS.EVENTS.BREAKOUTS_CLOSING, () => {
1335
+ Trigger.trigger(
1336
+ this,
1337
+ {
1338
+ file: 'meeting/index',
1339
+ function: 'setUpBreakoutsListener',
1340
+ },
1341
+ EVENT_TRIGGERS.MEETING_BREAKOUTS_CLOSING
1342
+ );
1343
+ });
1344
+
1345
+ this.breakouts.on(BREAKOUTS.EVENTS.MESSAGE, (messageEvent) => {
1346
+ Trigger.trigger(
1347
+ this,
1348
+ {
1349
+ file: 'meeting/index',
1350
+ function: 'setUpBreakoutsListener',
1351
+ },
1352
+ EVENT_TRIGGERS.MEETING_BREAKOUTS_MESSAGE,
1353
+ messageEvent
1354
+ );
1355
+ });
1356
+
1357
+ this.breakouts.on(BREAKOUTS.EVENTS.MEMBERS_UPDATE, () => {
1358
+ Trigger.trigger(
1359
+ this,
1360
+ {
1361
+ file: 'meeting/index',
1362
+ function: 'setUpBreakoutsListener',
1363
+ },
1364
+ EVENT_TRIGGERS.MEETING_BREAKOUTS_UPDATE
1365
+ );
1366
+ });
1244
1367
  }
1245
1368
 
1246
1369
  /**
@@ -1786,6 +1909,18 @@ export default class Meeting extends StatelessWebexPlugin {
1786
1909
  }
1787
1910
  );
1788
1911
 
1912
+ this.locusInfo.on(LOCUSINFO.EVENTS.CONTROLS_MEETING_BREAKOUT_UPDATED, ({breakout}) => {
1913
+ this.breakouts.updateBreakout(breakout);
1914
+ Trigger.trigger(
1915
+ this,
1916
+ {
1917
+ file: 'meeting/index',
1918
+ function: 'setupLocusControlsListener',
1919
+ },
1920
+ EVENT_TRIGGERS.MEETING_BREAKOUTS_UPDATE
1921
+ );
1922
+ });
1923
+
1789
1924
  this.locusInfo.on(LOCUSINFO.EVENTS.CONTROLS_ENTRY_EXIT_TONE_UPDATED, ({entryExitTone}) => {
1790
1925
  Trigger.trigger(
1791
1926
  this,
@@ -2041,8 +2176,26 @@ export default class Meeting extends StatelessWebexPlugin {
2041
2176
  private setUpLocusUrlListener() {
2042
2177
  this.locusInfo.on(EVENTS.LOCUS_INFO_UPDATE_URL, (payload) => {
2043
2178
  this.members.locusUrlUpdate(payload);
2179
+ this.breakouts.locusUrlUpdate(payload);
2044
2180
  this.locusUrl = payload;
2045
2181
  this.locusId = this.locusUrl?.split('/').pop();
2182
+ this.recordingController.setLocusUrl(this.locusUrl);
2183
+ });
2184
+ }
2185
+
2186
+ /**
2187
+ * Set up the locus info service link listener
2188
+ * update the locusInfo for recording controller
2189
+ * does not currently re-emit the event as it's internal only
2190
+ * payload is unused
2191
+ * @returns {undefined}
2192
+ * @private
2193
+ * @memberof Meeting
2194
+ */
2195
+ private setUpLocusServicesListener() {
2196
+ this.locusInfo.on(LOCUSINFO.EVENTS.LINKS_SERVICES, (payload) => {
2197
+ this.recordingController.setServiceUrl(payload?.services?.record?.url);
2198
+ this.recordingController.setSessionId(this.locusInfo?.fullState?.sessionId);
2046
2199
  });
2047
2200
  }
2048
2201
 
@@ -2092,10 +2245,10 @@ export default class Meeting extends StatelessWebexPlugin {
2092
2245
  canAdmitParticipant: MeetingUtil.canAdmitParticipant(payload.info.userDisplayHints),
2093
2246
  canLock: MeetingUtil.canUserLock(payload.info.userDisplayHints),
2094
2247
  canUnlock: MeetingUtil.canUserUnlock(payload.info.userDisplayHints),
2095
- canStartRecording: MeetingUtil.canUserRecord(payload.info.userDisplayHints),
2096
- canStopRecording: MeetingUtil.canUserStop(payload.info.userDisplayHints),
2097
- canPauseRecording: MeetingUtil.canUserPause(payload.info.userDisplayHints),
2098
- canResumeRecording: MeetingUtil.canUserResume(payload.info.userDisplayHints),
2248
+ canStartRecording: RecordingUtil.canUserStart(payload.info.userDisplayHints),
2249
+ canStopRecording: RecordingUtil.canUserStop(payload.info.userDisplayHints),
2250
+ canPauseRecording: RecordingUtil.canUserPause(payload.info.userDisplayHints),
2251
+ canResumeRecording: RecordingUtil.canUserResume(payload.info.userDisplayHints),
2099
2252
  canRaiseHand: MeetingUtil.canUserRaiseHand(payload.info.userDisplayHints),
2100
2253
  canLowerAllHands: MeetingUtil.canUserLowerAllHands(payload.info.userDisplayHints),
2101
2254
  canLowerSomeoneElsesHand: MeetingUtil.canUserLowerSomeoneElsesHand(
@@ -2117,8 +2270,18 @@ export default class Meeting extends StatelessWebexPlugin {
2117
2270
  payload.info.userDisplayHints
2118
2271
  ),
2119
2272
  waitingForOthersToJoin: MeetingUtil.waitingForOthersToJoin(payload.info.userDisplayHints),
2273
+ canEnableReactions: MeetingUtil.canEnableReactions(
2274
+ this.inMeetingActions.canEnableReactions,
2275
+ payload.info.userDisplayHints
2276
+ ),
2277
+ canSendReactions: MeetingUtil.canSendReactions(
2278
+ this.inMeetingActions.canSendReactions,
2279
+ payload.info.userDisplayHints
2280
+ ),
2120
2281
  });
2121
2282
 
2283
+ this.recordingController.setDisplayHints(payload.info.userDisplayHints);
2284
+
2122
2285
  if (changed) {
2123
2286
  Trigger.trigger(
2124
2287
  this,
@@ -2142,6 +2305,7 @@ export default class Meeting extends StatelessWebexPlugin {
2142
2305
  * @returns {void}
2143
2306
  */
2144
2307
  handleDataChannelUrlChange(datachannelUrl) {
2308
+ // @ts-ignore - config coming from registerPlugin
2145
2309
  if (datachannelUrl && this.config.enableAutomaticLLM) {
2146
2310
  // Defer this as updateLLMConnection relies upon this.locusInfo.url which is only set
2147
2311
  // after the MEETING_INFO_UPDATED callback finishes
@@ -2322,6 +2486,18 @@ export default class Meeting extends StatelessWebexPlugin {
2322
2486
  );
2323
2487
  });
2324
2488
 
2489
+ this.locusInfo.on(LOCUSINFO.EVENTS.SELF_MEETING_BREAKOUTS_CHANGED, (payload) => {
2490
+ this.breakouts.updateBreakoutSessions(payload);
2491
+ Trigger.trigger(
2492
+ this,
2493
+ {
2494
+ file: 'meeting/index',
2495
+ function: 'setUpLocusInfoSelfListener',
2496
+ },
2497
+ EVENT_TRIGGERS.MEETING_BREAKOUTS_UPDATE
2498
+ );
2499
+ });
2500
+
2325
2501
  this.locusInfo.on(LOCUSINFO.EVENTS.SELF_IS_SHARING_BLOCKED_CHANGE, (payload) => {
2326
2502
  Trigger.trigger(
2327
2503
  this,
@@ -2357,7 +2533,7 @@ export default class Meeting extends StatelessWebexPlugin {
2357
2533
  .catch((error) => {
2358
2534
  // @ts-ignore
2359
2535
  LoggerProxy.logger.error(
2360
- `Meeting:index#setUpLocusInfoMeetingListener --> REMOTE_RESPONSE. Issue with leave for meeting, meeting still in collection: ${this.meeting}, error: ${error}`
2536
+ `Meeting:index#setUpLocusInfoMeetingListener --> REMOTE_RESPONSE. Issue with leave for meeting, meeting still in collection: ${this}, error: ${error}`
2361
2537
  );
2362
2538
  });
2363
2539
  }
@@ -2392,7 +2568,7 @@ export default class Meeting extends StatelessWebexPlugin {
2392
2568
  .catch((error) => {
2393
2569
  // @ts-ignore
2394
2570
  LoggerProxy.logger.error(
2395
- `Meeting:index#setUpLocusInfoMeetingListener --> DESTROY_MEETING. Issue with leave for meeting, meeting still in collection: ${this.meeting}, error: ${error}`
2571
+ `Meeting:index#setUpLocusInfoMeetingListener --> DESTROY_MEETING. Issue with leave for meeting, meeting still in collection: ${this}, error: ${error}`
2396
2572
  );
2397
2573
  });
2398
2574
  } else {
@@ -2634,6 +2810,7 @@ export default class Meeting extends StatelessWebexPlugin {
2634
2810
  this.locusUrl = locusMeetingObject?.url || webexMeetingInfo?.locusUrl || this.locusUrl;
2635
2811
  // @ts-ignore - config coming from registerPlugin
2636
2812
  this.setSipUri(
2813
+ // @ts-ignore
2637
2814
  this.config.experimental.enableUnifiedMeetings
2638
2815
  ? locusMeetingObject?.info.sipUri || webexMeetingInfo?.sipUrl
2639
2816
  : locusMeetingObject?.info.sipUri || webexMeetingInfo?.sipMeetingUri || this.sipUri
@@ -3582,6 +3759,20 @@ export default class Meeting extends StatelessWebexPlugin {
3582
3759
  return false;
3583
3760
  }
3584
3761
 
3762
+ /**
3763
+ * Check if the meeting supports the Reactions
3764
+ * @returns {boolean}
3765
+ */
3766
+ isReactionsSupported() {
3767
+ if (this.locusInfo?.controls?.reactions.enabled) {
3768
+ return true;
3769
+ }
3770
+
3771
+ LoggerProxy.logger.error('Meeting:index#isReactionsSupported --> Reactions is not supported');
3772
+
3773
+ return false;
3774
+ }
3775
+
3585
3776
  /**
3586
3777
  * Monitor the Low-Latency Mercury (LLM) web socket connection on `onError` and `onClose` states
3587
3778
  * @private
@@ -3633,6 +3824,7 @@ export default class Meeting extends StatelessWebexPlugin {
3633
3824
  // @ts-ignore - fix type
3634
3825
  const {
3635
3826
  body: {webSocketUrl},
3827
+ // @ts-ignore
3636
3828
  } = await this.request({
3637
3829
  method: HTTP_VERBS.POST,
3638
3830
  uri: datachannelUrl,
@@ -3682,6 +3874,44 @@ export default class Meeting extends StatelessWebexPlugin {
3682
3874
  }
3683
3875
  }
3684
3876
 
3877
+ /**
3878
+ * Callback called when a relay event is received from meeting LLM Connection
3879
+ * @param {RelayEvent} e Event object coming from LLM Connection
3880
+ * @private
3881
+ * @returns {void}
3882
+ */
3883
+ private processRelayEvent = (e: RelayEvent): void => {
3884
+ switch (e.data.relayType) {
3885
+ case REACTION_RELAY_TYPES.REACTION:
3886
+ if (
3887
+ // @ts-ignore - config coming from registerPlugin
3888
+ (this.config.receiveReactions || options.receiveReactions) &&
3889
+ this.isReactionsSupported()
3890
+ ) {
3891
+ const {name} = this.members.membersCollection.get(e.data.sender.participantId);
3892
+ const processedReaction: ProcessedReaction = {
3893
+ reaction: e.data.reaction,
3894
+ sender: {
3895
+ id: e.data.sender.participantId,
3896
+ name,
3897
+ },
3898
+ };
3899
+ Trigger.trigger(
3900
+ this,
3901
+ {
3902
+ file: 'meeting/index',
3903
+ function: 'join',
3904
+ },
3905
+ EVENT_TRIGGERS.MEETING_RECEIVE_REACTIONS,
3906
+ processedReaction
3907
+ );
3908
+ }
3909
+ break;
3910
+ default:
3911
+ break;
3912
+ }
3913
+ };
3914
+
3685
3915
  /**
3686
3916
  * stop recieving Transcription by closing
3687
3917
  * the web socket connection properly
@@ -3855,8 +4085,12 @@ export default class Meeting extends StatelessWebexPlugin {
3855
4085
  return join;
3856
4086
  })
3857
4087
  .then(async (join) => {
4088
+ // @ts-ignore - config coming from registerPlugin
3858
4089
  if (this.config.enableAutomaticLLM) {
3859
4090
  await this.updateLLMConnection();
4091
+ // @ts-ignore - Fix type
4092
+ this.webex.internal.llm.on('event:relay.event', this.processRelayEvent);
4093
+ LoggerProxy.logger.info('Meeting:index#join --> enabled to receive relay events!');
3860
4094
  }
3861
4095
 
3862
4096
  return join;
@@ -3923,21 +4157,28 @@ export default class Meeting extends StatelessWebexPlugin {
3923
4157
  * @returns {Promise}
3924
4158
  */
3925
4159
  async updateLLMConnection() {
4160
+ // @ts-ignore - Fix type
3926
4161
  const {url, info: {datachannelUrl} = {}} = this.locusInfo;
3927
4162
 
3928
4163
  const isJoined = this.joinedWith && this.joinedWith.state === 'JOINED';
3929
4164
 
4165
+ // @ts-ignore - Fix type
3930
4166
  if (this.webex.internal.llm.isConnected()) {
4167
+ // @ts-ignore - Fix type
3931
4168
  if (url === this.webex.internal.llm.getLocusUrl() && isJoined) {
3932
4169
  return undefined;
3933
4170
  }
4171
+ // @ts-ignore - Fix type
3934
4172
  await this.webex.internal.llm.disconnectLLM();
4173
+ // @ts-ignore - Fix type
4174
+ this.webex.internal.llm.off('event:relay.event', this.processRelayEvent);
3935
4175
  }
3936
4176
 
3937
4177
  if (!isJoined) {
3938
4178
  return undefined;
3939
4179
  }
3940
4180
 
4181
+ // @ts-ignore - Fix type
3941
4182
  return this.webex.internal.llm.registerAndConnect(url, datachannelUrl);
3942
4183
  }
3943
4184
 
@@ -3980,28 +4221,31 @@ export default class Meeting extends StatelessWebexPlugin {
3980
4221
 
3981
4222
  if (!this.dialInUrl) this.dialInUrl = `dialin:///${uuid.v4()}`;
3982
4223
 
3983
- return this.meetingRequest
3984
- .dialIn({
3985
- correlationId,
3986
- dialInUrl: this.dialInUrl,
3987
- locusUrl,
3988
- clientUrl: this.deviceUrl,
3989
- })
3990
- .then((res) => {
3991
- this.locusInfo.onFullLocus(res.body.locus);
3992
- })
3993
- .catch((error) => {
3994
- Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.ADD_DIAL_IN_FAILURE, {
3995
- correlation_id: this.correlationId,
3996
- dial_in_url: this.dialInUrl,
3997
- locus_id: locusUrl.split('/').pop(),
3998
- client_url: this.deviceUrl,
3999
- reason: error.error?.message,
4000
- stack: error.stack,
4001
- });
4224
+ return (
4225
+ this.meetingRequest
4226
+ // @ts-ignore
4227
+ .dialIn({
4228
+ correlationId,
4229
+ dialInUrl: this.dialInUrl,
4230
+ locusUrl,
4231
+ clientUrl: this.deviceUrl,
4232
+ })
4233
+ .then((res) => {
4234
+ this.locusInfo.onFullLocus(res.body.locus);
4235
+ })
4236
+ .catch((error) => {
4237
+ Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.ADD_DIAL_IN_FAILURE, {
4238
+ correlation_id: this.correlationId,
4239
+ dial_in_url: this.dialInUrl,
4240
+ locus_id: locusUrl.split('/').pop(),
4241
+ client_url: this.deviceUrl,
4242
+ reason: error.error?.message,
4243
+ stack: error.stack,
4244
+ });
4002
4245
 
4003
- return Promise.reject(error);
4004
- });
4246
+ return Promise.reject(error);
4247
+ })
4248
+ );
4005
4249
  }
4006
4250
 
4007
4251
  /**
@@ -4018,29 +4262,32 @@ export default class Meeting extends StatelessWebexPlugin {
4018
4262
 
4019
4263
  if (!this.dialOutUrl) this.dialOutUrl = `dialout:///${uuid.v4()}`;
4020
4264
 
4021
- return this.meetingRequest
4022
- .dialOut({
4023
- correlationId,
4024
- dialOutUrl: this.dialOutUrl,
4025
- phoneNumber,
4026
- locusUrl,
4027
- clientUrl: this.deviceUrl,
4028
- })
4029
- .then((res) => {
4030
- this.locusInfo.onFullLocus(res.body.locus);
4031
- })
4032
- .catch((error) => {
4033
- Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.ADD_DIAL_OUT_FAILURE, {
4034
- correlation_id: this.correlationId,
4035
- dial_out_url: this.dialOutUrl,
4036
- locus_id: locusUrl.split('/').pop(),
4037
- client_url: this.deviceUrl,
4038
- reason: error.error?.message,
4039
- stack: error.stack,
4040
- });
4265
+ return (
4266
+ this.meetingRequest
4267
+ // @ts-ignore
4268
+ .dialOut({
4269
+ correlationId,
4270
+ dialOutUrl: this.dialOutUrl,
4271
+ phoneNumber,
4272
+ locusUrl,
4273
+ clientUrl: this.deviceUrl,
4274
+ })
4275
+ .then((res) => {
4276
+ this.locusInfo.onFullLocus(res.body.locus);
4277
+ })
4278
+ .catch((error) => {
4279
+ Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.ADD_DIAL_OUT_FAILURE, {
4280
+ correlation_id: this.correlationId,
4281
+ dial_out_url: this.dialOutUrl,
4282
+ locus_id: locusUrl.split('/').pop(),
4283
+ client_url: this.deviceUrl,
4284
+ reason: error.error?.message,
4285
+ stack: error.stack,
4286
+ });
4041
4287
 
4042
- return Promise.reject(error);
4043
- });
4288
+ return Promise.reject(error);
4289
+ })
4290
+ );
4044
4291
  }
4045
4292
 
4046
4293
  /**
@@ -4387,7 +4634,7 @@ export default class Meeting extends StatelessWebexPlugin {
4387
4634
  Metrics.sendBehavioralMetric(metricName, data, metadata);
4388
4635
  };
4389
4636
 
4390
- if (error instanceof MC.Errors.SdpOfferCreationError) {
4637
+ if (error instanceof Errors.SdpOfferCreationError) {
4391
4638
  sendBehavioralMetric(BEHAVIORAL_METRICS.PEERCONNECTION_FAILURE, error, this.id);
4392
4639
 
4393
4640
  Metrics.postEvent({
@@ -4401,8 +4648,8 @@ export default class Meeting extends StatelessWebexPlugin {
4401
4648
  },
4402
4649
  });
4403
4650
  } else if (
4404
- error instanceof MC.Errors.SdpOfferHandlingError ||
4405
- error instanceof MC.Errors.SdpAnswerHandlingError
4651
+ error instanceof Errors.SdpOfferHandlingError ||
4652
+ error instanceof Errors.SdpAnswerHandlingError
4406
4653
  ) {
4407
4654
  sendBehavioralMetric(BEHAVIORAL_METRICS.PEERCONNECTION_FAILURE, error, this.id);
4408
4655
 
@@ -4416,8 +4663,8 @@ export default class Meeting extends StatelessWebexPlugin {
4416
4663
  ],
4417
4664
  },
4418
4665
  });
4419
- } else if (error instanceof MC.Errors.SdpError) {
4420
- // this covers also the case of MC.Errors.IceGatheringError which extends MC.Errors.SdpError
4666
+ } else if (error instanceof Errors.SdpError) {
4667
+ // this covers also the case of Errors.IceGatheringError which extends Errors.SdpError
4421
4668
  sendBehavioralMetric(BEHAVIORAL_METRICS.INVALID_ICE_CANDIDATE, error, this.id);
4422
4669
 
4423
4670
  Metrics.postEvent({
@@ -4434,19 +4681,19 @@ export default class Meeting extends StatelessWebexPlugin {
4434
4681
  };
4435
4682
 
4436
4683
  setupMediaConnectionListeners = () => {
4437
- this.mediaProperties.webrtcMediaConnection.on(MC.Event.ROAP_STARTED, () => {
4684
+ this.mediaProperties.webrtcMediaConnection.on(Event.ROAP_STARTED, () => {
4438
4685
  this.isRoapInProgress = true;
4439
4686
  });
4440
4687
 
4441
- this.mediaProperties.webrtcMediaConnection.on(MC.Event.ROAP_DONE, () => {
4688
+ this.mediaProperties.webrtcMediaConnection.on(Event.ROAP_DONE, () => {
4442
4689
  this.mediaNegotiatedEvent();
4443
4690
  this.isRoapInProgress = false;
4444
4691
  this.processNextQueuedMediaUpdate();
4445
4692
  });
4446
4693
 
4447
- this.mediaProperties.webrtcMediaConnection.on(MC.Event.ROAP_FAILURE, this.handleRoapFailure);
4694
+ this.mediaProperties.webrtcMediaConnection.on(Event.ROAP_FAILURE, this.handleRoapFailure);
4448
4695
 
4449
- this.mediaProperties.webrtcMediaConnection.on(MC.Event.ROAP_MESSAGE_TO_SEND, (event) => {
4696
+ this.mediaProperties.webrtcMediaConnection.on(Event.ROAP_MESSAGE_TO_SEND, (event) => {
4450
4697
  const LOG_HEADER = 'Meeting:index#setupMediaConnectionListeners.ROAP_MESSAGE_TO_SEND -->';
4451
4698
 
4452
4699
  switch (event.roapMessage.messageType) {
@@ -4528,8 +4775,8 @@ export default class Meeting extends StatelessWebexPlugin {
4528
4775
 
4529
4776
  case 'ERROR':
4530
4777
  if (
4531
- event.roapMessage.errorType === MC.ErrorType.CONFLICT ||
4532
- event.roapMessage.errorType === MC.ErrorType.DOUBLECONFLICT
4778
+ event.roapMessage.errorType === ErrorType.CONFLICT ||
4779
+ event.roapMessage.errorType === ErrorType.DOUBLECONFLICT
4533
4780
  ) {
4534
4781
  Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.ROAP_GLARE_CONDITION, {
4535
4782
  correlation_id: this.correlationId,
@@ -4561,7 +4808,7 @@ export default class Meeting extends StatelessWebexPlugin {
4561
4808
  });
4562
4809
 
4563
4810
  // eslint-disable-next-line no-param-reassign
4564
- this.mediaProperties.webrtcMediaConnection.on(MC.Event.REMOTE_TRACK_ADDED, (event) => {
4811
+ this.mediaProperties.webrtcMediaConnection.on(Event.REMOTE_TRACK_ADDED, (event) => {
4565
4812
  LoggerProxy.logger.log(
4566
4813
  `Meeting:index#setupMediaConnectionListeners --> REMOTE_TRACK_ADDED event received for webrtcMediaConnection: ${JSON.stringify(
4567
4814
  event
@@ -4574,15 +4821,15 @@ export default class Meeting extends StatelessWebexPlugin {
4574
4821
  let eventType;
4575
4822
 
4576
4823
  switch (event.type) {
4577
- case MC.RemoteTrackType.AUDIO:
4824
+ case RemoteTrackType.AUDIO:
4578
4825
  eventType = EVENT_TYPES.REMOTE_AUDIO;
4579
4826
  this.mediaProperties.setRemoteAudioTrack(event.track);
4580
4827
  break;
4581
- case MC.RemoteTrackType.VIDEO:
4828
+ case RemoteTrackType.VIDEO:
4582
4829
  eventType = EVENT_TYPES.REMOTE_VIDEO;
4583
4830
  this.mediaProperties.setRemoteVideoTrack(event.track);
4584
4831
  break;
4585
- case MC.RemoteTrackType.SCREENSHARE_VIDEO:
4832
+ case RemoteTrackType.SCREENSHARE_VIDEO:
4586
4833
  if (event.track) {
4587
4834
  eventType = EVENT_TYPES.REMOTE_SHARE;
4588
4835
  this.mediaProperties.setRemoteShare(event.track);
@@ -4615,7 +4862,7 @@ export default class Meeting extends StatelessWebexPlugin {
4615
4862
  }
4616
4863
  });
4617
4864
 
4618
- this.mediaProperties.webrtcMediaConnection.on(MC.Event.CONNECTION_STATE_CHANGED, (event) => {
4865
+ this.mediaProperties.webrtcMediaConnection.on(Event.CONNECTION_STATE_CHANGED, (event) => {
4619
4866
  const connectionFailed = () => {
4620
4867
  // we know the media connection failed and browser will not attempt to recover it any more
4621
4868
  // so reset the timer as it's not needed anymore, we want to reconnect immediately
@@ -4648,10 +4895,10 @@ export default class Meeting extends StatelessWebexPlugin {
4648
4895
  `Meeting:index#setupMediaConnectionListeners --> connection state changed to ${event.state}`
4649
4896
  );
4650
4897
  switch (event.state) {
4651
- case MC.ConnectionState.Connecting:
4898
+ case ConnectionState.Connecting:
4652
4899
  Metrics.postEvent({event: eventType.ICE_START, meeting: this});
4653
4900
  break;
4654
- case MC.ConnectionState.Connected:
4901
+ case ConnectionState.Connected:
4655
4902
  Metrics.postEvent({event: eventType.ICE_END, meeting: this});
4656
4903
  Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.CONNECTION_SUCCESS, {
4657
4904
  correlation_id: this.correlationId,
@@ -4660,7 +4907,7 @@ export default class Meeting extends StatelessWebexPlugin {
4660
4907
  this.setNetworkStatus(NETWORK_STATUS.CONNECTED);
4661
4908
  this.reconnectionManager.iceReconnected();
4662
4909
  break;
4663
- case MC.ConnectionState.Disconnected:
4910
+ case ConnectionState.Disconnected:
4664
4911
  this.setNetworkStatus(NETWORK_STATUS.DISCONNECTED);
4665
4912
  this.reconnectionManager.waitForIceReconnect().catch(() => {
4666
4913
  LoggerProxy.logger.info(
@@ -4670,7 +4917,7 @@ export default class Meeting extends StatelessWebexPlugin {
4670
4917
  connectionFailed();
4671
4918
  });
4672
4919
  break;
4673
- case MC.ConnectionState.Failed:
4920
+ case ConnectionState.Failed:
4674
4921
  connectionFailed();
4675
4922
  break;
4676
4923
  default:
@@ -4678,7 +4925,7 @@ export default class Meeting extends StatelessWebexPlugin {
4678
4925
  }
4679
4926
  });
4680
4927
 
4681
- this.mediaProperties.webrtcMediaConnection.on(MC.Event.ACTIVE_SPEAKERS_CHANGED, (msg) => {
4928
+ this.mediaProperties.webrtcMediaConnection.on(Event.ACTIVE_SPEAKERS_CHANGED, (msg) => {
4682
4929
  Trigger.trigger(
4683
4930
  this,
4684
4931
  {
@@ -4689,6 +4936,7 @@ export default class Meeting extends StatelessWebexPlugin {
4689
4936
  {
4690
4937
  seqNum: msg.seqNum,
4691
4938
  memberIds: msg.csis
4939
+ // @ts-ignore
4692
4940
  .map((csi) => this.members.findMemberByCsi(csi)?.id)
4693
4941
  .filter((item) => item !== undefined),
4694
4942
  }
@@ -4696,7 +4944,7 @@ export default class Meeting extends StatelessWebexPlugin {
4696
4944
  });
4697
4945
 
4698
4946
  this.mediaProperties.webrtcMediaConnection.on(
4699
- MC.Event.VIDEO_SOURCES_COUNT_CHANGED,
4947
+ Event.VIDEO_SOURCES_COUNT_CHANGED,
4700
4948
  (numTotalSources, numLiveSources) => {
4701
4949
  Trigger.trigger(
4702
4950
  this,
@@ -4714,7 +4962,7 @@ export default class Meeting extends StatelessWebexPlugin {
4714
4962
  );
4715
4963
 
4716
4964
  this.mediaProperties.webrtcMediaConnection.on(
4717
- MC.Event.AUDIO_SOURCES_COUNT_CHANGED,
4965
+ Event.AUDIO_SOURCES_COUNT_CHANGED,
4718
4966
  (numTotalSources, numLiveSources) => {
4719
4967
  Trigger.trigger(
4720
4968
  this,
@@ -4744,6 +4992,7 @@ export default class Meeting extends StatelessWebexPlugin {
4744
4992
  // Add ip address info if geo hint is present
4745
4993
  // @ts-ignore fix type
4746
4994
  options.data.intervalMetadata.peerReflexiveIP =
4995
+ // @ts-ignore
4747
4996
  this.webex.meetings.geoHintInfo?.clientAddress ||
4748
4997
  options.data.intervalMetadata.peerReflexiveIP ||
4749
4998
  MQA_STATS.DEFAULT_IP;
@@ -5074,7 +5323,7 @@ export default class Meeting extends StatelessWebexPlugin {
5074
5323
  this
5075
5324
  );
5076
5325
 
5077
- if (error instanceof MC.Errors.SdpError) {
5326
+ if (error instanceof Errors.SdpError) {
5078
5327
  this.leave({reason: MEETING_REMOVED_REASON.MEETING_CONNECTION_FAILED});
5079
5328
  }
5080
5329
 
@@ -5844,7 +6093,7 @@ export default class Meeting extends StatelessWebexPlugin {
5844
6093
  * @memberof Meeting
5845
6094
  */
5846
6095
  public startRecording() {
5847
- return MeetingUtil.startRecording(this.meetingRequest, this.locusUrl, this.locusInfo);
6096
+ return this.recordingController.startRecording();
5848
6097
  }
5849
6098
 
5850
6099
  /**
@@ -5854,7 +6103,7 @@ export default class Meeting extends StatelessWebexPlugin {
5854
6103
  * @memberof Meeting
5855
6104
  */
5856
6105
  public stopRecording() {
5857
- return MeetingUtil.stopRecording(this.meetingRequest, this.locusUrl, this.locusInfo);
6106
+ return this.recordingController.stopRecording();
5858
6107
  }
5859
6108
 
5860
6109
  /**
@@ -5864,7 +6113,7 @@ export default class Meeting extends StatelessWebexPlugin {
5864
6113
  * @memberof Meeting
5865
6114
  */
5866
6115
  public pauseRecording() {
5867
- return MeetingUtil.pauseRecording(this.meetingRequest, this.locusUrl, this.locusInfo);
6116
+ return this.recordingController.pauseRecording();
5868
6117
  }
5869
6118
 
5870
6119
  /**
@@ -5874,7 +6123,7 @@ export default class Meeting extends StatelessWebexPlugin {
5874
6123
  * @memberof Meeting
5875
6124
  */
5876
6125
  public resumeRecording() {
5877
- return MeetingUtil.resumeRecording(this.meetingRequest, this.locusUrl, this.locusInfo);
6126
+ return this.recordingController.resumeRecording();
5878
6127
  }
5879
6128
 
5880
6129
  /**