@webex/plugin-meetings 3.0.0-beta.17 → 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 (152) 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 +38 -5
  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/index.js +651 -460
  24. package/dist/meeting/index.js.map +1 -1
  25. package/dist/meeting/request.js +25 -44
  26. package/dist/meeting/request.js.map +1 -1
  27. package/dist/meeting/request.type.js.map +1 -1
  28. package/dist/meeting/util.js +4 -57
  29. package/dist/meeting/util.js.map +1 -1
  30. package/dist/meeting-info/meeting-info-v2.js +2 -0
  31. package/dist/meeting-info/meeting-info-v2.js.map +1 -1
  32. package/dist/meetings/index.js +28 -18
  33. package/dist/meetings/index.js.map +1 -1
  34. package/dist/meetings/request.js +14 -12
  35. package/dist/meetings/request.js.map +1 -1
  36. package/dist/member/index.js +9 -0
  37. package/dist/member/index.js.map +1 -1
  38. package/dist/member/util.js +14 -1
  39. package/dist/member/util.js.map +1 -1
  40. package/dist/members/index.js +8 -6
  41. package/dist/members/index.js.map +1 -1
  42. package/dist/members/request.js +3 -1
  43. package/dist/members/request.js.map +1 -1
  44. package/dist/multistream/mediaRequestManager.js +46 -6
  45. package/dist/multistream/mediaRequestManager.js.map +1 -1
  46. package/dist/multistream/multistreamMedia.js +4 -0
  47. package/dist/multistream/multistreamMedia.js.map +1 -1
  48. package/dist/multistream/receiveSlot.js +3 -3
  49. package/dist/multistream/receiveSlot.js.map +1 -1
  50. package/dist/multistream/receiveSlotManager.js +8 -6
  51. package/dist/multistream/receiveSlotManager.js.map +1 -1
  52. package/dist/multistream/remoteMedia.js.map +1 -1
  53. package/dist/multistream/remoteMediaGroup.js.map +1 -1
  54. package/dist/multistream/remoteMediaManager.js +168 -63
  55. package/dist/multistream/remoteMediaManager.js.map +1 -1
  56. package/dist/reachability/index.js +63 -51
  57. package/dist/reachability/index.js.map +1 -1
  58. package/dist/reactions/constants.js +13 -0
  59. package/dist/reactions/constants.js.map +1 -0
  60. package/dist/reactions/reactions.type.js.map +1 -1
  61. package/dist/reconnection-manager/index.js +25 -12
  62. package/dist/reconnection-manager/index.js.map +1 -1
  63. package/dist/recording-controller/enums.js +17 -0
  64. package/dist/recording-controller/enums.js.map +1 -0
  65. package/dist/recording-controller/index.js +343 -0
  66. package/dist/recording-controller/index.js.map +1 -0
  67. package/dist/recording-controller/util.js +63 -0
  68. package/dist/recording-controller/util.js.map +1 -0
  69. package/dist/roap/request.js +88 -68
  70. package/dist/roap/request.js.map +1 -1
  71. package/dist/roap/turnDiscovery.js +72 -47
  72. package/dist/roap/turnDiscovery.js.map +1 -1
  73. package/dist/statsAnalyzer/index.js +3 -3
  74. package/dist/statsAnalyzer/index.js.map +1 -1
  75. package/dist/statsAnalyzer/mqaUtil.js +18 -6
  76. package/dist/statsAnalyzer/mqaUtil.js.map +1 -1
  77. package/package.json +24 -19
  78. package/src/breakouts/README.md +190 -0
  79. package/src/breakouts/breakout.ts +110 -0
  80. package/src/breakouts/collection.ts +19 -0
  81. package/src/breakouts/index.ts +225 -0
  82. package/src/config.ts +4 -1
  83. package/src/constants.ts +35 -1
  84. package/src/locus-info/controlsUtils.ts +2 -0
  85. package/src/locus-info/index.ts +59 -1
  86. package/src/locus-info/parser.ts +1 -0
  87. package/src/locus-info/selfUtils.ts +8 -0
  88. package/src/media/index.ts +1 -2
  89. package/src/media/properties.ts +6 -9
  90. package/src/meeting/index.ts +352 -111
  91. package/src/meeting/request.ts +9 -31
  92. package/src/meeting/request.type.ts +2 -0
  93. package/src/meeting/util.ts +3 -60
  94. package/src/meeting-info/meeting-info-v2.ts +2 -0
  95. package/src/meetings/index.ts +10 -5
  96. package/src/meetings/request.ts +1 -1
  97. package/src/member/index.ts +9 -0
  98. package/src/member/util.ts +14 -1
  99. package/src/members/index.ts +1 -0
  100. package/src/members/request.ts +1 -0
  101. package/src/multistream/mediaRequestManager.ts +79 -15
  102. package/src/multistream/multistreamMedia.ts +4 -0
  103. package/src/multistream/receiveSlot.ts +17 -12
  104. package/src/multistream/receiveSlotManager.ts +22 -21
  105. package/src/multistream/remoteMedia.ts +1 -1
  106. package/src/multistream/remoteMediaGroup.ts +2 -2
  107. package/src/multistream/remoteMediaManager.ts +150 -37
  108. package/src/reachability/index.ts +16 -13
  109. package/src/reactions/constants.ts +4 -0
  110. package/src/reactions/reactions.type.ts +25 -0
  111. package/src/reconnection-manager/index.ts +18 -9
  112. package/src/recording-controller/enums.ts +8 -0
  113. package/src/recording-controller/index.ts +315 -0
  114. package/src/recording-controller/util.ts +58 -0
  115. package/src/roap/request.ts +78 -73
  116. package/src/roap/turnDiscovery.ts +8 -6
  117. package/src/statsAnalyzer/index.ts +4 -4
  118. package/src/statsAnalyzer/mqaUtil.ts +6 -0
  119. package/test/unit/spec/breakouts/breakout.ts +119 -0
  120. package/test/unit/spec/breakouts/collection.ts +15 -0
  121. package/test/unit/spec/breakouts/index.ts +293 -0
  122. package/test/unit/spec/locus-info/controlsUtils.js +20 -0
  123. package/test/unit/spec/locus-info/index.js +103 -0
  124. package/test/unit/spec/locus-info/selfConstant.js +25 -0
  125. package/test/unit/spec/locus-info/selfUtils.js +84 -0
  126. package/test/unit/spec/media/index.ts +1 -1
  127. package/test/unit/spec/media/properties.ts +9 -9
  128. package/test/unit/spec/meeting/effectsState.js +5 -1
  129. package/test/unit/spec/meeting/index.js +235 -50
  130. package/test/unit/spec/meeting/request.js +17 -0
  131. package/test/unit/spec/meeting/utils.js +20 -129
  132. package/test/unit/spec/meetings/index.js +1 -0
  133. package/test/unit/spec/member/util.js +26 -1
  134. package/test/unit/spec/multistream/mediaRequestManager.ts +312 -50
  135. package/test/unit/spec/multistream/receiveSlot.ts +6 -6
  136. package/test/unit/spec/multistream/receiveSlotManager.ts +13 -13
  137. package/test/unit/spec/multistream/remoteMedia.ts +2 -2
  138. package/test/unit/spec/multistream/remoteMediaGroup.ts +5 -5
  139. package/test/unit/spec/multistream/remoteMediaManager.ts +354 -65
  140. package/test/unit/spec/reachability/index.ts +58 -24
  141. package/test/unit/spec/reconnection-manager/index.js +42 -13
  142. package/test/unit/spec/recording-controller/index.js +231 -0
  143. package/test/unit/spec/recording-controller/util.js +102 -0
  144. package/test/unit/spec/roap/index.ts +2 -1
  145. package/test/unit/spec/roap/request.ts +114 -0
  146. package/test/unit/spec/roap/turnDiscovery.ts +45 -29
  147. package/test/unit/spec/stats-analyzer/index.js +2 -2
  148. package/test/utils/webex-test-users.js +1 -0
  149. package/tsconfig.json +6 -0
  150. package/dist/media/internal-media-core-wrapper.js +0 -18
  151. package/dist/media/internal-media-core-wrapper.js.map +0 -1
  152. 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(
@@ -2127,6 +2280,8 @@ export default class Meeting extends StatelessWebexPlugin {
2127
2280
  ),
2128
2281
  });
