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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (233) hide show
  1. package/README.md +12 -0
  2. package/dist/breakouts/breakout.js +1 -1
  3. package/dist/breakouts/index.js +1 -1
  4. package/dist/common/errors/no-meeting-info.js +51 -0
  5. package/dist/common/errors/no-meeting-info.js.map +1 -0
  6. package/dist/common/errors/reclaim-host-role-errors.js +158 -0
  7. package/dist/common/errors/reclaim-host-role-errors.js.map +1 -0
  8. package/dist/common/errors/webex-errors.js +23 -3
  9. package/dist/common/errors/webex-errors.js.map +1 -1
  10. package/dist/common/logs/request.js +5 -1
  11. package/dist/common/logs/request.js.map +1 -1
  12. package/dist/config.js +1 -1
  13. package/dist/config.js.map +1 -1
  14. package/dist/constants.js +67 -9
  15. package/dist/constants.js.map +1 -1
  16. package/dist/index.js +11 -1
  17. package/dist/index.js.map +1 -1
  18. package/dist/interceptors/index.js +15 -0
  19. package/dist/interceptors/index.js.map +1 -0
  20. package/dist/interceptors/locusRetry.js +93 -0
  21. package/dist/interceptors/locusRetry.js.map +1 -0
  22. package/dist/interpretation/index.js +16 -2
  23. package/dist/interpretation/index.js.map +1 -1
  24. package/dist/interpretation/siLanguage.js +1 -1
  25. package/dist/locus-info/index.js +15 -10
  26. package/dist/locus-info/index.js.map +1 -1
  27. package/dist/locus-info/mediaSharesUtils.js +15 -1
  28. package/dist/locus-info/mediaSharesUtils.js.map +1 -1
  29. package/dist/locus-info/parser.js +37 -21
  30. package/dist/locus-info/parser.js.map +1 -1
  31. package/dist/media/index.js +10 -6
  32. package/dist/media/index.js.map +1 -1
  33. package/dist/media/properties.js +13 -3
  34. package/dist/media/properties.js.map +1 -1
  35. package/dist/mediaQualityMetrics/config.js +135 -330
  36. package/dist/mediaQualityMetrics/config.js.map +1 -1
  37. package/dist/meeting/in-meeting-actions.js +4 -0
  38. package/dist/meeting/in-meeting-actions.js.map +1 -1
  39. package/dist/meeting/index.js +2143 -1087
  40. package/dist/meeting/index.js.map +1 -1
  41. package/dist/meeting/muteState.js +37 -25
  42. package/dist/meeting/muteState.js.map +1 -1
  43. package/dist/meeting/request.js +33 -18
  44. package/dist/meeting/request.js.map +1 -1
  45. package/dist/meeting/util.js +71 -0
  46. package/dist/meeting/util.js.map +1 -1
  47. package/dist/meeting-info/index.js +48 -23
  48. package/dist/meeting-info/index.js.map +1 -1
  49. package/dist/meeting-info/meeting-info-v2.js +25 -4
  50. package/dist/meeting-info/meeting-info-v2.js.map +1 -1
  51. package/dist/meeting-info/utilv2.js +1 -1
  52. package/dist/meeting-info/utilv2.js.map +1 -1
  53. package/dist/meetings/collection.js +17 -0
  54. package/dist/meetings/collection.js.map +1 -1
  55. package/dist/meetings/index.js +142 -57
  56. package/dist/meetings/index.js.map +1 -1
  57. package/dist/meetings/util.js +2 -6
  58. package/dist/meetings/util.js.map +1 -1
  59. package/dist/member/index.js +9 -0
  60. package/dist/member/index.js.map +1 -1
  61. package/dist/member/util.js +11 -0
  62. package/dist/member/util.js.map +1 -1
  63. package/dist/members/index.js +17 -1
  64. package/dist/members/index.js.map +1 -1
  65. package/dist/members/types.js.map +1 -1
  66. package/dist/members/util.js +15 -4
  67. package/dist/members/util.js.map +1 -1
  68. package/dist/metrics/constants.js +13 -1
  69. package/dist/metrics/constants.js.map +1 -1
  70. package/dist/multistream/mediaRequestManager.js +1 -1
  71. package/dist/multistream/mediaRequestManager.js.map +1 -1
  72. package/dist/multistream/remoteMediaGroup.js +16 -2
  73. package/dist/multistream/remoteMediaGroup.js.map +1 -1
  74. package/dist/multistream/remoteMediaManager.js +177 -65
  75. package/dist/multistream/remoteMediaManager.js.map +1 -1
  76. package/dist/multistream/sendSlotManager.js +22 -0
  77. package/dist/multistream/sendSlotManager.js.map +1 -1
  78. package/dist/reachability/clusterReachability.js +356 -0
  79. package/dist/reachability/clusterReachability.js.map +1 -0
  80. package/dist/reachability/index.js +262 -432
  81. package/dist/reachability/index.js.map +1 -1
  82. package/dist/reachability/request.js +1 -1
  83. package/dist/reachability/request.js.map +1 -1
  84. package/dist/reachability/util.js +29 -0
  85. package/dist/reachability/util.js.map +1 -0
  86. package/dist/reconnection-manager/index.js +113 -96
  87. package/dist/reconnection-manager/index.js.map +1 -1
  88. package/dist/roap/index.js +57 -25
  89. package/dist/roap/index.js.map +1 -1
  90. package/dist/roap/request.js +5 -13
  91. package/dist/roap/request.js.map +1 -1
  92. package/dist/roap/turnDiscovery.js +173 -81
  93. package/dist/roap/turnDiscovery.js.map +1 -1
  94. package/dist/rtcMetrics/index.js +68 -6
  95. package/dist/rtcMetrics/index.js.map +1 -1
  96. package/dist/statsAnalyzer/index.js +338 -289
  97. package/dist/statsAnalyzer/index.js.map +1 -1
  98. package/dist/statsAnalyzer/mqaUtil.js +296 -156
  99. package/dist/statsAnalyzer/mqaUtil.js.map +1 -1
  100. package/dist/types/common/errors/no-meeting-info.d.ts +14 -0
  101. package/dist/types/common/errors/reclaim-host-role-errors.d.ts +60 -0
  102. package/dist/types/common/errors/webex-errors.d.ts +13 -1
  103. package/dist/types/common/logs/request.d.ts +2 -0
  104. package/dist/types/config.d.ts +1 -1
  105. package/dist/types/constants.d.ts +65 -13
  106. package/dist/types/index.d.ts +1 -1
  107. package/dist/types/interceptors/index.d.ts +2 -0
  108. package/dist/types/interceptors/locusRetry.d.ts +27 -0
  109. package/dist/types/locus-info/index.d.ts +1 -1
  110. package/dist/types/locus-info/parser.d.ts +3 -2
  111. package/dist/types/mediaQualityMetrics/config.d.ts +99 -223
  112. package/dist/types/meeting/in-meeting-actions.d.ts +4 -0
  113. package/dist/types/meeting/index.d.ts +272 -35
  114. package/dist/types/meeting/muteState.d.ts +2 -8
  115. package/dist/types/meeting/request.d.ts +2 -0
  116. package/dist/types/meeting/util.d.ts +16 -0
  117. package/dist/types/meeting-info/index.d.ts +7 -0
  118. package/dist/types/meeting-info/meeting-info-v2.d.ts +1 -0
  119. package/dist/types/meetings/collection.d.ts +9 -0
  120. package/dist/types/meetings/index.d.ts +42 -14
  121. package/dist/types/member/index.d.ts +1 -0
  122. package/dist/types/members/types.d.ts +1 -0
  123. package/dist/types/members/util.d.ts +5 -0
  124. package/dist/types/metrics/constants.d.ts +12 -0
  125. package/dist/types/multistream/mediaRequestManager.d.ts +2 -0
  126. package/dist/types/multistream/remoteMediaGroup.d.ts +2 -0
  127. package/dist/types/multistream/remoteMediaManager.d.ts +16 -0
  128. package/dist/types/multistream/sendSlotManager.d.ts +9 -0
  129. package/dist/types/reachability/clusterReachability.d.ts +109 -0
  130. package/dist/types/reachability/index.d.ts +59 -106
  131. package/dist/types/reachability/util.d.ts +8 -0
  132. package/dist/types/reconnection-manager/index.d.ts +10 -0
  133. package/dist/types/roap/index.d.ts +2 -1
  134. package/dist/types/roap/turnDiscovery.d.ts +21 -4
  135. package/dist/types/rtcMetrics/index.d.ts +15 -1
  136. package/dist/types/statsAnalyzer/index.d.ts +28 -11
  137. package/dist/types/statsAnalyzer/mqaUtil.d.ts +28 -4
  138. package/dist/types/webinar/collection.d.ts +16 -0
  139. package/dist/types/webinar/index.d.ts +5 -0
  140. package/dist/webinar/collection.js +44 -0
  141. package/dist/webinar/collection.js.map +1 -0
  142. package/dist/webinar/index.js +69 -0
  143. package/dist/webinar/index.js.map +1 -0
  144. package/package.json +3 -2
  145. package/src/common/errors/no-meeting-info.ts +24 -0
  146. package/src/common/errors/reclaim-host-role-errors.ts +134 -0
  147. package/src/common/errors/webex-errors.ts +19 -2
  148. package/src/common/logs/request.ts +5 -1
  149. package/src/config.ts +1 -1
  150. package/src/constants.ts +70 -6
  151. package/src/index.ts +5 -0
  152. package/src/interceptors/index.ts +3 -0
  153. package/src/interceptors/locusRetry.ts +67 -0
  154. package/src/interpretation/index.ts +18 -1
  155. package/src/locus-info/index.ts +19 -14
  156. package/src/locus-info/mediaSharesUtils.ts +16 -0
  157. package/src/locus-info/parser.ts +40 -21
  158. package/src/media/index.ts +8 -6
  159. package/src/media/properties.ts +17 -2
  160. package/src/mediaQualityMetrics/config.ts +103 -238
  161. package/src/meeting/in-meeting-actions.ts +8 -0
  162. package/src/meeting/index.ts +1471 -533
  163. package/src/meeting/muteState.ts +34 -20
  164. package/src/meeting/request.ts +18 -0
  165. package/src/meeting/util.ts +97 -0
  166. package/src/meeting-info/index.ts +47 -20
  167. package/src/meeting-info/meeting-info-v2.ts +27 -5
  168. package/src/meeting-info/utilv2.ts +1 -1
  169. package/src/meetings/collection.ts +13 -0
  170. package/src/meetings/index.ts +112 -31
  171. package/src/meetings/util.ts +2 -8
  172. package/src/member/index.ts +9 -0
  173. package/src/member/util.ts +14 -0
  174. package/src/members/index.ts +29 -2
  175. package/src/members/types.ts +1 -0
  176. package/src/members/util.ts +15 -1
  177. package/src/metrics/constants.ts +12 -0
  178. package/src/multistream/mediaRequestManager.ts +4 -1
  179. package/src/multistream/remoteMediaGroup.ts +19 -0
  180. package/src/multistream/remoteMediaManager.ts +101 -15
  181. package/src/multistream/sendSlotManager.ts +29 -0
  182. package/src/reachability/clusterReachability.ts +320 -0
  183. package/src/reachability/index.ts +221 -382
  184. package/src/reachability/request.ts +1 -1
  185. package/src/reachability/util.ts +24 -0
  186. package/src/reconnection-manager/index.ts +87 -83
  187. package/src/roap/index.ts +60 -24
  188. package/src/roap/request.ts +3 -16
  189. package/src/roap/turnDiscovery.ts +112 -39
  190. package/src/rtcMetrics/index.ts +71 -5
  191. package/src/statsAnalyzer/index.ts +430 -427
  192. package/src/statsAnalyzer/mqaUtil.ts +317 -168
  193. package/src/webinar/collection.ts +31 -0
  194. package/src/webinar/index.ts +62 -0
  195. package/test/integration/spec/journey.js +22 -22
  196. package/test/unit/spec/interceptors/locusRetry.ts +131 -0
  197. package/test/unit/spec/interpretation/index.ts +36 -3
  198. package/test/unit/spec/locus-info/index.js +87 -11
  199. package/test/unit/spec/locus-info/lib/SeqCmp.json +16 -0
  200. package/test/unit/spec/locus-info/mediaSharesUtils.ts +10 -0
  201. package/test/unit/spec/locus-info/parser.js +54 -13
  202. package/test/unit/spec/media/index.ts +20 -4
  203. package/test/unit/spec/media/properties.ts +2 -2
  204. package/test/unit/spec/meeting/in-meeting-actions.ts +4 -0
  205. package/test/unit/spec/meeting/index.js +4178 -1289
  206. package/test/unit/spec/meeting/muteState.js +219 -67
  207. package/test/unit/spec/meeting/request.js +63 -12
  208. package/test/unit/spec/meeting/utils.js +93 -0
  209. package/test/unit/spec/meeting-info/index.js +180 -61
  210. package/test/unit/spec/meeting-info/meetinginfov2.js +196 -53
  211. package/test/unit/spec/meetings/collection.js +12 -0
  212. package/test/unit/spec/meetings/index.js +617 -204
  213. package/test/unit/spec/meetings/utils.js +35 -12
  214. package/test/unit/spec/member/index.js +8 -7
  215. package/test/unit/spec/member/util.js +32 -0
  216. package/test/unit/spec/members/index.js +130 -17
  217. package/test/unit/spec/members/utils.js +26 -0
  218. package/test/unit/spec/multistream/mediaRequestManager.ts +20 -2
  219. package/test/unit/spec/multistream/remoteMediaGroup.ts +80 -1
  220. package/test/unit/spec/multistream/remoteMediaManager.ts +200 -1
  221. package/test/unit/spec/multistream/sendSlotManager.ts +50 -18
  222. package/test/unit/spec/reachability/clusterReachability.ts +279 -0
  223. package/test/unit/spec/reachability/index.ts +505 -135
  224. package/test/unit/spec/reachability/util.ts +40 -0
  225. package/test/unit/spec/reconnection-manager/index.js +74 -17
  226. package/test/unit/spec/roap/index.ts +181 -61
  227. package/test/unit/spec/roap/request.ts +27 -3
  228. package/test/unit/spec/roap/turnDiscovery.ts +362 -101
  229. package/test/unit/spec/rtcMetrics/index.ts +57 -3
  230. package/test/unit/spec/stats-analyzer/index.js +1225 -12
  231. package/test/unit/spec/webinar/collection.ts +13 -0
  232. package/test/unit/spec/webinar/index.ts +60 -0
  233. package/test/utils/webex-test-users.js +12 -4
