@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
@@ -17,11 +17,11 @@ import {
17
17
  RECONNECTION_STATE,
18
18
  } from '../constants';
19
19
  import BEHAVIORAL_METRICS from '../metrics/constants';
20
- import ReconnectInProgress from '../common/errors/reconnection-in-progress';
20
+ import ReconnectionError from '../common/errors/reconnection';
21
+ import ReconnectionNotStartedError from '../common/errors/reconnection-not-started';
21
22
  import Metrics from '../metrics';
22
23
  import Meeting from '../meeting';
23
24
  import {MediaRequestManager} from '../multistream/mediaRequestManager';
24
- import ReconnectionError from '../common/errors/reconnection';
25
25
 
26
26
  /**
27
27
  * Used to indicate that the reconnect logic needs to be retried.
@@ -73,7 +73,6 @@ export default class ReconnectionManager {
73
73
  rejoinAttempts: any;
74
74
  shareStatus: any;
75
75
  status: any;
76
- tryCount: any;
77
76
  webex: any;
78
77
  /**
79
78
  * @param {Meeting} meeting
@@ -102,13 +101,6 @@ export default class ReconnectionManager {
102
101
  * @memberof ReconnectionManager
103
102
  */
104
103
  this.status = RECONNECTION.STATE.DEFAULT_STATUS;
105
- /**
106
- * @instance
107
- * @type {Number}
108
- * @private
109
- * @memberof ReconnectionManager
110
- */
111
- this.tryCount = RECONNECTION.STATE.DEFAULT_TRY_COUNT;
112
104
  /**
113
105
  * @instance
114
106
  * @type {Object}
@@ -131,7 +123,7 @@ export default class ReconnectionManager {
131
123
 
132
124
  // @ts-ignore
133
125
  this.maxRejoinAttempts = meeting.config.reconnection.maxRejoinAttempts;
134
- this.rejoinAttempts = RECONNECTION.STATE.DEFAULT_TRY_COUNT;
126
+ this.rejoinAttempts = 0;
135
127
  // @ts-ignore
136
128
  this.autoRejoinEnabled = meeting.config.reconnection.autoRejoin;
137
129
 
@@ -217,8 +209,7 @@ export default class ReconnectionManager {
217
209
  */
218
210
  public reset() {
219
211
  this.status = RECONNECTION.STATE.DEFAULT_STATUS;
220
- this.tryCount = RECONNECTION.STATE.DEFAULT_TRY_COUNT;
221
- this.rejoinAttempts = RECONNECTION.STATE.DEFAULT_TRY_COUNT;
212
+ this.rejoinAttempts = 0;
222
213
  }
223
214
 
224
215
  /**
@@ -265,43 +256,30 @@ export default class ReconnectionManager {
265
256
  return this.status === RECONNECTION.STATE.IN_PROGRESS;
266
257
  }
267
258
 
268
- /**
269
- * Sets the reconnection status
270
- *
271
- * @public
272
- * @param {RECONNECTION_STATE} status
273
- * @memberof ReconnectionManager
274
- * @returns {undefined}
275
- */
276
- public setStatus(status: RECONNECTION_STATE) {
277
- this.status = status;
278
- }
279
-
280
259
  /**
281
260
  * @returns {Boolean}
282
- * @throws {ReconnectionError}
261
+ * @throws {ReconnectInProgress, ReconnectionDisabled}
283
262
  * @private
284
263
  * @memberof ReconnectionManager
285
264
  */
