@webex/plugin-meetings 3.1.0 → 3.3.0

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 (206) hide show
  1. package/dist/breakouts/breakout.js +1 -1
  2. package/dist/breakouts/index.js +1 -1
  3. package/dist/common/errors/{reconnection-in-progress.js → reconnection-not-started.js} +27 -15
  4. package/dist/common/errors/reconnection-not-started.js.map +1 -0
  5. package/dist/constants.js +12 -3
  6. package/dist/constants.js.map +1 -1
  7. package/dist/index.js +80 -0
  8. package/dist/index.js.map +1 -1
  9. package/dist/interpretation/index.js +1 -1
  10. package/dist/interpretation/siLanguage.js +1 -1
  11. package/dist/locus-info/controlsUtils.js +7 -1
  12. package/dist/locus-info/controlsUtils.js.map +1 -1
  13. package/dist/locus-info/index.js +10 -0
  14. package/dist/locus-info/index.js.map +1 -1
  15. package/dist/media/properties.js +102 -57
  16. package/dist/media/properties.js.map +1 -1
  17. package/dist/meeting/in-meeting-actions.js +6 -0
  18. package/dist/meeting/in-meeting-actions.js.map +1 -1
  19. package/dist/meeting/index.js +543 -467
  20. package/dist/meeting/index.js.map +1 -1
  21. package/dist/meeting/locusMediaRequest.js +27 -0
  22. package/dist/meeting/locusMediaRequest.js.map +1 -1
  23. package/dist/meeting/util.js +9 -16
  24. package/dist/meeting/util.js.map +1 -1
  25. package/dist/meeting/voicea-meeting.js +37 -49
  26. package/dist/meeting/voicea-meeting.js.map +1 -1
  27. package/dist/meeting-info/util.js +304 -267
  28. package/dist/meeting-info/util.js.map +1 -1
  29. package/dist/meeting-info/utilv2.js +334 -298
  30. package/dist/meeting-info/utilv2.js.map +1 -1
  31. package/dist/meetings/index.js +6 -27
  32. package/dist/meetings/index.js.map +1 -1
  33. package/dist/reachability/index.js +6 -0
  34. package/dist/reachability/index.js.map +1 -1
  35. package/dist/reconnection-manager/index.js +138 -109
  36. package/dist/reconnection-manager/index.js.map +1 -1
  37. package/dist/roap/request.js +3 -27
  38. package/dist/roap/request.js.map +1 -1
  39. package/dist/statsAnalyzer/index.js +4 -0
  40. package/dist/statsAnalyzer/index.js.map +1 -1
  41. package/dist/statsAnalyzer/mqaUtil.js +3 -0
  42. package/dist/statsAnalyzer/mqaUtil.js.map +1 -1
  43. package/dist/types/common/errors/reconnection-not-started.d.ts +13 -0
  44. package/dist/{constants.d.ts → types/constants.d.ts} +11 -2
  45. package/dist/types/index.d.ts +19 -0
  46. package/dist/{media → types/media}/properties.d.ts +26 -2
  47. package/dist/{meeting → types/meeting}/in-meeting-actions.d.ts +6 -0
  48. package/dist/{meeting → types/meeting}/index.d.ts +5 -6
  49. package/dist/{meeting → types/meeting}/locusMediaRequest.d.ts +1 -0
  50. package/dist/{meeting → types/meeting}/util.d.ts +3 -0
  51. package/dist/{meeting → types/meeting}/voicea-meeting.d.ts +3 -2
  52. package/dist/{meeting-info → types/meeting-info}/index.d.ts +1 -1
  53. package/dist/{meeting-info → types/meeting-info}/meeting-info-v2.d.ts +1 -1
  54. package/dist/types/meeting-info/util.d.ts +49 -0
  55. package/dist/types/meeting-info/utilv2.d.ts +65 -0
  56. package/dist/{meetings → types/meetings}/index.d.ts +1 -16
  57. package/dist/{reconnection-manager → types/reconnection-manager}/index.d.ts +4 -14
  58. package/dist/webinar/index.js +1 -1
  59. package/package.json +22 -22
  60. package/src/common/errors/reconnection-not-started.ts +25 -0
  61. package/src/constants.ts +12 -4
  62. package/src/index.ts +30 -0
  63. package/src/locus-info/controlsUtils.ts +11 -0
  64. package/src/locus-info/index.ts +16 -0
  65. package/src/media/properties.ts +67 -15
  66. package/src/meeting/in-meeting-actions.ts +12 -0
  67. package/src/meeting/index.ts +121 -98
  68. package/src/meeting/locusMediaRequest.ts +31 -0
  69. package/src/meeting/util.ts +9 -16
  70. package/src/meeting/voicea-meeting.ts +44 -46
  71. package/src/meeting-info/util.ts +241 -233
  72. package/src/meeting-info/utilv2.ts +250 -244
  73. package/src/meetings/index.ts +8 -25
  74. package/src/reachability/index.ts +3 -0
  75. package/src/reconnection-manager/index.ts +128 -105
  76. package/src/roap/request.ts +1 -24
  77. package/src/statsAnalyzer/index.ts +4 -0
  78. package/src/statsAnalyzer/mqaUtil.ts +5 -0
  79. package/test/unit/spec/locus-info/controlsUtils.js +20 -0
  80. package/test/unit/spec/locus-info/index.js +21 -0
  81. package/test/unit/spec/media/properties.ts +145 -140
  82. package/test/unit/spec/meeting/in-meeting-actions.ts +6 -0
  83. package/test/unit/spec/meeting/index.js +243 -97
  84. package/test/unit/spec/meeting/locusMediaRequest.ts +49 -0
  85. package/test/unit/spec/meeting/utils.js +3 -10
  86. package/test/unit/spec/meeting/voicea-meeting.ts +5 -14
  87. package/test/unit/spec/meetings/index.js +27 -8
  88. package/test/unit/spec/reconnection-manager/index.js +127 -39
  89. package/test/unit/spec/roap/request.ts +0 -37
  90. package/test/unit/spec/stats-analyzer/index.js +11 -0
  91. package/dist/common/errors/reconnection-in-progress.d.ts +0 -9
  92. package/dist/common/errors/reconnection-in-progress.js.map +0 -1
  93. package/dist/index.d.ts +0 -7
  94. package/dist/meeting-info/util.d.ts +0 -2
  95. package/dist/meeting-info/utilv2.d.ts +0 -2
  96. package/src/common/errors/reconnection-in-progress.ts +0 -8
  97. /package/dist/{annotation → types/annotation}/annotation.types.d.ts +0 -0
  98. /package/dist/{annotation → types/annotation}/constants.d.ts +0 -0
  99. /package/dist/{annotation → types/annotation}/index.d.ts +0 -0
  100. /package/dist/{breakouts → types/breakouts}/breakout.d.ts +0 -0
  101. /package/dist/{breakouts → types/breakouts}/collection.d.ts +0 -0
  102. /package/dist/{breakouts → types/breakouts}/edit-lock-error.d.ts +0 -0
  103. /package/dist/{breakouts → types/breakouts}/events.d.ts +0 -0
  104. /package/dist/{breakouts → types/breakouts}/index.d.ts +0 -0
  105. /package/dist/{breakouts → types/breakouts}/request.d.ts +0 -0
  106. /package/dist/{breakouts → types/breakouts}/utils.d.ts +0 -0
  107. /package/dist/{common → types/common}/browser-detection.d.ts +0 -0
  108. /package/dist/{common → types/common}/collection.d.ts +0 -0
  109. /package/dist/{common → types/common}/config.d.ts +0 -0
  110. /package/dist/{common → types/common}/errors/captcha-error.d.ts +0 -0
  111. /package/dist/{common → types/common}/errors/intent-to-join.d.ts +0 -0
  112. /package/dist/{common → types/common}/errors/join-meeting.d.ts +0 -0
  113. /package/dist/{common → types/common}/errors/media.d.ts +0 -0
  114. /package/dist/{common → types/common}/errors/no-meeting-info.d.ts +0 -0
  115. /package/dist/{common → types/common}/errors/parameter.d.ts +0 -0
  116. /package/dist/{common → types/common}/errors/password-error.d.ts +0 -0
  117. /package/dist/{common → types/common}/errors/permission.d.ts +0 -0
  118. /package/dist/{common → types/common}/errors/reclaim-host-role-errors.d.ts +0 -0
  119. /package/dist/{common → types/common}/errors/reconnection.d.ts +0 -0
  120. /package/dist/{common → types/common}/errors/stats.d.ts +0 -0
  121. /package/dist/{common → types/common}/errors/webex-errors.d.ts +0 -0
  122. /package/dist/{common → types/common}/errors/webex-meetings-error.d.ts +0 -0
  123. /package/dist/{common → types/common}/events/events-scope.d.ts +0 -0
  124. /package/dist/{common → types/common}/events/events.d.ts +0 -0
  125. /package/dist/{common → types/common}/events/trigger-proxy.d.ts +0 -0
  126. /package/dist/{common → types/common}/events/util.d.ts +0 -0
  127. /package/dist/{common → types/common}/logs/logger-config.d.ts +0 -0
  128. /package/dist/{common → types/common}/logs/logger-proxy.d.ts +0 -0
  129. /package/dist/{common → types/common}/logs/request.d.ts +0 -0
  130. /package/dist/{common → types/common}/queue.d.ts +0 -0
  131. /package/dist/{config.d.ts → types/config.d.ts} +0 -0
  132. /package/dist/{controls-options-manager → types/controls-options-manager}/constants.d.ts +0 -0
  133. /package/dist/{controls-options-manager → types/controls-options-manager}/enums.d.ts +0 -0
  134. /package/dist/{controls-options-manager → types/controls-options-manager}/index.d.ts +0 -0
  135. /package/dist/{controls-options-manager → types/controls-options-manager}/types.d.ts +0 -0
  136. /package/dist/{controls-options-manager → types/controls-options-manager}/util.d.ts +0 -0
  137. /package/dist/{interceptors → types/interceptors}/index.d.ts +0 -0
  138. /package/dist/{interceptors → types/interceptors}/locusRetry.d.ts +0 -0
  139. /package/dist/{interpretation → types/interpretation}/collection.d.ts +0 -0
  140. /package/dist/{interpretation → types/interpretation}/index.d.ts +0 -0
  141. /package/dist/{interpretation → types/interpretation}/siLanguage.d.ts +0 -0
  142. /package/dist/{locus-info → types/locus-info}/controlsUtils.d.ts +0 -0
  143. /package/dist/{locus-info → types/locus-info}/embeddedAppsUtils.d.ts +0 -0
  144. /package/dist/{locus-info → types/locus-info}/fullState.d.ts +0 -0
  145. /package/dist/{locus-info → types/locus-info}/hostUtils.d.ts +0 -0
  146. /package/dist/{locus-info → types/locus-info}/index.d.ts +0 -0
  147. /package/dist/{locus-info → types/locus-info}/infoUtils.d.ts +0 -0
  148. /package/dist/{locus-info → types/locus-info}/mediaSharesUtils.d.ts +0 -0
  149. /package/dist/{locus-info → types/locus-info}/parser.d.ts +0 -0
  150. /package/dist/{locus-info → types/locus-info}/selfUtils.d.ts +0 -0
  151. /package/dist/{media → types/media}/MediaConnectionAwaiter.d.ts +0 -0
  152. /package/dist/{media → types/media}/index.d.ts +0 -0
  153. /package/dist/{media → types/media}/util.d.ts +0 -0
  154. /package/dist/{mediaQualityMetrics → types/mediaQualityMetrics}/config.d.ts +0 -0
  155. /package/dist/{meeting → types/meeting}/muteState.d.ts +0 -0
  156. /package/dist/{meeting → types/meeting}/request.d.ts +0 -0
  157. /package/dist/{meeting → types/meeting}/request.type.d.ts +0 -0
  158. /package/dist/{meeting → types/meeting}/state.d.ts +0 -0
  159. /package/dist/{meeting-info → types/meeting-info}/collection.d.ts +0 -0
  160. /package/dist/{meeting-info → types/meeting-info}/request.d.ts +0 -0
  161. /package/dist/{meetings → types/meetings}/collection.d.ts +0 -0
  162. /package/dist/{meetings → types/meetings}/meetings.types.d.ts +0 -0
  163. /package/dist/{meetings → types/meetings}/request.d.ts +0 -0
  164. /package/dist/{meetings → types/meetings}/util.d.ts +0 -0
  165. /package/dist/{member → types/member}/index.d.ts +0 -0
  166. /package/dist/{member → types/member}/types.d.ts +0 -0
  167. /package/dist/{member → types/member}/util.d.ts +0 -0
  168. /package/dist/{members → types/members}/collection.d.ts +0 -0
  169. /package/dist/{members → types/members}/index.d.ts +0 -0
  170. /package/dist/{members → types/members}/request.d.ts +0 -0
  171. /package/dist/{members → types/members}/types.d.ts +0 -0
  172. /package/dist/{members → types/members}/util.d.ts +0 -0
  173. /package/dist/{metrics → types/metrics}/constants.d.ts +0 -0
  174. /package/dist/{metrics → types/metrics}/index.d.ts +0 -0
  175. /package/dist/{multistream → types/multistream}/mediaRequestManager.d.ts +0 -0
  176. /package/dist/{multistream → types/multistream}/receiveSlot.d.ts +0 -0
  177. /package/dist/{multistream → types/multistream}/receiveSlotManager.d.ts +0 -0
  178. /package/dist/{multistream → types/multistream}/remoteMedia.d.ts +0 -0
  179. /package/dist/{multistream → types/multistream}/remoteMediaGroup.d.ts +0 -0
  180. /package/dist/{multistream → types/multistream}/remoteMediaManager.d.ts +0 -0
  181. /package/dist/{multistream → types/multistream}/sendSlotManager.d.ts +0 -0
  182. /package/dist/{networkQualityMonitor → types/networkQualityMonitor}/index.d.ts +0 -0
  183. /package/dist/{personal-meeting-room → types/personal-meeting-room}/index.d.ts +0 -0
  184. /package/dist/{personal-meeting-room → types/personal-meeting-room}/request.d.ts +0 -0
  185. /package/dist/{personal-meeting-room → types/personal-meeting-room}/util.d.ts +0 -0
  186. /package/dist/{reachability → types/reachability}/clusterReachability.d.ts +0 -0
  187. /package/dist/{reachability → types/reachability}/index.d.ts +0 -0
  188. /package/dist/{reachability → types/reachability}/request.d.ts +0 -0
  189. /package/dist/{reachability → types/reachability}/util.d.ts +0 -0
  190. /package/dist/{reactions → types/reactions}/constants.d.ts +0 -0
  191. /package/dist/{reactions → types/reactions}/reactions.d.ts +0 -0
  192. /package/dist/{reactions → types/reactions}/reactions.type.d.ts +0 -0
  193. /package/dist/{recording-controller → types/recording-controller}/enums.d.ts +0 -0
  194. /package/dist/{recording-controller → types/recording-controller}/index.d.ts +0 -0
  195. /package/dist/{recording-controller → types/recording-controller}/util.d.ts +0 -0
  196. /package/dist/{roap → types/roap}/index.d.ts +0 -0
  197. /package/dist/{roap → types/roap}/request.d.ts +0 -0
  198. /package/dist/{roap → types/roap}/turnDiscovery.d.ts +0 -0
  199. /package/dist/{rtcMetrics → types/rtcMetrics}/constants.d.ts +0 -0
  200. /package/dist/{rtcMetrics → types/rtcMetrics}/index.d.ts +0 -0
  201. /package/dist/{statsAnalyzer → types/statsAnalyzer}/global.d.ts +0 -0
  202. /package/dist/{statsAnalyzer → types/statsAnalyzer}/index.d.ts +0 -0
  203. /package/dist/{statsAnalyzer → types/statsAnalyzer}/mqaUtil.d.ts +0 -0
  204. /package/dist/{transcription → types/transcription}/index.d.ts +0 -0
  205. /package/dist/{webinar → types/webinar}/collection.d.ts +0 -0
  206. /package/dist/{webinar → types/webinar}/index.d.ts +0 -0
