@webex/plugin-meetings 3.0.0-beta.18 → 3.0.0-beta.181

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