@webex/plugin-meetings 3.0.0-beta.21 → 3.0.0-beta.211

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 (422) 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 +179 -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 +106 -1
  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 +359 -64
  51. package/dist/locus-info/index.js.map +1 -1
  52. package/dist/locus-info/infoUtils.js +7 -1
  53. package/dist/locus-info/infoUtils.js.map +1 -1
  54. package/dist/locus-info/mediaSharesUtils.js +43 -1
  55. package/dist/locus-info/mediaSharesUtils.js.map +1 -1
  56. package/dist/locus-info/parser.js +219 -63
  57. package/dist/locus-info/parser.js.map +1 -1
  58. package/dist/locus-info/selfUtils.js +89 -14
  59. package/dist/locus-info/selfUtils.js.map +1 -1
  60. package/dist/media/index.js +48 -135
  61. package/dist/media/index.js.map +1 -1
  62. package/dist/media/properties.js +29 -90
  63. package/dist/media/properties.js.map +1 -1
  64. package/dist/mediaQualityMetrics/config.js +505 -493
  65. package/dist/mediaQualityMetrics/config.js.map +1 -1
  66. package/dist/meeting/in-meeting-actions.js +90 -2
  67. package/dist/meeting/in-meeting-actions.js.map +1 -1
  68. package/dist/meeting/index.js +2770 -2547
  69. package/dist/meeting/index.js.map +1 -1
  70. package/dist/meeting/locusMediaRequest.js +291 -0
  71. package/dist/meeting/locusMediaRequest.js.map +1 -0
  72. package/dist/meeting/muteState.js +229 -124
  73. package/dist/meeting/muteState.js.map +1 -1
  74. package/dist/meeting/request.js +199 -193
  75. package/dist/meeting/request.js.map +1 -1
  76. package/dist/meeting/util.js +532 -414
  77. package/dist/meeting/util.js.map +1 -1
  78. package/dist/meeting-info/index.js +48 -7
  79. package/dist/meeting-info/index.js.map +1 -1
  80. package/dist/meeting-info/meeting-info-v2.js +171 -51
  81. package/dist/meeting-info/meeting-info-v2.js.map +1 -1
  82. package/dist/meeting-info/utilv2.js +20 -5
  83. package/dist/meeting-info/utilv2.js.map +1 -1
  84. package/dist/meetings/collection.js +22 -0
  85. package/dist/meetings/collection.js.map +1 -1
  86. package/dist/meetings/index.js +357 -66
  87. package/dist/meetings/index.js.map +1 -1
  88. package/dist/meetings/meetings.types.js +7 -0
  89. package/dist/meetings/meetings.types.js.map +1 -0
  90. package/dist/meetings/request.js +2 -0
  91. package/dist/meetings/request.js.map +1 -1
  92. package/dist/meetings/util.js +88 -1
  93. package/dist/meetings/util.js.map +1 -1
  94. package/dist/member/index.js +49 -0
  95. package/dist/member/index.js.map +1 -1
  96. package/dist/member/types.js +25 -0
  97. package/dist/member/types.js.map +1 -0
  98. package/dist/member/util.js +121 -25
  99. package/dist/member/util.js.map +1 -1
  100. package/dist/members/collection.js +10 -0
  101. package/dist/members/collection.js.map +1 -1
  102. package/dist/members/index.js +86 -5
  103. package/dist/members/index.js.map +1 -1
  104. package/dist/members/request.js +106 -38
  105. package/dist/members/request.js.map +1 -1
  106. package/dist/members/types.js +15 -0
  107. package/dist/members/types.js.map +1 -0
  108. package/dist/members/util.js +316 -233
  109. package/dist/members/util.js.map +1 -1
  110. package/dist/metrics/constants.js +3 -5
  111. package/dist/metrics/constants.js.map +1 -1
  112. package/dist/metrics/index.js +1 -468
  113. package/dist/metrics/index.js.map +1 -1
  114. package/dist/multistream/mediaRequestManager.js +238 -49
  115. package/dist/multistream/mediaRequestManager.js.map +1 -1
  116. package/dist/multistream/receiveSlot.js +49 -16
  117. package/dist/multistream/receiveSlot.js.map +1 -1
  118. package/dist/multistream/receiveSlotManager.js +52 -34
  119. package/dist/multistream/receiveSlotManager.js.map +1 -1
  120. package/dist/multistream/remoteMedia.js +44 -18
  121. package/dist/multistream/remoteMedia.js.map +1 -1
  122. package/dist/multistream/remoteMediaGroup.js +60 -3
  123. package/dist/multistream/remoteMediaGroup.js.map +1 -1
  124. package/dist/multistream/remoteMediaManager.js +173 -59
  125. package/dist/multistream/remoteMediaManager.js.map +1 -1
  126. package/dist/networkQualityMonitor/index.js +4 -2
  127. package/dist/networkQualityMonitor/index.js.map +1 -1
  128. package/dist/reachability/index.js +72 -27
  129. package/dist/reachability/index.js.map +1 -1
  130. package/dist/reachability/request.js +12 -5
  131. package/dist/reachability/request.js.map +1 -1
  132. package/dist/reconnection-manager/index.js +196 -155
  133. package/dist/reconnection-manager/index.js.map +1 -1
  134. package/dist/recording-controller/index.js +21 -2
  135. package/dist/recording-controller/index.js.map +1 -1
  136. package/dist/recording-controller/util.js +9 -8
  137. package/dist/recording-controller/util.js.map +1 -1
  138. package/dist/roap/index.js +21 -29
  139. package/dist/roap/index.js.map +1 -1
  140. package/dist/roap/request.js +110 -89
  141. package/dist/roap/request.js.map +1 -1
  142. package/dist/roap/turnDiscovery.js +93 -36
  143. package/dist/roap/turnDiscovery.js.map +1 -1
  144. package/dist/rtcMetrics/constants.js +12 -0
  145. package/dist/rtcMetrics/constants.js.map +1 -0
  146. package/dist/rtcMetrics/index.js +117 -0
  147. package/dist/rtcMetrics/index.js.map +1 -0
  148. package/dist/statsAnalyzer/global.js +1 -93
  149. package/dist/statsAnalyzer/global.js.map +1 -1
  150. package/dist/statsAnalyzer/index.js +326 -311
  151. package/dist/statsAnalyzer/index.js.map +1 -1
  152. package/dist/statsAnalyzer/mqaUtil.js +90 -53
  153. package/dist/statsAnalyzer/mqaUtil.js.map +1 -1
  154. package/dist/types/annotation/annotation.types.d.ts +42 -0
  155. package/dist/types/annotation/constants.d.ts +31 -0
  156. package/dist/types/annotation/index.d.ts +117 -0
  157. package/dist/types/breakouts/breakout.d.ts +8 -0
  158. package/dist/types/breakouts/collection.d.ts +5 -0
  159. package/dist/types/breakouts/edit-lock-error.d.ts +15 -0
  160. package/dist/types/breakouts/events.d.ts +8 -0
  161. package/dist/types/breakouts/index.d.ts +5 -0
  162. package/dist/types/breakouts/request.d.ts +22 -0
  163. package/dist/types/breakouts/utils.d.ts +15 -0
  164. package/dist/types/common/browser-detection.d.ts +9 -0
  165. package/dist/types/common/collection.d.ts +48 -0
  166. package/dist/types/common/config.d.ts +2 -0
  167. package/dist/types/common/errors/captcha-error.d.ts +15 -0
  168. package/dist/types/common/errors/intent-to-join.d.ts +16 -0
  169. package/dist/types/common/errors/join-meeting.d.ts +17 -0
  170. package/dist/types/common/errors/media.d.ts +15 -0
  171. package/dist/types/common/errors/parameter.d.ts +15 -0
  172. package/dist/types/common/errors/password-error.d.ts +15 -0
  173. package/dist/types/common/errors/permission.d.ts +14 -0
  174. package/dist/types/common/errors/reconnection-in-progress.d.ts +9 -0
  175. package/dist/types/common/errors/reconnection.d.ts +15 -0
  176. package/dist/types/common/errors/stats.d.ts +15 -0
  177. package/dist/types/common/errors/webex-errors.d.ts +69 -0
  178. package/dist/types/common/errors/webex-meetings-error.d.ts +20 -0
  179. package/dist/types/common/events/events-scope.d.ts +17 -0
  180. package/dist/types/common/events/events.d.ts +12 -0
  181. package/dist/types/common/events/trigger-proxy.d.ts +2 -0
  182. package/dist/types/common/events/util.d.ts +2 -0
  183. package/dist/types/common/logs/logger-config.d.ts +2 -0
  184. package/dist/types/common/logs/logger-proxy.d.ts +2 -0
  185. package/dist/types/common/logs/request.d.ts +34 -0
  186. package/dist/types/common/queue.d.ts +34 -0
  187. package/dist/types/config.d.ts +72 -0
  188. package/dist/types/constants.d.ts +1020 -0
  189. package/dist/types/controls-options-manager/constants.d.ts +4 -0
  190. package/dist/types/controls-options-manager/enums.d.ts +15 -0
  191. package/dist/types/controls-options-manager/index.d.ts +136 -0
  192. package/dist/types/controls-options-manager/types.d.ts +43 -0
  193. package/dist/types/controls-options-manager/util.d.ts +1 -0
  194. package/dist/types/index.d.ts +7 -0
  195. package/dist/types/interpretation/collection.d.ts +5 -0
  196. package/dist/types/interpretation/index.d.ts +5 -0
  197. package/dist/types/interpretation/siLanguage.d.ts +5 -0
  198. package/dist/types/locus-info/controlsUtils.d.ts +2 -0
  199. package/dist/types/locus-info/embeddedAppsUtils.d.ts +2 -0
  200. package/dist/types/locus-info/fullState.d.ts +2 -0
  201. package/dist/types/locus-info/hostUtils.d.ts +2 -0
  202. package/dist/types/locus-info/index.d.ts +322 -0
  203. package/dist/types/locus-info/infoUtils.d.ts +2 -0
  204. package/dist/types/locus-info/mediaSharesUtils.d.ts +2 -0
  205. package/dist/types/locus-info/parser.d.ts +271 -0
  206. package/dist/types/locus-info/selfUtils.d.ts +2 -0
  207. package/dist/types/media/index.d.ts +34 -0
  208. package/dist/types/media/properties.d.ts +93 -0
  209. package/dist/types/media/util.d.ts +2 -0
  210. package/dist/types/mediaQualityMetrics/config.d.ts +365 -0
  211. package/dist/types/meeting/in-meeting-actions.d.ts +163 -0
  212. package/dist/types/meeting/index.d.ts +1482 -0
  213. package/dist/types/meeting/locusMediaRequest.d.ts +72 -0
  214. package/dist/types/meeting/muteState.d.ts +184 -0
  215. package/dist/types/meeting/request.d.ts +257 -0
  216. package/dist/types/meeting/request.type.d.ts +11 -0
  217. package/dist/types/meeting/state.d.ts +9 -0
  218. package/dist/types/meeting/util.d.ts +79 -0
  219. package/dist/types/meeting-info/collection.d.ts +20 -0
  220. package/dist/types/meeting-info/index.d.ts +62 -0
  221. package/dist/types/meeting-info/meeting-info-v2.d.ts +122 -0
  222. package/dist/types/meeting-info/request.d.ts +22 -0
  223. package/dist/types/meeting-info/util.d.ts +2 -0
  224. package/dist/types/meeting-info/utilv2.d.ts +2 -0
  225. package/dist/types/meetings/collection.d.ts +31 -0
  226. package/dist/types/meetings/index.d.ts +367 -0
  227. package/dist/types/meetings/meetings.types.d.ts +4 -0
  228. package/dist/types/meetings/request.d.ts +27 -0
  229. package/dist/types/meetings/util.d.ts +18 -0
  230. package/dist/types/member/index.d.ts +159 -0
  231. package/dist/types/member/types.d.ts +32 -0
  232. package/dist/types/member/util.d.ts +2 -0
  233. package/dist/types/members/collection.d.ts +29 -0
  234. package/dist/types/members/index.d.ts +353 -0
  235. package/dist/types/members/request.d.ts +114 -0
  236. package/dist/types/members/types.d.ts +24 -0
  237. package/dist/types/members/util.d.ts +210 -0
  238. package/dist/types/metrics/constants.d.ts +55 -0
  239. package/dist/types/metrics/index.d.ts +45 -0
  240. package/dist/types/multistream/mediaRequestManager.d.ts +118 -0
  241. package/dist/types/multistream/receiveSlot.d.ts +68 -0
  242. package/dist/types/multistream/receiveSlotManager.d.ts +56 -0
  243. package/dist/types/multistream/remoteMedia.d.ts +72 -0
  244. package/dist/types/multistream/remoteMediaGroup.d.ts +47 -0
  245. package/dist/types/multistream/remoteMediaManager.d.ts +277 -0
  246. package/dist/types/networkQualityMonitor/index.d.ts +70 -0
  247. package/dist/types/personal-meeting-room/index.d.ts +47 -0
  248. package/dist/types/personal-meeting-room/request.d.ts +14 -0
  249. package/dist/types/personal-meeting-room/util.d.ts +2 -0
  250. package/dist/types/reachability/index.d.ts +152 -0
  251. package/dist/types/reachability/request.d.ts +37 -0
  252. package/dist/types/reactions/constants.d.ts +3 -0
  253. package/dist/types/reactions/reactions.d.ts +4 -0
  254. package/dist/types/reactions/reactions.type.d.ts +52 -0
  255. package/dist/types/reconnection-manager/index.d.ts +126 -0
  256. package/dist/types/recording-controller/enums.d.ts +7 -0
  257. package/dist/types/recording-controller/index.d.ts +207 -0
  258. package/dist/types/recording-controller/util.d.ts +14 -0
  259. package/dist/types/roap/index.d.ts +77 -0
  260. package/dist/types/roap/request.d.ts +36 -0
  261. package/dist/types/roap/turnDiscovery.d.ts +91 -0
  262. package/dist/types/rtcMetrics/constants.d.ts +4 -0
  263. package/dist/types/rtcMetrics/index.d.ts +46 -0
  264. package/dist/types/statsAnalyzer/global.d.ts +36 -0
  265. package/dist/types/statsAnalyzer/index.d.ts +200 -0
  266. package/dist/types/statsAnalyzer/mqaUtil.d.ts +24 -0
  267. package/dist/types/transcription/index.d.ts +64 -0
  268. package/package.json +23 -20
  269. package/src/annotation/annotation.types.ts +50 -0
  270. package/src/annotation/constants.ts +36 -0
  271. package/src/annotation/index.ts +328 -0
  272. package/src/breakouts/README.md +44 -14
  273. package/src/breakouts/breakout.ts +87 -9
  274. package/src/breakouts/edit-lock-error.ts +25 -0
  275. package/src/breakouts/events.ts +56 -0
  276. package/src/breakouts/index.ts +710 -10
  277. package/src/breakouts/request.ts +55 -0
  278. package/src/breakouts/utils.ts +57 -0
  279. package/src/common/errors/webex-errors.ts +6 -2
  280. package/src/common/logs/logger-proxy.ts +1 -1
  281. package/src/common/queue.ts +22 -8
  282. package/src/config.ts +2 -7
  283. package/src/constants.ts +165 -21
  284. package/src/controls-options-manager/constants.ts +5 -0
  285. package/src/controls-options-manager/enums.ts +18 -0
  286. package/src/controls-options-manager/index.ts +278 -0
  287. package/src/controls-options-manager/types.ts +59 -0
  288. package/src/controls-options-manager/util.ts +300 -0
  289. package/src/index.ts +39 -0
  290. package/src/interpretation/README.md +60 -0
  291. package/src/interpretation/collection.ts +19 -0
  292. package/src/interpretation/index.ts +332 -0
  293. package/src/interpretation/siLanguage.ts +18 -0
  294. package/src/locus-info/controlsUtils.ts +108 -0
  295. package/src/locus-info/index.ts +383 -61
  296. package/src/locus-info/infoUtils.ts +10 -2
  297. package/src/locus-info/mediaSharesUtils.ts +48 -0
  298. package/src/locus-info/parser.ts +224 -39
  299. package/src/locus-info/selfUtils.ts +81 -5
  300. package/src/media/index.ts +87 -140
  301. package/src/media/properties.ts +49 -90
  302. package/src/mediaQualityMetrics/config.ts +379 -377
  303. package/src/meeting/in-meeting-actions.ts +179 -3
  304. package/src/meeting/index.ts +2099 -2083
  305. package/src/meeting/locusMediaRequest.ts +311 -0
  306. package/src/meeting/muteState.ts +228 -132
  307. package/src/meeting/request.ts +105 -115
  308. package/src/meeting/util.ts +511 -397
  309. package/src/meeting-info/index.ts +54 -8
  310. package/src/meeting-info/meeting-info-v2.ts +148 -14
  311. package/src/meeting-info/utilv2.ts +13 -3
  312. package/src/meetings/collection.ts +20 -0
  313. package/src/meetings/index.ts +392 -84
  314. package/src/meetings/meetings.types.ts +12 -0
  315. package/src/meetings/request.ts +2 -0
  316. package/src/meetings/util.ts +103 -4
  317. package/src/member/index.ts +49 -0
  318. package/src/member/types.ts +38 -0
  319. package/src/member/util.ts +127 -25
  320. package/src/members/collection.ts +8 -0
  321. package/src/members/index.ts +107 -6
  322. package/src/members/request.ts +97 -17
  323. package/src/members/types.ts +28 -0
  324. package/src/members/util.ts +319 -240
  325. package/src/metrics/constants.ts +2 -4
  326. package/src/metrics/index.ts +1 -490
  327. package/src/multistream/mediaRequestManager.ts +289 -79
  328. package/src/multistream/receiveSlot.ts +55 -18
  329. package/src/multistream/receiveSlotManager.ts +46 -24
  330. package/src/multistream/remoteMedia.ts +27 -2
  331. package/src/multistream/remoteMediaGroup.ts +59 -0
  332. package/src/multistream/remoteMediaManager.ts +113 -32
  333. package/src/networkQualityMonitor/index.ts +6 -6
  334. package/src/reachability/index.ts +62 -15
  335. package/src/reachability/request.ts +10 -5
  336. package/src/reconnection-manager/index.ts +68 -43
  337. package/src/recording-controller/index.ts +20 -3
  338. package/src/recording-controller/util.ts +26 -9
  339. package/src/roap/index.ts +21 -30
  340. package/src/roap/request.ts +101 -95
  341. package/src/roap/turnDiscovery.ts +47 -25
  342. package/src/rtcMetrics/constants.ts +3 -0
  343. package/src/rtcMetrics/index.ts +100 -0
  344. package/src/statsAnalyzer/global.ts +1 -94
  345. package/src/statsAnalyzer/index.ts +376 -386
  346. package/src/statsAnalyzer/mqaUtil.ts +100 -99
  347. package/test/integration/spec/converged-space-meetings.js +233 -0
  348. package/test/integration/spec/journey.js +336 -259
  349. package/test/integration/spec/space-meeting.js +77 -4
  350. package/test/unit/spec/annotation/index.ts +418 -0
  351. package/test/unit/spec/breakouts/breakout.ts +142 -24
  352. package/test/unit/spec/breakouts/edit-lock-error.ts +30 -0
  353. package/test/unit/spec/breakouts/events.ts +89 -0
  354. package/test/unit/spec/breakouts/index.ts +1545 -48
  355. package/test/unit/spec/breakouts/request.ts +104 -0
  356. package/test/unit/spec/breakouts/utils.js +72 -0
  357. package/test/unit/spec/common/queue.js +31 -2
  358. package/test/unit/spec/controls-options-manager/index.js +287 -0
  359. package/test/unit/spec/controls-options-manager/util.js +582 -0
  360. package/test/unit/spec/fixture/locus.js +1 -0
  361. package/test/unit/spec/interpretation/collection.ts +15 -0
  362. package/test/unit/spec/interpretation/index.ts +589 -0
  363. package/test/unit/spec/interpretation/siLanguage.ts +28 -0
  364. package/test/unit/spec/locus-info/controlsUtils.js +316 -43
  365. package/test/unit/spec/locus-info/index.js +1169 -36
  366. package/test/unit/spec/locus-info/infoUtils.js +37 -15
  367. package/test/unit/spec/locus-info/mediaSharesUtils.ts +22 -0
  368. package/test/unit/spec/locus-info/parser.js +62 -22
  369. package/test/unit/spec/locus-info/selfConstant.js +27 -4
  370. package/test/unit/spec/locus-info/selfUtils.js +208 -17
  371. package/test/unit/spec/media/index.ts +138 -28
  372. package/test/unit/spec/meeting/in-meeting-actions.ts +89 -3
  373. package/test/unit/spec/meeting/index.js +3573 -1663
  374. package/test/unit/spec/meeting/locusMediaRequest.ts +438 -0
  375. package/test/unit/spec/meeting/muteState.js +370 -208
  376. package/test/unit/spec/meeting/request.js +339 -44
  377. package/test/unit/spec/meeting/utils.js +456 -53
  378. package/test/unit/spec/meeting-info/index.js +181 -0
  379. package/test/unit/spec/meeting-info/meetinginfov2.js +383 -5
  380. package/test/unit/spec/meeting-info/utilv2.js +21 -0
  381. package/test/unit/spec/meetings/collection.js +14 -0
  382. package/test/unit/spec/meetings/index.js +867 -125
  383. package/test/unit/spec/meetings/utils.js +206 -2
  384. package/test/unit/spec/member/index.js +58 -4
  385. package/test/unit/spec/member/util.js +479 -35
  386. package/test/unit/spec/members/index.js +319 -1
  387. package/test/unit/spec/members/request.js +206 -27
  388. package/test/unit/spec/members/utils.js +184 -0
  389. package/test/unit/spec/metrics/index.js +1 -50
  390. package/test/unit/spec/multistream/mediaRequestManager.ts +803 -162
  391. package/test/unit/spec/multistream/receiveSlot.ts +72 -13
  392. package/test/unit/spec/multistream/receiveSlotManager.ts +58 -28
  393. package/test/unit/spec/multistream/remoteMedia.ts +30 -0
  394. package/test/unit/spec/multistream/remoteMediaGroup.ts +266 -0
  395. package/test/unit/spec/multistream/remoteMediaManager.ts +318 -0
  396. package/test/unit/spec/networkQualityMonitor/index.js +4 -4
  397. package/test/unit/spec/reachability/index.ts +125 -8
  398. package/test/unit/spec/reachability/request.js +66 -0
  399. package/test/unit/spec/reconnection-manager/index.js +59 -6
  400. package/test/unit/spec/recording-controller/index.js +294 -218
  401. package/test/unit/spec/recording-controller/util.js +223 -96
  402. package/test/unit/spec/roap/index.ts +26 -51
  403. package/test/unit/spec/roap/request.ts +196 -85
  404. package/test/unit/spec/roap/turnDiscovery.ts +30 -7
  405. package/test/unit/spec/rtcMetrics/index.ts +60 -0
  406. package/test/unit/spec/stats-analyzer/index.js +92 -41
  407. package/test/utils/constants.js +9 -0
  408. package/test/utils/integrationTestUtils.js +46 -0
  409. package/test/utils/testUtils.js +0 -45
  410. package/test/utils/webex-config.js +4 -0
  411. package/test/utils/webex-test-users.js +6 -3
  412. package/dist/meeting/effectsState.js +0 -262
  413. package/dist/meeting/effectsState.js.map +0 -1
  414. package/dist/metrics/config.js +0 -299
  415. package/dist/metrics/config.js.map +0 -1
  416. package/dist/multistream/multistreamMedia.js +0 -110
  417. package/dist/multistream/multistreamMedia.js.map +0 -1
  418. package/src/index.js +0 -16
  419. package/src/meeting/effectsState.ts +0 -211
  420. package/src/metrics/config.ts +0 -495
  421. package/src/multistream/multistreamMedia.ts +0 -97
  422. 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,599 @@ 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),
