@webex/plugin-meetings 3.0.0-beta.15 → 3.0.0-beta.151

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