@webex/plugin-meetings 3.0.0-beta.20 → 3.0.0-beta.201

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 (424) hide show
  1. package/README.md +45 -7
  2. package/dist/annotation/annotation.types.js +7 -0
  3. package/dist/annotation/annotation.types.js.map +1 -0
  4. package/dist/annotation/constants.js +49 -0
  5. package/dist/annotation/constants.js.map +1 -0
  6. package/dist/annotation/index.js +342 -0
  7. package/dist/annotation/index.js.map +1 -0
  8. package/dist/breakouts/breakout.js +114 -14
  9. package/dist/breakouts/breakout.js.map +1 -1
  10. package/dist/breakouts/edit-lock-error.js +52 -0
  11. package/dist/breakouts/edit-lock-error.js.map +1 -0
  12. package/dist/breakouts/events.js +45 -0
  13. package/dist/breakouts/events.js.map +1 -0
  14. package/dist/breakouts/index.js +841 -19
  15. package/dist/breakouts/index.js.map +1 -1
  16. package/dist/breakouts/request.js +78 -0
  17. package/dist/breakouts/request.js.map +1 -0
  18. package/dist/breakouts/utils.js +67 -0
  19. package/dist/breakouts/utils.js.map +1 -0
  20. package/dist/common/errors/webex-errors.js +3 -2
  21. package/dist/common/errors/webex-errors.js.map +1 -1
  22. package/dist/common/logs/logger-proxy.js +1 -1
  23. package/dist/common/logs/logger-proxy.js.map +1 -1
  24. package/dist/common/queue.js +24 -9
  25. package/dist/common/queue.js.map +1 -1
  26. package/dist/config.js +3 -8
  27. package/dist/config.js.map +1 -1
  28. package/dist/constants.js +172 -30
  29. package/dist/constants.js.map +1 -1
  30. package/dist/controls-options-manager/constants.js +14 -0
  31. package/dist/controls-options-manager/constants.js.map +1 -0
  32. package/dist/controls-options-manager/enums.js +27 -0
  33. package/dist/controls-options-manager/enums.js.map +1 -0
  34. package/dist/controls-options-manager/index.js +297 -0
  35. package/dist/controls-options-manager/index.js.map +1 -0
  36. package/dist/controls-options-manager/types.js +7 -0
  37. package/dist/controls-options-manager/types.js.map +1 -0
  38. package/dist/controls-options-manager/util.js +319 -0
  39. package/dist/controls-options-manager/util.js.map +1 -0
  40. package/dist/index.js +107 -0
  41. package/dist/index.js.map +1 -1
  42. package/dist/interpretation/collection.js +23 -0
  43. package/dist/interpretation/collection.js.map +1 -0
  44. package/dist/interpretation/index.js +366 -0
  45. package/dist/interpretation/index.js.map +1 -0
  46. package/dist/interpretation/siLanguage.js +25 -0
  47. package/dist/interpretation/siLanguage.js.map +1 -0
  48. package/dist/locus-info/controlsUtils.js +91 -2
  49. package/dist/locus-info/controlsUtils.js.map +1 -1
  50. package/dist/locus-info/index.js +355 -57
  51. package/dist/locus-info/index.js.map +1 -1
  52. package/dist/locus-info/mediaSharesUtils.js +43 -1
  53. package/dist/locus-info/mediaSharesUtils.js.map +1 -1
  54. package/dist/locus-info/parser.js +219 -63
  55. package/dist/locus-info/parser.js.map +1 -1
  56. package/dist/locus-info/selfUtils.js +89 -14
  57. package/dist/locus-info/selfUtils.js.map +1 -1
  58. package/dist/media/index.js +48 -135
  59. package/dist/media/index.js.map +1 -1
  60. package/dist/media/properties.js +29 -90
  61. package/dist/media/properties.js.map +1 -1
  62. package/dist/mediaQualityMetrics/config.js +505 -493
  63. package/dist/mediaQualityMetrics/config.js.map +1 -1
  64. package/dist/meeting/in-meeting-actions.js +80 -2
  65. package/dist/meeting/in-meeting-actions.js.map +1 -1
  66. package/dist/meeting/index.js +2692 -2544
  67. package/dist/meeting/index.js.map +1 -1
  68. package/dist/meeting/locusMediaRequest.js +291 -0
  69. package/dist/meeting/locusMediaRequest.js.map +1 -0
  70. package/dist/meeting/muteState.js +229 -124
  71. package/dist/meeting/muteState.js.map +1 -1
  72. package/dist/meeting/request.js +196 -190
  73. package/dist/meeting/request.js.map +1 -1
  74. package/dist/meeting/util.js +529 -414
  75. package/dist/meeting/util.js.map +1 -1
  76. package/dist/meeting-info/index.js +48 -7
  77. package/dist/meeting-info/index.js.map +1 -1
  78. package/dist/meeting-info/meeting-info-v2.js +171 -51
  79. package/dist/meeting-info/meeting-info-v2.js.map +1 -1
  80. package/dist/meeting-info/utilv2.js +20 -5
  81. package/dist/meeting-info/utilv2.js.map +1 -1
  82. package/dist/meetings/collection.js +22 -0
  83. package/dist/meetings/collection.js.map +1 -1
  84. package/dist/meetings/index.js +357 -66
  85. package/dist/meetings/index.js.map +1 -1
  86. package/dist/meetings/meetings.types.js +7 -0
  87. package/dist/meetings/meetings.types.js.map +1 -0
  88. package/dist/meetings/request.js +2 -0
  89. package/dist/meetings/request.js.map +1 -1
  90. package/dist/meetings/util.js +88 -1
  91. package/dist/meetings/util.js.map +1 -1
  92. package/dist/member/index.js +49 -0
  93. package/dist/member/index.js.map +1 -1
  94. package/dist/member/types.js +25 -0
  95. package/dist/member/types.js.map +1 -0
  96. package/dist/member/util.js +121 -25
  97. package/dist/member/util.js.map +1 -1
  98. package/dist/members/collection.js +10 -0
  99. package/dist/members/collection.js.map +1 -1
  100. package/dist/members/index.js +86 -5
  101. package/dist/members/index.js.map +1 -1
  102. package/dist/members/request.js +106 -38
  103. package/dist/members/request.js.map +1 -1
  104. package/dist/members/types.js +15 -0
  105. package/dist/members/types.js.map +1 -0
  106. package/dist/members/util.js +316 -233
  107. package/dist/members/util.js.map +1 -1
  108. package/dist/metrics/constants.js +3 -5
  109. package/dist/metrics/constants.js.map +1 -1
  110. package/dist/metrics/index.js +1 -468
  111. package/dist/metrics/index.js.map +1 -1
  112. package/dist/multistream/mediaRequestManager.js +238 -49
  113. package/dist/multistream/mediaRequestManager.js.map +1 -1
  114. package/dist/multistream/receiveSlot.js +49 -16
  115. package/dist/multistream/receiveSlot.js.map +1 -1
  116. package/dist/multistream/receiveSlotManager.js +52 -34
  117. package/dist/multistream/receiveSlotManager.js.map +1 -1
  118. package/dist/multistream/remoteMedia.js +44 -18
  119. package/dist/multistream/remoteMedia.js.map +1 -1
  120. package/dist/multistream/remoteMediaGroup.js +60 -3
  121. package/dist/multistream/remoteMediaGroup.js.map +1 -1
  122. package/dist/multistream/remoteMediaManager.js +173 -59
  123. package/dist/multistream/remoteMediaManager.js.map +1 -1
  124. package/dist/networkQualityMonitor/index.js +4 -2
  125. package/dist/networkQualityMonitor/index.js.map +1 -1
  126. package/dist/reachability/index.js +72 -27
  127. package/dist/reachability/index.js.map +1 -1
  128. package/dist/reachability/request.js +12 -5
  129. package/dist/reachability/request.js.map +1 -1
  130. package/dist/reactions/reactions.js +2 -2
  131. package/dist/reactions/reactions.js.map +1 -1
  132. package/dist/reactions/reactions.type.js +18 -18
  133. package/dist/reactions/reactions.type.js.map +1 -1
  134. package/dist/reconnection-manager/index.js +196 -155
  135. package/dist/reconnection-manager/index.js.map +1 -1
  136. package/dist/recording-controller/index.js +21 -1
  137. package/dist/recording-controller/index.js.map +1 -1
  138. package/dist/recording-controller/util.js +9 -8
  139. package/dist/recording-controller/util.js.map +1 -1
  140. package/dist/roap/index.js +21 -29
  141. package/dist/roap/index.js.map +1 -1
  142. package/dist/roap/request.js +110 -89
  143. package/dist/roap/request.js.map +1 -1
  144. package/dist/roap/turnDiscovery.js +93 -36
  145. package/dist/roap/turnDiscovery.js.map +1 -1
  146. package/dist/rtcMetrics/constants.js +12 -0
  147. package/dist/rtcMetrics/constants.js.map +1 -0
  148. package/dist/rtcMetrics/index.js +115 -0
  149. package/dist/rtcMetrics/index.js.map +1 -0
  150. package/dist/statsAnalyzer/global.js +1 -93
  151. package/dist/statsAnalyzer/global.js.map +1 -1
  152. package/dist/statsAnalyzer/index.js +326 -311
  153. package/dist/statsAnalyzer/index.js.map +1 -1
  154. package/dist/statsAnalyzer/mqaUtil.js +90 -53
  155. package/dist/statsAnalyzer/mqaUtil.js.map +1 -1
  156. package/dist/types/annotation/annotation.types.d.ts +42 -0
  157. package/dist/types/annotation/constants.d.ts +31 -0
  158. package/dist/types/annotation/index.d.ts +117 -0
  159. package/dist/types/breakouts/breakout.d.ts +8 -0
  160. package/dist/types/breakouts/collection.d.ts +5 -0
  161. package/dist/types/breakouts/edit-lock-error.d.ts +15 -0
  162. package/dist/types/breakouts/events.d.ts +8 -0
  163. package/dist/types/breakouts/index.d.ts +5 -0
  164. package/dist/types/breakouts/request.d.ts +22 -0
  165. package/dist/types/breakouts/utils.d.ts +15 -0
  166. package/dist/types/common/browser-detection.d.ts +9 -0
  167. package/dist/types/common/collection.d.ts +48 -0
  168. package/dist/types/common/config.d.ts +2 -0
  169. package/dist/types/common/errors/captcha-error.d.ts +15 -0
  170. package/dist/types/common/errors/intent-to-join.d.ts +16 -0
  171. package/dist/types/common/errors/join-meeting.d.ts +17 -0
  172. package/dist/types/common/errors/media.d.ts +15 -0
  173. package/dist/types/common/errors/parameter.d.ts +15 -0
  174. package/dist/types/common/errors/password-error.d.ts +15 -0
  175. package/dist/types/common/errors/permission.d.ts +14 -0
  176. package/dist/types/common/errors/reconnection-in-progress.d.ts +9 -0
  177. package/dist/types/common/errors/reconnection.d.ts +15 -0
  178. package/dist/types/common/errors/stats.d.ts +15 -0
  179. package/dist/types/common/errors/webex-errors.d.ts +69 -0
  180. package/dist/types/common/errors/webex-meetings-error.d.ts +20 -0
  181. package/dist/types/common/events/events-scope.d.ts +17 -0
  182. package/dist/types/common/events/events.d.ts +12 -0
  183. package/dist/types/common/events/trigger-proxy.d.ts +2 -0
  184. package/dist/types/common/events/util.d.ts +2 -0
  185. package/dist/types/common/logs/logger-config.d.ts +2 -0
  186. package/dist/types/common/logs/logger-proxy.d.ts +2 -0
  187. package/dist/types/common/logs/request.d.ts +34 -0
  188. package/dist/types/common/queue.d.ts +34 -0
  189. package/dist/types/config.d.ts +72 -0
  190. package/dist/types/constants.d.ts +1016 -0
  191. package/dist/types/controls-options-manager/constants.d.ts +4 -0
  192. package/dist/types/controls-options-manager/enums.d.ts +15 -0
  193. package/dist/types/controls-options-manager/index.d.ts +136 -0
  194. package/dist/types/controls-options-manager/types.d.ts +43 -0
  195. package/dist/types/controls-options-manager/util.d.ts +1 -0
  196. package/dist/types/index.d.ts +7 -0
  197. package/dist/types/interpretation/collection.d.ts +5 -0
  198. package/dist/types/interpretation/index.d.ts +5 -0
  199. package/dist/types/interpretation/siLanguage.d.ts +5 -0
  200. package/dist/types/locus-info/controlsUtils.d.ts +2 -0
  201. package/dist/types/locus-info/embeddedAppsUtils.d.ts +2 -0
  202. package/dist/types/locus-info/fullState.d.ts +2 -0
  203. package/dist/types/locus-info/hostUtils.d.ts +2 -0
  204. package/dist/types/locus-info/index.d.ts +322 -0
  205. package/dist/types/locus-info/infoUtils.d.ts +2 -0
  206. package/dist/types/locus-info/mediaSharesUtils.d.ts +2 -0
  207. package/dist/types/locus-info/parser.d.ts +271 -0
  208. package/dist/types/locus-info/selfUtils.d.ts +2 -0
  209. package/dist/types/media/index.d.ts +34 -0
  210. package/dist/types/media/properties.d.ts +93 -0
  211. package/dist/types/media/util.d.ts +2 -0
  212. package/dist/types/mediaQualityMetrics/config.d.ts +365 -0
  213. package/dist/types/meeting/in-meeting-actions.d.ts +153 -0
  214. package/dist/types/meeting/index.d.ts +1471 -0
  215. package/dist/types/meeting/locusMediaRequest.d.ts +70 -0
  216. package/dist/types/meeting/muteState.d.ts +184 -0
  217. package/dist/types/meeting/request.d.ts +257 -0
  218. package/dist/types/meeting/request.type.d.ts +11 -0
  219. package/dist/types/meeting/state.d.ts +9 -0
  220. package/dist/types/meeting/util.d.ts +78 -0
  221. package/dist/types/meeting-info/collection.d.ts +20 -0
  222. package/dist/types/meeting-info/index.d.ts +62 -0
  223. package/dist/types/meeting-info/meeting-info-v2.d.ts +122 -0
  224. package/dist/types/meeting-info/request.d.ts +22 -0
  225. package/dist/types/meeting-info/util.d.ts +2 -0
  226. package/dist/types/meeting-info/utilv2.d.ts +2 -0
  227. package/dist/types/meetings/collection.d.ts +31 -0
  228. package/dist/types/meetings/index.d.ts +367 -0
  229. package/dist/types/meetings/meetings.types.d.ts +4 -0
  230. package/dist/types/meetings/request.d.ts +27 -0
  231. package/dist/types/meetings/util.d.ts +18 -0
  232. package/dist/types/member/index.d.ts +159 -0
  233. package/dist/types/member/types.d.ts +32 -0
  234. package/dist/types/member/util.d.ts +2 -0
  235. package/dist/types/members/collection.d.ts +29 -0
  236. package/dist/types/members/index.d.ts +353 -0
  237. package/dist/types/members/request.d.ts +114 -0
  238. package/dist/types/members/types.d.ts +24 -0
  239. package/dist/types/members/util.d.ts +210 -0
  240. package/dist/types/metrics/constants.d.ts +55 -0
  241. package/dist/types/metrics/index.d.ts +45 -0
  242. package/dist/types/multistream/mediaRequestManager.d.ts +118 -0
  243. package/dist/types/multistream/receiveSlot.d.ts +68 -0
  244. package/dist/types/multistream/receiveSlotManager.d.ts +56 -0
  245. package/dist/types/multistream/remoteMedia.d.ts +72 -0
  246. package/dist/types/multistream/remoteMediaGroup.d.ts +47 -0
  247. package/dist/types/multistream/remoteMediaManager.d.ts +277 -0
  248. package/dist/types/networkQualityMonitor/index.d.ts +70 -0
  249. package/dist/types/personal-meeting-room/index.d.ts +47 -0
  250. package/dist/types/personal-meeting-room/request.d.ts +14 -0
  251. package/dist/types/personal-meeting-room/util.d.ts +2 -0
  252. package/dist/types/reachability/index.d.ts +152 -0
  253. package/dist/types/reachability/request.d.ts +37 -0
  254. package/dist/types/reactions/constants.d.ts +3 -0
  255. package/dist/types/reactions/reactions.d.ts +4 -0
  256. package/dist/types/reactions/reactions.type.d.ts +52 -0
  257. package/dist/types/reconnection-manager/index.d.ts +126 -0
  258. package/dist/types/recording-controller/enums.d.ts +7 -0
  259. package/dist/types/recording-controller/index.d.ts +208 -0
  260. package/dist/types/recording-controller/util.d.ts +14 -0
  261. package/dist/types/roap/index.d.ts +77 -0
  262. package/dist/types/roap/request.d.ts +36 -0
  263. package/dist/types/roap/turnDiscovery.d.ts +91 -0
  264. package/dist/types/rtcMetrics/constants.d.ts +4 -0
  265. package/dist/types/rtcMetrics/index.d.ts +46 -0
  266. package/dist/types/statsAnalyzer/global.d.ts +36 -0
  267. package/dist/types/statsAnalyzer/index.d.ts +200 -0
  268. package/dist/types/statsAnalyzer/mqaUtil.d.ts +24 -0
  269. package/dist/types/transcription/index.d.ts +64 -0
  270. package/package.json +25 -22
  271. package/src/annotation/annotation.types.ts +50 -0
  272. package/src/annotation/constants.ts +36 -0
  273. package/src/annotation/index.ts +328 -0
  274. package/src/breakouts/README.md +44 -14
  275. package/src/breakouts/breakout.ts +87 -9
  276. package/src/breakouts/edit-lock-error.ts +25 -0
  277. package/src/breakouts/events.ts +56 -0
  278. package/src/breakouts/index.ts +710 -10
  279. package/src/breakouts/request.ts +55 -0
  280. package/src/breakouts/utils.ts +57 -0
  281. package/src/common/errors/webex-errors.ts +6 -2
  282. package/src/common/logs/logger-proxy.ts +1 -1
  283. package/src/common/queue.ts +22 -8
  284. package/src/config.ts +2 -7
  285. package/src/constants.ts +157 -21
  286. package/src/controls-options-manager/constants.ts +5 -0
  287. package/src/controls-options-manager/enums.ts +18 -0
  288. package/src/controls-options-manager/index.ts +278 -0
  289. package/src/controls-options-manager/types.ts +59 -0
  290. package/src/controls-options-manager/util.ts +300 -0
  291. package/src/index.ts +39 -0
  292. package/src/interpretation/README.md +60 -0
  293. package/src/interpretation/collection.ts +19 -0
  294. package/src/interpretation/index.ts +332 -0
  295. package/src/interpretation/siLanguage.ts +18 -0
  296. package/src/locus-info/controlsUtils.ts +108 -0
  297. package/src/locus-info/index.ts +375 -52
  298. package/src/locus-info/mediaSharesUtils.ts +48 -0
  299. package/src/locus-info/parser.ts +224 -39
  300. package/src/locus-info/selfUtils.ts +81 -5
  301. package/src/media/index.ts +87 -140
  302. package/src/media/properties.ts +49 -90
  303. package/src/mediaQualityMetrics/config.ts +379 -377
  304. package/src/meeting/in-meeting-actions.ts +159 -3
  305. package/src/meeting/index.ts +1980 -2030
  306. package/src/meeting/locusMediaRequest.ts +309 -0
  307. package/src/meeting/muteState.ts +228 -132
  308. package/src/meeting/request.ts +102 -112
  309. package/src/meeting/util.ts +509 -397
  310. package/src/meeting-info/index.ts +54 -8
  311. package/src/meeting-info/meeting-info-v2.ts +148 -14
  312. package/src/meeting-info/utilv2.ts +13 -3
  313. package/src/meetings/collection.ts +20 -0
  314. package/src/meetings/index.ts +392 -84
  315. package/src/meetings/meetings.types.ts +12 -0
  316. package/src/meetings/request.ts +2 -0
  317. package/src/meetings/util.ts +103 -4
  318. package/src/member/index.ts +49 -0
  319. package/src/member/types.ts +38 -0
  320. package/src/member/util.ts +127 -25
  321. package/src/members/collection.ts +8 -0
  322. package/src/members/index.ts +107 -6
  323. package/src/members/request.ts +97 -17
  324. package/src/members/types.ts +28 -0
  325. package/src/members/util.ts +319 -240
  326. package/src/metrics/constants.ts +2 -4
  327. package/src/metrics/index.ts +1 -490
  328. package/src/multistream/mediaRequestManager.ts +289 -79
  329. package/src/multistream/receiveSlot.ts +55 -18
  330. package/src/multistream/receiveSlotManager.ts +46 -24
  331. package/src/multistream/remoteMedia.ts +27 -2
  332. package/src/multistream/remoteMediaGroup.ts +59 -0
  333. package/src/multistream/remoteMediaManager.ts +113 -32
  334. package/src/networkQualityMonitor/index.ts +6 -6
  335. package/src/reachability/index.ts +62 -15
  336. package/src/reachability/request.ts +10 -5
  337. package/src/reactions/reactions.ts +4 -4
  338. package/src/reactions/reactions.type.ts +3 -3
  339. package/src/reconnection-manager/index.ts +68 -43
  340. package/src/recording-controller/index.ts +20 -2
  341. package/src/recording-controller/util.ts +26 -9
  342. package/src/roap/index.ts +21 -30
  343. package/src/roap/request.ts +101 -95
  344. package/src/roap/turnDiscovery.ts +47 -25
  345. package/src/rtcMetrics/constants.ts +3 -0
  346. package/src/rtcMetrics/index.ts +96 -0
  347. package/src/statsAnalyzer/global.ts +1 -94
  348. package/src/statsAnalyzer/index.ts +376 -386
  349. package/src/statsAnalyzer/mqaUtil.ts +100 -99
  350. package/test/integration/spec/converged-space-meetings.js +233 -0
  351. package/test/integration/spec/journey.js +336 -259
  352. package/test/integration/spec/space-meeting.js +77 -4
  353. package/test/unit/spec/annotation/index.ts +418 -0
  354. package/test/unit/spec/breakouts/breakout.ts +142 -24
  355. package/test/unit/spec/breakouts/edit-lock-error.ts +30 -0
  356. package/test/unit/spec/breakouts/events.ts +89 -0
  357. package/test/unit/spec/breakouts/index.ts +1545 -48
  358. package/test/unit/spec/breakouts/request.ts +104 -0
  359. package/test/unit/spec/breakouts/utils.js +72 -0
  360. package/test/unit/spec/common/queue.js +31 -2
  361. package/test/unit/spec/controls-options-manager/index.js +287 -0
  362. package/test/unit/spec/controls-options-manager/util.js +582 -0
  363. package/test/unit/spec/fixture/locus.js +1 -0
  364. package/test/unit/spec/interpretation/collection.ts +15 -0
  365. package/test/unit/spec/interpretation/index.ts +589 -0
  366. package/test/unit/spec/interpretation/siLanguage.ts +28 -0
  367. package/test/unit/spec/locus-info/controlsUtils.js +316 -43
  368. package/test/unit/spec/locus-info/index.js +1094 -38
  369. package/test/unit/spec/locus-info/mediaSharesUtils.ts +22 -0
  370. package/test/unit/spec/locus-info/parser.js +62 -22
  371. package/test/unit/spec/locus-info/selfConstant.js +27 -4
  372. package/test/unit/spec/locus-info/selfUtils.js +208 -17
  373. package/test/unit/spec/media/index.ts +138 -28
  374. package/test/unit/spec/meeting/in-meeting-actions.ts +79 -3
  375. package/test/unit/spec/meeting/index.js +3092 -1571
  376. package/test/unit/spec/meeting/locusMediaRequest.ts +436 -0
  377. package/test/unit/spec/meeting/muteState.js +370 -208
  378. package/test/unit/spec/meeting/request.js +338 -43
  379. package/test/unit/spec/meeting/utils.js +449 -53
  380. package/test/unit/spec/meeting-info/index.js +181 -0
  381. package/test/unit/spec/meeting-info/meetinginfov2.js +383 -5
  382. package/test/unit/spec/meeting-info/utilv2.js +21 -0
  383. package/test/unit/spec/meetings/collection.js +14 -0
  384. package/test/unit/spec/meetings/index.js +866 -124
  385. package/test/unit/spec/meetings/utils.js +206 -2
  386. package/test/unit/spec/member/index.js +58 -4
  387. package/test/unit/spec/member/util.js +479 -35
  388. package/test/unit/spec/members/index.js +319 -1
  389. package/test/unit/spec/members/request.js +206 -27
  390. package/test/unit/spec/members/utils.js +184 -0
  391. package/test/unit/spec/metrics/index.js +1 -50
  392. package/test/unit/spec/multistream/mediaRequestManager.ts +803 -162
  393. package/test/unit/spec/multistream/receiveSlot.ts +72 -13
  394. package/test/unit/spec/multistream/receiveSlotManager.ts +58 -28
  395. package/test/unit/spec/multistream/remoteMedia.ts +30 -0
  396. package/test/unit/spec/multistream/remoteMediaGroup.ts +266 -0
  397. package/test/unit/spec/multistream/remoteMediaManager.ts +318 -0
  398. package/test/unit/spec/networkQualityMonitor/index.js +4 -4
  399. package/test/unit/spec/reachability/index.ts +125 -8
  400. package/test/unit/spec/reachability/request.js +66 -0
  401. package/test/unit/spec/reconnection-manager/index.js +59 -6
  402. package/test/unit/spec/recording-controller/index.js +294 -218
  403. package/test/unit/spec/recording-controller/util.js +223 -96
  404. package/test/unit/spec/roap/index.ts +26 -51
  405. package/test/unit/spec/roap/request.ts +196 -85
  406. package/test/unit/spec/roap/turnDiscovery.ts +30 -7
  407. package/test/unit/spec/rtcMetrics/index.ts +60 -0
  408. package/test/unit/spec/stats-analyzer/index.js +92 -41
  409. package/test/utils/constants.js +9 -0
  410. package/test/utils/integrationTestUtils.js +46 -0
  411. package/test/utils/testUtils.js +0 -45
  412. package/test/utils/webex-config.js +4 -0
  413. package/test/utils/webex-test-users.js +6 -3
  414. package/dist/meeting/effectsState.js +0 -262
  415. package/dist/meeting/effectsState.js.map +0 -1
  416. package/dist/metrics/config.js +0 -299
  417. package/dist/metrics/config.js.map +0 -1
  418. package/dist/multistream/multistreamMedia.js +0 -110
  419. package/dist/multistream/multistreamMedia.js.map +0 -1
  420. package/src/index.js +0 -15
  421. package/src/meeting/effectsState.ts +0 -211
  422. package/src/metrics/config.ts +0 -495
  423. package/src/multistream/multistreamMedia.ts +0 -97
  424. package/test/unit/spec/meeting/effectsState.js +0 -285