500
+
501
+ canShareWhiteBoard: (displayHints) => displayHints.includes(DISPLAY_HINTS.SHARE_WHITEBOARD),
453
502
 
454
- MeetingUtil.canEnableClosedCaption = (displayHints) =>
455
- displayHints.includes(DISPLAY_HINTS.CAPTION_START);
503
+ /**
504
+ * Adds the current locus sequence information to a request body
505
+ * @param {Object} meeting The meeting object
506
+ * @param {Object} requestBody The body of a request to locus
507
+ * @returns {void}
508
+ */
509
+ addSequence: (meeting, requestBody) => {
510
+ const sequence = meeting?.locusInfo?.sequence;
456
511
 
457
- MeetingUtil.canStartTranscribing = (displayHints) =>
458
- displayHints.includes(DISPLAY_HINTS.TRANSCRIPTION_CONTROL_START);
512
+ if (!sequence) {
513
+ return;
514
+ }
515
+
516
+ requestBody.sequence = sequence;
517
+ },
518
+
519
+ /**
520
+ * Updates the locus info for the meeting with the delta locus
521
+ * returned from requests that include the sequence information
522
+ * Returns the original response object
523
+ * @param {Object} meeting The meeting object
524
+ * @param {Object} response The response of the http request
525
+ * @returns {Object}
526
+ */
527
+ updateLocusWithDelta: (meeting, response) => {
528
+ if (!meeting) {
529
+ return response;
530
+ }
459
531
 
460
- MeetingUtil.canStopTranscribing = (displayHints) =>
461
- displayHints.includes(DISPLAY_HINTS.TRANSCRIPTION_CONTROL_STOP);
532
+ const locus = response?.body?.locus;
462
533
 
463
- MeetingUtil.isClosedCaptionActive = (displayHints) =>
464
- displayHints.includes(DISPLAY_HINTS.CAPTION_STATUS_ACTIVE);
534
+ if (locus) {
535
+ meeting.locusInfo.handleLocusDelta(locus, meeting);
536
+ }
465
537
 
466
- MeetingUtil.isWebexAssistantActive = (displayHints) =>
467
- displayHints.includes(DISPLAY_HINTS.WEBEX_ASSISTANT_STATUS_ACTIVE);
538
+ return response;
539
+ },
468
540
 
