@webex/plugin-meetings 3.0.0-beta.22 → 3.0.0-beta.221

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