2129
2282
 
2283
+ this.recordingController.setDisplayHints(payload.info.userDisplayHints);
2284
+
2130
2285
  if (changed) {
2131
2286
  Trigger.trigger(
2132
2287
  this,
@@ -2150,6 +2305,7 @@ export default class Meeting extends StatelessWebexPlugin {
2150
2305
  * @returns {void}
2151
2306
  */
2152
2307
  handleDataChannelUrlChange(datachannelUrl) {
2308
+ // @ts-ignore - config coming from registerPlugin
2153
2309
  if (datachannelUrl && this.config.enableAutomaticLLM) {
2154
2310
  // Defer this as updateLLMConnection relies upon this.locusInfo.url which is only set
2155
2311
  // after the MEETING_INFO_UPDATED callback finishes
@@ -2330,6 +2486,18 @@ export default class Meeting extends StatelessWebexPlugin {
2330
2486
  );
2331
2487
  });
2332
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
+
2333
2501
  this.locusInfo.on(LOCUSINFO.EVENTS.SELF_IS_SHARING_BLOCKED_CHANGE, (payload) => {
2334
2502
  Trigger.trigger(
2335
2503
  this,
@@ -2365,7 +2533,7 @@ export default class Meeting extends StatelessWebexPlugin {
2365
2533
  .catch((error) => {
2366
2534
  // @ts-ignore
2367
2535
  LoggerProxy.logger.error(
2368
- `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}`
2369
2537
  );
2370
2538
  });
2371
2539
  }
@@ -2400,7 +2568,7 @@ export default class Meeting extends StatelessWebexPlugin {
2400
2568
  .catch((error) => {
2401
2569
  // @ts-ignore
2402
2570
  LoggerProxy.logger.error(
2403
- `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}`
2404
2572
  );
2405
2573
  });
2406
2574
  } else {
@@ -2642,6 +2810,7 @@ export default class Meeting extends StatelessWebexPlugin {
2642
2810
  this.locusUrl = locusMeetingObject?.url || webexMeetingInfo?.locusUrl || this.locusUrl;
2643
2811
  // @ts-ignore - config coming from registerPlugin
2644
2812
  this.setSipUri(
2813
+ // @ts-ignore
2645
2814
  this.config.experimental.enableUnifiedMeetings
2646
2815
  ? locusMeetingObject?.info.sipUri || webexMeetingInfo?.sipUrl
2647
2816
  : locusMeetingObject?.info.sipUri || webexMeetingInfo?.sipMeetingUri || this.sipUri
@@ -3590,6 +3759,20 @@ export default class Meeting extends StatelessWebexPlugin {
3590
3759
  return false;
3591
3760
  }
3592
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
+
3593
3776
  /**
3594
3777
  * Monitor the Low-Latency Mercury (LLM) web socket connection on `onError` and `onClose` states
3595
3778
  * @private
@@ -3641,6 +3824,7 @@ export default class Meeting extends StatelessWebexPlugin {
3641
3824
  // @ts-ignore - fix type
3642
3825
  const {
3643
3826
  body: {webSocketUrl},
3827
+ // @ts-ignore
3644
3828
  } = await this.request({
3645
3829
  method: HTTP_VERBS.POST,
3646
3830
  uri: datachannelUrl,
@@ -3690,6 +3874,44 @@ export default class Meeting extends StatelessWebexPlugin {
3690
3874
  }
3691
3875
  }
3692
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
+
3693
3915
  /**
3694
3916
  * stop recieving Transcription by closing
3695
3917
  * the web socket connection properly
@@ -3863,8 +4085,12 @@ export default class Meeting extends StatelessWebexPlugin {
3863
4085
  return join;
3864
4086
  })
3865
4087
  .then(async (join) => {
4088
+ // @ts-ignore - config coming from registerPlugin
3866
4089
  if (this.config.enableAutomaticLLM) {
3867
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!');
3868
4094
  }
3869
4095
 
3870
4096
  return join;
@@ -3931,21 +4157,28 @@ export default class Meeting extends StatelessWebexPlugin {
3931
4157
  * @returns {Promise}
3932
4158
  */
3933
4159
  async updateLLMConnection() {
4160
+ // @ts-ignore - Fix type
3934
4161
  const {url, info: {datachannelUrl} = {}} = this.locusInfo;
3935
4162
 
3936
4163
  const isJoined = this.joinedWith && this.joinedWith.state === 'JOINED';
3937
4164
 
4165
+ // @ts-ignore - Fix type
3938
4166
  if (this.webex.internal.llm.isConnected()) {
4167
+ // @ts-ignore - Fix type
3939
4168
  if (url === this.webex.internal.llm.getLocusUrl() && isJoined) {
3940
4169
  return undefined;
3941
4170
  }
4171
+ // @ts-ignore - Fix type
3942
4172
  await this.webex.internal.llm.disconnectLLM();
4173
+ // @ts-ignore - Fix type
4174
+ this.webex.internal.llm.off('event:relay.event', this.processRelayEvent);
3943
4175
  }
3944
4176
 
3945
4177
  if (!isJoined) {
3946
4178
  return undefined;
3947
4179
  }
3948
4180
 
4181
+ // @ts-ignore - Fix type
3949
4182
  return this.webex.internal.llm.registerAndConnect(url, datachannelUrl);
3950
4183
  }
3951
4184
 
@@ -3988,28 +4221,31 @@ export default class Meeting extends StatelessWebexPlugin {
3988
4221
 
3989
4222
  if (!this.dialInUrl) this.dialInUrl = `dialin:///${uuid.v4()}`;
3990
4223
 
3991
- return this.meetingRequest
3992
- .dialIn({
3993
- correlationId,
3994
- dialInUrl: this.dialInUrl,
3995
- locusUrl,
3996
- clientUrl: this.deviceUrl,
3997
- })
3998
- .then((res) => {
3999
- this.locusInfo.onFullLocus(res.body.locus);
4000
- })
4001
- .catch((error) => {
4002
- Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.ADD_DIAL_IN_FAILURE, {
4003
- correlation_id: this.correlationId,
4004
- dial_in_url: this.dialInUrl,
4005
- locus_id: locusUrl.split('/').pop(),
4006
- client_url: this.deviceUrl,
4007
- reason: error.error?.message,
4008
- stack: error.stack,
4009
- });
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
+ });
4010
4245
 
4011
- return Promise.reject(error);
4012
- });
4246
+ return Promise.reject(error);
4247
+ })
4248
+ );
4013
4249
  }
4014
4250
 
4015
4251
  /**
@@ -4026,29 +4262,32 @@ export default class Meeting extends StatelessWebexPlugin {
4026
4262
 
4027
4263
  if (!this.dialOutUrl) this.dialOutUrl = `dialout:///${uuid.v4()}`;
4028
4264
 
4029
- return this.meetingRequest
4030
- .dialOut({
4031
- correlationId,
4032
- dialOutUrl: this.dialOutUrl,
4033
- phoneNumber,
4034
- locusUrl,
4035
- clientUrl: this.deviceUrl,
4036
- })
4037
- .then((res) => {
4038
- this.locusInfo.onFullLocus(res.body.locus);
4039
- })
4040
- .catch((error) => {
4041
- Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.ADD_DIAL_OUT_FAILURE, {
4042
- correlation_id: this.correlationId,
4043
- dial_out_url: this.dialOutUrl,
4044
- locus_id: locusUrl.split('/').pop(),
4045
- client_url: this.deviceUrl,
4046
- reason: error.error?.message,
4047
- stack: error.stack,
4048
- });
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
+ });
4049
4287
 
4050
- return Promise.reject(error);
4051
- });
4288
+ return Promise.reject(error);
4289
+ })
4290
+ );
4052
4291
  }
4053
4292
 
4054
4293
  /**
@@ -4395,7 +4634,7 @@ export default class Meeting extends StatelessWebexPlugin {
4395
4634
  Metrics.sendBehavioralMetric(metricName, data, metadata);
4396
4635
  };
4397
4636
 
4398
- if (error instanceof MC.Errors.SdpOfferCreationError) {
4637
+ if (error instanceof Errors.SdpOfferCreationError) {
4399
4638
  sendBehavioralMetric(BEHAVIORAL_METRICS.PEERCONNECTION_FAILURE, error, this.id);
4400
4639
 
4401
4640
  Metrics.postEvent({
@@ -4409,8 +4648,8 @@ export default class Meeting extends StatelessWebexPlugin {
4409
4648
  },
4410
4649
  });
4411
4650
  } else if (
4412
- error instanceof MC.Errors.SdpOfferHandlingError ||
4413
- error instanceof MC.Errors.SdpAnswerHandlingError
4651
+ error instanceof Errors.SdpOfferHandlingError ||
4652
+ error instanceof Errors.SdpAnswerHandlingError
4414
4653
  ) {
4415
4654
  sendBehavioralMetric(BEHAVIORAL_METRICS.PEERCONNECTION_FAILURE, error, this.id);
4416
4655
 
@@ -4424,8 +4663,8 @@ export default class Meeting extends StatelessWebexPlugin {
4424
4663
  ],
4425
4664
  },
4426
4665
  });
4427
- } else if (error instanceof MC.Errors.SdpError) {
4428
- // 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
4429
4668
  sendBehavioralMetric(BEHAVIORAL_METRICS.INVALID_ICE_CANDIDATE, error, this.id);
4430
4669
 
4431
4670
  Metrics.postEvent({
@@ -4442,19 +4681,19 @@ export default class Meeting extends StatelessWebexPlugin {
4442
4681
  };
4443
4682
 
4444
4683
  setupMediaConnectionListeners = () => {
4445
- this.mediaProperties.webrtcMediaConnection.on(MC.Event.ROAP_STARTED, () => {
4684
+ this.mediaProperties.webrtcMediaConnection.on(Event.ROAP_STARTED, () => {
4446
4685
  this.isRoapInProgress = true;
4447
4686
  });
4448
4687
 
4449
- this.mediaProperties.webrtcMediaConnection.on(MC.Event.ROAP_DONE, () => {
4688
+ this.mediaProperties.webrtcMediaConnection.on(Event.ROAP_DONE, () => {
4450
4689
  this.mediaNegotiatedEvent();
4451
4690
  this.isRoapInProgress = false;
4452
4691
  this.processNextQueuedMediaUpdate();
4453
4692
  });
4454
4693
 
4455
- this.mediaProperties.webrtcMediaConnection.on(MC.Event.ROAP_FAILURE, this.handleRoapFailure);
4694
+ this.mediaProperties.webrtcMediaConnection.on(Event.ROAP_FAILURE, this.handleRoapFailure);
4456
4695
 
4457
- this.mediaProperties.webrtcMediaConnection.on(MC.Event.ROAP_MESSAGE_TO_SEND, (event) => {
4696
+ this.mediaProperties.webrtcMediaConnection.on(Event.ROAP_MESSAGE_TO_SEND, (event) => {
4458
4697
  const LOG_HEADER = 'Meeting:index#setupMediaConnectionListeners.ROAP_MESSAGE_TO_SEND -->';
4459
4698
 
4460
4699
  switch (event.roapMessage.messageType) {
@@ -4536,8 +4775,8 @@ export default class Meeting extends StatelessWebexPlugin {
4536
4775
 
4537
4776
  case 'ERROR':
4538
4777
  if (
4539
- event.roapMessage.errorType === MC.ErrorType.CONFLICT ||
4540
- event.roapMessage.errorType === MC.ErrorType.DOUBLECONFLICT
4778
+ event.roapMessage.errorType === ErrorType.CONFLICT ||
4779
+ event.roapMessage.errorType === ErrorType.DOUBLECONFLICT
4541
4780
  ) {
4542
4781
  Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.ROAP_GLARE_CONDITION, {
4543
4782
  correlation_id: this.correlationId,
@@ -4569,7 +4808,7 @@ export default class Meeting extends StatelessWebexPlugin {
4569
4808
  });
4570
4809
 
4571
4810
  // eslint-disable-next-line no-param-reassign
4572
- this.mediaProperties.webrtcMediaConnection.on(MC.Event.REMOTE_TRACK_ADDED, (event) => {
4811
+ this.mediaProperties.webrtcMediaConnection.on(Event.REMOTE_TRACK_ADDED, (event) => {
4573
4812
  LoggerProxy.logger.log(
4574
4813
  `Meeting:index#setupMediaConnectionListeners --> REMOTE_TRACK_ADDED event received for webrtcMediaConnection: ${JSON.stringify(
4575
4814
  event
@@ -4582,15 +4821,15 @@ export default class Meeting extends StatelessWebexPlugin {
4582
4821
  let eventType;
4583
4822
 
4584
4823
  switch (event.type) {
4585
- case MC.RemoteTrackType.AUDIO:
4824
+ case RemoteTrackType.AUDIO:
4586
4825
  eventType = EVENT_TYPES.REMOTE_AUDIO;
4587
4826
  this.mediaProperties.setRemoteAudioTrack(event.track);
4588
4827
  break;
4589
- case MC.RemoteTrackType.VIDEO:
4828
+ case RemoteTrackType.VIDEO:
4590
4829
  eventType = EVENT_TYPES.REMOTE_VIDEO;
4591
4830
  this.mediaProperties.setRemoteVideoTrack(event.track);
4592
4831
  break;
4593
- case MC.RemoteTrackType.SCREENSHARE_VIDEO:
4832
+ case RemoteTrackType.SCREENSHARE_VIDEO:
4594
4833
  if (event.track) {
4595
4834
  eventType = EVENT_TYPES.REMOTE_SHARE;
4596
4835
  this.mediaProperties.setRemoteShare(event.track);
@@ -4623,7 +4862,7 @@ export default class Meeting extends StatelessWebexPlugin {
4623
4862
  }
4624
4863
  });
4625
4864
 
4626
- this.mediaProperties.webrtcMediaConnection.on(MC.Event.CONNECTION_STATE_CHANGED, (event) => {
4865
+ this.mediaProperties.webrtcMediaConnection.on(Event.CONNECTION_STATE_CHANGED, (event) => {
4627
4866
  const connectionFailed = () => {
4628
4867
  // we know the media connection failed and browser will not attempt to recover it any more
4629
4868
  // so reset the timer as it's not needed anymore, we want to reconnect immediately
@@ -4656,10 +4895,10 @@ export default class Meeting extends StatelessWebexPlugin {
4656
4895
  `Meeting:index#setupMediaConnectionListeners --> connection state changed to ${event.state}`
4657
4896
  );
4658
4897
  switch (event.state) {
4659
- case MC.ConnectionState.Connecting:
4898
+ case ConnectionState.Connecting:
4660
4899
  Metrics.postEvent({event: eventType.ICE_START, meeting: this});
4661
4900
  break;
4662
- case MC.ConnectionState.Connected:
4901
+ case ConnectionState.Connected:
4663
4902
  Metrics.postEvent({event: eventType.ICE_END, meeting: this});
4664
4903
  Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.CONNECTION_SUCCESS, {
4665
4904
  correlation_id: this.correlationId,
@@ -4668,7 +4907,7 @@ export default class Meeting extends StatelessWebexPlugin {
4668
4907
  this.setNetworkStatus(NETWORK_STATUS.CONNECTED);
4669
4908
  this.reconnectionManager.iceReconnected();
4670
4909
  break;
4671
- case MC.ConnectionState.Disconnected:
4910
+ case ConnectionState.Disconnected:
4672
4911
  this.setNetworkStatus(NETWORK_STATUS.DISCONNECTED);
4673
4912
  this.reconnectionManager.waitForIceReconnect().catch(() => {
4674
4913
  LoggerProxy.logger.info(
@@ -4678,7 +4917,7 @@ export default class Meeting extends StatelessWebexPlugin {
4678
4917
  connectionFailed();
4679
4918
  });
4680
4919
  break;
4681
- case MC.ConnectionState.Failed:
4920
+ case ConnectionState.Failed:
4682
4921
  connectionFailed();
4683
4922
  break;
4684
4923
  default:
@@ -4686,7 +4925,7 @@ export default class Meeting extends StatelessWebexPlugin {
4686
4925
  }
4687
4926
  });
4688
4927
 
4689
- this.mediaProperties.webrtcMediaConnection.on(MC.Event.ACTIVE_SPEAKERS_CHANGED, (msg) => {
4928
+ this.mediaProperties.webrtcMediaConnection.on(Event.ACTIVE_SPEAKERS_CHANGED, (msg) => {
4690
4929
  Trigger.trigger(
4691
4930
  this,
4692
4931
  {
@@ -4697,6 +4936,7 @@ export default class Meeting extends StatelessWebexPlugin {
4697
4936
  {
4698
4937
  seqNum: msg.seqNum,
4699
4938
  memberIds: msg.csis
4939
+ // @ts-ignore
4700
4940
  .map((csi) => this.members.findMemberByCsi(csi)?.id)
4701
4941
  .filter((item) => item !== undefined),
4702
4942
  }
@@ -4704,7 +4944,7 @@ export default class Meeting extends StatelessWebexPlugin {
4704
4944
  });
4705
4945
 
4706
4946
  this.mediaProperties.webrtcMediaConnection.on(
4707
- MC.Event.VIDEO_SOURCES_COUNT_CHANGED,
4947
+ Event.VIDEO_SOURCES_COUNT_CHANGED,
4708
4948
  (numTotalSources, numLiveSources) => {
4709
4949
  Trigger.trigger(
4710
4950
  this,
@@ -4722,7 +4962,7 @@ export default class Meeting extends StatelessWebexPlugin {
4722
4962
  );
4723
4963
 
4724
4964
  this.mediaProperties.webrtcMediaConnection.on(
4725
- MC.Event.AUDIO_SOURCES_COUNT_CHANGED,
4965
+ Event.AUDIO_SOURCES_COUNT_CHANGED,
4726
4966
  (numTotalSources, numLiveSources) => {
4727
4967
  Trigger.trigger(
4728
4968
  this,
@@ -4752,6 +4992,7 @@ export default class Meeting extends StatelessWebexPlugin {
4752
4992
  // Add ip address info if geo hint is present
4753
4993
  // @ts-ignore fix type
4754
4994
  options.data.intervalMetadata.peerReflexiveIP =
4995
+ // @ts-ignore
4755
4996
  this.webex.meetings.geoHintInfo?.clientAddress ||
4756
4997
  options.data.intervalMetadata.peerReflexiveIP ||
4757
4998
  MQA_STATS.DEFAULT_IP;
@@ -5082,7 +5323,7 @@ export default class Meeting extends StatelessWebexPlugin {
5082
5323
  this
5083
5324
  );
5084
5325
 
5085
- if (error instanceof MC.Errors.SdpError) {
5326
+ if (error instanceof Errors.SdpError) {
5086
5327
  this.leave({reason: MEETING_REMOVED_REASON.MEETING_CONNECTION_FAILED});
5087
5328
  }
5088
5329
 
@@ -5852,7 +6093,7 @@ export default class Meeting extends StatelessWebexPlugin {
5852
6093
  * @memberof Meeting
5853
6094
  */
5854
6095
  public startRecording() {
5855
- return MeetingUtil.startRecording(this.meetingRequest, this.locusUrl, this.locusInfo);
6096
+ return this.recordingController.startRecording();
5856
6097
  }
5857
6098
 
5858
6099
  /**
@@ -5862,7 +6103,7 @@ export default class Meeting extends StatelessWebexPlugin {
5862
6103
  * @memberof Meeting
5863
6104
  */
5864
6105
  public stopRecording() {
5865
- return MeetingUtil.stopRecording(this.meetingRequest, this.locusUrl, this.locusInfo);
6106
+ return this.recordingController.stopRecording();
5866
6107
  }
5867
6108
 
5868
6109
  /**
@@ -5872,7 +6113,7 @@ export default class Meeting extends StatelessWebexPlugin {
5872
6113
  * @memberof Meeting
5873
6114
  */
5874
6115
  public pauseRecording() {
5875
- return MeetingUtil.pauseRecording(this.meetingRequest, this.locusUrl, this.locusInfo);
6116
+ return this.recordingController.pauseRecording();
5876
6117
  }
5877
6118
 
5878
6119
  /**
@@ -5882,7 +6123,7 @@ export default class Meeting extends StatelessWebexPlugin {
5882
6123
  * @memberof Meeting
5883
6124
  */
5884
6125
  public resumeRecording() {
5885
- return MeetingUtil.resumeRecording(this.meetingRequest, this.locusUrl, this.locusInfo);
6126
+ return this.recordingController.resumeRecording();
5886
6127
  }
5887
6128
 
5888
6129
  /**