469
- MeetingUtil.canViewCaptionPanel = (displayHints) =>
470
- displayHints.includes(DISPLAY_HINTS.ENABLE_CAPTION_PANEL);
541
+ generateLocusDeltaRequest: (originalMeeting) => {
542
+ const meetingRef = new WeakRef(originalMeeting);
471
543
 
472
- MeetingUtil.isRealTimeTranslationEnabled = (displayHints) =>
473
- displayHints.includes(DISPLAY_HINTS.DISPLAY_REAL_TIME_TRANSLATION);
544
+ const locusDeltaRequest = (originalOptions) => {
545
+ const meeting = meetingRef.deref();
474
546
 
475
- MeetingUtil.canSelectSpokenLanguages = (displayHints) =>
476
- displayHints.includes(DISPLAY_HINTS.DISPLAY_NON_ENGLISH_ASR);
547
+ if (!meeting) {
548
+ return Promise.resolve();
549
+ }
477
550
 
478
- MeetingUtil.waitingForOthersToJoin = (displayHints) =>
479
- displayHints.includes(DISPLAY_HINTS.WAITING_FOR_OTHERS);
551
+ const options = cloneDeep(originalOptions);
480
552
 
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
- }
553
+ if (!options.body) {
554
+ options.body = {};
555
+ }
488
556
 
489
- return originalValue;
490
- };
557
+ MeetingUtil.addSequence(meeting, options.body);
491
558
 
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
- }
559
+ return meeting
560
+ .request(options)
561
+ .then((response) => MeetingUtil.updateLocusWithDelta(meeting, response));
562
+ };
499
563
 