@@ -38,6 +38,7 @@ import {
38
38
  import {
39
39
  EVENT_TRIGGERS as VOICEAEVENTS,
40
40
  TURN_ON_CAPTION_STATUS,
41
+ type MeetingTranscriptPayload,
41
42
  } from '@webex/internal-plugin-voicea';
42
43
  import {processNewCaptions} from './voicea-meeting';
43
44
 
@@ -66,6 +67,7 @@ import {createMuteState} from './muteState';
66
67
  import LocusInfo from '../locus-info';
67
68
  import Metrics from '../metrics';
68
69
  import ReconnectionManager from '../reconnection-manager';
70
+ import ReconnectionNotStartedError from '../common/errors/reconnection-not-started';
69
71
  import MeetingRequest from './request';
70
72
  import Members from '../members/index';
71
73
  import MeetingUtil from './util';
@@ -76,8 +78,6 @@ import MediaUtil from '../media/util';
76
78
  import {Reactions, SkinTones} from '../reactions/reactions';
77
79
  import PasswordError from '../common/errors/password-error';
78
80
  import CaptchaError from '../common/errors/captcha-error';
79
- import ReconnectionError from '../common/errors/reconnection';
80
- import ReconnectInProgress from '../common/errors/reconnection-in-progress';
81
81
  import {
82
82
  _CONVERSATION_URL_,
83
83
  _INCOMING_,
@@ -631,6 +631,7 @@ export default class Meeting extends StatelessWebexPlugin {
631
631
  turnDiscoverySkippedReason: TurnDiscoverySkipReason;
632
632
  turnServerUsed: boolean;
633
633
  areVoiceaEventsSetup = false;
634
+ isMoveToInProgress = false;
634
635
 
635
636
  voiceaListenerCallbacks: object = {
636
637
  [VOICEAEVENTS.VOICEA_ANNOUNCEMENT]: (payload: Transcription['languageOptions']) => {
@@ -655,7 +656,7 @@ export default class Meeting extends StatelessWebexPlugin {
655
656
  this.transcription.isListening = !!data.isListening;
656
657
  this.transcription.commandText = data.text ?? '';
657
658
  },
658
- [VOICEAEVENTS.NEW_CAPTION]: (data) => {
659
+ [VOICEAEVENTS.NEW_CAPTION]: (data: MeetingTranscriptPayload) => {
659
660
  processNewCaptions({data, meeting: this});
660
661
 
661
662
  LoggerProxy.logger.debug(
@@ -678,6 +679,7 @@ export default class Meeting extends StatelessWebexPlugin {
678
679
  private deferSDPAnswer?: Defer; // used for waiting for a response
679
680
  private sdpResponseTimer?: ReturnType<typeof setTimeout>;
680
681
  private hasMediaConnectionConnectedAtLeastOnce: boolean;
682
+ private joinWithMediaRetryInfo?: {isRetry: boolean; prevJoinResponse?: any};
681
683
 
682
684
  /**
683
685
  * @param {Object} attrs
@@ -1389,11 +1391,11 @@ export default class Meeting extends StatelessWebexPlugin {
1389
1391
  this.remoteMediaManager = null;
1390
1392
 
1391
1393
  this.localAudioStreamMuteStateHandler = () => {
1392
- this.audio.handleLocalStreamMuteStateChange(this);
1394
+ this.audio?.handleLocalStreamMuteStateChange(this);
1393
1395
  };
1394
1396
 
1395
1397
  this.localVideoStreamMuteStateHandler = () => {
1396
- this.video.handleLocalStreamMuteStateChange(this);
1398
+ this.video?.handleLocalStreamMuteStateChange(this);
1397
1399
  };
1398
1400
 
1399
1401
  // The handling of output track changes should be done inside
@@ -1459,6 +1461,15 @@ export default class Meeting extends StatelessWebexPlugin {
1459
1461
  * @memberof Meeting
1460
1462
  */
1461
1463
  this.hasMediaConnectionConnectedAtLeastOnce = false;
1464
+
1465
+ /**
1466
+ * Information needed for a retry of a call to joinWithMedia
1467
+ * @instance
1468
+ * @type {{isRetry: boolean; prevJoinResponse?: any}}
1469
+ * @private
1470
+ * @memberof Meeting
1471
+ */
1472
+ this.joinWithMediaRetryInfo = {isRetry: false, prevJoinResponse: undefined};
1462
1473
  }
1463
1474
 
1464
1475
  /**
@@ -2401,6 +2412,18 @@ export default class Meeting extends StatelessWebexPlugin {
2401
2412
  }
2402
2413
  );
2403
2414
 
2415
+ this.locusInfo.on(LOCUSINFO.EVENTS.CONTROLS_MEETING_MANUAL_CAPTION_UPDATED, ({enable}) => {
2416
+ Trigger.trigger(
2417
+ this,
2418
+ {
2419
+ file: 'meeting/index',
2420
+ function: 'setupLocusControlsListener',
2421
+ },
2422
+ EVENT_TRIGGERS.MEETING_MANUAL_CAPTION_UPDATED,
2423
+ {enable}
2424
+ );
2425
+ });
2426
+
2404
2427
  this.locusInfo.on(LOCUSINFO.EVENTS.CONTROLS_MEETING_BREAKOUT_UPDATED, ({breakout}) => {
2405
2428
  this.breakouts.updateBreakout(breakout);
2406
2429
  Trigger.trigger(
@@ -3058,6 +3081,7 @@ export default class Meeting extends StatelessWebexPlugin {
3058
3081
  options: {meetingId: this.id},
3059
3082
  });
3060
3083
  }
3084
+ this.updateLLMConnection();
3061
3085
  });
3062
3086
  this.locusInfo.on(LOCUSINFO.EVENTS.SELF_ADMITTED_GUEST, async (payload) => {
3063
3087
  this.stopKeepAlive();
@@ -3575,6 +3599,9 @@ export default class Meeting extends StatelessWebexPlugin {
3575
3599
  canStartTranscribing: MeetingUtil.canStartTranscribing(this.userDisplayHints),
3576
3600
  canStopTranscribing: MeetingUtil.canStopTranscribing(this.userDisplayHints),
3577
3601
  isClosedCaptionActive: MeetingUtil.isClosedCaptionActive(this.userDisplayHints),
3602
+ canStartManualCaption: MeetingUtil.canStartManualCaption(this.userDisplayHints),
3603
+ canStopManualCaption: MeetingUtil.canStopManualCaption(this.userDisplayHints),
3604
+ isManualCaptionActive: MeetingUtil.isManualCaptionActive(this.userDisplayHints),
3578
3605
  isSaveTranscriptsEnabled: MeetingUtil.isSaveTranscriptsEnabled(this.userDisplayHints),
3579
3606
  isWebexAssistantActive: MeetingUtil.isWebexAssistantActive(this.userDisplayHints),
3580
3607
  canViewCaptionPanel: MeetingUtil.canViewCaptionPanel(this.userDisplayHints),
@@ -3918,7 +3945,7 @@ export default class Meeting extends StatelessWebexPlugin {
3918
3945
  // we don't update this.mediaProperties.mediaDirection.sendAudio, because we always keep it as true to avoid extra SDP exchanges
3919
3946
  this.mediaProperties.setLocalAudioStream(localStream);
3920
3947
 
3921
- this.audio.handleLocalStreamChange(this);
3948
+ this.audio?.handleLocalStreamChange(this);
3922
3949
 
3923
3950
  localStream?.on(
3924
3951
  LocalStreamEventNames.UserMuteStateChange,
@@ -3960,7 +3987,7 @@ export default class Meeting extends StatelessWebexPlugin {
3960
3987
  // we don't update this.mediaProperties.mediaDirection.sendVideo, because we always keep it as true to avoid extra SDP exchanges
3961
3988
  this.mediaProperties.setLocalVideoStream(localStream);
3962
3989
 
3963
- this.video.handleLocalStreamChange(this);
3990
+ this.video?.handleLocalStreamChange(this);
3964
3991
 
3965
3992
  localStream?.on(
3966
3993
  LocalStreamEventNames.UserMuteStateChange,
@@ -4512,6 +4539,7 @@ export default class Meeting extends StatelessWebexPlugin {
4512
4539
  } = {}
4513
4540
  ) {
4514
4541
  const {mediaOptions, joinOptions = {}} = options;
4542
+ const {isRetry, prevJoinResponse} = this.joinWithMediaRetryInfo;
4515
4543
 
4516
4544
  if (!mediaOptions?.allowMediaInLobby) {
4517
4545
  return Promise.reject(
@@ -4523,6 +4551,7 @@ export default class Meeting extends StatelessWebexPlugin {
4523
4551
  LoggerProxy.logger.info('Meeting:index#joinWithMedia called');
4524
4552
 
4525
4553
  let joined = false;
4554
+ let joinResponse = prevJoinResponse;
4526
4555
 
4527
4556
  try {
4528
4557
  let turnServerInfo;
@@ -4535,7 +4564,14 @@ export default class Meeting extends StatelessWebexPlugin {
4535
4564
  ({turnDiscoverySkippedReason} = turnDiscoveryRequest);
4536
4565
  joinOptions.roapMessage = turnDiscoveryRequest.roapMessage;
4537
4566
 
4538
- const joinResponse = await this.join(joinOptions);
4567
+ if (!joinResponse) {
4568
+ LoggerProxy.logger.info(
4569
+ 'Meeting:index#joinWithMedia ---> calling join with joinOptions, ',
4570
+ joinOptions
4571
+ );
4572
+
4573
+ joinResponse = await this.join(joinOptions);
4574
+ }
4539
4575
 
4540
4576
  joined = true;
4541
4577
 
@@ -4553,6 +4589,8 @@ export default class Meeting extends StatelessWebexPlugin {
4553
4589
 
4554
4590
  const mediaResponse = await this.addMedia(mediaOptions, turnServerInfo);
4555
4591
 
4592
+ this.joinWithMediaRetryInfo = {isRetry: false, prevJoinResponse: undefined};
4593
+
4556
4594
  return {
4557
4595
  join: joinResponse,
4558
4596
  media: mediaResponse,
@@ -4564,7 +4602,7 @@ export default class Meeting extends StatelessWebexPlugin {
4564
4602
 
4565
4603
  this.roap.abortTurnDiscovery();
4566
4604
 
4567
- if (joined) {
4605
+ if (joined && isRetry) {
4568
4606
  try {
4569
4607
  await this.leave({resourceId: joinOptions?.resourceId, reason: 'joinWithMedia failure'});
4570
4608
  } catch (e) {
@@ -4581,12 +4619,23 @@ export default class Meeting extends StatelessWebexPlugin {
4581
4619
  reason: error.message,
4582
4620
  stack: error.stack,
4583
4621
  leaveErrorReason: leaveError?.message,
4622
+ isRetry,
4584
4623
  },
4585
4624
  {
4586
4625
  type: error.name,
4587
4626
  }
4588
4627
  );
4589
4628
 
4629
+ if (!isRetry) {
4630
+ LoggerProxy.logger.warn('Meeting:index#joinWithMedia --> retrying call to joinWithMedia');
4631
+ this.joinWithMediaRetryInfo.isRetry = true;
4632
+ this.joinWithMediaRetryInfo.prevJoinResponse = joinResponse;
4633
+
4634
+ return this.joinWithMedia(options);
4635
+ }
4636
+
4637
+ this.joinWithMediaRetryInfo = {isRetry: false, prevJoinResponse: undefined};
4638
+
4590
4639
  throw error;
4591
4640
  }
4592
4641
  }
@@ -4617,90 +4666,28 @@ export default class Meeting extends StatelessWebexPlugin {
4617
4666
  );
4618
4667
  }
4619
4668
 
4620
- try {
4621
- LoggerProxy.logger.info('Meeting:index#reconnect --> Validating reconnect ability.');
4622
- // @ts-ignore
4623
- this.reconnectionManager.validate();
4624
- } catch (error) {
4625
- // Unable to reconnect this call
4626
- if (error instanceof ReconnectInProgress) {
4627
- LoggerProxy.logger.info(
4628
- 'Meeting:index#reconnect --> Unable to reconnect, reconnection in progress.'
4629
- );
4630
- } else {
4631
- LoggerProxy.logger.log('Meeting:index#reconnect --> Unable to reconnect.', error);
4632
- }
4633
-
4634
- return Promise.resolve();
4635
- }
4636
-
4637
- Trigger.trigger(
4638
- this,
4639
- {
4640
- file: 'meeting/index',
4641
- function: 'reconnect',
4642
- },
4643
- EVENT_TRIGGERS.MEETING_RECONNECTION_STARTING
4644
- );
4645
-
4646
4669
  return this.reconnectionManager
4647
- .reconnect(options)
4648
- .then(() => this.waitForRemoteSDPAnswer())
4649
- .then(() => this.waitForMediaConnectionConnected())
4670
+ .reconnect(options, async () => {
4671
+ await this.waitForRemoteSDPAnswer();
4672
+ await this.waitForMediaConnectionConnected();
4673
+ })
4650
4674
  .then(() => {
4651
- Trigger.trigger(
4652
- this,
4653
- {
4654
- file: 'meeting/index',
4655
- function: 'reconnect',
4656
- },
4657
- EVENT_TRIGGERS.MEETING_RECONNECTION_SUCCESS
4658
- );
4659
4675
  LoggerProxy.logger.log('Meeting:index#reconnect --> Meeting reconnect success');
4660
-
4661
- // @ts-ignore
4662
- this.webex.internal.newMetrics.submitClientEvent({
4663
- name: 'client.media.recovered',
4664
- payload: {
4665
- recoveredBy: 'new',
4666
- },
4667
- options: {
4668
- meetingId: this.id,
4669
- },
4670
- });
4671
- this.reconnectionManager.setStatus(RECONNECTION.STATE.COMPLETE);
4672
4676
  })
4673
4677
  .catch((error) => {
4674
- Trigger.trigger(
4675
- this,
4676
- {
4677
- file: 'meeting/index',
4678
- function: 'reconnect',
4679
- },
4680
- EVENT_TRIGGERS.MEETING_RECONNECTION_FAILURE,
4681
- {
4682
- error: new ReconnectionError('Reconnection failure event', error),
4683
- }
4684
- );
4678
+ if (error instanceof ReconnectionNotStartedError) {
4679
+ LoggerProxy.logger.log('Meeting:index#reconnect --> Meeting reconnect not started');
4685
4680
 
4681
+ return Promise.resolve();
4682
+ }
4686
4683
  LoggerProxy.logger.error('Meeting:index#reconnect --> Meeting reconnect failed', error);
4687
4684
 
4688
- Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.MEETING_RECONNECT_FAILURE, {
4689
- correlation_id: this.correlationId,
4690
- locus_id: this.locusUrl.split('/').pop(),
4691
- reason: error.message,
4692
- stack: error.stack,
4693
- });
4694
-
4695
4685
  this.uploadLogs({
4696
4686
  file: 'meeting/index',
4697
4687
  function: 'reconnect',
4698
4688
  });
4699
4689
 
4700
- return Promise.reject(new ReconnectionError('Reconnection failure event', error));
4701
- })
4702
- .finally(() => {
4703
- this.reconnectionManager.reset();
4690
+ return Promise.reject(error);
4704
4691
  });
4705
4692
  }
4706
4693
 
@@ -4710,12 +4697,12 @@ export default class Meeting extends StatelessWebexPlugin {
4710
4697
  * @throws TranscriptionNotSupportedError
4711
4698
  */
4712
4699
  isTranscriptionSupported() {
4713
- if (this.locusInfo.controls.transcribe?.transcribing) {
4700
+ if (this.locusInfo.controls.transcribe?.caption) {
4714
4701
  return true;
4715
4702
  }
4716
4703
 
4717
4704
  LoggerProxy.logger.error(
4718
- 'Meeting:index#isTranscriptionSupported --> Webex Assistant is not enabled/supported'
4705
+ 'Meeting:index#isTranscriptionSupported --> Closed Captions is not enabled/supported'
4719
4706
  );
4720
4707
 
4721
4708
  return false;
@@ -4854,7 +4841,7 @@ export default class Meeting extends StatelessWebexPlugin {
4854
4841
 
4855
4842
  if (this.getCurUserType() === 'host') {
4856
4843
  // @ts-ignore
4857
- await this.webex.internal.voicea.toggleTranscribing(true, options?.spokenLanguage);
4844
+ await this.webex.internal.voicea.turnOnCaptions(options?.spokenLanguage);
4858
4845
  }
4859
4846
  } catch (error) {
4860
4847
  LoggerProxy.logger.error(`Meeting:index#startTranscription --> ${error}`);
@@ -5442,17 +5429,28 @@ export default class Meeting extends StatelessWebexPlugin {
5442
5429
  },
5443
5430
  };
5444
5431
 
5445
- this.cleanupLocalStreams();
5446
-
5447
5432
  this.mediaProperties.setMediaDirection(mediaSettings.mediaDirection);
5448
5433
  this.mediaProperties.unsetRemoteMedia();
5449
5434
 
5450
- // when a move to is intiated by the client , Locus delets the existing media node from the server as soon the DX answers the meeting
5451
- // once the DX answers we establish connection back the media server with only receiveShare enabled
5452
- // @ts-ignore - reconnectMedia does not accept any argument
5453
- await this.reconnectionManager.reconnectMedia(mediaSettings).then(() => {
5454
- Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.MOVE_TO_SUCCESS);
5435
+ // when a move to is intiated by the client , Locus delets the existing media node from the server as soon the device answers the meeting
5436
+ // once the device answers we close the old connection and create new media server connection with only share enabled
5437
+ if (this.statsAnalyzer) {
5438
+ await this.statsAnalyzer.stopAnalyzer();
5439
+ }
5440
+ await this.closeRemoteStreams();
5441
+ await this.closePeerConnections();
5442
+ this.cleanupLocalStreams();
5443
+ this.unsetRemoteStreams();
5444
+ this.unsetPeerConnections();
5445
+ this.reconnectionManager.cleanUp();
5446
+
5447
+ await this.addMedia({
5448
+ audioEnabled: false,
5449
+ videoEnabled: false,
5450
+ shareVideoEnabled: true,
5455
5451
  });
5452
+ Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.MOVE_TO_SUCCESS);
5453
+ this.isMoveToInProgress = false;
5456
5454
  } catch (error) {
5457
5455
  LoggerProxy.logger.error('Meeting:index#moveTo --> Failed to moveTo resourceId', error);
5458
5456
  Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.MOVE_TO_FAILURE, {
@@ -5461,6 +5459,7 @@ export default class Meeting extends StatelessWebexPlugin {
5461
5459
  reason: error.message,
5462
5460
  stack: error.stack,
5463
5461
  });
5462
+ this.isMoveToInProgress = false;
5464
5463
  }
5465
5464
  });
5466
5465
 
@@ -5469,6 +5468,10 @@ export default class Meeting extends StatelessWebexPlugin {
5469
5468
  resourceId
5470
5469
  );
5471
5470
 
5471
+ // TODO: Check with locus if SELF_OBSERVING event would ever be not emitted
5472
+ // If yes, introduce a timeout mechanism
5473
+ this.isMoveToInProgress = true;
5474
+
5472
5475
  return MeetingUtil.joinMeetingOptions(this, {resourceId, moveToResource: true})
5473
5476
  .then(() => {
5474
5477
  this.meetingFiniteStateMachine.join();
@@ -5482,6 +5485,7 @@ export default class Meeting extends StatelessWebexPlugin {
5482
5485
  stack: error.stack,
5483
5486
  });
5484
5487
  LoggerProxy.logger.error('Meeting:index#moveTo --> Failed to moveTo resourceId', error);
5488
+ this.isMoveToInProgress = false;
5485
5489
 
5486
5490
  return Promise.reject(error);
5487
5491
  });
@@ -6468,11 +6472,14 @@ export default class Meeting extends StatelessWebexPlugin {
6468
6472
  /**
6469
6473
  * Performs TURN discovery as a separate call to the Locus /media API
6470
6474
  *
6471
- * @param {boolean} isRetry
6475
+ * @param {boolean} isReconnecting
6472
6476
  * @param {boolean} isForced
6473
6477
  * @returns {Promise}
6474
6478
  */
6475
- private async doTurnDiscovery(isRetry: boolean, isForced: boolean): Promise<TurnDiscoveryResult> {
6479
+ private async doTurnDiscovery(
6480
+ isReconnecting: boolean,
6481
+ isForced: boolean
6482
+ ): Promise<TurnDiscoveryResult> {
6476
6483
  // @ts-ignore
6477
6484
  const cdl = this.webex.internal.newMetrics.callDiagnosticLatencies;
6478
6485
 
@@ -6481,7 +6488,7 @@ export default class Meeting extends StatelessWebexPlugin {
6481
6488
  name: 'internal.client.add-media.turn-discovery.start',
6482
6489
  });
6483
6490
 
6484
- const turnDiscoveryResult = await this.roap.doTurnDiscovery(this, isRetry, isForced);
6491
+ const turnDiscoveryResult = await this.roap.doTurnDiscovery(this, isReconnecting, isForced);
6485
6492
 
6486
6493
  this.turnDiscoverySkippedReason = turnDiscoveryResult?.turnDiscoverySkippedReason;
6487
6494
  this.turnServerUsed = !this.turnDiscoverySkippedReason;
@@ -6520,11 +6527,16 @@ export default class Meeting extends StatelessWebexPlugin {
6520
6527
  turnServerInfo?: TurnServerInfo
6521
6528
  ): Promise<void> {
6522
6529
  const LOG_HEADER = 'Meeting:index#addMedia():establishMediaConnection -->';
6523
- const isRetry = this.retriedWithTurnServer;
6530
+ const isReconnecting = this.isMoveToInProgress || this.retriedWithTurnServer;
6531
+
6532
+ // We are forcing turn discovery if the case is moveTo and a turn server was used already
6533
+ if (this.isMoveToInProgress && this.turnServerUsed) {
6534
+ isForced = true;
6535
+ }
6524
6536
 
6525
6537
  try {
6526
6538
  if (!turnServerInfo) {
6527
- ({turnServerInfo} = await this.doTurnDiscovery(isRetry, isForced));
6539
+ ({turnServerInfo} = await this.doTurnDiscovery(isReconnecting, isForced));
6528
6540
  }
6529
6541
 
6530
6542
  const mc = await this.createMediaConnection(turnServerInfo, bundlePolicy);
@@ -6721,6 +6733,7 @@ export default class Meeting extends StatelessWebexPlugin {
6721
6733
  this.locusMediaRequest = new LocusMediaRequest(
6722
6734
  {
6723
6735
  correlationId: this.correlationId,
6736
+ meetingId: this.id,
6724
6737
  device: {
6725
6738
  url: this.deviceUrl,
6726
6739
  // @ts-ignore
@@ -6765,7 +6778,8 @@ export default class Meeting extends StatelessWebexPlugin {
6765
6778
  await this.enqueueScreenShareFloorRequest();
6766
6779
  }
6767
6780
 
6768
- const connectionType = await this.mediaProperties.getCurrentConnectionType();
6781
+ const {connectionType, selectedCandidatePairChanges, numTransports} =
6782
+ await this.mediaProperties.getCurrentConnectionInfo();
6769
6783
  // @ts-ignore
6770
6784
  const reachabilityStats = await this.webex.meetings.reachability.getReachabilityMetrics();
6771
6785
 
@@ -6773,8 +6787,11 @@ export default class Meeting extends StatelessWebexPlugin {
6773
6787
  correlation_id: this.correlationId,
6774
6788
  locus_id: this.locusUrl.split('/').pop(),
6775
6789
  connectionType,
6790
+ selectedCandidatePairChanges,
6791
+ numTransports,
6776
6792
  isMultistream: this.isMultistream,
6777
6793
  retriedWithTurnServer: this.retriedWithTurnServer,
6794
+ isJoinWithMediaRetry: this.joinWithMediaRetryInfo.isRetry,
6778
6795
  ...reachabilityStats,
6779
6796
  });
6780
6797
  // @ts-ignore
@@ -6796,16 +6813,22 @@ export default class Meeting extends StatelessWebexPlugin {
6796
6813
  // @ts-ignore
6797
6814
  const reachabilityMetrics = await this.webex.meetings.reachability.getReachabilityMetrics();
6798
6815
 
6816
+ const {selectedCandidatePairChanges, numTransports} =
6817
+ await this.mediaProperties.getCurrentConnectionInfo();
6818
+
6799
6819
  Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.ADD_MEDIA_FAILURE, {
6800
6820
  correlation_id: this.correlationId,
6801
6821
  locus_id: this.locusUrl.split('/').pop(),
6802
6822
  reason: error.message,
6803
6823
  stack: error.stack,
6804
6824
  code: error.code,
6825
+ selectedCandidatePairChanges,
6826
+ numTransports,
6805
6827
  turnDiscoverySkippedReason: this.turnDiscoverySkippedReason,
6806
6828
  turnServerUsed: this.turnServerUsed,
6807
6829
  retriedWithTurnServer: this.retriedWithTurnServer,
6808
6830
  isMultistream: this.isMultistream,
6831
+ isJoinWithMediaRetry: this.joinWithMediaRetryInfo.isRetry,
6809
6832
  signalingState:
6810
6833
  this.mediaProperties.webrtcMediaConnection?.multistreamConnection?.pc?.pc
6811
6834
  ?.signalingState ||
@@ -7013,7 +7036,7 @@ export default class Meeting extends StatelessWebexPlugin {
7013
7036
  if (audioEnabled !== undefined) {
7014
7037
  this.mediaProperties.mediaDirection.sendAudio = audioEnabled;
7015
7038
  this.mediaProperties.mediaDirection.receiveAudio = audioEnabled;
7016
- this.audio.enable(this, audioEnabled);
7039
+ this.audio?.enable(this, audioEnabled);
7017
7040
  if (this.isMultistream) {
7018
7041
  this.sendSlotManager.setActive(MediaType.AudioMain, audioEnabled);
7019
7042
  }
@@ -7022,7 +7045,7 @@ export default class Meeting extends StatelessWebexPlugin {
7022
7045
  if (videoEnabled !== undefined) {
7023
7046
  this.mediaProperties.mediaDirection.sendVideo = videoEnabled;
7024
7047
  this.mediaProperties.mediaDirection.receiveVideo = videoEnabled;
7025
- this.video.enable(this, videoEnabled);
7048
+ this.video?.enable(this, videoEnabled);
7026
7049
  if (this.isMultistream) {
7027
7050
  this.sendSlotManager.setActive(MediaType.VideoMain, videoEnabled);
7028
7051
  }
@@ -88,6 +88,7 @@ export type Config = {
88
88
  regionCode?: string;
89
89
  };
90
90
  correlationId: string;
91
+ meetingId: string;
91
92
  preferTranscoding: boolean;
92
93
  };
93
94
 
@@ -223,6 +224,14 @@ export class LocusMediaRequest extends WebexPlugin {
223
224
  localMedias.roapMessage = request.roapMessage;
224
225
  localMedias.reachability = request.reachability;
225
226
  body.clientMediaPreferences.joinCookie = request.joinCookie;
227
+
228
+ // @ts-ignore
229
+ this.webex.internal.newMetrics.submitClientEvent({
230
+ name: 'client.locus.media.request',
231
+ options: {
232
+ meetingId: this.config.meetingId,
233
+ },
234
+ });
226
235
  break;
227
236
  }
228
237
 
@@ -256,6 +265,16 @@ export class LocusMediaRequest extends WebexPlugin {
256
265
  this.confluenceState = 'created';
257
266
  }
258
267
 
268
+ if (request.type === 'RoapMessage') {
269
+ // @ts-ignore
270
+ this.webex.internal.newMetrics.submitClientEvent({
271
+ name: 'client.locus.media.response',
272
+ options: {
273
+ meetingId: this.config.meetingId,
274
+ },
275
+ });
276
+ }
277
+
259
278
  return result;
260
279
  })
261
280
  .catch((e) => {
@@ -265,6 +284,18 @@ export class LocusMediaRequest extends WebexPlugin {
265
284
  ) {
266
285
  this.confluenceState = 'not created';
267
286
  }
287
+
288
+ if (request.type === 'RoapMessage') {
289
+ // @ts-ignore
290
+ this.webex.internal.newMetrics.submitClientEvent({
291
+ name: 'client.locus.media.response',
292
+ options: {
293
+ meetingId: this.config.meetingId,
294
+ rawError: e,
295
+ },
296
+ });
297
+ }
298
+
268
299
  throw e;
269
300
  });
270
301
  }
@@ -47,7 +47,6 @@ const MeetingUtil = {
47
47
  },
48
48
 
49
49
  remoteUpdateAudioVideo: (meeting, audioMuted?: boolean, videoMuted?: boolean) => {
50
- const webex = meeting.getWebexObject();
51
50
  if (!meeting) {
52
51
  return Promise.reject(new ParameterError('You need a meeting object.'));
53
52
  }
@@ -60,12 +59,6 @@ const MeetingUtil = {
60
59
  );
61
60
  }
62
61
 
63
- // @ts-ignore
64
- webex.internal.newMetrics.submitClientEvent({
65
- name: 'client.locus.media.request',
66
- options: {meetingId: meeting.id},
67
- });
68
-
69
62
  return meeting.locusMediaRequest
70
63
  .send({
71
64
  type: 'LocalMute',
@@ -77,15 +70,7 @@ const MeetingUtil = {
77
70
  videoMuted,
78
71
  },
79
72
  })
80
- .then((response) => {
81
- // @ts-ignore
82
- webex.internal.newMetrics.submitClientEvent({
83
- name: 'client.locus.media.response',
84
- options: {meetingId: meeting.id},
85
- });
86
-
87
- return response?.body?.locus;
88
- });
73
+ .then((response) => response?.body?.locus);
89
74
  },
90
75
 
91
76
  hasOwner: (info) => info && info.owner,
@@ -535,6 +520,14 @@ const MeetingUtil = {
535
520
  isClosedCaptionActive: (displayHints) =>
536
521
  displayHints.includes(DISPLAY_HINTS.CAPTION_STATUS_ACTIVE),
537
522
 
523
+ canStartManualCaption: (displayHints) =>
524
+ displayHints.includes(DISPLAY_HINTS.MANUAL_CAPTION_START),
525
+
526
+ canStopManualCaption: (displayHints) => displayHints.includes(DISPLAY_HINTS.MANUAL_CAPTION_STOP),
527
+
528
+ isManualCaptionActive: (displayHints) =>
529
+ displayHints.includes(DISPLAY_HINTS.MANUAL_CAPTION_STATUS_ACTIVE),
530
+
538
531
  isWebexAssistantActive: (displayHints) =>
539
532
  displayHints.includes(DISPLAY_HINTS.WEBEX_ASSISTANT_STATUS_ACTIVE),
540
533