package/src/constants.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  // @ts-ignore
2
2
  import {hydraTypes} from '@webex/common';
3
3
 
4
+ type Enum<T extends Record<string, unknown>> = T[keyof T];
5
+
4
6
  // *********** LOWERCASE / CAMELCASE STRINGS ************
5
7
 
6
8
  export const AUDIO = 'audio';
@@ -190,7 +192,8 @@ export const ICE_FAIL_TIMEOUT = 3000;
190
192
 
191
193
  export const RETRY_TIMEOUT = 3000;
192
194
 
193
- export const PC_BAIL_TIMEOUT = 15000;
195
+ export const ICE_AND_DTLS_CONNECTION_TIMEOUT = 10000;
196
+ export const ROAP_OFFER_ANSWER_EXCHANGE_TIMEOUT = 35000;
194
197
 
195
198
  // ******************** REGEX **********************
196
199
  // Please alphabetize
@@ -236,6 +239,13 @@ export const CALENDAR_EVENTS = {
236
239
  DELETE: 'event:calendar.meeting.delete',
237
240
  };
238
241
 
242
+ export const ASSIGN_ROLES_ERROR_CODES = {
243
+ ReclaimHostNotSupportedErrorCode: 2400127,
244
+ ReclaimHostNotAllowedErrorCode: 2403135,
245
+ ReclaimHostEmptyWrongKeyErrorCode: 2403136,
246
+ ReclaimHostIsHostAlreadyErrorCode: 2409150,
247
+ };
248
+
239
249
  export const DEFAULT_GET_STATS_FILTER = {
240
250
  types: [
241
251
  'track',
@@ -331,6 +341,7 @@ export const EVENT_TRIGGERS = {
331
341
  MEETING_UNLOCKED: 'meeting:unlocked',
332
342
  MEETING_LOCKED: 'meeting:locked',
333
343
  MEETING_INFO_AVAILABLE: 'meeting:meetingInfoAvailable',
344
+ MEETING_INFO_UPDATED: 'meeting:meetingInfoUpdated',
334
345
  MEETING_LOG_UPLOAD_SUCCESS: 'meeting:logUpload:success',
335
346
  MEETING_LOG_UPLOAD_FAILURE: 'meeting:logUpload:failure',
336
347
  MEETING_ACTIONS_UPDATE: 'meeting:actionsUpdate',
@@ -348,6 +359,7 @@ export const EVENT_TRIGGERS = {
348
359
  REMOTE_VIDEO_SOURCE_COUNT_CHANGED: 'media:remoteVideoSourceCountChanged',
349
360
  REMOTE_AUDIO_SOURCE_COUNT_CHANGED: 'media:remoteAudioSourceCountChanged',
350
361
  REMOTE_MEDIA_AUDIO_CREATED: 'media:remoteAudio:created',
362
+ REMOTE_MEDIA_INTERPRETATION_AUDIO_CREATED: 'media:remoteInterpretationAudio:created',
351
363
  REMOTE_MEDIA_SCREEN_SHARE_AUDIO_CREATED: 'media:remoteScreenShareAudio:created',
352
364
  REMOTE_MEDIA_VIDEO_LAYOUT_CHANGED: 'media:remoteVideo:layoutChanged',
353
365
  // Controls
@@ -389,6 +401,7 @@ export const MEETING_REMOVED_REASON = {
389
401
  NO_MEETINGS_TO_SYNC: 'NO_MEETINGS_TO_SYNC', // After the syncMeeting no meeting exists
390
402
  MEETING_CONNECTION_FAILED: 'MEETING_CONNECTION_FAILED', // meeting failed to connect due to ice failures or firewall issue
391
403
  LOCUS_DTO_SYNC_FAILED: 'LOCUS_DTO_SYNC_FAILED', // failed to get any Locus DTO for that meeting
404
+ MISSING_MEETING_INFO: 'MISSING_MEETING_INFO', // meeting info failed to be fetched
392
405
  };
393
406
 
394
407
  // One one one calls ends for the following reasons
@@ -485,6 +498,35 @@ export const ERROR_DICTIONARY = {
485
498
  MESSAGE: 'Edit lock token mismatch',
486
499
  CODE: 9,
487
500
  },
501
+ NO_MEETING_INFO: {
502
+ NAME: 'NoMeetingInfo',
503
+ MESSAGE: 'No meeting info found for the meeting',
504
+ CODE: 10,
505
+ },
506
+ RECLAIM_HOST_ROLE_NOT_SUPPORTED: {
507
+ NAME: 'ReclaimHostRoleNotSupported',
508
+ MESSAGE:
509
+ 'Non converged meetings, PSTN or SIP users in converged meetings are not supported currently.',
510
+ CODE: 11,
511
+ },
512
+ RECLAIM_HOST_ROLE_NOT_ALLOWED: {
513
+ NAME: 'ReclaimHostRoleNotAllowed',
514
+ MESSAGE:
515
+ 'Reclaim Host Role Not Allowed For Other Participants. Participants cannot claim host role in PMR meeting, space instant meeting or escalated instant meeting. However, the original host still can reclaim host role when it manually makes another participant to be the host.',
516
+ CODE: 12,
517
+ },
518
+ RECLAIM_HOST_ROLE_EMPTY_OR_WRONG_KEY: {
519
+ NAME: 'ReclaimHostRoleEmptyOrWrongKey',
520
+ MESSAGE:
521
+ 'Host Key Not Specified Or Matched. The original host can reclaim the host role without entering the host key. However, any other person who claims the host role must enter the host key to get it.',
522
+ CODE: 13,
523
+ },
524
+ RECLAIM_HOST_ROLE_IS_ALREADY_HOST: {
525
+ NAME: 'ReclaimHostRoleIsAlreadyHost',
526
+ MESSAGE:
527
+ 'Participant Having Host Role Already. Participant who sends request to reclaim host role has already a host role.',
528
+ CODE: 14,
529
+ },
488
530
  };
489
531
 
490
532
  export const FLOOR_ACTION = {
@@ -540,6 +582,8 @@ export const LOCUS = {
540
582
  INACTIVE: 'INACTIVE',
541
583
  ENDED: 'ENDED',
542
584
  INITIALIZING: 'INITIALIZING',
585
+ ACTIVE: 'ACTIVE',
586
+ TERMINATING: 'TERMINATING',
543
587
  },
544
588
  SEQUENCE: {
545
589
  UN_DEF: 'undef',
@@ -623,7 +667,6 @@ export const LOCUSINFO = {
623
667
  CONTROLS_MEETING_CONTAINER_UPDATED: 'CONTROLS_MEETING_CONTAINER_UPDATED',
624
668
  CONTROLS_MEETING_INTERPRETATION_UPDATED: 'CONTROLS_MEETING_INTERPRETATION_UPDATED',
625
669
  CONTROLS_ENTRY_EXIT_TONE_UPDATED: 'CONTROLS_ENTRY_EXIT_TONE_UPDATED',
626
- CONTROLS_JOIN_BREAKOUT_FROM_MAIN: 'CONTROLS_JOIN_BREAKOUT_FROM_MAIN',
627
670
  CONTROLS_MUTE_ON_ENTRY_CHANGED: 'CONTROLS_MUTE_ON_ENTRY_CHANGED',
628
671
  CONTROLS_SHARE_CONTROL_CHANGED: 'CONTROLS_SHARE_CONTROL_CHANGED',
629
672
  CONTROLS_DISALLOW_UNMUTE_CHANGED: 'CONTROLS_DISALLOW_UNMUTE_CHANGED',
@@ -996,7 +1039,9 @@ export const RECONNECTION = {
996
1039
  DEFAULT_TRY_COUNT: 0,
997
1040
  DEFAULT_STATUS: '',
998
1041
  },
999
- };
1042
+ } as const;
1043
+
1044
+ export type RECONNECTION_STATE = Enum<typeof RECONNECTION.STATE>;
1000
1045
 
1001
1046
  export const RESOURCE = {
1002
1047
  CLUSTERS: 'clusters',
@@ -1032,7 +1077,9 @@ export const NETWORK_STATUS = {
1032
1077
  DISCONNECTED: 'DISCONNECTED',
1033
1078
  RECONNECTING: 'RECONNECTING',
1034
1079
  CONNECTED: 'CONNECTED',
1035
- };
1080
+ } as const;
1081
+
1082
+ export type NETWORK_STATUS = Enum<typeof NETWORK_STATUS>;
1036
1083
 
1037
1084
  export const NETWORK_TYPE = {
1038
1085
  VPN: 'vpn',
@@ -1191,7 +1238,7 @@ export const AVAILABLE_RESOLUTIONS = {
1191
1238
  * mqa Interval for sending stats metrics
1192
1239
  */
1193
1240
 
1194
- export const MQA_INTEVAL = 60000; // mqa analyzer interval its fixed to 60000
1241
+ export const MQA_INTERVAL = 60000; // mqa analyzer interval its fixed to 60000
1195
1242
 
1196
1243
  export const MEDIA_DEVICES = {
1197
1244
  MICROPHONE: 'microphone',
@@ -1248,4 +1295,21 @@ export const IP_VERSION = {
1248
1295
  ipv4_and_ipv6: 1,
1249
1296
  } as const;
1250
1297
 
1251
- export type IP_VERSION = (typeof IP_VERSION)[keyof typeof IP_VERSION];
1298
+ export const LOCAL_SHARE_ERRORS = {
1299
+ DEVICE_NOT_JOINED: 'Floor requested but device not yet joined',
1300
+ UNDEFINED: 'undefined PUT',
1301
+ NO_MEDIA_FOR_DEVICE: 'No media session found for device',
1302
+ NO_CONFLUENCE_ID: 'Failed to request floor: 404 (null) could not find confluence id',
1303
+ CONTENT_SHARING_DISABLED: 'Content share policies are disabled',
1304
+ LOCUS_PARTICIPANT_DNE: 'does not exist in Locus',
1305
+ CONTENT_REQUEST_WHILE_PENDING_WHITEBOARD:
1306
+ 'Content share request is not allowed while whiteboard floor request is pending',
1307
+ };
1308
+ export type IP_VERSION = Enum<typeof IP_VERSION>;
1309
+
1310
+ // constant for if the permissionToken is about to expire in the next 30 seconds, refresh it
1311
+ export const MEETING_PERMISSION_TOKEN_REFRESH_THRESHOLD_IN_SEC = 30;
1312
+ export const MEETING_PERMISSION_TOKEN_REFRESH_REASON = 'ttl-join';
1313
+
1314
+ // constant for named media group type
1315
+ export const NAMED_MEDIA_GROUP_TYPE_AUDIO = 1;
package/src/index.ts CHANGED
@@ -3,9 +3,13 @@ import {registerPlugin} from '@webex/webex-core';
3
3
 
4
4
  import Meetings from './meetings';
5
5
  import config from './config';
6
+ import {LocusRetryStatusInterceptor} from './interceptors';
6
7
 
7
8
  registerPlugin('meetings', Meetings, {
8
9
  config,
10
+ interceptors: {
11
+ LocusRetryStatusInterceptor: LocusRetryStatusInterceptor.create,
12
+ },
9
13
  });
10
14
 
11
15
  export {
@@ -15,6 +19,7 @@ export {
15
19
  LocalSystemAudioStream,
16
20
  LocalStreamEventNames,
17
21
  StreamEventNames,
22
+ RemoteStreamEventNames,
18
23
  type ServerMuteReason,
19
24
  LocalMicrophoneStreamEventNames,
20
25
  LocalCameraStreamEventNames,
@@ -0,0 +1,3 @@
1
+ import LocusRetryStatusInterceptor from './locusRetry';
2
+
3
+ export {LocusRetryStatusInterceptor};
@@ -0,0 +1,67 @@
1
+ /*!
2
+ * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
3
+ */
4
+
5
+ import {Interceptor} from '@webex/http-core';
6
+
7
+ const rateLimitExpiryTime = new WeakMap();
8
+ /**
9
+ * @class
10
+ */
11
+ export default class LocusRetryStatusInterceptor extends Interceptor {
12
+ /**
13
+ * @returns {LocusRetryStatusInterceptor}
14
+ */
15
+ static create() {
16
+ // @ts-ignore
17
+ return new LocusRetryStatusInterceptor({webex: this});
18
+ }
19
+
20
+ /**
21
+ * Handle response errors
22
+ * @param {Object} options
23
+ * @param {WebexHttpError} reason
24
+ * @returns {Promise<WebexHttpError>}
25
+ */
26
+ onResponseError(options, reason) {
27
+ if ((reason.statusCode === 503 || reason.statusCode === 429) && options.uri.includes('locus')) {
28
+ const hasRetriedLocusRequest = rateLimitExpiryTime.get(this);
29
+ const retryAfterTime = options.headers['retry-after'] || 2000;
30
+
31
+ if (hasRetriedLocusRequest) {
32
+ rateLimitExpiryTime.set(this, false);
33
+
34
+ return Promise.reject(options);
35
+ }
36
+ rateLimitExpiryTime.set(this, true);
37
+
38
+ return this.handleRetryRequestLocusServiceError(options, retryAfterTime);
39
+ }
40
+
41
+ return Promise.reject(reason);
42
+ }
43
+
44
+ /**
45
+ * Handle retries for locus service unavailable errors
46
+ * @param {Object} options associated with the request
47
+ * @param {number} retryAfterTime retry after time in milliseconds
48
+ * @returns {Promise}
49
+ */
50
+ handleRetryRequestLocusServiceError(options, retryAfterTime) {
51
+ return new Promise((resolve, reject) => {
52
+ const timeout = setTimeout(() => {
53
+ clearTimeout(timeout);
54
+
55
+ // @ts-ignore
56
+ this.webex
57
+ .request({
58
+ method: options.method,
59
+ uri: options.uri,
60
+ body: options.body,
61
+ })
62
+ .then(resolve)
63
+ .catch(reject);
64
+ }, retryAfterTime);
65
+ });
66
+ }
67
+ }
@@ -121,14 +121,31 @@ const SimultaneousInterpretation = WebexPlugin.extend({
121
121
  * Update self's interpretation information (self is interpreter)
122
122
  * @param {Object} interpretation
123
123
  * @param {String} selfParticipantId
124
- * @returns {void}
124
+ * @returns {bool} is target language changed
125
125
  */
126
126
  updateSelfInterpretation({interpretation, selfParticipantId}) {
127
+ this.set('selfIsInterpreter', true);
128
+ const preTargetLanguage = this.targetLanguage;
127
129
  const {originalLanguage, sourceLanguage, order, isActive, targetLanguage, receiveLanguage} =
128
130
  interpretation || {};
129
131
  this.set({originalLanguage, sourceLanguage, order, isActive, targetLanguage, receiveLanguage});
130
132
  this.set('selfParticipantId', selfParticipantId);
133
+
134
+ return !!(targetLanguage && preTargetLanguage !== targetLanguage);
131
135
  },
136
+
137
+ /**
138
+ * Get the language code of the interpreter target language
139
+ * @returns {number}
140
+ */
141
+ getTargetLanguageCode() {
142
+ if (this.selfIsInterpreter) {
143
+ return this.siLanguages.get(this.targetLanguage)?.languageCode;
144
+ }
145
+
146
+ return 0;
147
+ },
148
+
132
149
  /**
133
150
  * query interpretation languages
134
151
  * @returns {Promise}
@@ -169,7 +169,7 @@ export default class LocusInfo extends EventsScope {
169
169
  * @returns {undefined}
170
170
  */
171
171
  applyLocusDeltaData(action: string, locus: any, meeting: any) {
172
- const {DESYNC, USE_CURRENT, USE_INCOMING, WAIT} = LocusDeltaParser.loci;
172
+ const {DESYNC, USE_CURRENT, USE_INCOMING, WAIT, LOCUS_URL_CHANGED} = LocusDeltaParser.loci;
173
173
 
174
174
  switch (action) {
175
175
  case USE_INCOMING:
@@ -180,6 +180,7 @@ export default class LocusInfo extends EventsScope {
180
180
  // do nothing
181
181
  break;
182
182
  case DESYNC:
183
+ case LOCUS_URL_CHANGED:
183
184
  this.doLocusSync(meeting);
184
185
  break;
185
186
  default:
@@ -1168,7 +1169,10 @@ export default class LocusInfo extends EventsScope {
1168
1169
  file: 'locus-info',
1169
1170
  function: 'updateMeetingInfo',
1170
1171
  },
1171
- LOCUSINFO.EVENTS.MEETING_INFO_UPDATED
1172
+ LOCUSINFO.EVENTS.MEETING_INFO_UPDATED,
1173
+ {
1174
+ isInitializing: !self, // if self is undefined, then the update is caused by locus init
1175
+ }
1172
1176
  );
1173
1177
  }
1174
1178
  this.roles = roles;
@@ -1603,7 +1607,7 @@ export default class LocusInfo extends EventsScope {
1603
1607
 
1604
1608
  /**
1605
1609
  * if return from breakout to main session, need to use cached main session DTO since locus won't send the full locus (participants)
1606
- * if join breakout from main session, need to query main locus url (if response with 403 means no privilege, need to clear the cache)
1610
+ * if join breakout from main session, main session is not active for the attendee and remove main session locus cache
1607
1611
  * @param {Object} newLocus
1608
1612
  * @returns {Object}
1609
1613
  * @memberof LocusInfo
@@ -1613,17 +1617,18 @@ export default class LocusInfo extends EventsScope {
1613
1617
  if (switchStatus.isReturnToMain && this.mainSessionLocusCache) {
1614
1618
  return cloneDeep(this.mainSessionLocusCache);
1615
1619
  }
1616
- if (switchStatus.isJoinToBreakout) {
1617
- this.emitScoped(
1618
- {
1619
- file: 'locus-info',
1620
- function: 'updateControls',
1621
- },
1622
- LOCUSINFO.EVENTS.CONTROLS_JOIN_BREAKOUT_FROM_MAIN,
1623
- {
1624
- mainLocusUrl: this.url,
1625
- }
1626
- );
1620
+ const isMainSessionDTO =
1621
+ this.mainSessionLocusCache && ControlsUtils.isMainSessionDTO(this.mainSessionLocusCache);
1622
+
1623
+ if (isMainSessionDTO) {
1624
+ const isActive =
1625
+ [LOCUS.STATE.ACTIVE, LOCUS.STATE.INITIALIZING, LOCUS.STATE.TERMINATING].includes(
1626
+ this.fullState?.state
1627
+ ) && !this.mainSessionLocusCache?.self?.removed;
1628
+
1629
+ if (!isActive) {
1630
+ this.clearMainSessionLocusCache();
1631
+ }
1627
1632
  }
1628
1633
 
1629
1634
  return newLocus;
@@ -16,6 +16,7 @@ MediaSharesUtils.parse = (mediaShares: object) => {
16
16
  annotation: MediaSharesUtils.getContentAnnotation(mediaShares),
17
17
  url: MediaSharesUtils.getContentUrl(mediaShares),
18
18
  shareInstanceId: MediaSharesUtils.getShareInstanceId(mediaShares),
19
+ deviceUrlSharing: MediaSharesUtils.getContentBeneficiaryDeviceUrl(mediaShares),
19
20
  },
20
21
  whiteboard: {
21
22
  beneficiaryId: MediaSharesUtils.getWhiteboardBeneficiaryId(mediaShares),
@@ -188,6 +189,21 @@ MediaSharesUtils.getShareInstanceId = (mediaShares: object) => {
188
189
  return extractContent.floor.shareInstanceId;
189
190
  };
190
191
 
192
+ /**
193
+ * get deviceUrl that is requesting the floor for media shares (content)
194
+ * @param {Object} mediaShares
195
+ * @returns {Object}
196
+ */
197
+ MediaSharesUtils.getContentBeneficiaryDeviceUrl = (mediaShares: object) => {
198
+ const contentFloor = MediaSharesUtils.extractContentFloor(mediaShares);
199
+
200
+ if (!contentFloor || !contentFloor.beneficiary || !contentFloor.beneficiary.deviceUrl) {
201
+ return null;
202
+ }
203
+
204
+ return contentFloor.beneficiary.deviceUrl;
205
+ };
206
+
191
207
  /**
192
208
  * get who is sharing from media shares (whiteboard)
193
209
  * @param {Object} mediaShares
@@ -11,6 +11,7 @@ const OOO_DELTA_WAIT_TIME = 10000; // [ms] minimum wait time before we do a sync
11
11
  const OOO_DELTA_WAIT_TIME_RANDOM_DELAY = 5000; // [ms] max random delay added to OOO_DELTA_WAIT_TIME
12
12
 
13
13
  type LocusDeltaDto = {
14
+ url: string;
14
15
  baseSequence: {
15
16
  rangeStart: number;
16
17
  rangeEnd: number;
@@ -47,11 +48,12 @@ export default class Parser {
47
48
  USE_CURRENT: 'USE_CURRENT',
48
49
  WAIT: 'WAIT',
49
50
  ERROR: 'ERROR',
51
+ LOCUS_URL_CHANGED: 'LOCUS_URL_CHANGED',
50
52
  };
51
53
 
52
54
  queue: SortedQueue<LocusDeltaDto>;
53
55
  workingCopy: any;
54
- syncTimer: null | number | NodeJS.Timeout;
56
+ syncTimer?: ReturnType<typeof setTimeout>;
55
57
 
56
58
  /**
57
59
  * @constructs Parser
@@ -83,7 +85,7 @@ export default class Parser {
83
85
  this.status = 'IDLE';
84
86
  this.onDeltaAction = null;
85
87
  this.workingCopy = null;
86
- this.syncTimer = null;
88
+ this.syncTimer = undefined;
87
89
  }
88
90
 
89
91
  /**
@@ -267,7 +269,7 @@ export default class Parser {
267
269
  * @returns {string} loci comparison state
268
270
  */
269
271
  private static compareDelta(current, incoming) {
270
- const {LT, GT, EQ, DESYNC, USE_INCOMING, WAIT} = Parser.loci;
272
+ const {LT, GT, EQ, DESYNC, USE_INCOMING, WAIT, LOCUS_URL_CHANGED} = Parser.loci;
271
273
 
272
274
  const {extractComparisonState: extract} = Parser;
273
275
  const {packComparisonResult: pack} = Parser;
@@ -279,6 +281,13 @@ export default class Parser {
279
281
  return pack(Parser.compareToAction(comparison), result);
280
282
  }
281
283
 
284
+ if (incoming.url !== current.url) {
285
+ // when moving to/from a breakout session, the locus URL will change and also
286
+ // the baseSequence, making incoming and current incomparable, so use a
287
+ // unique comparison state
288
+ return pack(LOCUS_URL_CHANGED, result);
289
+ }
290
+
282
291
  comparison = Parser.compareSequence(current.sequence, incoming.baseSequence);
283
292
 
284
293
  switch (extract(comparison)) {
@@ -664,11 +673,11 @@ export default class Parser {
664
673
  * @returns {undefined}
665
674
  */
666
675
  private startSyncTimer() {
667
- if (this.syncTimer === null) {
676
+ if (this.syncTimer === undefined) {
668
677
  const timeout = OOO_DELTA_WAIT_TIME + Math.random() * OOO_DELTA_WAIT_TIME_RANDOM_DELAY;
669
678
 
670
679
  this.syncTimer = setTimeout(() => {
671
- this.syncTimer = null;
680
+ this.syncTimer = undefined;
672
681
  this.triggerSync('timer expired, blocked on out-of-order delta');
673
682
  }, timeout);
674
683
  }
@@ -680,9 +689,9 @@ export default class Parser {
680
689
  * @returns {undefined}
681
690
  */
682
691
  private stopSyncTimer() {
683
- if (this.syncTimer !== null) {
692
+ if (this.syncTimer !== undefined) {
684
693
  clearTimeout(this.syncTimer);
685
- this.syncTimer = null;
694
+ this.syncTimer = undefined;
686
695
  }
687
696
  }
688
697
 
@@ -693,7 +702,7 @@ export default class Parser {
693
702
  * @returns {undefined}
694
703
  */
695
704
  processDeltaEvent() {
696
- const {DESYNC, USE_INCOMING, WAIT} = Parser.loci;
705
+ const {DESYNC, USE_INCOMING, WAIT, LOCUS_URL_CHANGED} = Parser.loci;
697
706
  const {extractComparisonState: extract} = Parser;
698
707
  const newLoci = this.queue.dequeue();
699
708
 
@@ -712,19 +721,29 @@ export default class Parser {
712
721
 
713
722
  let needToWait = false;
714
723
 
715
- if (lociComparison === DESYNC) {
716
- // wait for desync response
717
- this.pause();
718
- } else if (lociComparison === USE_INCOMING) {
719
- // update working copy for future comparisons.
720
- // Note: The working copy of parser gets updated in .onFullLocus()
721
- // and here when USE_INCOMING locus.
722
- this.workingCopy = newLoci;
723
- } else if (lociComparison === WAIT) {
724
- // we've taken newLoci from the front of the queue, so put it back there as we have to wait
725
- // for the one that should be in front of it, before we can process it
726
- this.queue.enqueue(newLoci);
727
- needToWait = true;
724
+ switch (lociComparison) {
725
+ case DESYNC:
726
+ // wait for desync response
727
+ this.pause();
728
+ break;
729
+
730
+ case USE_INCOMING:
731
+ case LOCUS_URL_CHANGED:
732
+ // update working copy for future comparisons.
733
+ // Note: The working copy of parser gets updated in .onFullLocus()
734
+ // and here when USE_INCOMING or LOCUS_URL_CHANGED locus.
735
+ this.workingCopy = newLoci;
736
+ break;
737
+
738
+ case WAIT:
739
+ // we've taken newLoci from the front of the queue, so put it back there as we have to wait
740
+ // for the one that should be in front of it, before we can process it
741
+ this.queue.enqueue(newLoci);
742
+ needToWait = true;
743
+ break;
744
+
745
+ default:
746
+ break;
728
747
  }
729
748
 
730
749
  if (needToWait) {
@@ -182,8 +182,10 @@ Media.createMediaConnection = (
182
182
  return new MultistreamRoapMediaConnection(
183
183
  config,
184
184
  meetingId,
185
+ /* the rtc metrics objects callbacks */
185
186
  (data) => rtcMetrics.addMetrics(data),
186
- () => rtcMetrics.closeMetrics()
187
+ () => rtcMetrics.closeMetrics(),
188
+ () => rtcMetrics.sendMetricsInQueue()
187
189
  );
188
190
  }
189
191
 
@@ -215,10 +217,10 @@ Media.createMediaConnection = (
215
217
  {
216
218
  // TODO: RoapMediaConnection is not ready to use stream classes yet, so we pass the raw MediaStreamTrack for now SPARK-460530
217
219
  localTracks: {
218
- audio: audioStream?.outputTrack,
219
- video: videoStream?.outputTrack,
220
- screenShareVideo: shareVideoStream?.outputTrack,
221
- screenShareAudio: shareAudioStream?.outputTrack, // TODO: add type for screenShareAudio in internal-media-core SPARK-446923
220
+ audio: audioStream?.outputStream?.getTracks()[0],
221
+ video: videoStream?.outputStream?.getTracks()[0],
222
+ screenShareVideo: shareVideoStream?.outputStream?.getTracks()[0],
223
+ screenShareAudio: shareAudioStream?.outputStream?.getTracks()[0], // TODO: add type for screenShareAudio in internal-media-core SPARK-446923
222
224
  } as unknown,
223
225
  direction: {
224
226
  audio: Media.getDirection(true, mediaDirection.receiveAudio, mediaDirection.sendAudio),
@@ -397,7 +399,7 @@ Media.stopStream = (stream: LocalStream) => {
397
399
  stream.stop();
398
400
  } catch (e) {
399
401
  LoggerProxy.logger.error(
400
- `Media:index#stopStream --> Unable to stop the stream with ready state of the output track => ${stream.outputTrack.readyState} & input track => ${stream.inputTrack.readyState}, error: ${e}`
402
+ `Media:index#stopStream --> Unable to stop the stream with ready state => ${stream.readyState}, error: ${e}`
401
403
  );
402
404
  }
403
405
  });
@@ -8,7 +8,7 @@ import {
8
8
  RemoteStream,
9
9
  } from '@webex/media-helpers';
10
10
 
11
- import {MEETINGS, PC_BAIL_TIMEOUT, QUALITY_LEVELS} from '../constants';
11
+ import {MEETINGS, ICE_AND_DTLS_CONNECTION_TIMEOUT, QUALITY_LEVELS} from '../constants';
12
12
  import LoggerProxy from '../common/logs/logger-proxy';
13
13
 
14
14
  export type MediaDirection = {
@@ -200,7 +200,7 @@ export default class MediaProperties {
200
200
  timer = setTimeout(() => {
201
201
  this.webrtcMediaConnection.off(Event.CONNECTION_STATE_CHANGED, connectionStateListener);
202
202
  reject();
203
- }, PC_BAIL_TIMEOUT);
203
+ }, ICE_AND_DTLS_CONNECTION_TIMEOUT);
204
204
 
205
205
  this.webrtcMediaConnection.on(Event.CONNECTION_STATE_CHANGED, connectionStateListener);
206
206
  });
@@ -259,10 +259,25 @@ export default class MediaProperties {
259
259
 
260
260
  return true;
261
261
  }
262
+ LoggerProxy.logger.warn(
263
+ `Media:properties#getCurrentConnectionType --> missing localCandidate.protocol, candidateType=${localCandidate.candidateType}`
264
+ );
262
265
 
263
266
  return false;
264
267
  });
265
268
 
269
+ if (foundConnectionType === 'unknown') {
270
+ const candidatePairStates = allStatsReports
271
+ .filter((report) => report.type === 'candidate-pair')
272
+ .map((report) => report.state);
273
+
274
+ LoggerProxy.logger.warn(
275
+ `Media:properties#getCurrentConnectionType --> all candidate pair states: ${JSON.stringify(
276
+ candidatePairStates
277
+ )}`
278
+ );
279
+ }
280
+
266
281
  return foundConnectionType;
267
282
  }
268
283
  }