@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,102 +1,229 @@
1
1
  import RecordingUtil from '@webex/plugin-meetings/src/recording-controller/util';
2
2
  import RecordingAction from '@webex/plugin-meetings/src/recording-controller/enums';
3
- import { assert } from 'chai';
3
+ import {SELF_POLICY} from '@webex/plugin-meetings/src/constants';
4
+
5
+ import {assert} from 'chai';
4
6
 
5
7
  describe('plugin-meetings', () => {
6
- describe('recording-controller tests', () => {
7
- describe('recording util tests', () => {
8
-
9
- let locusInfo;
10
-
11
- beforeEach(() => {
12
- locusInfo = {
13
- parsedLocus: {
14
- info: {
15
- userDisplayHints: [],
16
- },
17
- },
18
- };
19
- });
20
-
21
- describe('canUserStart', () => {
22
- it('can start recording when the correct display hint is present', () => {
23
- locusInfo.parsedLocus.info.userDisplayHints.push('RECORDING_CONTROL_START');
24
-
25
- assert.equal(RecordingUtil.canUserStart(locusInfo.parsedLocus.info.userDisplayHints), true);
26
- });
27
-
28
- it('rejects when correct display hint is not present', () => {
29
- assert.equal(RecordingUtil.canUserStart(locusInfo.parsedLocus.info.userDisplayHints), false);
30
- });
31
- });
32
-
33
- describe('canUserPause', () => {
34
- it('can pause recording when the correct display hint is present', () => {
35
- locusInfo.parsedLocus.info.userDisplayHints.push('RECORDING_CONTROL_PAUSE');
36
-
37
- assert.equal(RecordingUtil.canUserPause(locusInfo.parsedLocus.info.userDisplayHints), true);
38
- });
39
-
40
- it('rejects when correct display hint is not present', () => {
41
- assert.equal(RecordingUtil.canUserPause(locusInfo.parsedLocus.info.userDisplayHints), false);
42
- });
43
- });
44
-
45
- describe('canUserStop', () => {
46
- it('can stop recording when the correct display hint is present', () => {
47
- locusInfo.parsedLocus.info.userDisplayHints.push('RECORDING_CONTROL_STOP');
48
-
49
- assert.equal(RecordingUtil.canUserStop(locusInfo.parsedLocus.info.userDisplayHints), true);
50
- });
51
-
52
- it('rejects when correct display hint is not present', () => {
53
- assert.equal(RecordingUtil.canUserStop(locusInfo.parsedLocus.info.userDisplayHints), false);
54
- });
55
- });
56
-
57
- describe('canUserResume', () => {
58
- it('can start recording when the correct display hint is present', () => {
59
- locusInfo.parsedLocus.info.userDisplayHints.push('RECORDING_CONTROL_RESUME');
60
-
61
- assert.equal(RecordingUtil.canUserResume(locusInfo.parsedLocus.info.userDisplayHints), true);
62
- });
63
-
64
- it('rejects when correct display hint is not present', () => {
65
- assert.equal(RecordingUtil.canUserResume(locusInfo.parsedLocus.info.userDisplayHints), false);
66
- });
67
- });
68
-
69
- describe('deriveRecordingStates', () => {
70
- it('gets the correct values for a start recording action', () => {
71
- assert.deepEqual(RecordingUtil.deriveRecordingStates(RecordingAction.Start), {recording: true, paused: false});
72
- });
73
-
74
- it('gets the correct values for a stop recording action', () => {
75
- assert.deepEqual(RecordingUtil.deriveRecordingStates(RecordingAction.Stop), {recording: false, paused: false});
76
- });
77
-
78
- it('gets the correct values for a resume recording action', () => {
79
- assert.deepEqual(RecordingUtil.deriveRecordingStates(RecordingAction.Resume), {recording: true, paused: false});
80
- });
81
-
82
- it('gets the correct values for a paused recording action', () => {
83
- assert.deepEqual(RecordingUtil.deriveRecordingStates(RecordingAction.Pause), {recording: true, paused: true});
84
- });
85
- });
86
-
87
- describe('extractLocusId', () => {
88
- it('gets the correct id from the url param', () => {
89
- assert.equal(RecordingUtil.extractLocusId('test/id'), 'id');
90
- });
91
-
92
- it('works with empty string parameters passed', () => {
93
- assert.equal(RecordingUtil.extractLocusId(''), '');
94
- });
95
-
96
- it('works with no parameters passed', () => {
97
- assert.isUndefined(RecordingUtil.extractLocusId(undefined));
98
- });
99
- });
8
+ describe('recording-controller tests', () => {
9
+ describe('recording util tests', () => {
10
+ let locusInfo;
11
+
12
+ beforeEach(() => {
13
+ locusInfo = {
14
+ parsedLocus: {
15
+ info: {
16
+ userDisplayHints: [],
17
+ },
18
+ },
19
+ };
20
+ });
21
+
22
+ describe('canUserStart', () => {
23
+ it('can start recording when the correct display hint is present', () => {
24
+ locusInfo.parsedLocus.info.userDisplayHints.push('RECORDING_CONTROL_START');
25
+
26
+ assert.equal(
27
+ RecordingUtil.canUserStart(locusInfo.parsedLocus.info.userDisplayHints),
28
+ true
29
+ );
30
+ });
31
+
32
+ it('can start recording when the correct display hint is present and the policy is true', () => {
33
+ locusInfo.parsedLocus.info.userDisplayHints.push('RECORDING_CONTROL_START');
34
+
35
+ assert.equal(
36
+ RecordingUtil.canUserStart(locusInfo.parsedLocus.info.userDisplayHints, {
37
+ [SELF_POLICY.SUPPORT_NETWORK_BASED_RECORD]: true,
38
+ }),
39
+ true
40
+ );
41
+ });
42
+
43
+ it('rejects when correct display hint is not present', () => {
44
+ assert.equal(
45
+ RecordingUtil.canUserStart(locusInfo.parsedLocus.info.userDisplayHints),
46
+ false
47
+ );
48
+ });
49
+
50
+ it('rejects when correct display hint is present but policy is false', () => {
51
+ locusInfo.parsedLocus.info.userDisplayHints.push('RECORDING_CONTROL_START');
52
+
53
+ assert.equal(
54
+ RecordingUtil.canUserStart(locusInfo.parsedLocus.info.userDisplayHints, {
55
+ [SELF_POLICY.SUPPORT_NETWORK_BASED_RECORD]: false,
56
+ }),
57
+ false
58
+ );
59
+ });
60
+ });
61
+
62
+ describe('canUserPause', () => {
63
+ it('can pause recording when the correct display hint is present', () => {
64
+ locusInfo.parsedLocus.info.userDisplayHints.push('RECORDING_CONTROL_PAUSE');
65
+
66
+ assert.equal(
67
+ RecordingUtil.canUserPause(locusInfo.parsedLocus.info.userDisplayHints),
68
+ true
69
+ );
70
+ });
71
+
72
+ it('can pause recording when the correct display hint is present and the policy is true', () => {
73
+ locusInfo.parsedLocus.info.userDisplayHints.push('RECORDING_CONTROL_PAUSE');
74
+
75
+ assert.equal(
76
+ RecordingUtil.canUserPause(locusInfo.parsedLocus.info.userDisplayHints, {
77
+ [SELF_POLICY.SUPPORT_NETWORK_BASED_RECORD]: true,
78
+ }),
79
+ true
80
+ );
81
+ });
82
+
83
+ it('rejects when correct display hint is not present', () => {
84
+ assert.equal(
85
+ RecordingUtil.canUserPause(locusInfo.parsedLocus.info.userDisplayHints),
86
+ false
87
+ );
88
+ });
89
+
90
+ it('rejects when correct display hint is present but the policy is false', () => {
91
+ locusInfo.parsedLocus.info.userDisplayHints.push('RECORDING_CONTROL_PAUSE');
92
+
93
+ assert.equal(
94
+ RecordingUtil.canUserPause(locusInfo.parsedLocus.info.userDisplayHints, {
95
+ [SELF_POLICY.SUPPORT_NETWORK_BASED_RECORD]: false,
96
+ }),
97
+ false
98
+ );
99
+ });
100
+ });
101
+
102
+ describe('canUserStop', () => {
103
+ it('can stop recording when the correct display hint is present', () => {
104
+ locusInfo.parsedLocus.info.userDisplayHints.push('RECORDING_CONTROL_STOP');
105
+
106
+ assert.equal(
107
+ RecordingUtil.canUserStop(locusInfo.parsedLocus.info.userDisplayHints),
108
+ true
109
+ );
110
+ });
111
+
112
+ it('can stop recording when the correct display hint is present and the policy is true', () => {
113
+ locusInfo.parsedLocus.info.userDisplayHints.push('RECORDING_CONTROL_STOP', {
114
+ [SELF_POLICY.SUPPORT_NETWORK_BASED_RECORD]: true,
115
+ });
116
+
117
+ assert.equal(
118
+ RecordingUtil.canUserStop(locusInfo.parsedLocus.info.userDisplayHints),
119
+ true
120
+ );
121
+ });
122
+
123
+ it('rejects when correct display hint is not present', () => {
124
+ assert.equal(
125
+ RecordingUtil.canUserStop(locusInfo.parsedLocus.info.userDisplayHints),
126
+ false
127
+ );
128
+ });
129
+
130
+ it('rejects when correct display hint is present but the policy is false', () => {
131
+ locusInfo.parsedLocus.info.userDisplayHints.push('RECORDING_CONTROL_STOP', {
132
+ [SELF_POLICY.SUPPORT_NETWORK_BASED_RECORD]: true,
133
+ });
134
+
135
+ assert.equal(
136
+ RecordingUtil.canUserStop(locusInfo.parsedLocus.info.userDisplayHints, {
137
+ [SELF_POLICY.SUPPORT_NETWORK_BASED_RECORD]: false,
138
+ }),
139
+ false
140
+ );
141
+ });
142
+ });
143
+
144
+ describe('canUserResume', () => {
145
+ it('can start recording when the correct display hint is present', () => {
146
+ locusInfo.parsedLocus.info.userDisplayHints.push('RECORDING_CONTROL_RESUME');
147
+
148
+ assert.equal(
149
+ RecordingUtil.canUserResume(locusInfo.parsedLocus.info.userDisplayHints),
150
+ true
151
+ );
152
+ });
153
+
154
+ it('can start recording when the correct display hint is present and the policy is true', () => {
155
+ locusInfo.parsedLocus.info.userDisplayHints.push('RECORDING_CONTROL_RESUME');
156
+
157
+ assert.equal(
158
+ RecordingUtil.canUserResume(locusInfo.parsedLocus.info.userDisplayHints, {
159
+ [SELF_POLICY.SUPPORT_NETWORK_BASED_RECORD]: true,
160
+ }),
161
+ true
162
+ );
163
+ });
164
+
165
+ it('rejects when correct display hint is not present', () => {
166
+ assert.equal(
167
+ RecordingUtil.canUserResume(locusInfo.parsedLocus.info.userDisplayHints),
168
+ false
169
+ );
170
+ });
171
+
172
+ it('rejects when correct display hint is present but the policy is false', () => {
173
+ locusInfo.parsedLocus.info.userDisplayHints.push('RECORDING_CONTROL_RESUME');
174
+
175
+ assert.equal(
176
+ RecordingUtil.canUserResume(locusInfo.parsedLocus.info.userDisplayHints, {
177
+ [SELF_POLICY.SUPPORT_NETWORK_BASED_RECORD]: false,
178
+ }),
179
+ false
180
+ );
181
+ });
182
+ });
183
+
184
+ describe('deriveRecordingStates', () => {
185
+ it('gets the correct values for a start recording action', () => {
186
+ assert.deepEqual(RecordingUtil.deriveRecordingStates(RecordingAction.Start), {
187
+ recording: true,
188
+ paused: false,
189
+ });
190
+ });
191
+
192
+ it('gets the correct values for a stop recording action', () => {
193
+ assert.deepEqual(RecordingUtil.deriveRecordingStates(RecordingAction.Stop), {
194
+ recording: false,
195
+ paused: false,
196
+ });
197
+ });
198
+
199
+ it('gets the correct values for a resume recording action', () => {
200
+ assert.deepEqual(RecordingUtil.deriveRecordingStates(RecordingAction.Resume), {
201
+ recording: true,
202
+ paused: false,
203
+ });
204
+ });
205
+
206
+ it('gets the correct values for a paused recording action', () => {
207
+ assert.deepEqual(RecordingUtil.deriveRecordingStates(RecordingAction.Pause), {
208
+ recording: true,
209
+ paused: true,
210
+ });
211
+ });
212
+ });
213
+
214
+ describe('extractLocusId', () => {
215
+ it('gets the correct id from the url param', () => {
216
+ assert.equal(RecordingUtil.extractLocusId('test/id'), 'id');
217
+ });
218
+
219
+ it('works with empty string parameters passed', () => {
220
+ assert.equal(RecordingUtil.extractLocusId(''), '');
221
+ });
222
+
223
+ it('works with no parameters passed', () => {
224
+ assert.isUndefined(RecordingUtil.extractLocusId(undefined));
100
225
  });
226
+ });
101
227
  });
102
- });
228
+ });
229
+ });
@@ -1,38 +1,41 @@
1
1
  import {assert} from '@webex/test-helper-chai';
2
2
  import sinon from 'sinon';
3
3
  import TurnDiscovery from '@webex/plugin-meetings/src/roap/turnDiscovery';
4
+ import MockWebex from '@webex/test-helper-mock-webex';
4
5
 
5
6
  import RoapRequest from '@webex/plugin-meetings/src/roap/request';
6
7
  import Roap from '@webex/plugin-meetings/src/roap/';
7
8
  import Meeting from '@webex/plugin-meetings/src/meeting';
9
+ import MeetingUtil from '@webex/plugin-meetings/src/meeting/util';
10
+ import Metrics from '@webex/plugin-meetings/src/metrics';
11
+ import BEHAVIORAL_METRICS from '@webex/plugin-meetings/src/metrics/constants';
12
+
13
+ import { IP_VERSION } from '../../../../src/constants';
8
14
 
9
15
  describe('Roap', () => {
10
16
  describe('doTurnDiscovery', () => {
11
- it('calls this.turnDiscovery.doTurnDiscovery() and forwards all the arguments', async () => {
12
- const RESULT = {something: 'some value'};
13
- const meeting = {id: 'some meeting id'} as Meeting;
14
-
15
- const doTurnDiscoveryStub = sinon
16
- .stub(TurnDiscovery.prototype, 'doTurnDiscovery')
17
- .resolves(RESULT);
17
+ [false, true].forEach(function (isReconnecting) {
18
+ [false, true, undefined].forEach(function (isForced) {
19
+ it(`calls this.turnDiscovery.doTurnDiscovery() and forwards all the arguments when isReconnecting = ${isReconnecting} and isForced = ${isForced}`, async () => {
20
+ const webex = new MockWebex({});
18
21
 
19
- const roap = new Roap({}, {parent: 'fake'});
22
+ const RESULT = {something: 'some value'};
23
+ const meeting = {id: 'some meeting id'} as Meeting;
20
24
 
21
- // call with isReconnecting: true
22
- const result = await roap.doTurnDiscovery(meeting, true);
25
+ const doTurnDiscoveryStub = sinon
26
+ .stub(TurnDiscovery.prototype, 'doTurnDiscovery')
27
+ .resolves(RESULT);
23
28
 
24
- assert.calledOnceWithExactly(doTurnDiscoveryStub, meeting, true);
25
- assert.deepEqual(result, RESULT);
29
+ const roap = new Roap({}, {parent: webex});
26
30
 
27
- doTurnDiscoveryStub.resetHistory();
31
+ const result = await roap.doTurnDiscovery(meeting, isReconnecting, isForced);
28
32
 
29
- // and with isReconnecting: false
30
- const result2 = await roap.doTurnDiscovery(meeting, false);
33
+ assert.calledOnceWithExactly(doTurnDiscoveryStub, meeting, isReconnecting, isForced);
34
+ assert.deepEqual(result, RESULT);
31
35
 
32
- assert.calledOnceWithExactly(doTurnDiscoveryStub, meeting, false);
33
- assert.deepEqual(result2, RESULT);
34
-
35
- sinon.restore();
36
+ sinon.restore();
37
+ });
38
+ });
36
39
  });
37
40
  });
38
41
 
@@ -40,106 +43,200 @@ describe('Roap', () => {
40
43
  let sendRoapStub;
41
44
  let meeting;
42
45
 
46
+ let webex;
47
+ let roap;
48
+
49
+ const fakeLocus = {id: 'fake locus'};
50
+
43
51
  beforeEach(() => {
52
+ webex = new MockWebex({});
44
53
  meeting = {
45
54
  id: 'some meeting id',
46
55
  correlationId: 'correlation id',
47
56
  selfUrl: 'self url',
48
57
  mediaId: 'media id',
49
- audio:{
58
+ audio: {
50
59
  isLocallyMuted: () => true,
51
60
  },
52
- video:{
61
+ video: {
53
62
  isLocallyMuted: () => false,
54
63
  },
64
+ isMultistream: true,
55
65
  setRoapSeq: sinon.stub(),
56
- config: {experimental: {enableTurnDiscovery: false}},
66
+ locusMediaRequest: {fake: true},
67
+ webex: {meetings: {reachability: {isAnyPublicClusterReachable: () => true}}},
68
+ updateMediaConnections: sinon.stub(),
57
69
  };
58
70
 
71
+ sinon.stub(MeetingUtil, 'getIpVersion').returns(IP_VERSION.unknown);
72
+ sinon.stub(Metrics, 'sendBehavioralMetric');
73
+
59
74
  sendRoapStub = sinon.stub(RoapRequest.prototype, 'sendRoap').resolves({});
60
75
  meeting.setRoapSeq.resetHistory();
76
+
77
+ roap = new Roap({}, {parent: webex});
78
+ sinon.stub(roap.turnDiscovery, 'isSkipped').resolves(false);
61
79
  });
62
80
 
63
81
  afterEach(() => {
64
82
  sinon.restore();
65
83
  });
66
84
 
67
- [
68
- {reconnect: true, enableTurnDiscovery: true, expectEmptyMediaId: false},
69
- {reconnect: true, enableTurnDiscovery: false, expectEmptyMediaId: true},
70
- {reconnect: false, enableTurnDiscovery: true, expectEmptyMediaId: false},
71
- {reconnect: false, enableTurnDiscovery: false, expectEmptyMediaId: false},
72
- ].forEach(({reconnect, enableTurnDiscovery, expectEmptyMediaId}) =>
73
- it(`sends roap OFFER with ${expectEmptyMediaId ? 'empty ' : ''}mediaId when ${
74
- reconnect ? '' : 'not '
75
- }reconnecting and TURN discovery is ${
76
- enableTurnDiscovery ? 'enabled' : 'disabled'
77
- }`, async () => {
78
- meeting.config.experimental.enableTurnDiscovery = enableTurnDiscovery;
79
-
80
- const roap = new Roap({}, {parent: 'fake'});
81
-
82
- await roap.sendRoapMediaRequest({
83
- meeting,
84
- sdp: 'sdp',
85
- reconnect,
86
- seq: 2,
87
- tieBreaker: 4294967294,
88
- });
85
+ it(`sends roap OFFER`, async () => {
86
+ await roap.sendRoapMediaRequest({
87
+ meeting,
88
+ sdp: 'sdp',
89
+ seq: 2,
90
+ tieBreaker: 4294967294,
91
+ });
89
92
 
90
- const expectedRoapMessage = {
91
- messageType: 'OFFER',
92
- sdps: ['sdp'],
93
- version: '2',
94
- seq: 2,
95
- tieBreaker: 4294967294,
96
- };
93
+ const expectedRoapMessage = {
94
+ messageType: 'OFFER',
95
+ sdps: ['sdp'],
96
+ version: '2',
97
+ seq: 2,
98
+ tieBreaker: 4294967294,
99
+ headers: ['includeAnswerInHttpResponse', 'noOkInTransaction'],
100
+ };
97
101
 
98
- assert.calledOnce(sendRoapStub);
99
- assert.calledWith(sendRoapStub, {
102
+ assert.calledOnce(sendRoapStub);
103
+ assert.calledWith(
104
+ sendRoapStub,
105
+ sinon.match({
100
106
  roapMessage: expectedRoapMessage,
101
- correlationId: meeting.correlationId,
102
107
  locusSelfUrl: meeting.selfUrl,
103
- mediaId: expectEmptyMediaId ? '' : meeting.mediaId,
104
- audioMuted: meeting.audio?.isLocallyMuted(),
105
- videoMuted: meeting.video?.isLocallyMuted(),
108
+ mediaId: meeting.mediaId,
106
109
  meetingId: meeting.id,
107
- preferTranscoding: true,
108
- });
109
- })
110
- );
111
- it('sends roap request with preferTranscoding=false for multistream meetings', async () => {
112
- const roap = new Roap({}, {parent: 'fake'});
110
+ locusMediaRequest: meeting.locusMediaRequest,
111
+ })
112
+ );
113
+ });
113
114
 
114
- meeting.isMultistream = true;
115
+ it('reads SDP answer from the http response', async () => {
116
+ const roapAnswer = {
117
+ seq: 5,
118
+ messageType: 'ANSWER',
119
+ sdps: ['sdp answer'],
120
+ errorType: 'error type', // normally ANSWER would not have errorType or errorCause (only error messages have these)
121
+ errorCause: 'error cause', // but we're just testing here that all the fields are forwarded to the caller of sendRoapMediaRequest()
122
+ headers: ['header1', 'header2'],
123
+ };
124
+ const fakeMediaConnections = [
125
+ {
126
+ remoteSdp: JSON.stringify({
127
+ roapMessage: roapAnswer,
128
+ }),
129
+ },
130
+ ];
115
131
 
116
- await roap.sendRoapMediaRequest({
132
+ sendRoapStub.resolves({
133
+ mediaConnections: fakeMediaConnections,
134
+ locus: fakeLocus,
135
+ });
136
+
137
+ const result = await roap.sendRoapMediaRequest({
117
138
  meeting,
118
139
  sdp: 'sdp',
119
140
  reconnect: false,
120
- seq: 10,
121
- tieBreaker: 1,
141
+ seq: 1,
142
+ tieBreaker: 4294967294,
122
143
  });
123
144
 
124
- const expectedRoapMessage = {
125
- messageType: 'OFFER',
126
- sdps: ['sdp'],
127
- version: '2',
128
- seq: 10,
129
- tieBreaker: 1,
130
- };
145
+ assert.calledOnce(sendRoapStub);
146
+ assert.calledOnceWithExactly(meeting.updateMediaConnections, fakeMediaConnections);
147
+ assert.deepEqual(result, {
148
+ locus: fakeLocus,
149
+ roapAnswer: {
150
+ seq: 5,
151
+ messageType: 'ANSWER',
152
+ sdp: 'sdp answer',
153
+ errorType: 'error type',
154
+ errorCause: 'error cause',
155
+ headers: ['header1', 'header2'],
156
+ },
157
+ });
158
+ });
159
+
160
+ it('handles the case when there is no answer in the http response', async () => {
161
+ const fakeMediaConnections = [
162
+ {
163
+ // this is the actual value Locus returns to us when they don't send Roap ANSWER in the http response
164
+ remoteSdp:
165
+ '{"audioMuted":false,"videoMuted":false,"csis":[],"dtmfReceiveSupported":true,"type":"SDP"}',
166
+ },
167
+ ];
168
+
169
+ sendRoapStub.resolves({
170
+ mediaConnections: fakeMediaConnections,
171
+ locus: fakeLocus,
172
+ });
173
+
174
+ const result = await roap.sendRoapMediaRequest({
175
+ meeting,
176
+ sdp: 'sdp',
177
+ reconnect: false,
178
+ seq: 1,
179
+ tieBreaker: 4294967294,
180
+ });
131
181
 
132
182
  assert.calledOnce(sendRoapStub);
133
- assert.calledWith(sendRoapStub, {
134
- roapMessage: expectedRoapMessage,
135
- correlationId: meeting.correlationId,
136
- locusSelfUrl: meeting.selfUrl,
137
- mediaId: meeting.mediaId,
138
- audioMuted: meeting.audio.isLocallyMuted(),
139
- videoMuted: meeting.video.isLocallyMuted(),
140
- meetingId: meeting.id,
141
- preferTranscoding: false,
183
+ assert.calledOnceWithExactly(meeting.updateMediaConnections, fakeMediaConnections);
184
+ assert.deepEqual(result, {
185
+ locus: fakeLocus,
186
+ roapAnswer: undefined,
142
187
  });
188
+ assert.calledOnceWithExactly(
189
+ Metrics.sendBehavioralMetric,
190
+ BEHAVIORAL_METRICS.ROAP_HTTP_RESPONSE_MISSING,
191
+ {
192
+ correlationId: meeting.correlationId,
193
+ messageType: 'ANSWER',
194
+ isMultistream: meeting.isMultistream,
195
+ }
196
+ );
197
+ });
198
+
199
+ describe('does not crash when http response is missing things', () => {
200
+ [
201
+ {mediaConnections: undefined, title: 'mediaConnections are undefined'},
202
+ {mediaConnections: [], title: 'mediaConnections are empty array'},
203
+ {mediaConnections: [{}], title: 'mediaConnections[0] has no remoteSdp'},
204
+ {
205
+ mediaConnections: [{remoteSdp: '{}'}],
206
+ title: 'mediaConnections[0].remoteSdp is an empty json',
207
+ },
208
+ ].forEach(({mediaConnections, title}) =>
209
+ it(title, async () => {
210
+ sendRoapStub.resolves({
211
+ mediaConnections,
212
+ locus: fakeLocus,
213
+ });
214
+
215
+ const result = await roap.sendRoapMediaRequest({
216
+ meeting,
217
+ sdp: 'sdp',
218
+ reconnect: false,
219
+ seq: 1,
220
+ tieBreaker: 4294967294,
221
+ });
222
+
223
+ assert.calledOnce(sendRoapStub);
224
+ assert.deepEqual(result, {
225
+ locus: fakeLocus,
226
+ roapAnswer: undefined,
227
+ });
228
+
229
+ assert.calledOnceWithExactly(
230
+ Metrics.sendBehavioralMetric,
231
+ BEHAVIORAL_METRICS.ROAP_HTTP_RESPONSE_MISSING,
232
+ {
233
+ correlationId: meeting.correlationId,
234
+ messageType: 'ANSWER',
235
+ isMultistream: meeting.isMultistream,
236
+ }
237
+ );
238
+ })
239
+ );
143
240
  });
144
241
  });
145
242
  });