@@ -1,9 +1,6 @@
1
- import {isEmpty} from 'lodash';
2
-
1
+ import {LocalCameraTrack, LocalMicrophoneTrack} from '@webex/media-helpers';
2
+ import {cloneDeep} from 'lodash';
3
3
  import {MeetingNotActiveError, UserNotJoinedError} from '../common/errors/webex-errors';
4
- import Metrics from '../metrics';
5
- import {eventType, trigger} from '../metrics/config';
6
- import Media from '../media';
7
4
  import LoggerProxy from '../common/logs/logger-proxy';
8
5
  import {
9
6
  INTENT_TO_JOIN,
@@ -13,6 +10,8 @@ import {
13
10
  PASSWORD_STATUS,
14
11
  DISPLAY_HINTS,
15
12
  FULL_STATE,
13
+ SELF_POLICY,
14
+ EVENT_TRIGGERS,
16
15
  } from '../constants';
17
16
  import IntentToJoinError from '../common/errors/intent-to-join';
18
17
  import JoinMeetingError from '../common/errors/join-meeting';
@@ -20,484 +19,597 @@ import ParameterError from '../common/errors/parameter';
20
19
  import PermissionError from '../common/errors/permission';
21
20
  import PasswordError from '../common/errors/password-error';
22
21
  import CaptchaError from '../common/errors/captcha-error';
22
+ import Trigger from '../common/events/trigger-proxy';
23
+
24
+ const MeetingUtil = {
25
+ parseLocusJoin: (response) => {
26
+ const parsed: any = {};
27
+
28
+ // First todo: add check for existance
29
+ parsed.locus = response.body.locus;
30
+ parsed.mediaConnections = response.body.mediaConnections;
31
+ parsed.locusUrl = parsed.locus.url;
32
+ parsed.locusId = parsed.locus.url.split('/').pop();
33
+ parsed.selfId = parsed.locus.self.id;
34
+
35
+ // we need mediaId before making roap calls
36
+ parsed.mediaConnections.forEach((mediaConnection) => {
37
+ if (mediaConnection.mediaId) {
38
+ parsed.mediaId = mediaConnection.mediaId;
39
+ }
40
+ });
23
41
 
24
- const MeetingUtil: any = {};
25
-
26
- MeetingUtil.parseLocusJoin = (response) => {
27
- const parsed: any = {};
42
+ return parsed;
43
+ },
28
44
 
29
- // First todo: add check for existance
30
- parsed.locus = response.body.locus;
31
- parsed.mediaConnections = response.body.mediaConnections;
32
- parsed.locusUrl = parsed.locus.url;
33
- parsed.locusId = parsed.locus.url.split('/').pop();
34
- parsed.selfId = parsed.locus.self.id;
45
+ remoteUpdateAudioVideo: (meeting, audioMuted?: boolean, videoMuted?: boolean) => {
46
+ const webex = meeting.getWebexObject();
47
+ if (!meeting) {
48
+ return Promise.reject(new ParameterError('You need a meeting object.'));
49
+ }
35
50
 
36
- // we need mediaId before making roap calls
37
- parsed.mediaConnections.forEach((mediaConnection) => {
38
- if (mediaConnection.mediaId) {
39
- parsed.mediaId = mediaConnection.mediaId;
51
+ if (!meeting.locusMediaRequest) {
52
+ return Promise.reject(
53
+ new ParameterError(
54
+ 'You need a meeting with a media connection, call Meeting.addMedia() first.'
55
+ )
56
+ );
40
57
  }
41
- });
42
58
 
43
- return parsed;
44
- };
59
+ // @ts-ignore
60
+ webex.internal.newMetrics.submitClientEvent({
61
+ name: 'client.locus.media.request',
62
+ options: {meetingId: meeting.id},
63
+ });
45
64
 
46
- MeetingUtil.remoteUpdateAudioVideo = (audioMuted, videoMuted, meeting) => {
47
- if (!meeting) {
48
- return Promise.reject(new ParameterError('You need a meeting object.'));
49
- }
50
- const localMedias = Media.generateLocalMedias(meeting.mediaId, audioMuted, videoMuted);
65
+ return meeting.locusMediaRequest
66
+ .send({
67
+ type: 'LocalMute',
68
+ selfUrl: meeting.selfUrl,
69
+ mediaId: meeting.mediaId,
70
+ sequence: meeting.locusInfo.sequence,
71
+ muteOptions: {
72
+ audioMuted,
73
+ videoMuted,
74
+ },
75
+ })
76
+ .then((response) => {
77
+ // @ts-ignore
78
+ webex.internal.newMetrics.submitClientEvent({
79
+ name: 'client.locus.media.response',
80
+ options: {meetingId: meeting.id},
81
+ });
51
82
 
52
- if (isEmpty(localMedias)) {
53
- return Promise.reject(
54
- new ParameterError('You need a media id on the meeting to change remote audio.')
55
- );
56
- }
83
+ return response?.body?.locus;
84
+ });
85
+ },
86
+
87
+ hasOwner: (info) => info && info.owner,
88
+
89
+ isOwnerSelf: (owner, selfId) => owner === selfId,
90
+
91
+ isPinOrGuest: (err) => err?.body?.errorCode && INTENT_TO_JOIN.includes(err.body.errorCode),
92
+
93
+ joinMeeting: (meeting, options) => {
94
+ if (!meeting) {
95
+ return Promise.reject(new ParameterError('You need a meeting object.'));
96
+ }
97
+ const webex = meeting.getWebexObject();
98
+
99
+ // @ts-ignore
100
+ webex.internal.newMetrics.submitClientEvent({
101
+ name: 'client.locus.join.request',
102
+ options: {meetingId: meeting.id},
103
+ });
104
+
105
+ // eslint-disable-next-line no-warning-comments
106
+ // TODO: check if the meeting is in JOINING state
107
+ // if Joining state termintate the request as user might click multiple times
108
+ return meeting.meetingRequest
109
+ .joinMeeting({
110
+ inviteeAddress: meeting.meetingJoinUrl || meeting.sipUri,
111
+ meetingNumber: meeting.meetingNumber,
112
+ deviceUrl: meeting.deviceUrl,
113
+ locusUrl: meeting.locusUrl,
114
+ correlationId: meeting.correlationId,
115
+ roapMessage: options.roapMessage,
116
+ permissionToken: meeting.permissionToken,
117
+ resourceId: options.resourceId || null,
118
+ moderator: options.moderator,
119
+ pin: options.pin,
120
+ moveToResource: options.moveToResource,
121
+ preferTranscoding: !meeting.isMultistream,
122
+ asResourceOccupant: options.asResourceOccupant,
123
+ breakoutsSupported: options.breakoutsSupported,
124
+ locale: options.locale,
125
+ deviceCapabilities: options.deviceCapabilities,
126
+ liveAnnotationSupported: options.liveAnnotationSupported,
127
+ })
128
+ .then((res) => {
129
+ // @ts-ignore
130
+ webex.internal.newMetrics.submitClientEvent({
131
+ name: 'client.locus.join.response',
132
+ payload: {
133
+ trigger: 'loci-update',
134
+ identifiers: {
135
+ trackingId: res.headers.trackingid,
136
+ },
137
+ },
138
+ options: {
139
+ meetingId: meeting.id,
140
+ mediaConnections: res.body.mediaConnections,
141
+ },
142
+ });
57
143
 
58
- Metrics.postEvent({event: eventType.MEDIA_REQUEST, meeting});
144
+ return MeetingUtil.parseLocusJoin(res);
145
+ });
146
+ },
147
+
148
+ cleanUp: (meeting) => {
149
+ meeting.breakouts.cleanUp();
150
+ meeting.simultaneousInterpretation.cleanUp();
151
+
152
+ // make sure we send last metrics before we close the peerconnection
153
+ const stopStatsAnalyzer = meeting.statsAnalyzer
154
+ ? meeting.statsAnalyzer.stopAnalyzer()
155
+ : Promise.resolve();
156
+
157
+ return stopStatsAnalyzer
158
+ .then(() => meeting.closeRemoteTracks())
159
+ .then(() => meeting.closePeerConnections())
160
+ .then(() => {
161
+ meeting.cleanupLocalTracks();
162
+ meeting.unsetRemoteTracks();
163
+ meeting.unsetPeerConnections();
164
+ meeting.reconnectionManager.cleanUp();
165
+ })
166
+ .then(() => meeting.stopKeepAlive())
167
+ .then(() => meeting.updateLLMConnection());
168
+ },
169
+
170
+ disconnectPhoneAudio: (meeting, phoneUrl) => {
171
+ if (meeting.meetingState === FULL_STATE.INACTIVE) {
172
+ return Promise.reject(new MeetingNotActiveError());
173
+ }
59
174
 
60
- return meeting.meetingRequest
61
- .remoteAudioVideoToggle({
175
+ const options = {
62
176
  locusUrl: meeting.locusUrl,
63
177
  selfId: meeting.selfId,
64
- localMedias,
65
- deviceUrl: meeting.deviceUrl,
66
178
  correlationId: meeting.correlationId,
67
- preferTranscoding: !meeting.isMultistream,
68
- })
69
- .then((response) => {
70
- Metrics.postEvent({event: eventType.MEDIA_RESPONSE, meeting});
179
+ phoneUrl,
180
+ };
71
181
 
72
- return response.body.locus;
182
+ return meeting.meetingRequest.disconnectPhoneAudio(options).catch((err) => {
183
+ LoggerProxy.logger.error(
184
+ `Meeting:util#disconnectPhoneAudio --> An error occured while disconnecting phone audio in meeting ${meeting.id}, error: ${err}`
185
+ );
186
+
187
+ return Promise.reject(err);
73
188
  });
74
- };
189
+ },
190
+
191
+ // by default will leave on meeting's resourceId
192
+ // if you explicity want it not to leave on resource id, pass
193
+ // {resourceId: null}
194
+ // TODO: chris, you can modify this however you want
195
+ leaveMeeting: (meeting, options: any = {}) => {
196
+ if (meeting.meetingState === FULL_STATE.INACTIVE) {
197
+ // TODO: clean up if the meeting is already inactive
198
+ return Promise.reject(new MeetingNotActiveError());
199
+ }
75
200
 
76
- MeetingUtil.hasOwner = (info) => info && info.owner;
201
+ if (MeetingUtil.isUserInLeftState(meeting.locusInfo)) {
202
+ return Promise.reject(new UserNotJoinedError());
203
+ }
77
204
 
78
- MeetingUtil.isOwnerSelf = (owner, selfId) => owner === selfId;
205
+ const defaultOptions = {
206
+ locusUrl: meeting.locusUrl,
207
+ selfId: meeting.selfId,
208
+ correlationId: meeting.correlationId,
209
+ resourceId: meeting.resourceId,
210
+ deviceUrl: meeting.deviceUrl,
211
+ };
212
+
213
+ const leaveOptions = {...defaultOptions, ...options};
214
+
215
+ return meeting.meetingRequest
216
+ .leaveMeeting(leaveOptions)
217
+ .then(() => {
218
+ if (options.moveMeeting) {
219
+ return Promise.resolve();
220
+ }
221
+
222
+ return MeetingUtil.cleanUp(meeting);
223
+ })
224
+ .catch((err) => {
225
+ // TODO: If the meeting state comes as LEFT or INACTIVE as response then
226
+ // 1) on leave clean up the meeting or simply do a sync on the meeting
227
+ // 2) If the error says meeting is inactive then destroy the meeting object
228
+ LoggerProxy.logger.error(
229
+ `Meeting:util#leaveMeeting --> An error occured while trying to leave meeting with an id of ${meeting.id}, error: ${err}`
230
+ );
231
+
232
+ return Promise.reject(err);
233
+ });
234
+ },
235
+ declineMeeting: (meeting, reason) =>
236
+ meeting.meetingRequest.declineMeeting({
237
+ locusUrl: meeting.locusUrl,
238
+ deviceUrl: meeting.deviceUrl,
239
+ reason,
240
+ }),
79
241
 
80
- MeetingUtil.isPinOrGuest = (err) =>
81
- err?.body?.errorCode && INTENT_TO_JOIN.includes(err.body.errorCode);
242
+ isUserInLeftState: (locusInfo) => locusInfo.parsedLocus?.self?.state === _LEFT_,
82
243
 
83
- MeetingUtil.joinMeeting = (meeting, options) => {
84
- if (!meeting) {
85
- return Promise.reject(new ParameterError('You need a meeting object.'));
86
- }
244
+ isUserInIdleState: (locusInfo) => locusInfo.parsedLocus?.self?.state === _IDLE_,
87
245
 
88
- Metrics.postEvent({event: eventType.LOCUS_JOIN_REQUEST, meeting});
246
+ isUserInJoinedState: (locusInfo) => locusInfo.parsedLocus?.self?.state === _JOINED_,
89
247
 
90
- // eslint-disable-next-line no-warning-comments
91
- // TODO: check if the meeting is in JOINING state
92
- // if Joining state termintate the request as user might click multiple times
93
- return meeting.meetingRequest
94
- .joinMeeting({
95
- inviteeAddress: meeting.meetingJoinUrl || meeting.sipUri,
96
- meetingNumber: meeting.meetingNumber,
97
- deviceUrl: meeting.deviceUrl,
98
- locusUrl: meeting.locusUrl,
99
- correlationId: meeting.correlationId,
100
- roapMessage: options.roapMessage,
101
- permissionToken: meeting.permissionToken,
102
- resourceId: options.resourceId || null,
103
- moderator: options.moderator,
104
- pin: options.pin,
105
- moveToResource: options.moveToResource,
106
- preferTranscoding: !meeting.isMultistream,
107
- asResourceOccupant: options.asResourceOccupant,
108
- breakoutsSupported: options.breakoutsSupported,
109
- })
110
- .then((res) => {
111
- Metrics.postEvent({
112
- event: eventType.LOCUS_JOIN_RESPONSE,
113
- meeting,
114
- data: {
115
- trigger: trigger.LOCI_UPDATE,
116
- locus: res.body.locus,
117
- mediaConnections: res.body.mediaConnections,
118
- trackingId: res.headers.trackingid,
248
+ isMediaEstablished: (currentMediaStatus) =>
249
+ currentMediaStatus &&
250
+ (currentMediaStatus.audio || currentMediaStatus.video || currentMediaStatus.share),
251
+
252
+ joinMeetingOptions: (meeting, options: any = {}) => {
253
+ const webex = meeting.getWebexObject();
254
+
255
+ meeting.resourceId = meeting.resourceId || options.resourceId;
256
+
257
+ if (meeting.requiredCaptcha) {
258
+ return Promise.reject(new CaptchaError());
259
+ }
260
+ if (meeting.passwordStatus === PASSWORD_STATUS.REQUIRED) {
261
+ return Promise.reject(new PasswordError());
262
+ }
263
+
264
+ if (options.pin) {
265
+ // @ts-ignore
266
+ webex.internal.newMetrics.submitClientEvent({
267
+ name: 'client.pin.collected',
268
+ options: {
269
+ meetingId: meeting.id,
119
270
  },
120
271
  });
272
+ }
121
273
 
122
- return MeetingUtil.parseLocusJoin(res);
123
- });
124
- };
274
+ // normal join meeting, scenario A, D
275
+ return MeetingUtil.joinMeeting(meeting, options)
276
+ .then((response) => {
277
+ meeting.setLocus(response);
278
+
279
+ return Promise.resolve(response);
280
+ })
281
+ .catch((err) => {
282
+ // joining a claimed PMR that is not my own, scenario B
283
+ if (MeetingUtil.isPinOrGuest(err)) {
284
+ // @ts-ignore
285
+ webex.internal.newMetrics.submitClientEvent({
286
+ name: 'client.pin.prompt',
287
+ options: {
288
+ meetingId: meeting.id,
289
+ },
290
+ });
291
+
292
+ // request host pin or non host for unclaimed PMR, start of Scenario C
293
+ // see https://sqbu-github.cisco.com/WebExSquared/locus/wiki/Locus-Lobby-and--IVR-Feature
294
+ return Promise.reject(new IntentToJoinError('Error Joining Meeting', err));
295
+ }
296
+ LoggerProxy.logger.error(
297
+ 'Meeting:util#joinMeetingOptions --> Error joining the call, ',
298
+ err
299
+ );
300
+
301
+ return Promise.reject(new JoinMeetingError(options, 'Error Joining Meeting', err));
302
+ });
303
+ },
125
304
 
126
- MeetingUtil.cleanUp = (meeting) => {
127
- meeting.breakouts.cleanUp();
128
-
129
- // make sure we send last metrics before we close the peerconnection
130
- const stopStatsAnalyzer = meeting.statsAnalyzer
131
- ? meeting.statsAnalyzer.stopAnalyzer()
132
- : Promise.resolve();
133
-
134
- return stopStatsAnalyzer
135
- .then(() => meeting.closeLocalStream())
136
- .then(() => meeting.closeLocalShare())
137
- .then(() => meeting.closeRemoteTracks())
138
- .then(() => meeting.closePeerConnections())
139
- .then(() => {
140
- meeting.unsetLocalVideoTrack();
141
- meeting.unsetLocalShareTrack();
142
- meeting.unsetRemoteTracks();
143
- meeting.unsetPeerConnections();
144
- meeting.reconnectionManager.cleanUp();
145
- })
146
- .then(() => meeting.stopKeepAlive())
147
- .then(() => meeting.updateLLMConnection());
148
- };
305
+ getTrack: (stream) => {
306
+ let audioTrack = null;
307
+ let videoTrack = null;
308
+ let audioTracks = null;
309
+ let videoTracks = null;
149
310
 
150
- MeetingUtil.disconnectPhoneAudio = (meeting, phoneUrl) => {
151
- if (meeting.meetingState === FULL_STATE.INACTIVE) {
152
- return Promise.reject(new MeetingNotActiveError());
153
- }
154
-
155
- const options = {
156
- locusUrl: meeting.locusUrl,
157
- selfId: meeting.selfId,
158
- correlationId: meeting.correlationId,
159
- phoneUrl,
160
- };
161
-
162
- return meeting.meetingRequest
163
- .disconnectPhoneAudio(options)
164
- .then((response) => {
165
- if (response?.body?.locus) {
166
- meeting.locusInfo.onFullLocus(response.body.locus);
167
- }
168
- })
169
- .catch((err) => {
170
- LoggerProxy.logger.error(
171
- `Meeting:util#disconnectPhoneAudio --> An error occured while disconnecting phone audio in meeting ${meeting.id}, error: ${err}`
172
- );
311
+ if (!stream) {
312
+ return {audioTrack: null, videoTrack: null};
313
+ }
314
+ if (stream.getAudioTracks) {
315
+ audioTracks = stream.getAudioTracks();
316
+ }
317
+ if (stream.getVideoTracks) {
318
+ videoTracks = stream.getVideoTracks();
319
+ }
173
320
 
174
- return Promise.reject(err);
175
- });
176
- };
321
+ if (audioTracks && audioTracks.length > 0) {
322
+ [audioTrack] = audioTracks;
323
+ }
177
324
 
178
- // by default will leave on meeting's resourceId
179
- // if you explicity want it not to leave on resource id, pass
180
- // {resourceId: null}
181
- // TODO: chris, you can modify this however you want
182
- MeetingUtil.leaveMeeting = (meeting, options: any = {}) => {
183
- if (meeting.meetingState === FULL_STATE.INACTIVE) {
184
- // TODO: clean up if the meeting is already inactive
185
- return Promise.reject(new MeetingNotActiveError());
186
- }
187
-
188
- if (MeetingUtil.isUserInLeftState(meeting.locusInfo)) {
189
- return Promise.reject(new UserNotJoinedError());
190
- }
191
-
192
- const defaultOptions = {
193
- locusUrl: meeting.locusUrl,
194
- selfId: meeting.selfId,
195
- correlationId: meeting.correlationId,
196
- resourceId: meeting.resourceId,
197
- deviceUrl: meeting.deviceUrl,
198
- };
199
-
200
- const leaveOptions = {...defaultOptions, ...options};
201
-
202
- return meeting.meetingRequest
203
- .leaveMeeting(leaveOptions)
204
- .then((response) => {
205
- if (response && response.body && response.body.locus) {
206
- // && !options.moveMeeting) {
207
- meeting.locusInfo.onFullLocus(response.body.locus);
208
- }
325
+ if (videoTracks && videoTracks.length > 0) {
326
+ [videoTrack] = videoTracks;
327
+ }
209
328
 
210
- return Promise.resolve();
211
- })
212
- .then(() => {
213
- if (options.moveMeeting) {
214
- return Promise.resolve();
215
- }
329
+ return {audioTrack, videoTrack};
330
+ },
216
331
 
217
- return MeetingUtil.cleanUp(meeting);
218
- })
219
- .catch((err) => {
220
- // TODO: If the meeting state comes as LEFT or INACTIVE as response then
221
- // 1) on leave clean up the meeting or simply do a sync on the meeting
222
- // 2) If the error says meeting is inactive then destroy the meeting object
223
- LoggerProxy.logger.error(
224
- `Meeting:util#leaveMeeting --> An error occured while trying to leave meeting with an id of ${meeting.id}, error: ${err}`
225
- );
332
+ getModeratorFromLocusInfo: (locusInfo) =>
333
+ locusInfo &&
334
+ locusInfo.parsedLocus &&
335
+ locusInfo.parsedLocus.info &&
336
+ locusInfo.parsedLocus.info &&
337
+ locusInfo.parsedLocus.info.moderator,
226
338
 
227
- return Promise.reject(err);
228
- });
229
- };
230
- MeetingUtil.declineMeeting = (meeting, reason) =>
231
- meeting.meetingRequest.declineMeeting({
232
- locusUrl: meeting.locusUrl,
233
- deviceUrl: meeting.deviceUrl,
234
- reason,
235
- });
339
+ getPolicyFromLocusInfo: (locusInfo) =>
340
+ locusInfo &&
341
+ locusInfo.parsedLocus &&
342
+ locusInfo.parsedLocus.info &&
343
+ locusInfo.parsedLocus.info &&
344
+ locusInfo.parsedLocus.info.policy,
236
345
 
237
- MeetingUtil.isUserInLeftState = (locusInfo) => locusInfo.parsedLocus?.self?.state === _LEFT_;
346
+ getUserDisplayHintsFromLocusInfo: (locusInfo) =>
347
+ locusInfo?.parsedLocus?.info?.userDisplayHints || [],
238
348
 
239
- MeetingUtil.isUserInIdleState = (locusInfo) => locusInfo.parsedLocus?.self?.state === _IDLE_;
349
+ canInviteNewParticipants: (displayHints) => displayHints.includes(DISPLAY_HINTS.ADD_GUEST),
240
350
 
241
- MeetingUtil.isUserInJoinedState = (locusInfo) => locusInfo.parsedLocus?.self?.state === _JOINED_;
351
+ canAdmitParticipant: (displayHints) =>
352
+ displayHints.includes(DISPLAY_HINTS.ROSTER_WAITING_TO_JOIN),
242
353
 
243
- MeetingUtil.isMediaEstablished = (currentMediaStatus) =>
244
- currentMediaStatus &&
245
- (currentMediaStatus.audio || currentMediaStatus.video || currentMediaStatus.share);
354
+ canUserLock: (displayHints) =>
355
+ displayHints.includes(DISPLAY_HINTS.LOCK_CONTROL_LOCK) &&
356
+ displayHints.includes(DISPLAY_HINTS.LOCK_STATUS_UNLOCKED),
246
357
 
247
- MeetingUtil.joinMeetingOptions = (meeting, options: any = {}) => {
248
- meeting.resourceId = meeting.resourceId || options.resourceId;
358
+ canUserUnlock: (displayHints) =>
359
+ displayHints.includes(DISPLAY_HINTS.LOCK_CONTROL_UNLOCK) &&
360
+ displayHints.includes(DISPLAY_HINTS.LOCK_STATUS_LOCKED),
249
361
 
250
- if (meeting.requiredCaptcha) {
251
- return Promise.reject(new CaptchaError());
252
- }
253
- if (meeting.passwordStatus === PASSWORD_STATUS.REQUIRED) {
254
- return Promise.reject(new PasswordError());
255
- }
362
+ canUserRaiseHand: (displayHints) => displayHints.includes(DISPLAY_HINTS.RAISE_HAND),
256
363
 
257
- if (options.pin) {
258
- Metrics.postEvent({
259
- event: eventType.PIN_COLLECTED,
260
- meeting,
261
- });
262
- }
263
-
264
- // normal join meeting, scenario A, D
265
- return MeetingUtil.joinMeeting(meeting, options)
266
- .then((response) => {
267
- meeting.setLocus(response);
268
-
269
- return Promise.resolve(response);
270
- })
271
- .catch((err) => {
272
- // joining a claimed PMR that is not my own, scenario B
273
- if (MeetingUtil.isPinOrGuest(err)) {
274
- Metrics.postEvent({
275
- event: eventType.PIN_PROMPT,
276
- meeting,
277
- });
364
+ canUserLowerAllHands: (displayHints) => displayHints.includes(DISPLAY_HINTS.LOWER_ALL_HANDS),
278
365
 
279
- // request host pin or non host for unclaimed PMR, start of Scenario C
280
- // see https://sqbu-github.cisco.com/WebExSquared/locus/wiki/Locus-Lobby-and--IVR-Feature
281
- return Promise.reject(new IntentToJoinError('Error Joining Meeting', err));
282
- }
283
- LoggerProxy.logger.error('Meeting:util#joinMeetingOptions --> Error joining the call, ', err);
366
+ canUserLowerSomeoneElsesHand: (displayHints) =>
367
+ displayHints.includes(DISPLAY_HINTS.LOWER_SOMEONE_ELSES_HAND),
284
368
 
285
- return Promise.reject(new JoinMeetingError(options, 'Error Joining Meeting', err));
286
- });
287
- };
369
+ bothLeaveAndEndMeetingAvailable: (displayHints) =>
370
+ displayHints.includes(DISPLAY_HINTS.LEAVE_TRANSFER_HOST_END_MEETING) ||
371
+ displayHints.includes(DISPLAY_HINTS.LEAVE_END_MEETING),
288
372
 
289
- MeetingUtil.validateOptions = (options) => {
290
- const {sendVideo, sendAudio, sendShare, localStream, localShare} = options;
373
+ canManageBreakout: (displayHints) => displayHints.includes(DISPLAY_HINTS.BREAKOUT_MANAGEMENT),
374
+ canBroadcastMessageToBreakout: (displayHints, policies = {}) =>
375
+ displayHints.includes(DISPLAY_HINTS.BROADCAST_MESSAGE_TO_BREAKOUT) &&
376
+ !!policies[SELF_POLICY.SUPPORT_BROADCAST_MESSAGE],
291
377
 
292
- if (sendVideo && !MeetingUtil.getTrack(localStream).videoTrack) {
293
- return Promise.reject(new ParameterError('please pass valid video streams'));
294
- }
378
+ isSuppressBreakoutSupport: (displayHints) =>
379
+ displayHints.includes(DISPLAY_HINTS.UCF_SUPPRESS_BREAKOUTS_SUPPORT),
295
380
 
296
- if (sendAudio && !MeetingUtil.getTrack(localStream).audioTrack) {
297
- return Promise.reject(new ParameterError('please pass valid audio streams'));
298
- }
381
+ canAdmitLobbyToBreakout: (displayHints) =>
382
+ !displayHints.includes(DISPLAY_HINTS.DISABLE_LOBBY_TO_BREAKOUT),
299
383
 
300
- if (sendShare && !MeetingUtil.getTrack(localShare).videoTrack) {
301
- return Promise.reject(new ParameterError('please pass valid share streams'));
302
- }
384
+ isBreakoutPreassignmentsEnabled: (displayHints) =>
385
+ !displayHints.includes(DISPLAY_HINTS.DISABLE_BREAKOUT_PREASSIGNMENTS),
303
386
 
304
- return Promise.resolve();
305
- };
387
+ canUserAskForHelp: (displayHints) => !displayHints.includes(DISPLAY_HINTS.DISABLE_ASK_FOR_HELP),
306
388
 
307
- MeetingUtil.getTrack = (stream) => {
308
- let audioTrack = null;
309
- let videoTrack = null;
310
- let audioTracks = null;
311
- let videoTracks = null;
312
-
313
- if (!stream) {
314
- return {audioTrack: null, videoTrack: null};
315
- }
316
- if (stream.getAudioTracks) {
317
- audioTracks = stream.getAudioTracks();
318
- }
319
- if (stream.getVideoTracks) {
320
- videoTracks = stream.getVideoTracks();
321
- }
322
-
323
- if (audioTracks && audioTracks.length > 0) {
324
- [audioTrack] = audioTracks;
325
- }
326
-
327
- if (videoTracks && videoTracks.length > 0) {
328
- [videoTrack] = videoTracks;
329
- }
330
-
331
- return {audioTrack, videoTrack};
332
- };
389
+ lockMeeting: (actions, request, locusUrl) => {
390
+ if (actions && actions.canLock) {
391
+ return request.lockMeeting({locusUrl, lock: true});
392
+ }
333
393
 
334
- MeetingUtil.getModeratorFromLocusInfo = (locusInfo) =>
335
- locusInfo &&
336
- locusInfo.parsedLocus &&
337
- locusInfo.parsedLocus.info &&
338
- locusInfo.parsedLocus.info &&
339
- locusInfo.parsedLocus.info.moderator;
394
+ return Promise.reject(new PermissionError('Lock not allowed, due to joined property.'));
395
+ },
340
396
 
341
- MeetingUtil.getPolicyFromLocusInfo = (locusInfo) =>
342
- locusInfo &&
343
- locusInfo.parsedLocus &&
344
- locusInfo.parsedLocus.info &&
345
- locusInfo.parsedLocus.info &&
346
- locusInfo.parsedLocus.info.policy;
397
+ unlockMeeting: (actions, request, locusUrl) => {
398
+ if (actions && actions.canUnlock) {
399
+ return request.lockMeeting({locusUrl, lock: false});
400
+ }
347
401
 
348
- MeetingUtil.getUserDisplayHintsFromLocusInfo = (locusInfo) =>
349
- locusInfo?.parsedLocus?.info?.userDisplayHints || [];
402
+ return Promise.reject(new PermissionError('Unlock not allowed, due to joined property.'));
403
+ },
350
404
 
351
- MeetingUtil.canInviteNewParticipants = (displayHints) =>
352
- displayHints.includes(DISPLAY_HINTS.ADD_GUEST);
405
+ handleAudioLogging: (audioTrack?: LocalMicrophoneTrack) => {
406
+ const LOG_HEADER = 'MeetingUtil#handleAudioLogging -->';
353
407
 
354
- MeetingUtil.canAdmitParticipant = (displayHints) =>
355
- displayHints.includes(DISPLAY_HINTS.ROSTER_WAITING_TO_JOIN);
408
+ if (audioTrack) {
409
+ const settings = audioTrack.underlyingTrack.getSettings();
410
+ const {deviceId} = settings;
356
411
 
357
- MeetingUtil.canUserLock = (displayHints) =>
358
- displayHints.includes(DISPLAY_HINTS.LOCK_CONTROL_LOCK) &&
359
- displayHints.includes(DISPLAY_HINTS.LOCK_STATUS_UNLOCKED);
412
+ LoggerProxy.logger.log(LOG_HEADER, `deviceId = ${deviceId}`);
413
+ LoggerProxy.logger.log(LOG_HEADER, 'settings =', JSON.stringify(settings));
414
+ }
415
+ },
360
416
 
361
- MeetingUtil.canUserUnlock = (displayHints) =>
362
- displayHints.includes(DISPLAY_HINTS.LOCK_CONTROL_UNLOCK) &&
363
- displayHints.includes(DISPLAY_HINTS.LOCK_STATUS_LOCKED);
417
+ handleVideoLogging: (videoTrack?: LocalCameraTrack) => {
418
+ const LOG_HEADER = 'MeetingUtil#handleVideoLogging -->';
364
419
 
365
- MeetingUtil.canUserRaiseHand = (displayHints) => displayHints.includes(DISPLAY_HINTS.RAISE_HAND);
420
+ if (videoTrack) {
421
+ const settings = videoTrack.underlyingTrack.getSettings();
422
+ const {deviceId} = settings;
366
423
 
367
- MeetingUtil.canUserLowerAllHands = (displayHints) =>
368
- displayHints.includes(DISPLAY_HINTS.LOWER_ALL_HANDS);
424
+ LoggerProxy.logger.log(LOG_HEADER, `deviceId = ${deviceId}`);
425
+ LoggerProxy.logger.log(LOG_HEADER, 'settings =', JSON.stringify(settings));
426
+ }
427
+ },
369
428
 
370
- MeetingUtil.canUserLowerSomeoneElsesHand = (displayHints) =>
371
- displayHints.includes(DISPLAY_HINTS.LOWER_SOMEONE_ELSES_HAND);
429
+ handleDeviceLogging: (devices = []) => {
430
+ const LOG_HEADER = 'MeetingUtil#handleDeviceLogging -->';
372
431
 
373
- MeetingUtil.bothLeaveAndEndMeetingAvailable = (displayHints) =>
374
- displayHints.includes(DISPLAY_HINTS.LEAVE_TRANSFER_HOST_END_MEETING) ||
375
- displayHints.includes(DISPLAY_HINTS.LEAVE_END_MEETING);
432
+ devices.forEach((device) => {
433
+ LoggerProxy.logger.log(LOG_HEADER, `deviceId = ${device.deviceId}`);
434
+ LoggerProxy.logger.log(LOG_HEADER, 'settings', JSON.stringify(device));
435
+ });
436
+ },
376
437
 
377
- MeetingUtil.lockMeeting = (actions, request, locusUrl) => {
378
- if (actions && actions.canLock) {
379
- return request.lockMeeting({locusUrl, lock: true});
380
- }
438
+ endMeetingForAll: (meeting) => {
439
+ if (meeting.meetingState === FULL_STATE.INACTIVE) {
440
+ return Promise.reject(new MeetingNotActiveError());
441
+ }
381
442
 
382
- return Promise.reject(new PermissionError('Lock not allowed, due to joined property.'));
383
- };
443
+ const endOptions = {
444
+ locusUrl: meeting.locusUrl,
445
+ };
384
446
 
385
- MeetingUtil.unlockMeeting = (actions, request, locusUrl) => {
386
- if (actions && actions.canUnlock) {
387
- return request.lockMeeting({locusUrl, lock: false});
388
- }
447
+ return meeting.meetingRequest
448
+ .endMeetingForAll(endOptions)
449
+ .then(() => MeetingUtil.cleanUp(meeting))
450
+ .catch((err) => {
451
+ LoggerProxy.logger.error(
452
+ `Meeting:util#endMeetingForAll An error occured while trying to end meeting for all with an id of ${meeting.id}, error: ${err}`
453
+ );
389
454
 
390
- return Promise.reject(new PermissionError('Unlock not allowed, due to joined property.'));
391
- };
455
+ return Promise.reject(err);
456
+ });
457
+ },
392
458
 
393
- MeetingUtil.handleAudioLogging = (audioTrack) => {
394
- const LOG_HEADER = 'MeetingUtil#handleAudioLogging -->';
459
+ canEnableClosedCaption: (displayHints) => displayHints.includes(DISPLAY_HINTS.CAPTION_START),
395
460
 
396
- if (audioTrack) {
397
- const settings = audioTrack.getSettings();
398
- const {deviceId} = settings;
461
+ isSaveTranscriptsEnabled: (displayHints) =>
462
+ displayHints.includes(DISPLAY_HINTS.SAVE_TRANSCRIPTS_ENABLED),
399
463
 
400
- LoggerProxy.logger.log(LOG_HEADER, `deviceId = ${deviceId}`);
401
- LoggerProxy.logger.log(LOG_HEADER, 'settings =', JSON.stringify(settings));
402
- }
403
- };
464
+ canStartTranscribing: (displayHints) =>
465
+ displayHints.includes(DISPLAY_HINTS.TRANSCRIPTION_CONTROL_START),
404
466
 
405
- MeetingUtil.handleVideoLogging = (videoTrack) => {
406
- const LOG_HEADER = 'MeetingUtil#handleVideoLogging -->';
467
+ canStopTranscribing: (displayHints) =>
468
+ displayHints.includes(DISPLAY_HINTS.TRANSCRIPTION_CONTROL_STOP),
407
469
 
408
- if (videoTrack) {
409
- const settings = videoTrack.getSettings();
410
- const {deviceId} = settings;
470
+ isClosedCaptionActive: (displayHints) =>
471
+ displayHints.includes(DISPLAY_HINTS.CAPTION_STATUS_ACTIVE),
411
472
 
412
- LoggerProxy.logger.log(LOG_HEADER, `deviceId = ${deviceId}`);
413
- LoggerProxy.logger.log(LOG_HEADER, 'settings =', JSON.stringify(settings));
414
- }
415
- };
473
+ isWebexAssistantActive: (displayHints) =>
474
+ displayHints.includes(DISPLAY_HINTS.WEBEX_ASSISTANT_STATUS_ACTIVE),
416
475
 
417
- MeetingUtil.handleDeviceLogging = (devices = []) => {
418
- const LOG_HEADER = 'MeetingUtil#handleDeviceLogging -->';
476
+ canViewCaptionPanel: (displayHints) => displayHints.includes(DISPLAY_HINTS.ENABLE_CAPTION_PANEL),
419
477
 
420
- devices.forEach((device) => {
421
- LoggerProxy.logger.log(LOG_HEADER, `deviceId = ${device.deviceId}`);
422
- LoggerProxy.logger.log(LOG_HEADER, 'settings', JSON.stringify(device));
423
- });
424
- };
478
+ isRealTimeTranslationEnabled: (displayHints) =>
479
+ displayHints.includes(DISPLAY_HINTS.DISPLAY_REAL_TIME_TRANSLATION),
425
480
 
426
- MeetingUtil.endMeetingForAll = (meeting) => {
427
- if (meeting.meetingState === FULL_STATE.INACTIVE) {
428
- return Promise.reject(new MeetingNotActiveError());
429
- }
481
+ canSelectSpokenLanguages: (displayHints) =>
482
+ displayHints.includes(DISPLAY_HINTS.DISPLAY_NON_ENGLISH_ASR),
430
483
 
431
- const endOptions = {
432
- locusUrl: meeting.locusUrl,
433
- };
484
+ waitingForOthersToJoin: (displayHints) => displayHints.includes(DISPLAY_HINTS.WAITING_FOR_OTHERS),
434
485
 
435
- return meeting.meetingRequest
436
- .endMeetingForAll(endOptions)
437
- .then((response) => {
438
- if (response && response.body && response.body.locus) {
439
- meeting.locusInfo.onFullLocus(response.body.locus);
440
- }
486
+ canSendReactions: (originalValue, displayHints) => {
487
+ if (displayHints.includes(DISPLAY_HINTS.REACTIONS_ACTIVE)) {
488
+ return true;
489
+ }
490
+ if (displayHints.includes(DISPLAY_HINTS.REACTIONS_INACTIVE)) {
491
+ return false;
492
+ }
441
493
 
442
- return Promise.resolve();
443
- })
444
- .then(() => MeetingUtil.cleanUp(meeting))
445
- .catch((err) => {
446
- LoggerProxy.logger.error(
447
- `Meeting:util#endMeetingForAll An error occured while trying to end meeting for all with an id of ${meeting.id}, error: ${err}`
448
- );
494
+ return originalValue;
495
+ },
496
+ canUserRenameSelfAndObserved: (displayHints) =>
497
+ displayHints.includes(DISPLAY_HINTS.CAN_RENAME_SELF_AND_OBSERVED),
449
498
 
450
- return Promise.reject(err);
451
- });
452
- };
499
+ canUserRenameOthers: (displayHints) => displayHints.includes(DISPLAY_HINTS.CAN_RENAME_OTHERS),
453
500
 
454
- MeetingUtil.canEnableClosedCaption = (displayHints) =>
455
- displayHints.includes(DISPLAY_HINTS.CAPTION_START);
501
+ /**
502
+ * Adds the current locus sequence information to a request body
503
+ * @param {Object} meeting The meeting object
504
+ * @param {Object} requestBody The body of a request to locus
505
+ * @returns {void}
506
+ */
507
+ addSequence: (meeting, requestBody) => {
508
+ const sequence = meeting?.locusInfo?.sequence;
456
509
 
457
- MeetingUtil.canStartTranscribing = (displayHints) =>
458
- displayHints.includes(DISPLAY_HINTS.TRANSCRIPTION_CONTROL_START);
510
+ if (!sequence) {
511
+ return;
512
+ }
513
+
514
+ requestBody.sequence = sequence;
515
+ },
516
+
517
+ /**
518
+ * Updates the locus info for the meeting with the delta locus
519
+ * returned from requests that include the sequence information
520
+ * Returns the original response object
521
+ * @param {Object} meeting The meeting object
522
+ * @param {Object} response The response of the http request
523
+ * @returns {Object}
524
+ */
525
+ updateLocusWithDelta: (meeting, response) => {
526
+ if (!meeting) {
527
+ return response;
528
+ }
459
529
 
460
- MeetingUtil.canStopTranscribing = (displayHints) =>
461
- displayHints.includes(DISPLAY_HINTS.TRANSCRIPTION_CONTROL_STOP);
530
+ const locus = response?.body?.locus;
462
531
 
463
- MeetingUtil.isClosedCaptionActive = (displayHints) =>
464
- displayHints.includes(DISPLAY_HINTS.CAPTION_STATUS_ACTIVE);
532
+ if (locus) {
533
+ meeting.locusInfo.handleLocusDelta(locus, meeting);
534
+ }
465
535
 
466
- MeetingUtil.isWebexAssistantActive = (displayHints) =>
467
- displayHints.includes(DISPLAY_HINTS.WEBEX_ASSISTANT_STATUS_ACTIVE);
536
+ return response;
537
+ },
468
538
 
469
- MeetingUtil.canViewCaptionPanel = (displayHints) =>
470
- displayHints.includes(DISPLAY_HINTS.ENABLE_CAPTION_PANEL);
539
+ generateLocusDeltaRequest: (originalMeeting) => {
540
+ const meetingRef = new WeakRef(originalMeeting);
471
541
 
472
- MeetingUtil.isRealTimeTranslationEnabled = (displayHints) =>
473
- displayHints.includes(DISPLAY_HINTS.DISPLAY_REAL_TIME_TRANSLATION);
542
+ const locusDeltaRequest = (originalOptions) => {
543
+ const meeting = meetingRef.deref();
474
544
 
475
- MeetingUtil.canSelectSpokenLanguages = (displayHints) =>
476
- displayHints.includes(DISPLAY_HINTS.DISPLAY_NON_ENGLISH_ASR);
545
+ if (!meeting) {
546
+ return Promise.resolve();
547
+ }
477
548
 
478
- MeetingUtil.waitingForOthersToJoin = (displayHints) =>
479
- displayHints.includes(DISPLAY_HINTS.WAITING_FOR_OTHERS);
549
+ const options = cloneDeep(originalOptions);
480
550
 
481
- MeetingUtil.canEnableReactions = (originalValue, displayHints) => {
482
- if (displayHints.includes(DISPLAY_HINTS.ENABLE_REACTIONS)) {
483
- return true;
484
- }
485
- if (displayHints.includes(DISPLAY_HINTS.DISABLE_REACTIONS)) {
486
- return false;
487
- }
551
+ if (!options.body) {
552
+ options.body = {};
553
+ }
488
554
 
489
- return originalValue;
490
- };
555
+ MeetingUtil.addSequence(meeting, options.body);
491
556
 
492
- MeetingUtil.canSendReactions = (originalValue, displayHints) => {
493
- if (displayHints.includes(DISPLAY_HINTS.REACTIONS_ACTIVE)) {
494
- return true;
495
- }
496
- if (displayHints.includes(DISPLAY_HINTS.REACTIONS_INACTIVE)) {
497
- return false;
498
- }
557
+ return meeting
558
+ .request(options)
559
+ .then((response) => MeetingUtil.updateLocusWithDelta(meeting, response));
560
+ };
499
561
 
500
- return originalValue;
562
+ return locusDeltaRequest;
563
+ },
564
+
565
+ selfSupportsFeature: (feature: SELF_POLICY, userPolicies: Record<SELF_POLICY, boolean>) => {
566
+ if (!userPolicies) {
567
+ return true;
568
+ }
569
+
570
+ return userPolicies[feature];
571
+ },
572
+
573
+ parseInterpretationInfo: (meeting, meetingInfo) => {
574
+ if (!meeting || !meetingInfo) {
575
+ return;
576
+ }
577
+ const siInfo = meetingInfo.simultaneousInterpretation;
578
+ meeting.simultaneousInterpretation.updateMeetingSIEnabled(
579
+ !!meetingInfo.turnOnSimultaneousInterpretation,
580
+ !!siInfo?.currentSIInterpreter
581
+ );
582
+ const hostSIEnabled = !!(
583
+ meetingInfo.turnOnSimultaneousInterpretation &&
584
+ meetingInfo?.meetingSiteSetting?.enableHostInterpreterControlSI
585
+ );
586
+ meeting.simultaneousInterpretation.updateHostSIEnabled(hostSIEnabled);
587
+
588
+ function renameKey(obj, oldKey, newKey) {
589
+ if (oldKey in obj) {
590
+ obj[newKey] = obj[oldKey];
591
+ delete obj[oldKey];
592
+ }
593
+ }
594
+ if (siInfo) {
595
+ const lanuagesInfo = cloneDeep(siInfo.siLanguages);
596
+ for (const language of lanuagesInfo) {
597
+ renameKey(language, 'languageCode', 'languageName');
598
+ renameKey(language, 'languageGroupId', 'languageCode');
599
+ }
600
+ if (!meeting.simultaneousInterpretation?.siLanguages?.length) {
601
+ meeting.simultaneousInterpretation.updateInterpretation({siLanguages: lanuagesInfo});
602
+ }
603
+ }
604
+ Trigger.trigger(
605
+ meeting,
606
+ {
607
+ file: 'meeting/util',
608
+ function: 'parseInterpretationInfo',
609
+ },
610
+ EVENT_TRIGGERS.MEETING_INTERPRETATION_UPDATE
611
+ );
612
+ },
501
613
  };
502
614
 
503
615
  export default MeetingUtil;