500
- return originalValue;
564
+ return locusDeltaRequest;
565
+ },
566
+
567
+ selfSupportsFeature: (feature: SELF_POLICY, userPolicies: Record<SELF_POLICY, boolean>) => {
568
+ if (!userPolicies) {
569
+ return true;
570
+ }
571
+
572
+ return userPolicies[feature];
573
+ },
574
+
575
+ parseInterpretationInfo: (meeting, meetingInfo) => {
576
+ if (!meeting || !meetingInfo) {
577
+ return;
578
+ }
579
+ const siInfo = meetingInfo.simultaneousInterpretation;
580
+ meeting.simultaneousInterpretation.updateMeetingSIEnabled(
581
+ !!meetingInfo.turnOnSimultaneousInterpretation,
582
+ !!siInfo?.currentSIInterpreter
583
+ );
584
+ const hostSIEnabled = !!(
585
+ meetingInfo.turnOnSimultaneousInterpretation &&
586
+ meetingInfo?.meetingSiteSetting?.enableHostInterpreterControlSI
587
+ );
588
+ meeting.simultaneousInterpretation.updateHostSIEnabled(hostSIEnabled);
589
+
590
+ function renameKey(obj, oldKey, newKey) {
591
+ if (oldKey in obj) {
592
+ obj[newKey] = obj[oldKey];
593
+ delete obj[oldKey];
594
+ }
595
+ }
596
+ if (siInfo) {
597
+ const lanuagesInfo = cloneDeep(siInfo.siLanguages);
598
+ for (const language of lanuagesInfo) {
599
+ renameKey(language, 'languageCode', 'languageName');
600
+ renameKey(language, 'languageGroupId', 'languageCode');
601
+ }
602
+ if (!meeting.simultaneousInterpretation?.siLanguages?.length) {
603
+ meeting.simultaneousInterpretation.updateInterpretation({siLanguages: lanuagesInfo});
604
+ }
605
+ }
606
+ Trigger.trigger(
607
+ meeting,
608
+ {
609
+ file: 'meeting/util',
610
+ function: 'parseInterpretationInfo',
611
+ },
612
+ EVENT_TRIGGERS.MEETING_INTERPRETATION_UPDATE
613
+ );
614
+ },
501
615
  };
502
616
 
503
617
  export default MeetingUtil;