286
- private validate() {
265
+ private canStartReconnection() {
287
266
  if (this.meeting.config.reconnection.enabled) {
288
- if (
289
- this.status === RECONNECTION.STATE.DEFAULT_STATUS ||
290
- this.status === RECONNECTION.STATE.COMPLETE
291
- ) {
267
+ if (this.status === RECONNECTION.STATE.DEFAULT_STATUS) {
292
268
  return true;
293
269
  }
294
270
 
295
271
  LoggerProxy.logger.info(
296
- 'ReconnectionManager:index#validate --> Reconnection already in progress.'
272
+ 'ReconnectionManager:index#canStartReconnection --> Reconnection already in progress.'
297
273
  );
298
274
 
299
- throw new ReconnectInProgress('Reconnection already in progress.');
275
+ return false;
300
276
  }
301
277
 
302
- LoggerProxy.logger.info('ReconnectionManager:index#validate --> Reconnection is not enabled.');
278
+ LoggerProxy.logger.info(
279
+ 'ReconnectionManager:index#canStartReconnection --> Reconnection is not enabled.'
280
+ );
303
281
 
304
- throw new ReconnectionError('Reconnection is not enabled.');
282
+ return false;
305
283
  }
306
284
 
307
285
  /**
@@ -309,105 +287,152 @@ export default class ReconnectionManager {
309
287
  * @param {Object} reconnectOptions
310
288
  * @param {boolean} [reconnectOptions.networkDisconnect=false] indicates if a network disconnect event happened
311
289
  * @param {boolean} [reconnectOptions.networkRetry=false] indicates if we are retrying the reconnect
290
+ * @param {Function} [completionCallback] callback that gets called when reconnection is started successfully
312
291
  * @returns {Promise}
313
292
  * @public
314
293
  * @memberof ReconnectionManager
315
294
  */
316
- public async reconnect({
317
- networkDisconnect = false,
318
- networkRetry = false,
319
- }: {
320
- networkDisconnect?: boolean;
321
- networkRetry?: boolean;
322
- } = {}) {
295
+ public async reconnect(
296
+ {
297
+ networkDisconnect = false,
298
+ networkRetry = false,
299
+ }: {
300
+ networkDisconnect?: boolean;
301
+ networkRetry?: boolean;
302
+ } = {},
303
+ completionCallback: (() => Promise<void>) | undefined = undefined
304
+ ) {
323
305
  LoggerProxy.logger.info(
324
306
  `ReconnectionManager:index#reconnect --> Reconnection start for meeting ${this.meeting.id}.`
325
307
  );
326
- // First, validate that we can reconnect, if not, it will throw an error
327
- try {
328
- this.validate();
329
- } catch (error) {
330
- LoggerProxy.logger.info(
331
- 'ReconnectionManager:index#reconnect --> Reconnection unable to begin.',
332
- error
333
- );
334
- throw error;
335
- }
336
308
 
337
- if (!networkRetry) {
338
- // Only log START metrics on the initial reconnect
339
- LoggerProxy.logger.info(
340
- 'ReconnectionManager:index#reconnect --> Sending reconnect start metric.'
309
+ const triggerEvent = (event, payload = undefined) =>
310
+ Trigger.trigger(
311
+ this.meeting,
312
+ {
313
+ file: 'reconnection-manager/index',
314
+ function: 'reconnect',
315
+ },
316
+ event,
317
+ payload
341
318
  );
342
319
 
343
- // @ts-ignore
344
- this.webex.internal.newMetrics.submitClientEvent({
345
- name: 'client.media.reconnecting',
346
- options: {
347
- meetingId: this.meeting.id,
348
- },
349
- });
320
+ if (!this.canStartReconnection()) {
321
+ throw new ReconnectionNotStartedError();
350
322
  }
351
323
 
352
324
  try {
353
- await this.webex.meetings.startReachability();
354
- } catch (err) {
355
- LoggerProxy.logger.info(
356
- 'ReconnectionManager:index#reconnect --> Reachability failed, continuing with reconnection attempt, err: ',
357
- err
358
- );
359
- }
325
+ this.status = RECONNECTION.STATE.IN_PROGRESS;
360
326
 
361
- try {
362
- const media = await this.executeReconnection({networkDisconnect});
327
+ triggerEvent(EVENT_TRIGGERS.MEETING_RECONNECTION_STARTING);
363
328
 
364
- return media;
365
- } catch (reconnectError) {
366
- if (reconnectError instanceof NeedsRetryError) {
329
+ if (!networkRetry) {
330
+ // Only log START metrics on the initial reconnect
367
331
  LoggerProxy.logger.info(
368
- 'ReconnectionManager:index#reconnect --> Reconnection not successful, retrying.'
332
+ 'ReconnectionManager:index#reconnect --> Sending reconnect start metric.'
369
333
  );
370
- // Reset our reconnect status since we are looping back to the beginning
371
- this.status = RECONNECTION.STATE.DEFAULT_STATUS;
372
334
 
373
- // This is a network retry, so we should not log START metrics again
374
- return this.reconnect({networkDisconnect: true, networkRetry: true});
335
+ // @ts-ignore
336
+ this.webex.internal.newMetrics.submitClientEvent({
337
+ name: 'client.media.reconnecting',
338
+ options: {
339
+ meetingId: this.meeting.id,
340
+ },
341
+ });
375
342
  }
376
343
 
377
- // Reconnect has failed
378
- LoggerProxy.logger.error(
379
- 'ReconnectionManager:index#reconnect --> Reconnection failed.',
380
- reconnectError.message
381
- );
382
- LoggerProxy.logger.info(
383
- 'ReconnectionManager:index#reconnect --> Sending reconnect abort metric.'
384
- );
344
+ try {
345
+ await this.webex.meetings.startReachability();
346
+ } catch (err) {
347
+ LoggerProxy.logger.info(
348
+ 'ReconnectionManager:index#reconnect --> Reachability failed, continuing with reconnection attempt, err: ',
349
+ err
350
+ );
351
+ }
352
+
353
+ try {
354
+ await this.executeReconnection({networkDisconnect});
355
+ } catch (reconnectError) {
356
+ if (reconnectError instanceof NeedsRetryError) {
357
+ LoggerProxy.logger.info(
358
+ 'ReconnectionManager:index#reconnect --> Reconnection not successful, retrying.'
359
+ );
360
+ // Reset our reconnect status since we are looping back to the beginning
361
+ this.status = RECONNECTION.STATE.DEFAULT_STATUS;
362
+
363
+ // This is a network retry, so we should not log START metrics again
364
+ await this.reconnect({networkDisconnect: true, networkRetry: true}, completionCallback);
365
+
366
+ return;
367
+ }
368
+
369
+ // Reconnect has failed
370
+ LoggerProxy.logger.error(
371
+ 'ReconnectionManager:index#reconnect --> Reconnection failed.',
372
+ reconnectError.message
373
+ );
374
+
375
+ // send call aborted event with category as expected as we are trying to rejoin
376
+ // @ts-ignore
377
+ this.webex.internal.newMetrics.submitClientEvent({
378
+ name: 'client.call.aborted',
379
+ payload: {
380
+ errors: [
381
+ {
382
+ category: 'expected',
383
+ errorCode: 2008,
384
+ fatal: true,
385
+ name: 'media-engine',
386
+ shownToUser: false,
387
+ },
388
+ ],
389
+ },
390
+ options: {
391
+ meetingId: this.meeting.id,
392
+ },
393
+ });
394
+
395
+ if (reconnectError instanceof NeedsRejoinError && this.autoRejoinEnabled) {
396
+ await this.rejoinMeeting(reconnectError.wasSharing);
397
+
398
+ return;
399
+ }
400
+
401
+ throw reconnectError;
402
+ }
403
+
404
+ // finalize the reconnection process by calling the completionCallback
405
+ if (completionCallback) {
406
+ await completionCallback();
407
+ }
408
+
409
+ triggerEvent(EVENT_TRIGGERS.MEETING_RECONNECTION_SUCCESS);
385
410
 
386
- // send call aborted event with catogery as expected as we are trying to rejoin
387
411
  // @ts-ignore
388
412
  this.webex.internal.newMetrics.submitClientEvent({
389
- name: 'client.call.aborted',
413
+ name: 'client.media.recovered',
390
414
  payload: {
391
- errors: [
392
- {
393
- category: 'expected',
394
- errorCode: 2008,
395
- fatal: true,
396
- name: 'media-engine',
397
- shownToUser: false,
398
- },
399
- ],
415
+ recoveredBy: 'new',
400
416
  },
401
417
  options: {
402
418
  meetingId: this.meeting.id,
403
419
  },
404
420
  });
421
+ } catch (error) {
422
+ triggerEvent(EVENT_TRIGGERS.MEETING_RECONNECTION_FAILURE, {
423
+ error: new ReconnectionError('Reconnection failure event', error),
424
+ });
405
425
 
406
- if (reconnectError instanceof NeedsRejoinError && this.autoRejoinEnabled) {
407
- return this.rejoinMeeting(reconnectError.wasSharing);
408
- }
426
+ Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.MEETING_RECONNECT_FAILURE, {
427
+ correlation_id: this.meeting.correlationId,
428
+ locus_id: this.meeting.locusUrl.split('/').pop(),
429
+ reason: error.message,
430
+ stack: error.stack,
431
+ });
409
432
 
410
- throw reconnectError;
433
+ throw new ReconnectionError('Reconnection failure event', error);
434
+ } finally {
435
+ this.reset();
411
436
  }
412
437
  }
413
438
 
@@ -420,8 +445,6 @@ export default class ReconnectionManager {
420
445
  * @memberof ReconnectionManager
421
446
  */
422
447
  private async executeReconnection({networkDisconnect = false}: {networkDisconnect?: boolean}) {
423
- this.status = RECONNECTION.STATE.IN_PROGRESS;
424
-
425
448
  LoggerProxy.logger.info(
426
449
  'ReconnectionManager:index#executeReconnection --> Attempting to reconnect to meeting.'
427
450
  );
@@ -61,7 +61,7 @@ export default class RoapRequest extends StatelessWebexPlugin {
61
61
  ipVersion?: IP_VERSION;
62
62
  locusMediaRequest?: LocusMediaRequest;
63
63
  }) {
64
- const {roapMessage, locusSelfUrl, mediaId, meetingId, locusMediaRequest, ipVersion} = options;
64
+ const {roapMessage, locusSelfUrl, mediaId, locusMediaRequest, ipVersion} = options;
65
65
 
66
66
  if (!mediaId) {
67
67
  LoggerProxy.logger.info('Roap:request#sendRoap --> sending empty mediaID');
@@ -82,14 +82,6 @@ export default class RoapRequest extends StatelessWebexPlugin {
82
82
  `Roap:request#sendRoap --> ${locusSelfUrl} \n ${roapMessage.messageType} \n seq:${roapMessage.seq}`
83
83
  );
84
84
 
85
- // @ts-ignore
86
- this.webex.internal.newMetrics.submitClientEvent({
87
- name: 'client.locus.media.request',
88
- options: {
89
- meetingId,
90
- },
91
- });
92
-
93
85
  return locusMediaRequest
94
86
  .send({
95
87
  type: 'RoapMessage',
@@ -101,13 +93,6 @@ export default class RoapRequest extends StatelessWebexPlugin {
101
93
  ipVersion,
102
94
  })
103
95
  .then((res) => {
104
- // @ts-ignore
105
- this.webex.internal.newMetrics.submitClientEvent({
106
- name: 'client.locus.media.response',
107
- options: {
108
- meetingId,
109
- },
110
- });
111
96
  // always it will be the first mediaConnection Object
112
97
  const mediaConnections =
113
98
  res.body.mediaConnections &&
@@ -131,14 +116,6 @@ export default class RoapRequest extends StatelessWebexPlugin {
131
116
  };
132
117
  })
133
118
  .catch((err) => {
134
- // @ts-ignore
135
- this.webex.internal.newMetrics.submitClientEvent({
136
- name: 'client.locus.media.response',
137
- options: {
138
- meetingId,
139
- rawError: err,
140
- },
141
- });
142
119
  LoggerProxy.logger.error(`Roap:request#sendRoap --> Error:`, err);
143
120
  LoggerProxy.logger.error(
144
121
  `Roap:request#sendRoapRequest --> roapMessage that caused error:${JSON.stringify(
@@ -1004,6 +1004,8 @@ export class StatsAnalyzer extends EventsScope {
1004
1004
  this.statsResults[mediaType][sendrecvType].headerBytesSent = result.headerBytesSent;
1005
1005
  this.statsResults[mediaType][sendrecvType].retransmittedBytesSent =
1006
1006
  result.retransmittedBytesSent;
1007
+ this.statsResults[mediaType][sendrecvType].requestedBitrate = result.requestedBitrate;
1008
+ this.statsResults[mediaType][sendrecvType].requestedFrameSize = result.requestedFrameSize;
1007
1009
  }
1008
1010
  }
1009
1011
 
@@ -1116,6 +1118,8 @@ export class StatsAnalyzer extends EventsScope {
1116
1118
 
1117
1119
  this.statsResults[mediaType][sendrecvType].lastPacketReceivedTimestamp =
1118
1120
  result.lastPacketReceivedTimestamp;
1121
+ this.statsResults[mediaType][sendrecvType].requestedBitrate = result.requestedBitrate;
1122
+ this.statsResults[mediaType][sendrecvType].requestedFrameSize = result.requestedFrameSize;
1119
1123
 
1120
1124
  // From Thin
1121
1125
  this.statsResults[mediaType][sendrecvType].totalNackCount = result.nackCount;
@@ -216,6 +216,8 @@ export const getAudioSenderStreamMqa = ({
216
216
  statsResults[mediaType][sendrecvType].totalKeyFramesEncoded - lastFramesEncoded || 0;
217
217
  audioSenderStream.requestedKeyFrames =
218
218
  statsResults[mediaType][sendrecvType].totalFirCount - lastFirCount || 0;
219
+
220
+ audioSenderStream.requestedBitrate = statsResults[mediaType][sendrecvType].requestedBitrate || 0;
219
221
  };
220
222
 
221
223
  export const getVideoReceiverMqa = ({
@@ -437,4 +439,7 @@ export const getVideoSenderStreamMqa = ({
437
439
  videoSenderStream.transmittedWidth = statsResults[mediaType][sendrecvType].width || 0;
438
440
  videoSenderStream.transmittedFrameSize =
439
441
  (videoSenderStream.transmittedHeight * videoSenderStream.transmittedWidth) / 256;
442
+ videoSenderStream.requestedBitrate = statsResults[mediaType][sendrecvType].requestedBitrate || 0;
443
+ videoSenderStream.requestedFrameSize =
444
+ statsResults[mediaType][sendrecvType].requestedFrameSize || 0;
440
445
  };
@@ -269,6 +269,26 @@ describe('plugin-meetings', () => {
269
269
  assert.equal(updates.hasInterpretationChanged, false);
270
270
  });
271
271
 
272
+ it('returns hasManualCaptionChanged = true when it has changed', () => {
273
+ const newControls = {
274
+ manualCaptionControl: {enabled: false},
275
+ };
276
+
277
+ const {updates} = ControlsUtils.getControls({manualCaptionControl: {enabled: true}}, newControls);
278
+
279
+ assert.equal(updates.hasManualCaptionChanged, true);
280
+ });
281
+
282
+ it('returns hasManualCaptionChanged = false when it has not changed', () => {
283
+ const newControls = {
284
+ manualCaptionControl: {enabled: true},
285
+ };
286
+
287
+ const {updates} = ControlsUtils.getControls({manualCaptionControl: {enabled: true}}, newControls);
288
+
289
+ assert.equal(updates.hasManualCaptionChanged, false);
290
+ });
291
+
272
292
  describe('videoEnabled', () => {
273
293
  const testVideoEnabled = (oldControls, newControls, updatedProperty) => {
274
294
  const result = ControlsUtils.getControls(oldControls, newControls);
@@ -467,6 +467,27 @@ describe('plugin-meetings', () => {
467
467
  );
468
468
  });
469
469
 
470
+ it('should update the manual caption state', () => {
471
+ locusInfo.emitScoped = sinon.stub();
472
+ locusInfo.controls = {
473
+ manualCaptionControl: {enabled: false},
474
+ };
475
+
476
+ locusInfo.updateControls({manualCaptionControl: { enabled: true, }});
477
+
478
+ assert.calledWith(
479
+ locusInfo.emitScoped,
480
+ {
481
+ file: 'locus-info',
482
+ function: 'updateControls',
483
+ },
484
+ LOCUSINFO.EVENTS.CONTROLS_MEETING_MANUAL_CAPTION_UPDATED,
485
+ {
486
+ enabled: true,
487
+ }
488
+ );
489
+ });
490
+
470
491
  it('should update the meetingContainerURL from null', () => {
471
492
  locusInfo.controls = {
472
493
  meetingContainer: {meetingContainerUrl: null},