@webex/plugin-meetings 3.0.0-beta.39 → 3.0.0-beta.391

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