@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,23 +1,32 @@
1
1
  import sinon from 'sinon';
2
2
  import {assert} from '@webex/test-helper-chai';
3
+ import Meetings from '@webex/plugin-meetings';
3
4
  import MeetingUtil from '@webex/plugin-meetings/src/meeting/util';
5
+ import {LOCAL_SHARE_ERRORS} from '@webex/plugin-meetings/src/constants';
4
6
  import LoggerProxy from '@webex/plugin-meetings/src/common/logs/logger-proxy';
5
7
  import LoggerConfig from '@webex/plugin-meetings/src/common/logs/logger-config';
6
- import Metrics from '@webex/plugin-meetings/src/metrics/index';
7
- import {DISPLAY_HINTS} from '@webex/plugin-meetings/dist/constants';
8
+ import {SELF_POLICY, IP_VERSION} from '@webex/plugin-meetings/src/constants';
9
+ import MockWebex from '@webex/test-helper-mock-webex';
10
+ import * as BrowserDetectionModule from '@webex/plugin-meetings/src/common/browser-detection';
8
11
 
9
12
  describe('plugin-meetings', () => {
13
+ let webex;
10
14
  describe('Meeting utils function', () => {
11
15
  const sandbox = sinon.createSandbox();
12
16
  const meeting = {};
13
17
 
14
18
  beforeEach(() => {
15
- Metrics.postEvent = sinon.stub();
19
+ webex = new MockWebex({
20
+ children: {
21
+ meetings: Meetings,
22
+ },
23
+ });
16
24
  const logger = {
17
25
  info: sandbox.stub(),
18
26
  log: sandbox.stub(),
19
27
  error: sandbox.stub(),
20
28
  warn: sandbox.stub(),
29
+ debug: sandbox.stub(),
21
30
  };
22
31
 
23
32
  LoggerConfig.set({
@@ -26,42 +35,41 @@ describe('plugin-meetings', () => {
26
35
  });
27
36
  LoggerProxy.set(logger);
28
37
 
29
- meeting.closeLocalStream = sinon.stub().returns(Promise.resolve());
30
- meeting.closeLocalShare = sinon.stub().returns(Promise.resolve());
31
- meeting.closeRemoteTracks = sinon.stub().returns(Promise.resolve());
38
+ meeting.cleanupLocalStreams = sinon.stub().returns(Promise.resolve());
39
+ meeting.closeRemoteStreams = sinon.stub().returns(Promise.resolve());
32
40
  meeting.closePeerConnections = sinon.stub().returns(Promise.resolve());
33
41
 
34
- meeting.unsetLocalVideoTrack = sinon.stub();
35
- meeting.unsetLocalShareTrack = sinon.stub();
36
- meeting.unsetRemoteTracks = sinon.stub();
42
+ meeting.unsetRemoteStreams = sinon.stub();
37
43
  meeting.unsetPeerConnections = sinon.stub();
38
44
  meeting.reconnectionManager = {cleanUp: sinon.stub()};
39
45
  meeting.stopKeepAlive = sinon.stub();
40
46
  meeting.updateLLMConnection = sinon.stub();
41
47
  meeting.breakouts = {cleanUp: sinon.stub()};
48
+ meeting.annotaion = {cleanUp: sinon.stub()};
49
+ meeting.getWebexObject = sinon.stub().returns(webex);
50
+ meeting.simultaneousInterpretation = {cleanUp: sinon.stub()};
51
+ meeting.trigger = sinon.stub();
42
52
  });
43
53
 
44
54
  afterEach(() => {
45
55
  sandbox.restore();
56
+ sinon.restore();
46
57
  });
47
58
 
48
59
  describe('#cleanup', () => {
49
60
  it('do clean up on meeting object', async () => {
50
61
  await MeetingUtil.cleanUp(meeting);
51
- assert.calledOnce(meeting.closeLocalStream);
52
- assert.calledOnce(meeting.closeLocalStream);
53
- assert.calledOnce(meeting.closeLocalShare);
54
- assert.calledOnce(meeting.closeRemoteTracks);
62
+ assert.calledOnce(meeting.cleanupLocalStreams);
63
+ assert.calledOnce(meeting.closeRemoteStreams);
55
64
  assert.calledOnce(meeting.closePeerConnections);
56
65
 
57
- assert.calledOnce(meeting.unsetLocalVideoTrack);
58
- assert.calledOnce(meeting.unsetLocalShareTrack);
59
- assert.calledOnce(meeting.unsetRemoteTracks);
66
+ assert.calledOnce(meeting.unsetRemoteStreams);
60
67
  assert.calledOnce(meeting.unsetPeerConnections);
61
68
  assert.calledOnce(meeting.reconnectionManager.cleanUp);
62
69
  assert.calledOnce(meeting.stopKeepAlive);
63
70
  assert.calledOnce(meeting.updateLLMConnection);
64
71
  assert.calledOnce(meeting.breakouts.cleanUp);
72
+ assert.calledOnce(meeting.simultaneousInterpretation.cleanUp);
65
73
  });
66
74
  });
67
75
 
@@ -70,10 +78,8 @@ describe('plugin-meetings', () => {
70
78
  deviceId: 'device-1',
71
79
  });
72
80
 
73
- const mockTrack = {
74
- underlyingTrack: {
75
- getSettings: fakeDevice,
76
- }
81
+ const mockStream = {
82
+ getSettings: fakeDevice,
77
83
  };
78
84
 
79
85
  it('#log - should log [info, warn, error, log] to console', () => {
@@ -91,27 +97,27 @@ describe('plugin-meetings', () => {
91
97
  });
92
98
 
93
99
  describe('#handleAudioLogging', () => {
94
- it('should not log if called without track', () => {
100
+ it('should not log if called without stream', () => {
95
101
  MeetingUtil.handleAudioLogging();
96
102
  assert(!LoggerProxy.logger.log.called, 'log not called');
97
103
  });
98
104
 
99
- it('should log audioTrack settings', () => {
105
+ it('should log audioStream settings', () => {
100
106
  assert(MeetingUtil.handleAudioLogging, 'method is defined');
101
- MeetingUtil.handleAudioLogging(mockTrack);
107
+ MeetingUtil.handleAudioLogging(mockStream);
102
108
  assert(LoggerProxy.logger.log.called, 'log called');
103
109
  });
104
110
  });
105
111
 
106
112
  describe('#handleVideoLogging', () => {
107
- it('should not log if called without track', () => {
113
+ it('should not log if called without stream', () => {
108
114
  MeetingUtil.handleVideoLogging(null);
109
115
  assert(!LoggerProxy.logger.log.called, 'log not called');
110
116
  });
111
117
 
112
- it('should log videoTrack settings', () => {
118
+ it('should log videoStream settings', () => {
113
119
  assert(MeetingUtil.handleVideoLogging, 'method is defined');
114
- MeetingUtil.handleVideoLogging(mockTrack);
120
+ MeetingUtil.handleVideoLogging(mockStream);
115
121
  assert(LoggerProxy.logger.log.called, 'log called');
116
122
  });
117
123
  });
@@ -132,51 +138,216 @@ describe('plugin-meetings', () => {
132
138
  });
133
139
  });
134
140
 
135
- describe('remoteUpdateAudioVideo', () => {
136
- it('#Should call meetingRequest.remoteAudioVideoToggle with correct parameters (multistream)', async () => {
141
+ describe('addSequence', () => {
142
+ it('should add the sequence object to a request body', () => {
143
+ const body = {};
144
+
145
+ MeetingUtil.addSequence(
146
+ {
147
+ locusInfo: {
148
+ sequence: 'sequence',
149
+ },
150
+ },
151
+ body
152
+ );
153
+
154
+ assert.deepEqual(body, {
155
+ sequence: 'sequence',
156
+ });
157
+ });
158
+
159
+ it('should work with an undefined meeting', () => {
160
+ const body = {};
161
+
162
+ MeetingUtil.addSequence(undefined, body);
163
+
164
+ assert.deepEqual(body, {});
165
+ });
166
+
167
+ it('should work with an undefined locusInfo', () => {
168
+ const body = {};
169
+
170
+ MeetingUtil.addSequence({}, body);
171
+
172
+ assert.deepEqual(body, {});
173
+ });
174
+
175
+ it('should work with an undefined sequence', () => {
176
+ const body = {};
177
+
178
+ MeetingUtil.addSequence({locusInfo: {}}, body);
179
+
180
+ assert.deepEqual(body, {});
181
+ });
182
+ });
183
+
184
+ describe('updateLocusWithDelta', () => {
185
+ it('should call handleLocusDelta with the new delta locus', () => {
137
186
  const meeting = {
138
- correlationId: 'correlation id',
139
- isMultistream: true,
140
- mediaId: '12345',
141
- meetingJoinUrl: 'meetingJoinUrl',
142
- locusUrl: 'locusUrl',
143
- deviceUrl: 'some device url',
144
- selfId: 'self id',
145
- meetingRequest: {
146
- remoteAudioVideoToggle: sinon.stub().returns(Promise.resolve({body: {}, headers: {}})),
187
+ locusInfo: {
188
+ handleLocusDelta: sinon.stub(),
147
189
  },
148
190
  };
149
191
 
150
- await MeetingUtil.remoteUpdateAudioVideo(true, false, meeting);
192
+ const originalResponse = {
193
+ body: {
194
+ locus: 'locus',
195
+ },
196
+ };
151
197
 
152
- assert.calledOnce(meeting.meetingRequest.remoteAudioVideoToggle);
153
- const parameter = meeting.meetingRequest.remoteAudioVideoToggle.getCall(0).args[0];
198
+ const response = MeetingUtil.updateLocusWithDelta(meeting, originalResponse);
154
199
 
155
- assert.equal(parameter.locusUrl, 'locusUrl');
156
- assert.equal(parameter.selfId, 'self id');
157
- assert.equal(parameter.correlationId, 'correlation id');
158
- assert.equal(parameter.deviceUrl, 'some device url');
159
- assert.deepEqual(parameter.localMedias, [
160
- {localSdp: '{"audioMuted":true,"videoMuted":false}', mediaId: '12345'},
161
- ]);
162
- assert.equal(parameter.preferTranscoding, false);
200
+ assert.deepEqual(response, originalResponse);
201
+ assert.calledOnceWithExactly(meeting.locusInfo.handleLocusDelta, 'locus', meeting);
202
+ });
203
+
204
+ it('should handle locus being missing from the response', () => {
205
+ const meeting = {
206
+ locusInfo: {
207
+ handleLocusDelta: sinon.stub(),
208
+ },
209
+ };
210
+
211
+ const originalResponse = {
212
+ body: {},
213
+ };
214
+
215
+ const response = MeetingUtil.updateLocusWithDelta(meeting, originalResponse);
216
+
217
+ assert.deepEqual(response, originalResponse);
218
+ assert.notCalled(meeting.locusInfo.handleLocusDelta);
219
+ });
220
+
221
+ it('should work with an undefined meeting', () => {
222
+ const originalResponse = {
223
+ body: {
224
+ locus: 'locus',
225
+ },
226
+ };
227
+
228
+ const response = MeetingUtil.updateLocusWithDelta(undefined, originalResponse);
229
+ assert.deepEqual(response, originalResponse);
230
+ });
231
+ });
232
+
233
+ describe('generateLocusDeltaRequest', () => {
234
+ it('generates the correct wrapper function', async () => {
235
+ const updateLocusWithDeltaSpy = sinon.spy(MeetingUtil, 'updateLocusWithDelta');
236
+ const addSequenceSpy = sinon.spy(MeetingUtil, 'addSequence');
237
+
238
+ const meeting = {
239
+ request: sinon.stub().returns(Promise.resolve('result')),
240
+ };
241
+
242
+ const locusDeltaRequest = MeetingUtil.generateLocusDeltaRequest(meeting);
243
+
244
+ const options = {
245
+ some: 'option',
246
+ body: {},
247
+ };
248
+
249
+ let result = await locusDeltaRequest(options);
250
+
251
+ assert.equal(result, 'result');
252
+ assert.calledOnceWithExactly(updateLocusWithDeltaSpy, meeting, 'result');
253
+ assert.calledOnceWithExactly(addSequenceSpy, meeting, options.body);
254
+
255
+ updateLocusWithDeltaSpy.resetHistory();
256
+ addSequenceSpy.resetHistory();
257
+
258
+ // body missing from options
259
+ result = await locusDeltaRequest({});
260
+ assert.equal(result, 'result');
261
+ assert.calledOnceWithExactly(updateLocusWithDeltaSpy, meeting, 'result');
262
+ assert.calledOnceWithExactly(addSequenceSpy, meeting, options.body);
263
+
264
+ // meeting disappears so the WeakRef returns undefined
265
+ sinon.stub(WeakRef.prototype, 'deref').returns(undefined);
266
+
267
+ result = await locusDeltaRequest(options);
268
+ assert.equal(result, undefined);
269
+
270
+ WeakRef.prototype.deref.restore();
271
+ });
272
+
273
+ it('calls generateBuildLocusDeltaRequestOptions as expected', () => {
274
+ const generateBuildLocusDeltaRequestOptionsSpy = sinon.spy(
275
+ MeetingUtil,
276
+ 'generateBuildLocusDeltaRequestOptions'
277
+ );
278
+
279
+ const meeting = {};
280
+
281
+ MeetingUtil.generateLocusDeltaRequest(meeting);
282
+
283
+ assert.calledOnceWithExactly(generateBuildLocusDeltaRequestOptionsSpy, meeting);
284
+ });
285
+ });
286
+
287
+ describe('selfSupportsFeature', () => {
288
+ it('returns true if there are no user policies', () => {
289
+ assert.equal(
290
+ MeetingUtil.selfSupportsFeature(SELF_POLICY.SUPPORT_ANNOTATION, undefined),
291
+ true
292
+ );
293
+ });
294
+
295
+ it('returns true if policy is true', () => {
296
+ assert.equal(
297
+ MeetingUtil.selfSupportsFeature(SELF_POLICY.SUPPORT_ANNOTATION, {
298
+ [SELF_POLICY.SUPPORT_ANNOTATION]: true,
299
+ }),
300
+ true
301
+ );
302
+ });
303
+
304
+ it('returns false if policy is false', () => {
305
+ assert.equal(
306
+ MeetingUtil.selfSupportsFeature(SELF_POLICY.SUPPORT_ANNOTATION, {
307
+ [SELF_POLICY.SUPPORT_ANNOTATION]: false,
308
+ }),
309
+ false
310
+ );
163
311
  });
312
+ });
164
313
 
165
- it('#Should call meetingRequest.remoteAudioVideoToggle with preferTranscoding:true for non multistream connections', async () => {
314
+ describe('remoteUpdateAudioVideo', () => {
315
+ it('#Should call meetingRequest.locusMediaRequest with correct parameters', async () => {
166
316
  const meeting = {
167
- isMultistream: false,
317
+ id: 'meeting-id',
168
318
  mediaId: '12345',
169
- meetingRequest: {
170
- remoteAudioVideoToggle: sinon.stub().returns(Promise.resolve({body: {}, headers: {}})),
319
+ selfUrl: 'self url',
320
+ locusInfo: {
321
+ sequence: {},
171
322
  },
323
+ locusMediaRequest: {
324
+ send: sinon.stub().resolves({body: {}, headers: {}}),
325
+ },
326
+ getWebexObject: sinon.stub().returns(webex),
172
327
  };
173
328
 
174
- await MeetingUtil.remoteUpdateAudioVideo(true, false, meeting);
329
+ await MeetingUtil.remoteUpdateAudioVideo(meeting, true, false);
330
+
331
+ assert.calledOnceWithExactly(meeting.locusMediaRequest.send, {
332
+ mediaId: '12345',
333
+ muteOptions: {
334
+ audioMuted: true,
335
+ videoMuted: false,
336
+ },
337
+ selfUrl: 'self url',
338
+ sequence: {},
339
+ type: 'LocalMute',
340
+ });
175
341
 
176
- assert.calledOnce(meeting.meetingRequest.remoteAudioVideoToggle);
177
- const parameter = meeting.meetingRequest.remoteAudioVideoToggle.getCall(0).args[0];
342
+ assert.calledWith(webex.internal.newMetrics.submitClientEvent, {
343
+ name: 'client.locus.media.request',
344
+ options: {meetingId: meeting.id},
345
+ });
178
346
 
179
- assert.equal(parameter.preferTranscoding, true);
347
+ assert.calledWith(webex.internal.newMetrics.submitClientEvent, {
348
+ name: 'client.locus.media.response',
349
+ options: {meetingId: meeting.id},
350
+ });
180
351
  });
181
352
  });
182
353
 
@@ -186,8 +357,16 @@ describe('plugin-meetings', () => {
186
357
  meetingJoinUrl: 'meetingJoinUrl',
187
358
  locusUrl: 'locusUrl',
188
359
  meetingRequest: {
189
- joinMeeting: sinon.stub().returns(Promise.resolve({body: {}, headers: {}})),
360
+ joinMeeting: sinon.stub().returns(
361
+ Promise.resolve({
362
+ body: {mediaConnections: 'mediaConnections'},
363
+ headers: {
364
+ trackingid: 'trackingId',
365
+ },
366
+ })
367
+ ),
190
368
  },
369
+ getWebexObject: sinon.stub().returns(webex),
191
370
  };
192
371
 
193
372
  MeetingUtil.parseLocusJoin = sinon.stub();
@@ -198,16 +377,38 @@ describe('plugin-meetings', () => {
198
377
 
199
378
  assert.equal(parameter.inviteeAddress, 'meetingJoinUrl');
200
379
  assert.equal(parameter.preferTranscoding, true);
380
+
381
+ assert.calledWith(webex.internal.newMetrics.submitClientEvent, {
382
+ name: 'client.locus.join.request',
383
+ options: {meetingId: meeting.id},
384
+ });
385
+
386
+ assert.calledWith(webex.internal.newMetrics.submitClientEvent, {
387
+ name: 'client.locus.join.response',
388
+ payload: {
389
+ trigger: 'loci-update',
390
+ identifiers: {
391
+ trackingId: 'trackingId',
392
+ },
393
+ },
394
+ options: {
395
+ meetingId: meeting.id,
396
+ mediaConnections: 'mediaConnections',
397
+ },
398
+ });
201
399
  });
202
400
 
203
401
  it('#Should call meetingRequest.joinMeeting with breakoutsSupported=true when passed in as true', async () => {
204
402
  const meeting = {
205
- meetingRequest: {joinMeeting: sinon.stub().returns(Promise.resolve({body: {}, headers: {}}))}
403
+ meetingRequest: {
404
+ joinMeeting: sinon.stub().returns(Promise.resolve({body: {}, headers: {}})),
405
+ },
406
+ getWebexObject: sinon.stub().returns(webex),
206
407
  };
207
408
 
208
409
  MeetingUtil.parseLocusJoin = sinon.stub();
209
410
  await MeetingUtil.joinMeeting(meeting, {
210
- breakoutsSupported: true
411
+ breakoutsSupported: true,
211
412
  });
212
413
 
213
414
  assert.calledOnce(meeting.meetingRequest.joinMeeting);
@@ -216,6 +417,45 @@ describe('plugin-meetings', () => {
216
417
  assert.equal(parameter.breakoutsSupported, true);
217
418
  });
218
419
 
420
+ it('#Should call meetingRequest.joinMeeting with liveAnnotationSupported=true when passed in as true', async () => {
421
+ const meeting = {
422
+ meetingRequest: {
423
+ joinMeeting: sinon.stub().returns(Promise.resolve({body: {}, headers: {}})),
424
+ },
425
+ getWebexObject: sinon.stub().returns(webex),
426
+ };
427
+
428
+ MeetingUtil.parseLocusJoin = sinon.stub();
429
+ await MeetingUtil.joinMeeting(meeting, {
430
+ liveAnnotationSupported: true,
431
+ });
432
+
433
+ assert.calledOnce(meeting.meetingRequest.joinMeeting);
434
+ const parameter = meeting.meetingRequest.joinMeeting.getCall(0).args[0];
435
+
436
+ assert.equal(parameter.liveAnnotationSupported, true);
437
+ });
438
+
439
+ it('#Should call meetingRequest.joinMeeting with locale=en_UK, deviceCapabilities=["TEST"] when they are passed in as those values', async () => {
440
+ const meeting = {
441
+ meetingRequest: {
442
+ joinMeeting: sinon.stub().returns(Promise.resolve({body: {}, headers: {}})),
443
+ },
444
+ getWebexObject: sinon.stub().returns(webex),
445
+ };
446
+
447
+ MeetingUtil.parseLocusJoin = sinon.stub();
448
+ await MeetingUtil.joinMeeting(meeting, {
449
+ locale: 'en_UK',
450
+ deviceCapabilities: ['TEST'],
451
+ });
452
+
453
+ assert.calledOnce(meeting.meetingRequest.joinMeeting);
454
+ const parameter = meeting.meetingRequest.joinMeeting.getCall(0).args[0];
455
+
456
+ assert.equal(parameter.locale, 'en_UK');
457
+ assert.deepEqual(parameter.deviceCapabilities, ['TEST']);
458
+ });
219
459
 
220
460
  it('#Should call meetingRequest.joinMeeting with preferTranscoding=false when multistream is enabled', async () => {
221
461
  const meeting = {
@@ -225,6 +465,7 @@ describe('plugin-meetings', () => {
225
465
  meetingRequest: {
226
466
  joinMeeting: sinon.stub().returns(Promise.resolve({body: {}, headers: {}})),
227
467
  },
468
+ getWebexObject: sinon.stub().returns(webex),
228
469
  };
229
470
 
230
471
  MeetingUtil.parseLocusJoin = sinon.stub();
@@ -244,6 +485,7 @@ describe('plugin-meetings', () => {
244
485
  meetingRequest: {
245
486
  joinMeeting: sinon.stub().returns(Promise.resolve({body: {}, headers: {}})),
246
487
  },
488
+ getWebexObject: sinon.stub().returns(webex),
247
489
  };
248
490
 
249
491
  MeetingUtil.parseLocusJoin = sinon.stub();
@@ -262,6 +504,7 @@ describe('plugin-meetings', () => {
262
504
  meetingRequest: {
263
505
  joinMeeting: sinon.stub().returns(Promise.resolve({body: {}, headers: {}})),
264
506
  },
507
+ getWebexObject: sinon.stub().returns(webex),
265
508
  };
266
509
 
267
510
  MeetingUtil.parseLocusJoin = sinon.stub();
@@ -273,6 +516,63 @@ describe('plugin-meetings', () => {
273
516
  assert.isUndefined(parameter.inviteeAddress);
274
517
  assert.equal(parameter.meetingNumber, 'meetingNumber');
275
518
  });
519
+
520
+ it('should pass in the locusClusterUrl from meetingInfo', async () => {
521
+ const meeting = {
522
+ meetingInfo: {
523
+ locusClusterUrl: 'locusClusterUrl',
524
+ },
525
+ meetingRequest: {
526
+ joinMeeting: sinon.stub().returns(Promise.resolve({body: {}, headers: {}})),
527
+ },
528
+ getWebexObject: sinon.stub().returns(webex),
529
+ };
530
+
531
+ MeetingUtil.parseLocusJoin = sinon.stub();
532
+ await MeetingUtil.joinMeeting(meeting, {});
533
+
534
+ assert.calledOnce(meeting.meetingRequest.joinMeeting);
535
+ const parameter = meeting.meetingRequest.joinMeeting.getCall(0).args[0];
536
+
537
+ assert.equal(parameter.locusClusterUrl, 'locusClusterUrl');
538
+ });
539
+ });
540
+
541
+ describe('joinMeetingOptions', () => {
542
+ it('sends client events correctly', async () => {
543
+ MeetingUtil.joinMeeting = sinon.stub().rejects({});
544
+ MeetingUtil.isPinOrGuest = sinon.stub().returns(true);
545
+ const meeting = {
546
+ id: 'meeting-id',
547
+ mediaId: '12345',
548
+ selfUrl: 'self url',
549
+ locusInfo: {
550
+ sequence: {},
551
+ },
552
+ locusMediaRequest: {
553
+ send: sinon.stub().resolves({body: {}, headers: {}}),
554
+ },
555
+ getWebexObject: sinon.stub().returns(webex),
556
+ };
557
+
558
+ try {
559
+ await MeetingUtil.joinMeetingOptions(meeting, {pin: true});
560
+
561
+ assert.calledWith(webex.internal.newMetrics.submitClientEvent, {
562
+ name: 'client.pin.collected',
563
+ options: {
564
+ meetingId: meeting.id,
565
+ },
566
+ });
567
+ } catch (err) {
568
+ assert.calledWith(webex.internal.newMetrics.submitClientEvent, {
569
+ name: 'client.pin.prompt',
570
+ options: {
571
+ meetingId: meeting.id,
572
+ },
573
+ });
574
+ }
575
+ });
276
576
  });
277
577
 
278
578
  describe('getUserDisplayHintsFromLocusInfo', () => {
@@ -346,6 +646,30 @@ describe('plugin-meetings', () => {
346
646
  });
347
647
  });
348
648
 
649
+ describe('canUserRenameSelfAndObserved', () => {
650
+ it('works as expected', () => {
651
+ assert.deepEqual(
652
+ MeetingUtil.canUserRenameSelfAndObserved(['CAN_RENAME_SELF_AND_OBSERVED']),
653
+ true
654
+ );
655
+ assert.deepEqual(MeetingUtil.canUserRenameSelfAndObserved([]), false);
656
+ });
657
+ });
658
+
659
+ describe('canUserRenameOthers', () => {
660
+ it('works as expected', () => {
661
+ assert.deepEqual(MeetingUtil.canUserRenameOthers(['CAN_RENAME_OTHERS']), true);
662
+ assert.deepEqual(MeetingUtil.canUserRenameOthers([]), false);
663
+ });
664
+ });
665
+
666
+ describe('canShareWhiteBoard', () => {
667
+ it('works as expected', () => {
668
+ assert.deepEqual(MeetingUtil.canShareWhiteBoard(['SHARE_WHITEBOARD']), true);
669
+ assert.deepEqual(MeetingUtil.canShareWhiteBoard([]), false);
670
+ });
671
+ });
672
+
349
673
  describe('bothLeaveAndEndMeetingAvailable', () => {
350
674
  it('works as expected', () => {
351
675
  assert.deepEqual(
@@ -389,6 +713,7 @@ describe('plugin-meetings', () => {
389
713
  });
390
714
 
391
715
  [
716
+ {functionName: 'isSaveTranscriptsEnabled', displayHint: 'SAVE_TRANSCRIPTS_ENABLED'},
392
717
  {functionName: 'canEnableClosedCaption', displayHint: 'CAPTION_START'},
393
718
  {functionName: 'canStartTranscribing', displayHint: 'TRANSCRIPTION_CONTROL_START'},
394
719
  {functionName: 'canStopTranscribing', displayHint: 'TRANSCRIPTION_CONTROL_STOP'},
@@ -407,17 +732,398 @@ describe('plugin-meetings', () => {
407
732
  });
408
733
  });
409
734
 
410
- describe('reactions', () => {
411
- describe('canEnableReactions', () => {
412
- [[null, DISPLAY_HINTS.ENABLE_REACTIONS, true], [null, DISPLAY_HINTS.DISABLE_REACTIONS, false], [null, undefined, null]].forEach(() => ([originalValue, displayHint, expected]) => {
413
- assert.deepEqual(MeetingUtil.canEnableReactions(originalValue, [displayHint]), expected);
735
+ describe('canManageBreakout', () => {
736
+ it('works as expected', () => {
737
+ assert.deepEqual(MeetingUtil.canManageBreakout(['BREAKOUT_MANAGEMENT']), true);
738
+ assert.deepEqual(MeetingUtil.canManageBreakout([]), false);
739
+ });
740
+ });
741
+
742
+ describe('canBroadcastMessageToBreakout', () => {
743
+ it('works as expected', () => {
744
+ assert.deepEqual(
745
+ MeetingUtil.canBroadcastMessageToBreakout(['BROADCAST_MESSAGE_TO_BREAKOUT'], {
746
+ [SELF_POLICY.SUPPORT_BROADCAST_MESSAGE]: true,
747
+ }),
748
+ true
749
+ );
750
+ assert.deepEqual(
751
+ MeetingUtil.canBroadcastMessageToBreakout([], {
752
+ [SELF_POLICY.SUPPORT_BROADCAST_MESSAGE]: true,
753
+ }),
754
+ false
755
+ );
756
+ assert.deepEqual(
757
+ MeetingUtil.canBroadcastMessageToBreakout(['BROADCAST_MESSAGE_TO_BREAKOUT'], {
758
+ [SELF_POLICY.SUPPORT_BROADCAST_MESSAGE]: false,
759
+ }),
760
+ false
761
+ );
762
+ assert.deepEqual(
763
+ MeetingUtil.canBroadcastMessageToBreakout(['BROADCAST_MESSAGE_TO_BREAKOUT'], undefined),
764
+ false
765
+ );
766
+ });
767
+ });
768
+
769
+ describe('isSuppressBreakoutSupport', () => {
770
+ it('works as expected', () => {
771
+ assert.deepEqual(
772
+ MeetingUtil.isSuppressBreakoutSupport(['UCF_SUPPRESS_BREAKOUTS_SUPPORT']),
773
+ true
774
+ );
775
+ assert.deepEqual(MeetingUtil.isSuppressBreakoutSupport([]), false);
776
+ });
777
+ });
778
+
779
+ describe('canAdmitLobbyToBreakout', () => {
780
+ it('works as expected', () => {
781
+ assert.deepEqual(MeetingUtil.canAdmitLobbyToBreakout(['DISABLE_LOBBY_TO_BREAKOUT']), false);
782
+ assert.deepEqual(MeetingUtil.canAdmitLobbyToBreakout([]), true);
783
+ });
784
+ });
785
+
786
+ describe('canUserAskForHelp', () => {
787
+ it('works as expected', () => {
788
+ assert.deepEqual(MeetingUtil.canUserAskForHelp(['DISABLE_ASK_FOR_HELP']), false);
789
+ assert.deepEqual(MeetingUtil.canUserAskForHelp([]), true);
790
+ });
791
+ });
792
+
793
+ describe('isBreakoutPreassignmentsEnabled', () => {
794
+ it('works as expected', () => {
795
+ assert.deepEqual(
796
+ MeetingUtil.isBreakoutPreassignmentsEnabled(['DISABLE_BREAKOUT_PREASSIGNMENTS']),
797
+ false
798
+ );
799
+ assert.deepEqual(MeetingUtil.isBreakoutPreassignmentsEnabled([]), true);
800
+ });
801
+ });
802
+
803
+ describe('parseInterpretationInfo', () => {
804
+ let meetingInfo = {};
805
+ beforeEach(() => {
806
+ meeting.simultaneousInterpretation = {
807
+ updateMeetingSIEnabled: sinon.stub(),
808
+ updateHostSIEnabled: sinon.stub(),
809
+ updateInterpretation: sinon.stub(),
810
+ siLanguages: [],
811
+ };
812
+ });
813
+ it('should update simultaneous interpretation settings with SI and host enabled', () => {
814
+ meetingInfo.turnOnSimultaneousInterpretation = true;
815
+ meetingInfo.meetingSiteSetting = {
816
+ enableHostInterpreterControlSI: true,
817
+ };
818
+ meetingInfo.simultaneousInterpretation = {
819
+ currentSIInterpreter: true,
820
+ siLanguages: [
821
+ {languageCode: 'en', languageGroupId: 1},
822
+ {languageCode: 'es', languageGroupId: 2},
823
+ ],
824
+ };
825
+
826
+ MeetingUtil.parseInterpretationInfo(meeting, meetingInfo);
827
+ assert.calledWith(meeting.simultaneousInterpretation.updateMeetingSIEnabled, true, true);
828
+ assert.calledWith(meeting.simultaneousInterpretation.updateHostSIEnabled, true);
829
+ assert.calledWith(meeting.simultaneousInterpretation.updateInterpretation, {
830
+ siLanguages: [
831
+ {languageName: 'en', languageCode: 1},
832
+ {languageName: 'es', languageCode: 2},
833
+ ],
414
834
  });
415
835
  });
416
- describe('canEnableReactions', () => {
417
- [[null, DISPLAY_HINTS.REACTIONS_ACTIVE, true], [null, DISPLAY_HINTS.REACTIONS_INACTIVE, false], [null, undefined, null]].forEach(([originalValue, displayHint, expected]) => {
418
- assert.deepEqual(MeetingUtil.canSendReactions(originalValue, [displayHint]), expected);
836
+
837
+ it('should update simultaneous interpretation settings with host SI disabled', () => {
838
+ meetingInfo.meetingSiteSetting.enableHostInterpreterControlSI = false;
839
+ meetingInfo.simultaneousInterpretation.currentSIInterpreter = false;
840
+ MeetingUtil.parseInterpretationInfo(meeting, meetingInfo);
841
+ assert.calledWith(meeting.simultaneousInterpretation.updateMeetingSIEnabled, true, false);
842
+ assert.calledWith(meeting.simultaneousInterpretation.updateHostSIEnabled, false);
843
+ assert.calledWith(meeting.simultaneousInterpretation.updateInterpretation, {
844
+ siLanguages: [
845
+ {languageName: 'en', languageCode: 1},
846
+ {languageName: 'es', languageCode: 2},
847
+ ],
848
+ });
849
+ });
850
+ it('should update simultaneous interpretation settings with SI disabled', () => {
851
+ meetingInfo.turnOnSimultaneousInterpretation = false;
852
+ MeetingUtil.parseInterpretationInfo(meeting, meetingInfo);
853
+ assert.calledWith(meeting.simultaneousInterpretation.updateMeetingSIEnabled, false, false);
854
+ assert.calledWith(meeting.simultaneousInterpretation.updateHostSIEnabled, false);
855
+ });
856
+
857
+ it('should not update simultaneous interpretation settings for invalid input', () => {
858
+ // Call the function with invalid inputs
859
+ MeetingUtil.parseInterpretationInfo(null, null);
860
+
861
+ // Ensure that the update functions are not called
862
+ assert.notCalled(meeting.simultaneousInterpretation.updateMeetingSIEnabled);
863
+ assert.notCalled(meeting.simultaneousInterpretation.updateHostSIEnabled);
864
+ assert.notCalled(meeting.simultaneousInterpretation.updateInterpretation);
865
+ });
866
+ });
867
+
868
+ describe('prepareLeaveMeetingOptions', () => {
869
+ it('works as expected', () => {
870
+ const meeting = {
871
+ locusUrl: 'locusUrl',
872
+ selfId: 'selfId',
873
+ correlationId: 'correlationId',
874
+ resourceId: 'resourceId',
875
+ deviceUrl: 'deviceUrl',
876
+ };
877
+
878
+ const leaveOptions = MeetingUtil.prepareLeaveMeetingOptions(meeting, {
879
+ selfId: 'bob',
880
+ foo: 'bar',
881
+ });
882
+
883
+ assert.deepEqual(leaveOptions, {
884
+ correlationId: 'correlationId',
885
+ deviceUrl: 'deviceUrl',
886
+ foo: 'bar',
887
+ locusUrl: 'locusUrl',
888
+ resourceId: 'resourceId',
889
+ selfId: 'bob',
890
+ });
891
+ });
892
+ });
893
+
894
+ describe('leaveMeeting', () => {
895
+ it('calls prepareLeaveMeetingOptions as expected', () => {
896
+ const meeting = {
897
+ locusUrl: 'locusUrl',
898
+ selfId: 'selfId',
899
+ correlationId: 'correlationId',
900
+ resourceId: 'resourceId',
901
+ deviceUrl: 'deviceUrl',
902
+ locusInfo: {parsedLocus: {}},
903
+ meetingRequest: {
904
+ leaveMeeting: () => Promise.resolve(),
905
+ },
906
+ };
907
+
908
+ const prepareLeaveMeetingOptionsSpy = sinon.spy(MeetingUtil, 'prepareLeaveMeetingOptions');
909
+
910
+ MeetingUtil.leaveMeeting(meeting, {foo: 'bar'});
911
+
912
+ assert.calledOnce(prepareLeaveMeetingOptionsSpy);
913
+ assert.deepEqual(prepareLeaveMeetingOptionsSpy.getCall(0).args[0], meeting);
914
+ assert.deepEqual(prepareLeaveMeetingOptionsSpy.getCall(0).args[1], {foo: 'bar'});
915
+ });
916
+ });
917
+
918
+ describe('buildLeaveFetchRequestOptions', () => {
919
+ it('calls expected functions', () => {
920
+ const buildLeaveMeetingRequestOptionsSpy = sinon.stub();
921
+
922
+ const meeting = {
923
+ locusUrl: 'locusUrl',
924
+ selfId: 'selfId',
925
+ correlationId: 'correlationId',
926
+ resourceId: 'resourceId',
927
+ deviceUrl: 'deviceUrl',
928
+ meetingRequest: {
929
+ leaveMeeting: () => Promise.resolve(),
930
+ buildLeaveMeetingRequestOptions: buildLeaveMeetingRequestOptionsSpy,
931
+ },
932
+ };
933
+
934
+ const prepareLeaveMeetingOptionsSpy = sinon.spy(MeetingUtil, 'prepareLeaveMeetingOptions');
935
+
936
+ const options = MeetingUtil.buildLeaveFetchRequestOptions(meeting, {foo: 'bar'});
937
+
938
+ assert.calledOnce(prepareLeaveMeetingOptionsSpy);
939
+ assert.deepEqual(prepareLeaveMeetingOptionsSpy.getCall(0).args[0], meeting);
940
+ assert.deepEqual(prepareLeaveMeetingOptionsSpy.getCall(0).args[1], {foo: 'bar'});
941
+
942
+ assert.calledOnce(buildLeaveMeetingRequestOptionsSpy);
943
+ assert.deepEqual(buildLeaveMeetingRequestOptionsSpy.getCall(0).args[0], {
944
+ correlationId: 'correlationId',
945
+ deviceUrl: 'deviceUrl',
946
+ foo: 'bar',
947
+ locusUrl: 'locusUrl',
948
+ resourceId: 'resourceId',
949
+ selfId: 'selfId',
950
+ });
951
+ });
952
+ });
953
+
954
+ describe('generateBuildLocusDeltaRequestOptions', () => {
955
+ it('generates the correct wrapper function', async () => {
956
+ const addSequenceSpy = sinon.spy(MeetingUtil, 'addSequence');
957
+
958
+ const meeting = {locusInfo: {sequence: 123}};
959
+
960
+ const buildLocusDeltaRequestOptions =
961
+ MeetingUtil.generateBuildLocusDeltaRequestOptions(meeting);
962
+
963
+ let result = buildLocusDeltaRequestOptions({
964
+ some: 'option',
965
+ body: {},
966
+ });
967
+ assert.deepEqual(result, {some: 'option', body: {sequence: 123}});
968
+ assert.calledOnceWithExactly(addSequenceSpy, meeting, {sequence: 123});
969
+
970
+ addSequenceSpy.resetHistory();
971
+
972
+ // body missing from options
973
+ result = buildLocusDeltaRequestOptions({});
974
+ assert.deepEqual(result, {body: {sequence: 123}});
975
+ assert.calledOnceWithExactly(addSequenceSpy, meeting, {sequence: 123});
976
+
977
+ // meeting disappears so the WeakRef returns undefined
978
+ sinon.stub(WeakRef.prototype, 'deref').returns(undefined);
979
+
980
+ const input = {foo: 'bar'};
981
+ result = buildLocusDeltaRequestOptions(input);
982
+ assert.equal(result, input);
983
+ });
984
+ });
985
+
986
+ describe('getIpVersion', () => {
987
+ let isBrowserStub;
988
+ beforeEach(() => {
989
+ isBrowserStub = sinon.stub().returns(false);
990
+
991
+ sinon.stub(BrowserDetectionModule, 'default').returns({
992
+ isBrowser: isBrowserStub,
993
+ });
994
+ });
995
+
996
+ afterEach(() => {
997
+ sinon.restore();
998
+ });
999
+
1000
+ [
1001
+ {supportsIpV4: undefined, supportsIpV6: undefined, expectedOutput: IP_VERSION.unknown},
1002
+ {supportsIpV4: undefined, supportsIpV6: true, expectedOutput: IP_VERSION.only_ipv6},
1003
+ {supportsIpV4: undefined, supportsIpV6: false, expectedOutput: IP_VERSION.unknown},
1004
+ {supportsIpV4: true, supportsIpV6: undefined, expectedOutput: IP_VERSION.only_ipv4},
1005
+ {supportsIpV4: true, supportsIpV6: true, expectedOutput: IP_VERSION.ipv4_and_ipv6},
1006
+ {supportsIpV4: true, supportsIpV6: false, expectedOutput: IP_VERSION.only_ipv4},
1007
+ {supportsIpV4: false, supportsIpV6: undefined, expectedOutput: IP_VERSION.unknown},
1008
+ {supportsIpV4: false, supportsIpV6: true, expectedOutput: IP_VERSION.only_ipv6},
1009
+ {supportsIpV4: false, supportsIpV6: false, expectedOutput: IP_VERSION.unknown},
1010
+ ].forEach(({supportsIpV4, supportsIpV6, expectedOutput}) => {
1011
+ it(`returns ${expectedOutput} when supportsIpV4=${supportsIpV4} and supportsIpV6=${supportsIpV6}`, () => {
1012
+ sinon
1013
+ .stub(webex.internal.device.ipNetworkDetector, 'supportsIpV4')
1014
+ .get(() => supportsIpV4);
1015
+ sinon
1016
+ .stub(webex.internal.device.ipNetworkDetector, 'supportsIpV6')
1017
+ .get(() => supportsIpV6);
1018
+
1019
+ assert.equal(MeetingUtil.getIpVersion(webex), expectedOutput);
1020
+ });
1021
+
1022
+ it(`returns undefined when supportsIpV4=${supportsIpV4} and supportsIpV6=${supportsIpV6} and browser is firefox`, () => {
1023
+ sinon
1024
+ .stub(webex.internal.device.ipNetworkDetector, 'supportsIpV4')
1025
+ .get(() => supportsIpV4);
1026
+ sinon
1027
+ .stub(webex.internal.device.ipNetworkDetector, 'supportsIpV6')
1028
+ .get(() => supportsIpV6);
1029
+
1030
+ isBrowserStub.callsFake((name) => name === 'firefox');
1031
+
1032
+ assert.equal(MeetingUtil.getIpVersion(webex), undefined);
1033
+ });
1034
+ });
1035
+ });
1036
+
1037
+ describe('getChangeMeetingFloorErrorPayload', () => {
1038
+ [
1039
+ {
1040
+ reason: LOCAL_SHARE_ERRORS.UNDEFINED,
1041
+ expected: {
1042
+ category: 'signaling',
1043
+ errorCode: 1100,
1044
+ },
1045
+ },
1046
+ {
1047
+ reason: LOCAL_SHARE_ERRORS.DEVICE_NOT_JOINED,
1048
+ expected: {
1049
+ category: 'signaling',
1050
+ errorCode: 4050,
1051
+ },
1052
+ },
1053
+ {
1054
+ reason: LOCAL_SHARE_ERRORS.NO_MEDIA_FOR_DEVICE,
1055
+ expected: {
1056
+ category: 'media',
1057
+ errorCode: 2048,
1058
+ },
1059
+ },
1060
+ {
1061
+ reason: LOCAL_SHARE_ERRORS.NO_CONFLUENCE_ID,
1062
+ expected: {
1063
+ category: 'signaling',
1064
+ errorCode: 4064,
1065
+ },
1066
+ },
1067
+ {
1068
+ reason: LOCAL_SHARE_ERRORS.CONTENT_SHARING_DISABLED,
1069
+ expected: {
1070
+ category: 'expected',
1071
+ errorCode: 4065,
1072
+ },
1073
+ },
1074
+ {
1075
+ reason: LOCAL_SHARE_ERRORS.LOCUS_PARTICIPANT_DNE,
1076
+ expected: {
1077
+ category: 'signaling',
1078
+ errorCode: 4066,
1079
+ },
1080
+ },
1081
+ {
1082
+ reason: LOCAL_SHARE_ERRORS.CONTENT_REQUEST_WHILE_PENDING_WHITEBOARD,
1083
+ expected: {
1084
+ category: 'expected',
1085
+ errorCode: 4067,
1086
+ },
1087
+ },
1088
+ {
1089
+ reason: 'some unknown reason',
1090
+ expected: {
1091
+ category: 'signaling',
1092
+ errorCode: 1100,
1093
+ },
1094
+ },
1095
+ ].forEach(({reason, expected}) => {
1096
+ const expectedFull = {
1097
+ errorDescription: reason,
1098
+ name: 'locus.response',
1099
+ shownToUser: false,
1100
+ fatal: true,
1101
+ ...expected,
1102
+ };
1103
+ it(`returns expected when reason="${reason}"`, () => {
1104
+ const result = MeetingUtil.getChangeMeetingFloorErrorPayload(reason);
1105
+ assert.equal(result.length, 1);
1106
+
1107
+ const error = result[0];
1108
+ assert.deepEqual(error, expectedFull);
1109
+ });
1110
+ });
1111
+
1112
+ it('properly handles "includes"', () => {
1113
+ const reason = '>>> ' + LOCAL_SHARE_ERRORS.DEVICE_NOT_JOINED + ' <<<';
1114
+ const result = MeetingUtil.getChangeMeetingFloorErrorPayload(reason);
1115
+ assert.equal(result.length, 1);
1116
+
1117
+ const error = result[0];
1118
+ assert.deepEqual(error, {
1119
+ category: 'signaling',
1120
+ errorCode: 4050,
1121
+ errorDescription: reason,
1122
+ name: 'locus.response',
1123
+ shownToUser: false,
1124
+ fatal: true,
419
1125
  });
420
1126
  });
421
1127
  });
422
- })
1128
+ });
423
1129
  });