@webex/plugin-meetings 3.0.0-beta.4 → 3.0.0-beta.400

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 (629) hide show
  1. package/README.md +58 -8
  2. package/UPGRADING.md +9 -9
  3. package/browsers.js +19 -24
  4. package/dist/annotation/annotation.types.js +7 -0
  5. package/dist/annotation/annotation.types.js.map +1 -0
  6. package/dist/annotation/constants.js +49 -0
  7. package/dist/annotation/constants.js.map +1 -0
  8. package/dist/annotation/index.js +342 -0
  9. package/dist/annotation/index.js.map +1 -0
  10. package/dist/breakouts/breakout.js +216 -0
  11. package/dist/breakouts/breakout.js.map +1 -0
  12. package/dist/breakouts/collection.js +23 -0
  13. package/dist/breakouts/collection.js.map +1 -0
  14. package/dist/breakouts/edit-lock-error.js +52 -0
  15. package/dist/breakouts/edit-lock-error.js.map +1 -0
  16. package/dist/breakouts/events.js +45 -0
  17. package/dist/breakouts/events.js.map +1 -0
  18. package/dist/breakouts/index.js +1048 -0
  19. package/dist/breakouts/index.js.map +1 -0
  20. package/dist/breakouts/request.js +78 -0
  21. package/dist/breakouts/request.js.map +1 -0
  22. package/dist/breakouts/utils.js +67 -0
  23. package/dist/breakouts/utils.js.map +1 -0
  24. package/dist/common/browser-detection.js +1 -20
  25. package/dist/common/browser-detection.js.map +1 -1
  26. package/dist/common/collection.js +5 -20
  27. package/dist/common/collection.js.map +1 -1
  28. package/dist/common/config.js +0 -7
  29. package/dist/common/config.js.map +1 -1
  30. package/dist/common/errors/captcha-error.js +10 -24
  31. package/dist/common/errors/captcha-error.js.map +1 -1
  32. package/dist/common/errors/intent-to-join.js +11 -24
  33. package/dist/common/errors/intent-to-join.js.map +1 -1
  34. package/dist/common/errors/join-meeting.js +12 -25
  35. package/dist/common/errors/join-meeting.js.map +1 -1
  36. package/dist/common/errors/media.js +10 -24
  37. package/dist/common/errors/media.js.map +1 -1
  38. package/dist/common/errors/no-meeting-info.js +51 -0
  39. package/dist/common/errors/no-meeting-info.js.map +1 -0
  40. package/dist/common/errors/parameter.js +5 -33
  41. package/dist/common/errors/parameter.js.map +1 -1
  42. package/dist/common/errors/password-error.js +10 -24
  43. package/dist/common/errors/password-error.js.map +1 -1
  44. package/dist/common/errors/permission.js +9 -23
  45. package/dist/common/errors/permission.js.map +1 -1
  46. package/dist/common/errors/reclaim-host-role-errors.js +158 -0
  47. package/dist/common/errors/reclaim-host-role-errors.js.map +1 -0
  48. package/dist/common/errors/reconnection-in-progress.js +0 -17
  49. package/dist/common/errors/reconnection-in-progress.js.map +1 -1
  50. package/dist/common/errors/reconnection.js +10 -24
  51. package/dist/common/errors/reconnection.js.map +1 -1
  52. package/dist/common/errors/stats.js +10 -24
  53. package/dist/common/errors/stats.js.map +1 -1
  54. package/dist/common/errors/webex-errors.js +54 -48
  55. package/dist/common/errors/webex-errors.js.map +1 -1
  56. package/dist/common/errors/webex-meetings-error.js +5 -25
  57. package/dist/common/errors/webex-meetings-error.js.map +1 -1
  58. package/dist/common/events/events-scope.js +0 -22
  59. package/dist/common/events/events-scope.js.map +1 -1
  60. package/dist/common/events/events.js +0 -23
  61. package/dist/common/events/events.js.map +1 -1
  62. package/dist/common/events/trigger-proxy.js +0 -12
  63. package/dist/common/events/trigger-proxy.js.map +1 -1
  64. package/dist/common/events/util.js +0 -15
  65. package/dist/common/events/util.js.map +1 -1
  66. package/dist/common/logs/logger-config.js +0 -4
  67. package/dist/common/logs/logger-config.js.map +1 -1
  68. package/dist/common/logs/logger-proxy.js +1 -8
  69. package/dist/common/logs/logger-proxy.js.map +1 -1
  70. package/dist/common/logs/request.js +41 -60
  71. package/dist/common/logs/request.js.map +1 -1
  72. package/dist/common/queue.js +28 -23
  73. package/dist/common/queue.js.map +1 -1
  74. package/dist/config.js +11 -15
  75. package/dist/config.js.map +1 -1
  76. package/dist/constants.js +347 -74
  77. package/dist/constants.js.map +1 -1
  78. package/dist/controls-options-manager/constants.js +14 -0
  79. package/dist/controls-options-manager/constants.js.map +1 -0
  80. package/dist/controls-options-manager/enums.js +27 -0
  81. package/dist/controls-options-manager/enums.js.map +1 -0
  82. package/dist/controls-options-manager/index.js +297 -0
  83. package/dist/controls-options-manager/index.js.map +1 -0
  84. package/dist/controls-options-manager/types.js +7 -0
  85. package/dist/controls-options-manager/types.js.map +1 -0
  86. package/dist/controls-options-manager/util.js +319 -0
  87. package/dist/controls-options-manager/util.js.map +1 -0
  88. package/dist/index.js +125 -18
  89. package/dist/index.js.map +1 -1
  90. package/dist/interceptors/index.js +15 -0
  91. package/dist/interceptors/index.js.map +1 -0
  92. package/dist/interceptors/locusRetry.js +93 -0
  93. package/dist/interceptors/locusRetry.js.map +1 -0
  94. package/dist/interpretation/collection.js +23 -0
  95. package/dist/interpretation/collection.js.map +1 -0
  96. package/dist/interpretation/index.js +380 -0
  97. package/dist/interpretation/index.js.map +1 -0
  98. package/dist/interpretation/siLanguage.js +25 -0
  99. package/dist/interpretation/siLanguage.js.map +1 -0
  100. package/dist/locus-info/controlsUtils.js +101 -29
  101. package/dist/locus-info/controlsUtils.js.map +1 -1
  102. package/dist/locus-info/embeddedAppsUtils.js +3 -26
  103. package/dist/locus-info/embeddedAppsUtils.js.map +1 -1
  104. package/dist/locus-info/fullState.js +0 -15
  105. package/dist/locus-info/fullState.js.map +1 -1
  106. package/dist/locus-info/hostUtils.js +4 -12
  107. package/dist/locus-info/hostUtils.js.map +1 -1
  108. package/dist/locus-info/index.js +564 -246
  109. package/dist/locus-info/index.js.map +1 -1
  110. package/dist/locus-info/infoUtils.js +10 -38
  111. package/dist/locus-info/infoUtils.js.map +1 -1
  112. package/dist/locus-info/mediaSharesUtils.js +82 -38
  113. package/dist/locus-info/mediaSharesUtils.js.map +1 -1
  114. package/dist/locus-info/parser.js +314 -163
  115. package/dist/locus-info/parser.js.map +1 -1
  116. package/dist/locus-info/selfUtils.js +110 -92
  117. package/dist/locus-info/selfUtils.js.map +1 -1
  118. package/dist/media/index.js +107 -231
  119. package/dist/media/index.js.map +1 -1
  120. package/dist/media/properties.js +137 -222
  121. package/dist/media/properties.js.map +1 -1
  122. package/dist/media/util.js +2 -9
  123. package/dist/media/util.js.map +1 -1
  124. package/dist/mediaQualityMetrics/config.js +316 -501
  125. package/dist/mediaQualityMetrics/config.js.map +1 -1
  126. package/dist/meeting/in-meeting-actions.js +97 -14
  127. package/dist/meeting/in-meeting-actions.js.map +1 -1
  128. package/dist/meeting/index.js +5311 -3871
  129. package/dist/meeting/index.js.map +1 -1
  130. package/dist/meeting/locusMediaRequest.js +292 -0
  131. package/dist/meeting/locusMediaRequest.js.map +1 -0
  132. package/dist/meeting/muteState.js +260 -183
  133. package/dist/meeting/muteState.js.map +1 -1
  134. package/dist/meeting/request.js +421 -347
  135. package/dist/meeting/request.js.map +1 -1
  136. package/dist/meeting/request.type.js +7 -0
  137. package/dist/meeting/request.type.js.map +1 -0
  138. package/dist/meeting/state.js +21 -31
  139. package/dist/meeting/state.js.map +1 -1
  140. package/dist/meeting/util.js +672 -585
  141. package/dist/meeting/util.js.map +1 -1
  142. package/dist/meeting/voicea-meeting.js +172 -0
  143. package/dist/meeting/voicea-meeting.js.map +1 -0
  144. package/dist/meeting-info/collection.js +6 -25
  145. package/dist/meeting-info/collection.js.map +1 -1
  146. package/dist/meeting-info/index.js +87 -39
  147. package/dist/meeting-info/index.js.map +1 -1
  148. package/dist/meeting-info/meeting-info-v2.js +352 -283
  149. package/dist/meeting-info/meeting-info-v2.js.map +1 -1
  150. package/dist/meeting-info/request.js +3 -15
  151. package/dist/meeting-info/request.js.map +1 -1
  152. package/dist/meeting-info/util.js +99 -183
  153. package/dist/meeting-info/util.js.map +1 -1
  154. package/dist/meeting-info/utilv2.js +147 -234
  155. package/dist/meeting-info/utilv2.js.map +1 -1
  156. package/dist/meetings/collection.js +43 -19
  157. package/dist/meetings/collection.js.map +1 -1
  158. package/dist/meetings/index.js +895 -600
  159. package/dist/meetings/index.js.map +1 -1
  160. package/dist/meetings/meetings.types.js +7 -0
  161. package/dist/meetings/meetings.types.js.map +1 -0
  162. package/dist/meetings/request.js +26 -41
  163. package/dist/meetings/request.js.map +1 -1
  164. package/dist/meetings/util.js +184 -157
  165. package/dist/meetings/util.js.map +1 -1
  166. package/dist/member/index.js +134 -85
  167. package/dist/member/index.js.map +1 -1
  168. package/dist/member/types.js +25 -0
  169. package/dist/member/types.js.map +1 -0
  170. package/dist/member/util.js +158 -88
  171. package/dist/member/util.js.map +1 -1
  172. package/dist/members/collection.js +13 -12
  173. package/dist/members/collection.js.map +1 -1
  174. package/dist/members/index.js +194 -204
  175. package/dist/members/index.js.map +1 -1
  176. package/dist/members/request.js +113 -68
  177. package/dist/members/request.js.map +1 -1
  178. package/dist/members/types.js +15 -0
  179. package/dist/members/types.js.map +1 -0
  180. package/dist/members/util.js +324 -259
  181. package/dist/members/util.js.map +1 -1
  182. package/dist/metrics/constants.js +19 -7
  183. package/dist/metrics/constants.js.map +1 -1
  184. package/dist/metrics/index.js +11 -558
  185. package/dist/metrics/index.js.map +1 -1
  186. package/dist/multistream/mediaRequestManager.js +263 -50
  187. package/dist/multistream/mediaRequestManager.js.map +1 -1
  188. package/dist/multistream/receiveSlot.js +58 -65
  189. package/dist/multistream/receiveSlot.js.map +1 -1
  190. package/dist/multistream/receiveSlotManager.js +76 -95
  191. package/dist/multistream/receiveSlotManager.js.map +1 -1
  192. package/dist/multistream/remoteMedia.js +62 -76
  193. package/dist/multistream/remoteMedia.js.map +1 -1
  194. package/dist/multistream/remoteMediaGroup.js +82 -45
  195. package/dist/multistream/remoteMediaGroup.js.map +1 -1
  196. package/dist/multistream/remoteMediaManager.js +657 -448
  197. package/dist/multistream/remoteMediaManager.js.map +1 -1
  198. package/dist/multistream/sendSlotManager.js +255 -0
  199. package/dist/multistream/sendSlotManager.js.map +1 -0
  200. package/dist/networkQualityMonitor/index.js +40 -59
  201. package/dist/networkQualityMonitor/index.js.map +1 -1
  202. package/dist/personal-meeting-room/index.js +21 -45
  203. package/dist/personal-meeting-room/index.js.map +1 -1
  204. package/dist/personal-meeting-room/request.js +1 -31
  205. package/dist/personal-meeting-room/request.js.map +1 -1
  206. package/dist/personal-meeting-room/util.js +0 -13
  207. package/dist/personal-meeting-room/util.js.map +1 -1
  208. package/dist/reachability/clusterReachability.js +356 -0
  209. package/dist/reachability/clusterReachability.js.map +1 -0
  210. package/dist/reachability/index.js +297 -460
  211. package/dist/reachability/index.js.map +1 -1
  212. package/dist/reachability/request.js +20 -26
  213. package/dist/reachability/request.js.map +1 -1
  214. package/dist/reachability/util.js +29 -0
  215. package/dist/reachability/util.js.map +1 -0
  216. package/dist/reactions/constants.js +13 -0
  217. package/dist/reactions/constants.js.map +1 -0
  218. package/dist/reactions/reactions.js +109 -0
  219. package/dist/reactions/reactions.js.map +1 -0
  220. package/dist/reactions/reactions.type.js +36 -0
  221. package/dist/reactions/reactions.type.js.map +1 -0
  222. package/dist/reconnection-manager/index.js +413 -483
  223. package/dist/reconnection-manager/index.js.map +1 -1
  224. package/dist/recording-controller/enums.js +17 -0
  225. package/dist/recording-controller/enums.js.map +1 -0
  226. package/dist/recording-controller/index.js +362 -0
  227. package/dist/recording-controller/index.js.map +1 -0
  228. package/dist/recording-controller/util.js +64 -0
  229. package/dist/recording-controller/util.js.map +1 -0
  230. package/dist/roap/index.js +102 -86
  231. package/dist/roap/index.js.map +1 -1
  232. package/dist/roap/request.js +131 -135
  233. package/dist/roap/request.js.map +1 -1
  234. package/dist/roap/turnDiscovery.js +437 -116
  235. package/dist/roap/turnDiscovery.js.map +1 -1
  236. package/dist/rtcMetrics/constants.js +12 -0
  237. package/dist/rtcMetrics/constants.js.map +1 -0
  238. package/dist/rtcMetrics/index.js +179 -0
  239. package/dist/rtcMetrics/index.js.map +1 -0
  240. package/dist/statsAnalyzer/global.js +1 -95
  241. package/dist/statsAnalyzer/global.js.map +1 -1
  242. package/dist/statsAnalyzer/index.js +557 -583
  243. package/dist/statsAnalyzer/index.js.map +1 -1
  244. package/dist/statsAnalyzer/mqaUtil.js +326 -130
  245. package/dist/statsAnalyzer/mqaUtil.js.map +1 -1
  246. package/dist/transcription/index.js +22 -47
  247. package/dist/transcription/index.js.map +1 -1
  248. package/dist/types/annotation/annotation.types.d.ts +42 -0
  249. package/dist/types/annotation/constants.d.ts +31 -0
  250. package/dist/types/annotation/index.d.ts +117 -0
  251. package/dist/types/breakouts/breakout.d.ts +8 -0
  252. package/dist/types/breakouts/collection.d.ts +5 -0
  253. package/dist/types/breakouts/edit-lock-error.d.ts +15 -0
  254. package/dist/types/breakouts/events.d.ts +8 -0
  255. package/dist/types/breakouts/index.d.ts +5 -0
  256. package/dist/types/breakouts/request.d.ts +22 -0
  257. package/dist/types/breakouts/utils.d.ts +15 -0
  258. package/dist/types/common/browser-detection.d.ts +9 -0
  259. package/dist/types/common/collection.d.ts +48 -0
  260. package/dist/types/common/config.d.ts +2 -0
  261. package/dist/types/common/errors/captcha-error.d.ts +15 -0
  262. package/dist/types/common/errors/intent-to-join.d.ts +16 -0
  263. package/dist/types/common/errors/join-meeting.d.ts +17 -0
  264. package/dist/types/common/errors/media.d.ts +15 -0
  265. package/dist/types/common/errors/no-meeting-info.d.ts +14 -0
  266. package/dist/types/common/errors/parameter.d.ts +15 -0
  267. package/dist/types/common/errors/password-error.d.ts +15 -0
  268. package/dist/types/common/errors/permission.d.ts +14 -0
  269. package/dist/types/common/errors/reclaim-host-role-errors.d.ts +60 -0
  270. package/dist/types/common/errors/reconnection-in-progress.d.ts +9 -0
  271. package/dist/types/common/errors/reconnection.d.ts +15 -0
  272. package/dist/types/common/errors/stats.d.ts +15 -0
  273. package/dist/types/common/errors/webex-errors.d.ts +93 -0
  274. package/dist/types/common/errors/webex-meetings-error.d.ts +20 -0
  275. package/dist/types/common/events/events-scope.d.ts +17 -0
  276. package/dist/types/common/events/events.d.ts +12 -0
  277. package/dist/types/common/events/trigger-proxy.d.ts +2 -0
  278. package/dist/types/common/events/util.d.ts +2 -0
  279. package/dist/types/common/logs/logger-config.d.ts +2 -0
  280. package/dist/types/common/logs/logger-proxy.d.ts +2 -0
  281. package/dist/types/common/logs/request.d.ts +36 -0
  282. package/dist/types/common/queue.d.ts +34 -0
  283. package/dist/types/config.d.ts +72 -0
  284. package/dist/types/constants.d.ts +1088 -0
  285. package/dist/types/controls-options-manager/constants.d.ts +4 -0
  286. package/dist/types/controls-options-manager/enums.d.ts +15 -0
  287. package/dist/types/controls-options-manager/index.d.ts +136 -0
  288. package/dist/types/controls-options-manager/types.d.ts +43 -0
  289. package/dist/types/controls-options-manager/util.d.ts +1 -0
  290. package/dist/types/index.d.ts +7 -0
  291. package/dist/types/interceptors/index.d.ts +2 -0
  292. package/dist/types/interceptors/locusRetry.d.ts +27 -0
  293. package/dist/types/interpretation/collection.d.ts +5 -0
  294. package/dist/types/interpretation/index.d.ts +5 -0
  295. package/dist/types/interpretation/siLanguage.d.ts +5 -0
  296. package/dist/types/locus-info/controlsUtils.d.ts +2 -0
  297. package/dist/types/locus-info/embeddedAppsUtils.d.ts +2 -0
  298. package/dist/types/locus-info/fullState.d.ts +2 -0
  299. package/dist/types/locus-info/hostUtils.d.ts +2 -0
  300. package/dist/types/locus-info/index.d.ts +322 -0
  301. package/dist/types/locus-info/infoUtils.d.ts +2 -0
  302. package/dist/types/locus-info/mediaSharesUtils.d.ts +2 -0
  303. package/dist/types/locus-info/parser.d.ts +272 -0
  304. package/dist/types/locus-info/selfUtils.d.ts +2 -0
  305. package/dist/types/media/index.d.ts +34 -0
  306. package/dist/types/media/properties.d.ts +93 -0
  307. package/dist/types/media/util.d.ts +2 -0
  308. package/dist/types/mediaQualityMetrics/config.d.ts +241 -0
  309. package/dist/types/meeting/in-meeting-actions.d.ts +167 -0
  310. package/dist/types/meeting/index.d.ts +1824 -0
  311. package/dist/types/meeting/locusMediaRequest.d.ts +74 -0
  312. package/dist/types/meeting/muteState.d.ts +178 -0
  313. package/dist/types/meeting/request.d.ts +293 -0
  314. package/dist/types/meeting/request.type.d.ts +11 -0
  315. package/dist/types/meeting/state.d.ts +9 -0
  316. package/dist/types/meeting/util.d.ts +118 -0
  317. package/dist/types/meeting/voicea-meeting.d.ts +16 -0
  318. package/dist/types/meeting-info/collection.d.ts +20 -0
  319. package/dist/types/meeting-info/index.d.ts +69 -0
  320. package/dist/types/meeting-info/meeting-info-v2.d.ts +123 -0
  321. package/dist/types/meeting-info/request.d.ts +22 -0
  322. package/dist/types/meeting-info/util.d.ts +2 -0
  323. package/dist/types/meeting-info/utilv2.d.ts +2 -0
  324. package/dist/types/meetings/collection.d.ts +40 -0
  325. package/dist/types/meetings/index.d.ts +389 -0
  326. package/dist/types/meetings/meetings.types.d.ts +4 -0
  327. package/dist/types/meetings/request.d.ts +27 -0
  328. package/dist/types/meetings/util.d.ts +18 -0
  329. package/dist/types/member/index.d.ts +160 -0
  330. package/dist/types/member/types.d.ts +32 -0
  331. package/dist/types/member/util.d.ts +2 -0
  332. package/dist/types/members/collection.d.ts +29 -0
  333. package/dist/types/members/index.d.ts +353 -0
  334. package/dist/types/members/request.d.ts +114 -0
  335. package/dist/types/members/types.d.ts +25 -0
  336. package/dist/types/members/util.d.ts +215 -0
  337. package/dist/types/metrics/constants.d.ts +70 -0
  338. package/dist/types/metrics/index.d.ts +45 -0
  339. package/dist/types/multistream/mediaRequestManager.d.ts +120 -0
  340. package/dist/types/multistream/receiveSlot.d.ts +68 -0
  341. package/dist/types/multistream/receiveSlotManager.d.ts +56 -0
  342. package/dist/types/multistream/remoteMedia.d.ts +72 -0
  343. package/dist/types/multistream/remoteMediaGroup.d.ts +49 -0
  344. package/dist/types/multistream/remoteMediaManager.d.ts +301 -0
  345. package/dist/types/multistream/sendSlotManager.d.ts +70 -0
  346. package/dist/types/networkQualityMonitor/index.d.ts +70 -0
  347. package/dist/types/personal-meeting-room/index.d.ts +47 -0
  348. package/dist/types/personal-meeting-room/request.d.ts +14 -0
  349. package/dist/types/personal-meeting-room/util.d.ts +2 -0
  350. package/dist/types/reachability/clusterReachability.d.ts +109 -0
  351. package/dist/types/reachability/index.d.ts +105 -0
  352. package/dist/types/reachability/request.d.ts +39 -0
  353. package/dist/types/reachability/util.d.ts +8 -0
  354. package/dist/types/reactions/constants.d.ts +3 -0
  355. package/dist/types/reactions/reactions.d.ts +4 -0
  356. package/dist/types/reactions/reactions.type.d.ts +52 -0
  357. package/dist/types/reconnection-manager/index.d.ts +136 -0
  358. package/dist/types/recording-controller/enums.d.ts +7 -0
  359. package/dist/types/recording-controller/index.d.ts +207 -0
  360. package/dist/types/recording-controller/util.d.ts +14 -0
  361. package/dist/types/roap/index.d.ts +86 -0
  362. package/dist/types/roap/request.d.ts +39 -0
  363. package/dist/types/roap/turnDiscovery.d.ts +155 -0
  364. package/dist/types/rtcMetrics/constants.d.ts +4 -0
  365. package/dist/types/rtcMetrics/index.d.ts +61 -0
  366. package/dist/types/statsAnalyzer/global.d.ts +36 -0
  367. package/dist/types/statsAnalyzer/index.d.ts +217 -0
  368. package/dist/types/statsAnalyzer/mqaUtil.d.ts +48 -0
  369. package/dist/types/transcription/index.d.ts +64 -0
  370. package/dist/types/webinar/collection.d.ts +16 -0
  371. package/dist/types/webinar/index.d.ts +5 -0
  372. package/dist/webinar/collection.js +44 -0
  373. package/dist/webinar/collection.js.map +1 -0
  374. package/dist/webinar/index.js +69 -0
  375. package/dist/webinar/index.js.map +1 -0
  376. package/internal-README.md +7 -6
  377. package/package.json +30 -21
  378. package/src/annotation/annotation.types.ts +50 -0
  379. package/src/annotation/constants.ts +36 -0
  380. package/src/annotation/index.ts +328 -0
  381. package/src/breakouts/README.md +220 -0
  382. package/src/breakouts/breakout.ts +188 -0
  383. package/src/breakouts/collection.ts +19 -0
  384. package/src/breakouts/edit-lock-error.ts +25 -0
  385. package/src/breakouts/events.ts +56 -0
  386. package/src/breakouts/index.ts +925 -0
  387. package/src/breakouts/request.ts +55 -0
  388. package/src/breakouts/utils.ts +57 -0
  389. package/src/common/{browser-detection.js → browser-detection.ts} +9 -6
  390. package/src/common/collection.ts +9 -7
  391. package/src/common/{config.js → config.ts} +1 -1
  392. package/src/common/errors/{captcha-error.js → captcha-error.ts} +11 -7
  393. package/src/common/errors/{intent-to-join.js → intent-to-join.ts} +12 -7
  394. package/src/common/errors/{join-meeting.js → join-meeting.ts} +17 -8
  395. package/src/common/errors/{media.js → media.ts} +11 -7
  396. package/src/common/errors/no-meeting-info.ts +24 -0
  397. package/src/common/errors/parameter.ts +11 -7
  398. package/src/common/errors/{password-error.js → password-error.ts} +11 -7
  399. package/src/common/errors/{permission.js → permission.ts} +10 -6
  400. package/src/common/errors/reclaim-host-role-errors.ts +134 -0
  401. package/src/common/errors/{reconnection.js → reconnection.ts} +11 -7
  402. package/src/common/errors/{stats.js → stats.ts} +11 -7
  403. package/src/common/errors/{webex-errors.js → webex-errors.ts} +51 -8
  404. package/src/common/errors/{webex-meetings-error.js → webex-meetings-error.ts} +4 -2
  405. package/src/common/events/{events-scope.js → events-scope.ts} +6 -2
  406. package/src/common/events/{events.js → events.ts} +5 -1
  407. package/src/common/events/{trigger-proxy.js → trigger-proxy.ts} +9 -5
  408. package/src/common/events/{util.js → util.ts} +2 -3
  409. package/src/common/logs/{logger-config.js → logger-config.ts} +1 -2
  410. package/src/common/logs/logger-proxy.ts +44 -0
  411. package/src/common/logs/{request.js → request.ts} +26 -9
  412. package/src/common/queue.ts +22 -9
  413. package/src/{config.js → config.ts} +19 -21
  414. package/src/constants.ts +296 -27
  415. package/src/controls-options-manager/constants.ts +5 -0
  416. package/src/controls-options-manager/enums.ts +18 -0
  417. package/src/controls-options-manager/index.ts +278 -0
  418. package/src/controls-options-manager/types.ts +59 -0
  419. package/src/controls-options-manager/util.ts +300 -0
  420. package/src/index.ts +45 -0
  421. package/src/interceptors/index.ts +3 -0
  422. package/src/interceptors/locusRetry.ts +67 -0
  423. package/src/interpretation/README.md +60 -0
  424. package/src/interpretation/collection.ts +19 -0
  425. package/src/interpretation/index.ts +349 -0
  426. package/src/interpretation/siLanguage.ts +18 -0
  427. package/src/locus-info/controlsUtils.ts +222 -0
  428. package/src/locus-info/{embeddedAppsUtils.js → embeddedAppsUtils.ts} +5 -6
  429. package/src/locus-info/{fullState.js → fullState.ts} +16 -12
  430. package/src/locus-info/{hostUtils.js → hostUtils.ts} +9 -8
  431. package/src/locus-info/{index.js → index.ts} +561 -119
  432. package/src/locus-info/{infoUtils.js → infoUtils.ts} +29 -10
  433. package/src/locus-info/{mediaSharesUtils.js → mediaSharesUtils.ts} +97 -17
  434. package/src/locus-info/{parser.js → parser.ts} +303 -104
  435. package/src/locus-info/{selfUtils.js → selfUtils.ts} +199 -68
  436. package/src/media/index.ts +460 -0
  437. package/src/media/properties.ts +283 -0
  438. package/src/media/{util.js → util.ts} +2 -2
  439. package/src/mediaQualityMetrics/config.ts +249 -0
  440. package/src/meeting/in-meeting-actions.ts +199 -3
  441. package/src/meeting/index.ts +8494 -0
  442. package/src/meeting/locusMediaRequest.ts +313 -0
  443. package/src/meeting/muteState.ts +465 -0
  444. package/src/meeting/request.ts +912 -0
  445. package/src/meeting/request.type.ts +13 -0
  446. package/src/meeting/{state.js → state.ts} +50 -35
  447. package/src/meeting/util.ts +799 -0
  448. package/src/meeting/voicea-meeting.ts +122 -0
  449. package/src/meeting-info/{collection.js → collection.ts} +6 -2
  450. package/src/meeting-info/index.ts +210 -0
  451. package/src/meeting-info/meeting-info-v2.ts +423 -0
  452. package/src/meeting-info/{request.js → request.ts} +14 -4
  453. package/src/meeting-info/{util.js → util.ts} +70 -58
  454. package/src/meeting-info/{utilv2.js → utilv2.ts} +99 -82
  455. package/src/meetings/collection.ts +76 -0
  456. package/src/meetings/index.ts +1539 -0
  457. package/src/meetings/meetings.types.ts +12 -0
  458. package/src/meetings/{request.js → request.ts} +34 -25
  459. package/src/meetings/{util.js → util.ts} +133 -38
  460. package/src/member/{index.js → index.ts} +159 -56
  461. package/src/member/types.ts +38 -0
  462. package/src/member/util.ts +397 -0
  463. package/src/members/{collection.js → collection.ts} +10 -2
  464. package/src/members/{index.js → index.ts} +351 -146
  465. package/src/members/request.ts +255 -0
  466. package/src/members/types.ts +29 -0
  467. package/src/members/util.ts +353 -0
  468. package/src/metrics/{constants.js → constants.ts} +17 -6
  469. package/src/metrics/index.ts +73 -0
  470. package/src/multistream/mediaRequestManager.ts +341 -64
  471. package/src/multistream/receiveSlot.ts +69 -26
  472. package/src/multistream/receiveSlotManager.ts +66 -42
  473. package/src/multistream/remoteMedia.ts +40 -5
  474. package/src/multistream/remoteMediaGroup.ts +82 -3
  475. package/src/multistream/remoteMediaManager.ts +401 -81
  476. package/src/multistream/sendSlotManager.ts +199 -0
  477. package/src/networkQualityMonitor/{index.js → index.ts} +41 -29
  478. package/src/personal-meeting-room/{index.js → index.ts} +28 -19
  479. package/src/personal-meeting-room/{request.js → request.ts} +13 -4
  480. package/src/personal-meeting-room/{util.js → util.ts} +4 -4
  481. package/src/reachability/clusterReachability.ts +320 -0
  482. package/src/reachability/index.ts +371 -0
  483. package/src/reachability/request.ts +50 -35
  484. package/src/reachability/util.ts +24 -0
  485. package/src/reactions/constants.ts +4 -0
  486. package/src/reactions/reactions.ts +104 -0
  487. package/src/reactions/reactions.type.ts +62 -0
  488. package/src/reconnection-manager/index.ts +643 -0
  489. package/src/recording-controller/enums.ts +8 -0
  490. package/src/recording-controller/index.ts +332 -0
  491. package/src/recording-controller/util.ts +75 -0
  492. package/src/roap/index.ts +288 -0
  493. package/src/roap/request.ts +153 -0
  494. package/src/roap/turnDiscovery.ts +374 -70
  495. package/src/rtcMetrics/constants.ts +3 -0
  496. package/src/rtcMetrics/index.ts +166 -0
  497. package/src/statsAnalyzer/global.ts +37 -0
  498. package/src/statsAnalyzer/index.ts +1275 -0
  499. package/src/statsAnalyzer/mqaUtil.ts +440 -0
  500. package/src/transcription/{index.js → index.ts} +46 -39
  501. package/src/webinar/collection.ts +31 -0
  502. package/src/webinar/index.ts +62 -0
  503. package/test/integration/spec/converged-space-meetings.js +233 -0
  504. package/test/integration/spec/journey.js +791 -531
  505. package/test/integration/spec/space-meeting.js +391 -204
  506. package/test/integration/spec/transcription.js +7 -8
  507. package/test/unit/spec/annotation/index.ts +418 -0
  508. package/test/unit/spec/breakouts/breakout.ts +238 -0
  509. package/test/unit/spec/breakouts/collection.ts +15 -0
  510. package/test/unit/spec/breakouts/edit-lock-error.ts +30 -0
  511. package/test/unit/spec/breakouts/events.ts +89 -0
  512. package/test/unit/spec/breakouts/index.ts +1793 -0
  513. package/test/unit/spec/breakouts/request.ts +104 -0
  514. package/test/unit/spec/breakouts/utils.js +72 -0
  515. package/test/unit/spec/common/browser-detection.js +9 -28
  516. package/test/unit/spec/common/queue.js +31 -2
  517. package/test/unit/spec/controls-options-manager/index.js +287 -0
  518. package/test/unit/spec/controls-options-manager/util.js +582 -0
  519. package/test/unit/spec/fixture/locus.js +93 -90
  520. package/test/unit/spec/interceptors/locusRetry.ts +131 -0
  521. package/test/unit/spec/interpretation/collection.ts +15 -0
  522. package/test/unit/spec/interpretation/index.ts +625 -0
  523. package/test/unit/spec/interpretation/siLanguage.ts +28 -0
  524. package/test/unit/spec/locus-info/controlsUtils.js +325 -32
  525. package/test/unit/spec/locus-info/embeddedAppsUtils.js +8 -6
  526. package/test/unit/spec/locus-info/index.js +1458 -21
  527. package/test/unit/spec/locus-info/infoUtils.js +71 -40
  528. package/test/unit/spec/locus-info/lib/BasicSeqCmp.json +88 -430
  529. package/test/unit/spec/locus-info/lib/SeqCmp.json +529 -685
  530. package/test/unit/spec/locus-info/mediaSharesUtils.ts +41 -0
  531. package/test/unit/spec/locus-info/parser.js +119 -44
  532. package/test/unit/spec/locus-info/selfConstant.js +120 -103
  533. package/test/unit/spec/locus-info/selfUtils.js +291 -12
  534. package/test/unit/spec/media/index.ts +194 -111
  535. package/test/unit/spec/media/properties.ts +11 -11
  536. package/test/unit/spec/meeting/in-meeting-actions.ts +96 -3
  537. package/test/unit/spec/meeting/index.js +8616 -1921
  538. package/test/unit/spec/meeting/locusMediaRequest.ts +442 -0
  539. package/test/unit/spec/meeting/muteState.js +568 -207
  540. package/test/unit/spec/meeting/request.js +602 -82
  541. package/test/unit/spec/meeting/utils.js +867 -179
  542. package/test/unit/spec/meeting/voicea-meeting.ts +266 -0
  543. package/test/unit/spec/meeting-info/index.js +300 -0
  544. package/test/unit/spec/meeting-info/meetinginfov2.js +631 -78
  545. package/test/unit/spec/meeting-info/request.js +7 -9
  546. package/test/unit/spec/meeting-info/util.js +11 -12
  547. package/test/unit/spec/meeting-info/utilv2.js +131 -74
  548. package/test/unit/spec/meetings/collection.js +27 -1
  549. package/test/unit/spec/meetings/index.js +1826 -374
  550. package/test/unit/spec/meetings/utils.js +243 -14
  551. package/test/unit/spec/member/index.js +61 -7
  552. package/test/unit/spec/member/util.js +526 -26
  553. package/test/unit/spec/members/index.js +536 -55
  554. package/test/unit/spec/members/request.js +228 -40
  555. package/test/unit/spec/members/utils.js +217 -4
  556. package/test/unit/spec/metrics/index.js +13 -68
  557. package/test/unit/spec/multistream/mediaRequestManager.ts +1032 -110
  558. package/test/unit/spec/multistream/receiveSlot.ts +77 -18
  559. package/test/unit/spec/multistream/receiveSlotManager.ts +69 -39
  560. package/test/unit/spec/multistream/remoteMedia.ts +40 -2
  561. package/test/unit/spec/multistream/remoteMediaGroup.ts +350 -5
  562. package/test/unit/spec/multistream/remoteMediaManager.ts +937 -65
  563. package/test/unit/spec/multistream/sendSlotManager.ts +274 -0
  564. package/test/unit/spec/networkQualityMonitor/index.js +24 -18
  565. package/test/unit/spec/personal-meeting-room/personal-meeting-room.js +2 -7
  566. package/test/unit/spec/reachability/clusterReachability.ts +279 -0
  567. package/test/unit/spec/reachability/index.ts +606 -26
  568. package/test/unit/spec/reachability/request.js +68 -0
  569. package/test/unit/spec/reachability/util.ts +40 -0
  570. package/test/unit/spec/reconnection-manager/index.js +222 -34
  571. package/test/unit/spec/recording-controller/index.js +306 -0
  572. package/test/unit/spec/recording-controller/util.js +229 -0
  573. package/test/unit/spec/roap/index.ts +238 -82
  574. package/test/unit/spec/roap/request.ts +255 -0
  575. package/test/unit/spec/roap/turnDiscovery.ts +707 -110
  576. package/test/unit/spec/rtcMetrics/index.ts +122 -0
  577. package/test/unit/spec/stats-analyzer/index.js +1331 -62
  578. package/test/unit/spec/webinar/collection.ts +13 -0
  579. package/test/unit/spec/webinar/index.ts +60 -0
  580. package/test/utils/cmr.js +44 -42
  581. package/test/utils/constants.js +9 -0
  582. package/test/utils/integrationTestUtils.js +46 -0
  583. package/test/utils/testUtils.js +63 -99
  584. package/test/utils/webex-config.js +22 -18
  585. package/test/utils/webex-test-users.js +65 -50
  586. package/tsconfig.json +6 -0
  587. package/dist/media/internal-media-core-wrapper.js +0 -22
  588. package/dist/media/internal-media-core-wrapper.js.map +0 -1
  589. package/dist/meeting/effectsState.js +0 -327
  590. package/dist/meeting/effectsState.js.map +0 -1
  591. package/dist/metrics/config.js +0 -301
  592. package/dist/metrics/config.js.map +0 -1
  593. package/dist/multistream/multistreamMedia.js +0 -116
  594. package/dist/multistream/multistreamMedia.js.map +0 -1
  595. package/dist/peer-connection-manager/util.js +0 -124
  596. package/dist/peer-connection-manager/util.js.map +0 -1
  597. package/src/common/logs/logger-proxy.js +0 -33
  598. package/src/index.js +0 -15
  599. package/src/locus-info/controlsUtils.js +0 -102
  600. package/src/media/index.js +0 -459
  601. package/src/media/internal-media-core-wrapper.ts +0 -9
  602. package/src/media/properties.js +0 -289
  603. package/src/mediaQualityMetrics/config.js +0 -382
  604. package/src/meeting/effectsState.js +0 -205
  605. package/src/meeting/index.js +0 -6284
  606. package/src/meeting/muteState.js +0 -318
  607. package/src/meeting/request.js +0 -684
  608. package/src/meeting/util.js +0 -506
  609. package/src/meeting-info/index.js +0 -131
  610. package/src/meeting-info/meeting-info-v2.js +0 -255
  611. package/src/meetings/collection.js +0 -40
  612. package/src/meetings/index.js +0 -1015
  613. package/src/member/util.js +0 -254
  614. package/src/members/request.js +0 -131
  615. package/src/members/util.js +0 -258
  616. package/src/metrics/config.js +0 -324
  617. package/src/metrics/index.js +0 -530
  618. package/src/multistream/multistreamMedia.ts +0 -92
  619. package/src/peer-connection-manager/util.ts +0 -117
  620. package/src/reachability/index.js +0 -464
  621. package/src/reconnection-manager/index.js +0 -519
  622. package/src/roap/index.js +0 -220
  623. package/src/roap/request.js +0 -127
  624. package/src/statsAnalyzer/global.js +0 -133
  625. package/src/statsAnalyzer/index.js +0 -1006
  626. package/src/statsAnalyzer/mqaUtil.js +0 -173
  627. package/test/unit/spec/meeting/effectsState.js +0 -291
  628. package/test/unit/spec/peerconnection-manager/utils.test-fixtures.ts +0 -389
  629. /package/src/common/errors/{reconnection-in-progress.js → reconnection-in-progress.ts} +0 -0
@@ -2,11 +2,14 @@ import 'jsdom-global/register';
2
2
  import chai from 'chai';
3
3
  import chaiAsPromised from 'chai-as-promised';
4
4
  import sinon from 'sinon';
5
- import {MediaConnection as MC} from '@webex/internal-media-core';
5
+ import {ConnectionState} from '@webex/internal-media-core';
6
6
 
7
7
  import {StatsAnalyzer, EVENTS} from '../../../../src/statsAnalyzer';
8
8
  import NetworkQualityMonitor from '../../../../src/networkQualityMonitor';
9
9
  import testUtils from '../../../utils/testUtils';
10
+ import {MEDIA_DEVICES, MQA_INTERVAL, _UNKNOWN_} from '@webex/plugin-meetings/src/constants';
11
+ import LoggerProxy from '../../../../src/common/logs/logger-proxy';
12
+ import LoggerConfig from '../../../../src/common/logs/logger-config';
10
13
 
11
14
  const {assert} = chai;
12
15
 
@@ -15,36 +18,217 @@ sinon.assert.expose(chai.assert, {prefix: ''});
15
18
 
16
19
  describe('plugin-meetings', () => {
17
20
  describe('StatsAnalyzer', () => {
21
+ describe('parseStatsResult', () => {
22
+ const sandbox = sinon.createSandbox();
23
+ let statsAnalyzer;
24
+
25
+ const initialConfig = {};
26
+ const defaultStats = {};
27
+
28
+ beforeEach(() => {
29
+ const networkQualityMonitor = new NetworkQualityMonitor(initialConfig);
30
+
31
+ statsAnalyzer = new StatsAnalyzer(
32
+ initialConfig,
33
+ () => ({}),
34
+ networkQualityMonitor,
35
+ defaultStats
36
+ );
37
+ });
38
+
39
+ afterEach(() => {
40
+ sandbox.reset();
41
+ });
42
+
43
+ it('should call processOutboundRTPResult', () => {
44
+ const calledSpy = sandbox.spy(statsAnalyzer, 'processOutboundRTPResult');
45
+ statsAnalyzer.parseGetStatsResult({type: 'outbound-rtp'}, 'video-send');
46
+ assert(calledSpy.calledOnce);
47
+ });
48
+
49
+ it('should call processInboundRTPResult', () => {
50
+ const calledSpy = sandbox.spy(statsAnalyzer, 'processInboundRTPResult');
51
+ statsAnalyzer.parseGetStatsResult({type: 'inbound-rtp'}, 'video-recv');
52
+ assert(calledSpy.calledOnce);
53
+ });
54
+
55
+ it('should call compareSentAndReceived', () => {
56
+ const calledSpy = sandbox.spy(statsAnalyzer, 'compareSentAndReceived');
57
+ statsAnalyzer.parseGetStatsResult({type: 'remote-outbound-rtp'}, 'video-send');
58
+ assert(calledSpy.calledOnce);
59
+ });
60
+
61
+ it('should call parseCandidate', () => {
62
+ const calledSpy = sandbox.spy(statsAnalyzer, 'parseCandidate');
63
+ statsAnalyzer.parseGetStatsResult({type: 'local-candidate'}, 'video-send');
64
+ assert(calledSpy.calledOnce);
65
+ });
66
+
67
+ it('processOutboundRTPResult should create the correct stats results', () => {
68
+ // establish the `statsResults` object.
69
+ statsAnalyzer.parseGetStatsResult({type: 'none'}, 'audio-send', true);
70
+
71
+ statsAnalyzer.processOutboundRTPResult(
72
+ {
73
+ bytesSent: 50000,
74
+ codecId: 'RTCCodec_1_Outbound_111',
75
+ headerBytesSent: 25000,
76
+ id: 'RTCOutboundRTPAudioStream_123456789',
77
+ kind: 'audio',
78
+ mediaSourceId: 'RTCAudioSource_2',
79
+ mediaType: 'audio',
80
+ nackCount: 1,
81
+ packetsSent: 3600,
82
+ remoteId: 'RTCRemoteInboundRtpAudioStream_123456789',
83
+ retransmittedBytesSent: 100,
84
+ retransmittedPacketsSent: 2,
85
+ ssrc: 123456789,
86
+ targetBitrate: 256000,
87
+ timestamp: 1707341489336,
88
+ trackId: 'RTCMediaStreamTrack_sender_2',
89
+ transportId: 'RTCTransport_0_1',
90
+ type: 'outbound-rtp',
91
+ },
92
+ 'audio-send',
93
+ true
94
+ );
95
+
96
+ assert.strictEqual(statsAnalyzer.statsResults['audio-send'].send.headerBytesSent, 25000);
97
+ assert.strictEqual(statsAnalyzer.statsResults['audio-send'].send.totalBytesSent, 50000);
98
+ assert.strictEqual(statsAnalyzer.statsResults['audio-send'].send.totalNackCount, 1);
99
+ assert.strictEqual(statsAnalyzer.statsResults['audio-send'].send.totalPacketsSent, 3600);
100
+ assert.strictEqual(
101
+ statsAnalyzer.statsResults['audio-send'].send.retransmittedPacketsSent,
102
+ 2
103
+ );
104
+ assert.strictEqual(
105
+ statsAnalyzer.statsResults['audio-send'].send.retransmittedBytesSent,
106
+ 100
107
+ );
108
+ });
109
+
110
+ it('processInboundRTPResult should create the correct stats results', () => {
111
+ // establish the `statsResults` object.
112
+ statsAnalyzer.parseGetStatsResult({type: 'none'}, 'audio-recv-1', false);
113
+
114
+ statsAnalyzer.processInboundRTPResult(
115
+ {
116
+ audioLevel: 0,
117
+ bytesReceived: 509,
118
+ codecId: 'RTCCodec_6_Inbound_111',
119
+ concealedSamples: 200000,
120
+ concealmentEvents: 13,
121
+ fecPacketsDiscarded: 1,
122
+ fecPacketsReceived: 1,
123
+ headerBytesReceived: 250,
124
+ id: 'RTCInboundRTPAudioStream_123456789',
125
+ insertedSamplesForDeceleration: 0,
126
+ jitter: 0.012,
127
+ jitterBufferDelay: 1000,
128
+ jitterBufferEmittedCount: 10000,
129
+ kind: 'audio',
130
+ lastPacketReceivedTimestamp: 1707341488529,
131
+ mediaType: 'audio',
132
+ packetsDiscarded: 0,
133
+ packetsLost: 0,
134
+ packetsReceived: 12,
135
+ remoteId: 'RTCRemoteOutboundRTPAudioStream_123456789',
136
+ removedSamplesForAcceleration: 0,
137
+ silentConcealedSamples: 200000,
138
+ ssrc: 123456789,
139
+ timestamp: 1707341489419,
140
+ totalAudioEnergy: 133,
141
+ totalSamplesDuration: 7,
142
+ totalSamplesReceived: 300000,
143
+ trackId: 'RTCMediaStreamTrack_receiver_76',
144
+ transportId: 'RTCTransport_0_1',
145
+ type: 'inbound-rtp',
146
+ },
147
+ 'audio-recv-1',
148
+ false
149
+ );
150
+
151
+ assert.strictEqual(
152
+ statsAnalyzer.statsResults['audio-recv-1'].recv.totalPacketsReceived,
153
+ 12
154
+ );
155
+ assert.strictEqual(statsAnalyzer.statsResults['audio-recv-1'].recv.fecPacketsDiscarded, 1);
156
+ assert.strictEqual(statsAnalyzer.statsResults['audio-recv-1'].recv.fecPacketsReceived, 1);
157
+ assert.strictEqual(statsAnalyzer.statsResults['audio-recv-1'].recv.totalBytesReceived, 509);
158
+ assert.strictEqual(
159
+ statsAnalyzer.statsResults['audio-recv-1'].recv.headerBytesReceived,
160
+ 250
161
+ );
162
+ assert.strictEqual(statsAnalyzer.statsResults['audio-recv-1'].recv.audioLevel, 0);
163
+ assert.strictEqual(statsAnalyzer.statsResults['audio-recv-1'].recv.totalAudioEnergy, 133);
164
+ assert.strictEqual(
165
+ statsAnalyzer.statsResults['audio-recv-1'].recv.totalSamplesReceived,
166
+ 300000
167
+ );
168
+ assert.strictEqual(statsAnalyzer.statsResults['audio-recv-1'].recv.totalSamplesDecoded, 0);
169
+ assert.strictEqual(
170
+ statsAnalyzer.statsResults['audio-recv-1'].recv.concealedSamples,
171
+ 200000
172
+ );
173
+ });
174
+
175
+ it('parseAudioSource should create the correct stats results', () => {
176
+ // establish the `statsResults` object.
177
+ statsAnalyzer.parseGetStatsResult({type: 'none'}, 'audio-send', true);
178
+
179
+ statsAnalyzer.parseAudioSource(
180
+ {
181
+ audioLevel: 0.03,
182
+ echoReturnLoss: -30,
183
+ echoReturnLossEnhancement: 0.17,
184
+ id: 'RTCAudioSource_2',
185
+ kind: 'audio',
186
+ timestamp: 1707341488160.012,
187
+ totalAudioEnergy: 0.001,
188
+ totalSamplesDuration: 4.5,
189
+ trackIdentifier: '2207e5bf-c595-4301-93f7-283994d8143f',
190
+ type: 'media-source',
191
+ },
192
+ 'audio-send',
193
+ true
194
+ );
195
+
196
+ assert.strictEqual(statsAnalyzer.statsResults['audio-send'].send.audioLevel, 0.03);
197
+ assert.strictEqual(statsAnalyzer.statsResults['audio-send'].send.totalAudioEnergy, 0.001);
198
+ });
199
+ });
200
+
18
201
  describe('compareSentAndReceived()', () => {
19
202
  let statsAnalyzer;
20
203
  let sandBoxSpy;
21
204
 
22
205
  const initialConfig = {
23
- videoPacketLossRatioThreshold: 9
206
+ videoPacketLossRatioThreshold: 9,
24
207
  };
25
208
 
26
209
  const defaultStats = {
210
+ resolutions: {},
27
211
  internal: {
28
- video: {
212
+ 'video-send-1': {
29
213
  send: {
30
- totalPacketsLostOnReceiver: 10
31
- }
32
- }
214
+ totalPacketsLostOnReceiver: 10,
215
+ },
216
+ },
33
217
  },
34
- video: {
218
+ 'video-send-1': {
35
219
  send: {
36
220
  packetsSent: 2,
37
221
  meanRemoteJitter: [],
38
- meanRoundTripTime: []
39
- }
40
- }
222
+ meanRoundTripTime: [],
223
+ },
224
+ },
41
225
  };
42
226
 
43
227
  const statusResult = {
44
228
  type: 'remote-inbound-rtp',
45
229
  packetsLost: 11,
46
230
  rttThreshold: 501,
47
- jitterThreshold: 501
231
+ jitterThreshold: 501,
48
232
  };
49
233
 
50
234
  const sandbox = sinon.createSandbox();
@@ -52,9 +236,17 @@ describe('plugin-meetings', () => {
52
236
  beforeEach(() => {
53
237
  const networkQualityMonitor = new NetworkQualityMonitor(initialConfig);
54
238
 
55
- statsAnalyzer = new StatsAnalyzer(initialConfig, networkQualityMonitor, defaultStats);
239
+ statsAnalyzer = new StatsAnalyzer(
240
+ initialConfig,
241
+ () => ({}),
242
+ networkQualityMonitor,
243
+ defaultStats
244
+ );
56
245
 
57
- sandBoxSpy = sandbox.spy(statsAnalyzer.networkQualityMonitor, 'determineUplinkNetworkQuality');
246
+ sandBoxSpy = sandbox.spy(
247
+ statsAnalyzer.networkQualityMonitor,
248
+ 'determineUplinkNetworkQuality'
249
+ );
58
250
  });
59
251
 
60
252
  afterEach(() => {
@@ -62,14 +254,16 @@ describe('plugin-meetings', () => {
62
254
  });
63
255
 
64
256
  it('should trigger determineUplinkNetworkQuality with specific arguments', async () => {
65
- await statsAnalyzer.parseGetStatsResult(statusResult, 'video');
257
+ await statsAnalyzer.parseGetStatsResult(statusResult, 'video-send-1', true);
66
258
 
67
259
  assert.calledOnce(statsAnalyzer.networkQualityMonitor.determineUplinkNetworkQuality);
68
- assert(sandBoxSpy.calledWith({
69
- mediaType: 'video',
70
- remoteRtpResults: statusResult,
71
- statsAnalyzerCurrentStats: statsAnalyzer.statsResults
72
- }));
260
+ assert(
261
+ sandBoxSpy.calledWith({
262
+ mediaType: 'video-send-1',
263
+ remoteRtpResults: statusResult,
264
+ statsAnalyzerCurrentStats: statsAnalyzer.statsResults,
265
+ })
266
+ );
73
267
  });
74
268
  });
75
269
 
@@ -78,6 +272,9 @@ describe('plugin-meetings', () => {
78
272
  let pc;
79
273
  let networkQualityMonitor;
80
274
  let statsAnalyzer;
275
+ let mqeData;
276
+ let loggerSpy;
277
+ let receiveSlot;
81
278
 
82
279
  let receivedEventsData = {
83
280
  local: {},
@@ -90,6 +287,8 @@ describe('plugin-meetings', () => {
90
287
 
91
288
  let fakeStats;
92
289
 
290
+ const sandbox = sinon.createSandbox();
291
+
93
292
  const resetReceivedEvents = () => {
94
293
  receivedEventsData = {
95
294
  local: {},
@@ -97,65 +296,248 @@ describe('plugin-meetings', () => {
97
296
  };
98
297
  };
99
298
 
299
+ before(() => {
300
+ LoggerConfig.set({enable: false});
301
+ LoggerProxy.set();
302
+ loggerSpy = sandbox.spy(LoggerProxy.logger, 'info');
303
+ });
304
+
100
305
  beforeEach(() => {
101
306
  clock = sinon.useFakeTimers();
307
+ receiveSlot = undefined;
102
308
 
103
309
  resetReceivedEvents();
104
310
 
105
311
  // bytesReceived and bytesSent need to be non-zero in order for StatsAnalyzer to parse any other values
106
312
  fakeStats = {
107
313
  audio: {
108
- receiver: {
109
- type: 'inbound-rtp',
110
- packetsReceived: 0,
111
- bytesReceived: 1,
112
- },
113
- sender: {
114
- type: 'outbound-rtp',
115
- packetsSent: 0,
116
- bytesSent: 1,
117
- }
314
+ senders: [
315
+ {
316
+ localTrackLabel: 'fake-microphone',
317
+ report: [
318
+ {
319
+ type: 'outbound-rtp',
320
+ bytesSent: 1,
321
+ packetsSent: 0,
322
+ },
323
+ {
324
+ type: 'remote-inbound-rtp',
325
+ packetsLost: 0,
326
+ },
327
+ {
328
+ type: 'candidate-pair',
329
+ state: 'succeeded',
330
+ localCandidateId: 'fake-candidate-id',
331
+ },
332
+ {
333
+ type: 'candidate-pair',
334
+ state: 'failed',
335
+ localCandidateId: 'bad-candidate-id',
336
+ },
337
+ {
338
+ type: 'local-candidate',
339
+ id: 'fake-candidate-id',
340
+ protocol: 'tcp',
341
+ },
342
+ ],
343
+ },
344
+ ],
345
+ receivers: [
346
+ {
347
+ report: [
348
+ {
349
+ type: 'inbound-rtp',
350
+ bytesReceived: 1,
351
+ fecPacketsDiscarded: 0,
352
+ fecPacketsReceived: 0,
353
+ packetsLost: 0,
354
+ packetsReceived: 0,
355
+ },
356
+ {
357
+ type: 'remote-outbound-rtp',
358
+ },
359
+ {
360
+ type: 'candidate-pair',
361
+ state: 'succeeded',
362
+ localCandidateId: 'fake-candidate-id',
363
+ },
364
+ {
365
+ type: 'candidate-pair',
366
+ state: 'failed',
367
+ localCandidateId: 'bad-candidate-id',
368
+ },
369
+ {
370
+ type: 'local-candidate',
371
+ id: 'fake-candidate-id',
372
+ protocol: 'tcp',
373
+ },
374
+ ],
375
+ },
376
+ ],
118
377
  },
119
378
  video: {
120
- receiver: {
121
- type: 'inbound-rtp',
122
- framesDecoded: 0,
123
- bytesReceived: 1,
124
- },
125
- sender: {
126
- type: 'outbound-rtp',
127
- framesSent: 0,
128
- bytesSent: 1,
129
- }
130
- }
379
+ senders: [
380
+ {
381
+ localTrackLabel: 'fake-camera',
382
+ report: [
383
+ {
384
+ type: 'outbound-rtp',
385
+ bytesSent: 1,
386
+ framesSent: 0,
387
+ packetsSent: 0,
388
+ },
389
+ {
390
+ type: 'remote-inbound-rtp',
391
+ packetsLost: 0,
392
+ },
393
+ {
394
+ type: 'candidate-pair',
395
+ state: 'succeeded',
396
+ localCandidateId: 'fake-candidate-id',
397
+ },
398
+ {
399
+ type: 'candidate-pair',
400
+ state: 'failed',
401
+ localCandidateId: 'bad-candidate-id',
402
+ },
403
+ {
404
+ type: 'local-candidate',
405
+ id: 'fake-candidate-id',
406
+ protocol: 'tcp',
407
+ },
408
+ ],
409
+ },
410
+ ],
411
+ receivers: [
412
+ {
413
+ report: [
414
+ {
415
+ type: 'inbound-rtp',
416
+ bytesReceived: 1,
417
+ frameHeight: 720,
418
+ frameWidth: 1280,
419
+ framesDecoded: 0,
420
+ framesReceived: 0,
421
+ packetsLost: 0,
422
+ packetsReceived: 0,
423
+ },
424
+ {
425
+ type: 'remote-outbound-rtp',
426
+ },
427
+ {
428
+ type: 'candidate-pair',
429
+ state: 'succeeded',
430
+ localCandidateId: 'fake-candidate-id',
431
+ },
432
+ {
433
+ type: 'candidate-pair',
434
+ state: 'failed',
435
+ localCandidateId: 'bad-candidate-id',
436
+ },
437
+ {
438
+ type: 'local-candidate',
439
+ id: 'fake-candidate-id',
440
+ protocol: 'tcp',
441
+ },
442
+ ],
443
+ },
444
+ ],
445
+ },
446
+ share: {
447
+ senders: [
448
+ {
449
+ localTrackLabel: 'fake-share',
450
+ report: [
451
+ {
452
+ type: 'outbound-rtp',
453
+ bytesSent: 1,
454
+ framesSent: 0,
455
+ packetsSent: 0,
456
+ },
457
+ {
458
+ type: 'remote-inbound-rtp',
459
+ packetsLost: 0,
460
+ },
461
+ {
462
+ type: 'candidate-pair',
463
+ state: 'succeeded',
464
+ localCandidateId: 'fake-candidate-id',
465
+ },
466
+ {
467
+ type: 'candidate-pair',
468
+ state: 'failed',
469
+ localCandidateId: 'bad-candidate-id',
470
+ },
471
+ {
472
+ type: 'local-candidate',
473
+ id: 'fake-candidate-id',
474
+ protocol: 'tcp',
475
+ },
476
+ ],
477
+ },
478
+ ],
479
+ receivers: [
480
+ {
481
+ report: [
482
+ {
483
+ type: 'inbound-rtp',
484
+ bytesReceived: 1,
485
+ frameHeight: 720,
486
+ frameWidth: 1280,
487
+ framesDecoded: 0,
488
+ framesReceived: 0,
489
+ packetsLost: 0,
490
+ packetsReceived: 0,
491
+ },
492
+ {
493
+ type: 'remote-outbound-rtp',
494
+ },
495
+ {
496
+ type: 'candidate-pair',
497
+ state: 'succeeded',
498
+ localCandidateId: 'fake-candidate-id',
499
+ },
500
+ {
501
+ type: 'candidate-pair',
502
+ state: 'failed',
503
+ localCandidateId: 'bad-candidate-id',
504
+ },
505
+ {
506
+ type: 'local-candidate',
507
+ id: 'fake-candidate-id',
508
+ protocol: 'tcp',
509
+ },
510
+ ],
511
+ },
512
+ ],
513
+ },
131
514
  };
132
515
 
133
516
  pc = {
134
- getConnectionState: sinon.stub().returns(MC.ConnectionState.Connected),
517
+ getConnectionState: sinon.stub().returns(ConnectionState.Connected),
135
518
  getTransceiverStats: sinon.stub().resolves({
136
519
  audio: {
137
- sender: [fakeStats.audio.sender],
138
- receiver: [fakeStats.audio.receiver],
139
- currentDirection: 'sendrecv',
140
- localTrackLabel: 'fake mic',
520
+ senders: [fakeStats.audio.senders[0]],
521
+ receivers: [fakeStats.audio.receivers[0]],
141
522
  },
142
523
  video: {
143
- sender: [fakeStats.video.sender],
144
- receiver: [fakeStats.video.receiver],
145
- currentDirection: 'sendrecv',
146
- localTrackLabel: 'fake camera',
524
+ senders: [fakeStats.video.senders[0]],
525
+ receivers: [fakeStats.video.receivers[0]],
526
+ },
527
+ screenShareAudio: {
528
+ senders: [fakeStats.audio.senders[0]],
529
+ receivers: [fakeStats.audio.receivers[0]],
147
530
  },
148
531
  screenShareVideo: {
149
- sender: [],
150
- receiver: [],
151
- currentDirection: 'sendrecv'
152
- }
153
- })
532
+ senders: [fakeStats.share.senders[0]],
533
+ receivers: [fakeStats.share.receivers[0]],
534
+ },
535
+ }),
154
536
  };
155
537
 
156
538
  networkQualityMonitor = new NetworkQualityMonitor(initialConfig);
157
539
 
158
- statsAnalyzer = new StatsAnalyzer(initialConfig, networkQualityMonitor);
540
+ statsAnalyzer = new StatsAnalyzer(initialConfig, () => receiveSlot, networkQualityMonitor);
159
541
 
160
542
  statsAnalyzer.on(EVENTS.LOCAL_MEDIA_STARTED, (data) => {
161
543
  receivedEventsData.local.started = data;
@@ -169,21 +551,45 @@ describe('plugin-meetings', () => {
169
551
  statsAnalyzer.on(EVENTS.REMOTE_MEDIA_STOPPED, (data) => {
170
552
  receivedEventsData.remote.stopped = data;
171
553
  });
554
+ statsAnalyzer.on(EVENTS.MEDIA_QUALITY, ({data}) => {
555
+ mqeData = data;
556
+ });
172
557
  });
173
558
 
174
559
  afterEach(() => {
560
+ sandbox.reset();
175
561
  clock.restore();
176
562
  });
177
563
 
178
- const startStatsAnalyzer = async (mediaStatus) => {
564
+ const startStatsAnalyzer = async (mediaStatus, lastEmittedEvents) => {
179
565
  statsAnalyzer.updateMediaStatus(mediaStatus);
180
566
  statsAnalyzer.startAnalyzer(pc);
567
+ statsAnalyzer.lastEmittedStartStopEvent = lastEmittedEvents || {};
181
568
 
182
569
  await testUtils.flushPromises();
183
570
  };
184
571
 
185
- const progressTime = async () => {
186
- await clock.tickAsync(initialConfig.analyzerInterval);
572
+ const mergeProperties = (
573
+ target,
574
+ properties,
575
+ keyValue = 'fake-candidate-id',
576
+ matchKey = 'type',
577
+ matchValue = 'local-candidate'
578
+ ) => {
579
+ for (let key in target) {
580
+ if (target.hasOwnProperty(key)) {
581
+ if (typeof target[key] === 'object') {
582
+ mergeProperties(target[key], properties, keyValue, matchKey, matchValue);
583
+ }
584
+ if (key === 'id' && target[key] === keyValue && target[matchKey] === matchValue) {
585
+ Object.assign(target, properties);
586
+ }
587
+ }
588
+ }
589
+ };
590
+
591
+ const progressTime = async (time = initialConfig.analyzerInterval) => {
592
+ await clock.tickAsync(time);
187
593
  await testUtils.flushPromises();
188
594
  };
189
595
 
@@ -195,6 +601,23 @@ describe('plugin-meetings', () => {
195
601
  assert.deepEqual(receivedEventsData.remote.stopped, expected.remote?.stopped);
196
602
  };
197
603
 
604
+ const checkMqeData = () => {
605
+ for (const data of [
606
+ mqeData.audioTransmit,
607
+ mqeData.audioReceive,
608
+ mqeData.videoTransmit,
609
+ mqeData.videoReceive,
610
+ ]) {
611
+ assert.strictEqual(data.length, 2);
612
+ assert.strictEqual(data[0].common.common.isMain, true);
613
+ assert.strictEqual(data[1].common.common.isMain, false);
614
+ }
615
+
616
+ assert.strictEqual(mqeData.videoReceive[0].streams[0].receivedFrameSize, 3600);
617
+ assert.strictEqual(mqeData.videoReceive[0].streams[0].receivedHeight, 720);
618
+ assert.strictEqual(mqeData.videoReceive[0].streams[0].receivedWidth, 1280);
619
+ };
620
+
198
621
  it('emits LOCAL_MEDIA_STARTED and LOCAL_MEDIA_STOPPED events for audio', async () => {
199
622
  await startStatsAnalyzer({expected: {sendAudio: true}});
200
623
 
@@ -202,7 +625,7 @@ describe('plugin-meetings', () => {
202
625
  checkReceivedEvent({expected: {}});
203
626
 
204
627
  // setup a mock to return some values higher the previous ones
205
- fakeStats.audio.sender.packetsSent += 10;
628
+ fakeStats.audio.senders[0].report[0].packetsSent += 10;
206
629
 
207
630
  await progressTime();
208
631
 
@@ -222,7 +645,7 @@ describe('plugin-meetings', () => {
222
645
  checkReceivedEvent({expected: {}});
223
646
 
224
647
  // setup a mock to return some values higher the previous ones
225
- fakeStats.video.sender.framesSent += 1;
648
+ fakeStats.video.senders[0].report[0].framesSent += 1;
226
649
 
227
650
  await progressTime();
228
651
 
@@ -235,6 +658,26 @@ describe('plugin-meetings', () => {
235
658
  checkReceivedEvent({expected: {local: {stopped: {type: 'video'}}}});
236
659
  });
237
660
 
661
+ it('emits LOCAL_MEDIA_STARTED and LOCAL_MEDIA_STOPPED events for share', async () => {
662
+ await startStatsAnalyzer({expected: {sendShare: true}});
663
+
664
+ // check that we haven't received any events yet
665
+ checkReceivedEvent({expected: {}});
666
+
667
+ // setup a mock to return some values higher the previous ones
668
+ fakeStats.share.senders[0].report[0].framesSent += 1;
669
+
670
+ await progressTime();
671
+
672
+ // check that we got the LOCAL_MEDIA_STARTED event for audio
673
+ checkReceivedEvent({expected: {local: {started: {type: 'share'}}}});
674
+
675
+ // now advance the clock and the mock still returns same values, so only "stopped" event should be triggered
676
+ resetReceivedEvents();
677
+ await progressTime();
678
+ checkReceivedEvent({expected: {local: {stopped: {type: 'share'}}}});
679
+ });
680
+
238
681
  it('emits REMOTE_MEDIA_STARTED and REMOTE_MEDIA_STOPPED events for audio', async () => {
239
682
  await startStatsAnalyzer({expected: {receiveAudio: true}});
240
683
 
@@ -242,7 +685,7 @@ describe('plugin-meetings', () => {
242
685
  checkReceivedEvent({expected: {}});
243
686
 
244
687
  // setup a mock to return some values higher the previous ones
245
- fakeStats.audio.receiver.packetsReceived += 5;
688
+ fakeStats.audio.receivers[0].report[0].packetsReceived += 5;
246
689
 
247
690
  await progressTime();
248
691
  // check that we got the REMOTE_MEDIA_STARTED event for audio
@@ -262,7 +705,7 @@ describe('plugin-meetings', () => {
262
705
  checkReceivedEvent({expected: {}});
263
706
 
264
707
  // setup a mock to return some values higher the previous ones
265
- fakeStats.video.receiver.framesDecoded += 1;
708
+ fakeStats.video.receivers[0].report[0].framesDecoded += 1;
266
709
 
267
710
  await progressTime();
268
711
  // check that we got the REMOTE_MEDIA_STARTED event for video
@@ -274,6 +717,832 @@ describe('plugin-meetings', () => {
274
717
 
275
718
  checkReceivedEvent({expected: {remote: {stopped: {type: 'video'}}}});
276
719
  });
720
+
721
+ it('emits REMOTE_MEDIA_STARTED and REMOTE_MEDIA_STOPPED events for share', async () => {
722
+ await startStatsAnalyzer({expected: {receiveShare: true}});
723
+
724
+ // check that we haven't received any events yet
725
+ checkReceivedEvent({expected: {}});
726
+
727
+ // setup a mock to return some values higher the previous ones
728
+ fakeStats.share.receivers[0].report[0].framesDecoded += 1;
729
+
730
+ await progressTime();
731
+ // check that we got the REMOTE_MEDIA_STARTED event for video
732
+ checkReceivedEvent({expected: {remote: {started: {type: 'share'}}}});
733
+
734
+ // now advance the clock and the mock still returns same values, so only "stopped" event should be triggered
735
+ resetReceivedEvents();
736
+ await progressTime();
737
+
738
+ checkReceivedEvent({expected: {remote: {stopped: {type: 'share'}}}});
739
+ });
740
+
741
+ it('emits the correct MEDIA_QUALITY events', async () => {
742
+ await startStatsAnalyzer({expected: {receiveVideo: true}});
743
+
744
+ await progressTime();
745
+
746
+ // Check that the mqe data has been emitted and is correctly computed.
747
+ checkMqeData();
748
+ });
749
+
750
+ it('emits the correct transportType in MEDIA_QUALITY events', async () => {
751
+ await startStatsAnalyzer({expected: {receiveVideo: true}});
752
+
753
+ await progressTime();
754
+
755
+ assert.strictEqual(mqeData.audioTransmit[0].common.transportType, 'TCP');
756
+ assert.strictEqual(mqeData.videoReceive[0].common.transportType, 'TCP');
757
+ });
758
+
759
+ it('emits the correct transportType in MEDIA_QUALITY events when using a TURN server', async () => {
760
+ fakeStats.audio.senders[0].report[4].relayProtocol = 'tls';
761
+ fakeStats.video.senders[0].report[4].relayProtocol = 'tls';
762
+ fakeStats.audio.receivers[0].report[4].relayProtocol = 'tls';
763
+ fakeStats.video.receivers[0].report[4].relayProtocol = 'tls';
764
+
765
+ await startStatsAnalyzer({expected: {receiveVideo: true}});
766
+
767
+ await progressTime();
768
+
769
+ assert.strictEqual(mqeData.audioTransmit[0].common.transportType, 'TLS');
770
+ assert.strictEqual(mqeData.videoReceive[0].common.transportType, 'TLS');
771
+ });
772
+
773
+ it('emits the correct peripherals in MEDIA_QUALITY events', async () => {
774
+ await startStatsAnalyzer({expected: {receiveVideo: true}});
775
+
776
+ await progressTime();
777
+
778
+ assert.strictEqual(
779
+ mqeData.intervalMetadata.peripherals.find((val) => val.name === MEDIA_DEVICES.MICROPHONE)
780
+ .information,
781
+ 'fake-microphone'
782
+ );
783
+ assert.strictEqual(
784
+ mqeData.intervalMetadata.peripherals.find((val) => val.name === MEDIA_DEVICES.CAMERA)
785
+ .information,
786
+ 'fake-camera'
787
+ );
788
+ });
789
+
790
+ it('emits the correct peripherals in MEDIA_QUALITY events when localTrackLabel is undefined', async () => {
791
+ fakeStats.audio.senders[0].localTrackLabel = undefined;
792
+ fakeStats.video.senders[0].localTrackLabel = undefined;
793
+
794
+ await startStatsAnalyzer({expected: {receiveVideo: true}});
795
+
796
+ await progressTime();
797
+
798
+ assert.strictEqual(
799
+ mqeData.intervalMetadata.peripherals.find((val) => val.name === MEDIA_DEVICES.MICROPHONE)
800
+ .information,
801
+ _UNKNOWN_
802
+ );
803
+ assert.strictEqual(
804
+ mqeData.intervalMetadata.peripherals.find((val) => val.name === MEDIA_DEVICES.CAMERA)
805
+ .information,
806
+ _UNKNOWN_
807
+ );
808
+ });
809
+
810
+ it('emits the correct transmittedFrameRate/receivedFrameRate', async () => {
811
+ it('at the start of the stats analyzer', async () => {
812
+ await startStatsAnalyzer();
813
+ assert.strictEqual(mqeData.videoTransmit[0].streams[0].common.transmittedFrameRate, 0);
814
+ assert.strictEqual(mqeData.videoReceive[0].streams[0].common.receivedFrameRate, 0);
815
+ });
816
+
817
+ it('after frames are sent and received', async () => {
818
+ fakeStats.video.senders[0].report[0].framesSent += 300;
819
+ fakeStats.video.receivers[0].report[0].framesReceived += 300;
820
+ await progressTime(MQA_INTERVAL);
821
+
822
+ // 300 frames in 60 seconds = 5 frames per second
823
+ assert.strictEqual(mqeData.videoTransmit[0].streams[0].common.transmittedFrameRate, 5);
824
+ assert.strictEqual(mqeData.videoReceive[0].streams[0].common.receivedFrameRate, 5);
825
+ });
826
+ });
827
+
828
+ it('emits the correct rtpPackets', async () => {
829
+ it('at the start of the stats analyzer', async () => {
830
+ await startStatsAnalyzer();
831
+ assert.strictEqual(mqeData.audioTransmit[0].common.rtpPackets, 0);
832
+ assert.strictEqual(mqeData.audioTransmit[0].streams[0].common.rtpPackets, 0);
833
+ assert.strictEqual(mqeData.audioReceive[0].common.rtpPackets, 0);
834
+ assert.strictEqual(mqeData.audioReceive[0].streams[0].common.rtpPackets, 0);
835
+ assert.strictEqual(mqeData.videoTransmit[0].common.rtpPackets, 0);
836
+ assert.strictEqual(mqeData.videoTransmit[0].streams[0].common.rtpPackets, 0);
837
+ assert.strictEqual(mqeData.videoReceive[0].common.rtpPackets, 0);
838
+ assert.strictEqual(mqeData.videoReceive[0].streams[0].common.rtpPackets, 0);
839
+ });
840
+
841
+ it('after packets are sent', async () => {
842
+ fakeStats.audio.senders[0].report[0].packetsSent += 5;
843
+ fakeStats.video.senders[0].report[0].packetsSent += 5;
844
+ await progressTime(MQA_INTERVAL);
845
+
846
+ assert.strictEqual(mqeData.audioTransmit[0].common.rtpPackets, 5);
847
+ assert.strictEqual(mqeData.audioTransmit[0].streams[0].common.rtpPackets, 5);
848
+ assert.strictEqual(mqeData.videoTransmit[0].common.rtpPackets, 5);
849
+ assert.strictEqual(mqeData.videoTransmit[0].streams[0].common.rtpPackets, 5);
850
+ });
851
+
852
+ it('after packets are received', async () => {
853
+ fakeStats.audio.senders[0].report[0].packetsSent += 10;
854
+ fakeStats.video.senders[0].report[0].packetsSent += 10;
855
+ fakeStats.audio.receivers[0].report[0].packetsReceived += 10;
856
+ fakeStats.video.receivers[0].report[0].packetsReceived += 10;
857
+ await progressTime(MQA_INTERVAL);
858
+
859
+ assert.strictEqual(mqeData.audioReceive[0].common.rtpPackets, 10);
860
+ assert.strictEqual(mqeData.audioReceive[0].streams[0].common.rtpPackets, 10);
861
+ assert.strictEqual(mqeData.videoReceive[0].common.rtpPackets, 10);
862
+ assert.strictEqual(mqeData.videoReceive[0].streams[0].common.rtpPackets, 10);
863
+ });
864
+ });
865
+
866
+ it('emits the correct fecPackets', async () => {
867
+ it('at the start of the stats analyzer', async () => {
868
+ await startStatsAnalyzer();
869
+ assert.strictEqual(mqeData.audioReceive[0].common.fecPackets, 0);
870
+ });
871
+
872
+ it('after FEC packets are received', async () => {
873
+ fakeStats.audio.receivers[0].report[0].fecPacketsReceived += 5;
874
+ await progressTime(MQA_INTERVAL);
875
+
876
+ assert.strictEqual(mqeData.audioReceive[0].common.fecPackets, 5);
877
+ });
878
+
879
+ it('after FEC packets are received and some FEC packets are discarded', async () => {
880
+ fakeStats.audio.receivers[0].report[0].fecPacketsReceived += 15;
881
+ fakeStats.audio.receivers[0].report[0].fecPacketsDiscarded += 5;
882
+ await progressTime(MQA_INTERVAL);
883
+
884
+ assert.strictEqual(mqeData.audioReceive[0].common.fecPackets, 10);
885
+ });
886
+ });
887
+
888
+ it('emits the correct mediaHopByHopLost/rtpHopByHopLost', async () => {
889
+ it('at the start of the stats analyzer', async () => {
890
+ await startStatsAnalyzer();
891
+ assert.strictEqual(mqeData.audioReceive[0].common.mediaHopByHopLost, 0);
892
+ assert.strictEqual(mqeData.audioReceive[0].common.rtpHopByHopLost, 0);
893
+ assert.strictEqual(mqeData.videoReceive[0].common.mediaHopByHopLost, 0);
894
+ assert.strictEqual(mqeData.videoReceive[0].common.rtpHopByHopLost, 0);
895
+ });
896
+
897
+ it('after packets are lost', async () => {
898
+ fakeStats.audio.receivers[0].report[0].packetsLost += 5;
899
+ fakeStats.video.receivers[0].report[0].packetsLost += 5;
900
+ await progressTime(MQA_INTERVAL);
901
+
902
+ assert.strictEqual(mqeData.audioReceive[0].common.mediaHopByHopLost, 5);
903
+ assert.strictEqual(mqeData.audioReceive[0].common.rtpHopByHopLost, 5);
904
+ assert.strictEqual(mqeData.videoReceive[0].common.mediaHopByHopLost, 5);
905
+ assert.strictEqual(mqeData.videoReceive[0].common.rtpHopByHopLost, 5);
906
+ });
907
+ });
908
+
909
+ it('emits the correct remoteLossRate', async () => {
910
+ it('at the start of the stats analyzer', async () => {
911
+ await startStatsAnalyzer();
912
+ assert.strictEqual(mqeData.audioTransmit[0].common.remoteLossRate, 0);
913
+ assert.strictEqual(mqeData.videoTransmit[0].common.remoteLossRate, 0);
914
+ });
915
+
916
+ it('after packets are sent', async () => {
917
+ fakeStats.audio.senders[0].report[0].packetsSent += 100;
918
+ fakeStats.video.senders[0].report[0].packetsSent += 100;
919
+ await progressTime(MQA_INTERVAL);
920
+
921
+ assert.strictEqual(mqeData.audioTransmit[0].common.remoteLossRate, 0);
922
+ assert.strictEqual(mqeData.videoTransmit[0].common.remoteLossRate, 0);
923
+ });
924
+
925
+ it('after packets are sent and some packets are lost', async () => {
926
+ fakeStats.audio.senders[0].report[0].packetsSent += 200;
927
+ fakeStats.audio.senders[0].report[1].packetsLost += 10;
928
+ fakeStats.video.senders[0].report[0].packetsSent += 200;
929
+ fakeStats.video.senders[0].report[1].packetsLost += 10;
930
+ await progressTime(MQA_INTERVAL);
931
+
932
+ assert.strictEqual(mqeData.audioTransmit[0].common.remoteLossRate, 5);
933
+ assert.strictEqual(mqeData.videoTransmit[0].common.remoteLossRate, 5);
934
+ });
935
+ });
936
+
937
+ it('has the correct localIpAddress set when the candidateType is host', async () => {
938
+ await startStatsAnalyzer();
939
+
940
+ await progressTime();
941
+ assert.strictEqual(statsAnalyzer.getLocalIpAddress(), '');
942
+ mergeProperties(fakeStats, {address: 'test', candidateType: 'host'});
943
+ await progressTime();
944
+ assert.strictEqual(statsAnalyzer.getLocalIpAddress(), 'test');
945
+ });
946
+
947
+ it('has the correct localIpAddress set when the candidateType is prflx and relayProtocol is set', async () => {
948
+ await startStatsAnalyzer();
949
+
950
+ await progressTime();
951
+ assert.strictEqual(statsAnalyzer.getLocalIpAddress(), '');
952
+ mergeProperties(fakeStats, {
953
+ relayProtocol: 'test',
954
+ address: 'test2',
955
+ candidateType: 'prflx',
956
+ });
957
+ await progressTime();
958
+ assert.strictEqual(statsAnalyzer.getLocalIpAddress(), 'test2');
959
+ });
960
+
961
+ it('has the correct localIpAddress set when the candidateType is prflx and relayProtocol is not set', async () => {
962
+ await startStatsAnalyzer();
963
+
964
+ await progressTime();
965
+ assert.strictEqual(statsAnalyzer.getLocalIpAddress(), '');
966
+ mergeProperties(fakeStats, {
967
+ relatedAddress: 'relatedAddress',
968
+ address: 'test2',
969
+ candidateType: 'prflx',
970
+ });
971
+ await progressTime();
972
+ assert.strictEqual(statsAnalyzer.getLocalIpAddress(), 'relatedAddress');
973
+ });
974
+
975
+ it('has no localIpAddress set when the candidateType is invalid', async () => {
976
+ await startStatsAnalyzer();
977
+
978
+ await progressTime();
979
+ assert.strictEqual(statsAnalyzer.getLocalIpAddress(), '');
980
+ mergeProperties(fakeStats, {candidateType: 'invalid'});
981
+ await progressTime();
982
+ assert.strictEqual(statsAnalyzer.getLocalIpAddress(), '');
983
+ });
984
+
985
+ it('logs a message when audio send packets do not increase', async () => {
986
+ await startStatsAnalyzer(
987
+ {expected: {sendAudio: true}},
988
+ {audio: {local: EVENTS.LOCAL_MEDIA_STARTED}}
989
+ );
990
+
991
+ // don't increase the packets when time progresses.
992
+ await progressTime();
993
+
994
+ assert(
995
+ loggerSpy.calledWith(
996
+ 'StatsAnalyzer:index#compareLastStatsResult --> No audio RTP packets sent'
997
+ )
998
+ );
999
+ });
1000
+
1001
+ it('does not log a message when audio send packets increase', async () => {
1002
+ await startStatsAnalyzer(
1003
+ {expected: {sendAudio: true}},
1004
+ {audio: {local: EVENTS.LOCAL_MEDIA_STOPPED}}
1005
+ );
1006
+
1007
+ fakeStats.audio.senders[0].report[0].packetsSent += 5;
1008
+ await progressTime();
1009
+
1010
+ assert(
1011
+ loggerSpy.neverCalledWith(
1012
+ 'StatsAnalyzer:index#compareLastStatsResult --> No audio RTP packets sent'
1013
+ )
1014
+ );
1015
+ });
1016
+
1017
+ it('logs a message when video send packets do not increase', async () => {
1018
+ await startStatsAnalyzer(
1019
+ {expected: {sendVideo: true}},
1020
+ {video: {local: EVENTS.LOCAL_MEDIA_STARTED}}
1021
+ );
1022
+
1023
+ // don't increase the packets when time progresses.
1024
+ await progressTime();
1025
+
1026
+ assert(
1027
+ loggerSpy.calledWith(
1028
+ 'StatsAnalyzer:index#compareLastStatsResult --> No video RTP packets sent'
1029
+ )
1030
+ );
1031
+ });
1032
+
1033
+ it('does not log a message when video send packets increase', async () => {
1034
+ await startStatsAnalyzer(
1035
+ {expected: {sendVideo: true}},
1036
+ {video: {local: EVENTS.LOCAL_MEDIA_STOPPED}}
1037
+ );
1038
+
1039
+ fakeStats.video.senders[0].report[0].packetsSent += 5;
1040
+ await progressTime();
1041
+
1042
+ assert(
1043
+ loggerSpy.neverCalledWith(
1044
+ 'StatsAnalyzer:index#compareLastStatsResult --> No video RTP packets sent'
1045
+ )
1046
+ );
1047
+ });
1048
+
1049
+ it('logs a message when share send packets do not increase', async () => {
1050
+ await startStatsAnalyzer(
1051
+ {expected: {sendShare: true}},
1052
+ {share: {local: EVENTS.LOCAL_MEDIA_STARTED}}
1053
+ );
1054
+
1055
+ // don't increase the packets when time progresses.
1056
+ await progressTime();
1057
+
1058
+ assert(
1059
+ loggerSpy.calledWith(
1060
+ 'StatsAnalyzer:index#compareLastStatsResult --> No share RTP packets sent'
1061
+ )
1062
+ );
1063
+ });
1064
+
1065
+ it('does not log a message when share send packets increase', async () => {
1066
+ await startStatsAnalyzer(
1067
+ {expected: {sendShare: true}},
1068
+ {share: {local: EVENTS.LOCAL_MEDIA_STOPPED}}
1069
+ );
1070
+
1071
+ fakeStats.share.senders[0].report[0].packetsSent += 5;
1072
+ await progressTime();
1073
+
1074
+ assert(
1075
+ loggerSpy.neverCalledWith(
1076
+ 'StatsAnalyzer:index#compareLastStatsResult --> No share RTP packets sent'
1077
+ )
1078
+ );
1079
+ });
1080
+
1081
+ ['avatar', 'invalid', 'no source', 'bandwidth limited', 'policy violation'].forEach(
1082
+ (sourceState) => {
1083
+ it(`does not log a message when no packets are recieved for a receive slot with sourceState "${sourceState}"`, async () => {
1084
+ receiveSlot = {
1085
+ sourceState,
1086
+ csi: 2,
1087
+ id: '4',
1088
+ };
1089
+
1090
+ await startStatsAnalyzer();
1091
+
1092
+ // don't increase the packets when time progresses.
1093
+ await progressTime();
1094
+
1095
+ assert.neverCalledWith(
1096
+ loggerSpy,
1097
+ 'StatsAnalyzer:index#processInboundRTPResult --> No packets received for receive slot id: "4" and csi: 2. Total packets received on slot: ',
1098
+ 0
1099
+ );
1100
+ });
1101
+ }
1102
+ );
1103
+
1104
+ it(`logs a message if no packets are sent`, async () => {
1105
+ receiveSlot = {
1106
+ sourceState: 'live',
1107
+ csi: 2,
1108
+ id: '4',
1109
+ };
1110
+ await startStatsAnalyzer();
1111
+
1112
+ // don't increase the packets when time progresses.
1113
+ await progressTime();
1114
+
1115
+ assert.calledWith(
1116
+ loggerSpy,
1117
+ 'StatsAnalyzer:index#processInboundRTPResult --> No packets received for mediaType: video-recv-0, receive slot id: "4" and csi: 2. Total packets received on slot: ',
1118
+ 0
1119
+ );
1120
+
1121
+ assert.calledWith(
1122
+ loggerSpy,
1123
+ 'StatsAnalyzer:index#processInboundRTPResult --> No frames received for mediaType: video-recv-0, receive slot id: "4" and csi: 2. Total frames received on slot: ',
1124
+ 0
1125
+ );
1126
+
1127
+ assert.calledWith(
1128
+ loggerSpy,
1129
+ 'StatsAnalyzer:index#processInboundRTPResult --> No frames decoded for mediaType: video-recv-0, receive slot id: "4" and csi: 2. Total frames decoded on slot: ',
1130
+ 0
1131
+ );
1132
+
1133
+ assert.calledWith(
1134
+ loggerSpy,
1135
+ 'StatsAnalyzer:index#processInboundRTPResult --> No packets received for mediaType: audio-recv-0, receive slot id: "4" and csi: 2. Total packets received on slot: ',
1136
+ 0
1137
+ );
1138
+
1139
+ assert.calledWith(
1140
+ loggerSpy,
1141
+ 'StatsAnalyzer:index#processInboundRTPResult --> No packets received for mediaType: video-share-recv-0, receive slot id: "4" and csi: 2. Total packets received on slot: ',
1142
+ 0
1143
+ );
1144
+
1145
+ assert.calledWith(
1146
+ loggerSpy,
1147
+ 'StatsAnalyzer:index#processInboundRTPResult --> No frames received for mediaType: video-share-recv-0, receive slot id: "4" and csi: 2. Total frames received on slot: ',
1148
+ 0
1149
+ );
1150
+ assert.calledWith(
1151
+ loggerSpy,
1152
+ 'StatsAnalyzer:index#processInboundRTPResult --> No frames decoded for mediaType: video-share-recv-0, receive slot id: "4" and csi: 2. Total frames decoded on slot: ',
1153
+ 0
1154
+ );
1155
+ assert.calledWith(
1156
+ loggerSpy,
1157
+ 'StatsAnalyzer:index#processInboundRTPResult --> No packets received for mediaType: audio-share-recv-0, receive slot id: "4" and csi: 2. Total packets received on slot: ',
1158
+ 0
1159
+ );
1160
+ });
1161
+
1162
+ it(`does not log a message if receiveSlot is undefined`, async () => {
1163
+ await startStatsAnalyzer();
1164
+
1165
+ // don't increase the packets when time progresses.
1166
+ await progressTime();
1167
+
1168
+ assert.neverCalledWith(
1169
+ loggerSpy,
1170
+ 'StatsAnalyzer:index#processInboundRTPResult --> No packets received for receive slot "". Total packets received on slot: ',
1171
+ 0
1172
+ );
1173
+ });
1174
+
1175
+ it('has the correct number of senders and receivers (2)', async () => {
1176
+ await startStatsAnalyzer({expected: {receiveVideo: true}});
1177
+
1178
+ await progressTime();
1179
+
1180
+ assert.lengthOf(mqeData.audioTransmit, 2);
1181
+ assert.lengthOf(mqeData.audioReceive, 2);
1182
+ assert.lengthOf(mqeData.videoTransmit, 2);
1183
+ assert.lengthOf(mqeData.videoReceive, 2);
1184
+ });
1185
+
1186
+ it('has one stream per sender/reciever', async () => {
1187
+ await startStatsAnalyzer({expected: {receiveVideo: true}});
1188
+
1189
+ await progressTime();
1190
+
1191
+ assert.deepEqual(mqeData.audioTransmit[0].streams, [
1192
+ {
1193
+ common: {
1194
+ codec: 'opus',
1195
+ csi: [],
1196
+ requestedBitrate: 0,
1197
+ requestedFrames: 0,
1198
+ rtpPackets: 0,
1199
+ ssci: 0,
1200
+ transmittedBitrate: 0.13333333333333333,
1201
+ transmittedFrameRate: 0,
1202
+ },
1203
+ transmittedKeyFrames: 0,
1204
+ requestedKeyFrames: 0,
1205
+ },
1206
+ ]);
1207
+ assert.deepEqual(mqeData.audioTransmit[1].streams, [
1208
+ {
1209
+ common: {
1210
+ codec: 'opus',
1211
+ csi: [],
1212
+ requestedBitrate: 0,
1213
+ requestedFrames: 0,
1214
+ rtpPackets: 0,
1215
+ ssci: 0,
1216
+ transmittedBitrate: 0.13333333333333333,
1217
+ transmittedFrameRate: 0,
1218
+ },
1219
+ transmittedKeyFrames: 0,
1220
+ requestedKeyFrames: 0,
1221
+ },
1222
+ ]);
1223
+ assert.deepEqual(mqeData.audioReceive[0].streams, [
1224
+ {
1225
+ common: {
1226
+ codec: 'opus',
1227
+ concealedFrames: 0,
1228
+ csi: [],
1229
+ maxConcealRunLength: 0,
1230
+ optimalBitrate: 0,
1231
+ optimalFrameRate: 0,
1232
+ receivedBitrate: 0.13333333333333333,
1233
+ receivedFrameRate: 0,
1234
+ renderedFrameRate: 0,
1235
+ requestedBitrate: 0,
1236
+ requestedFrameRate: 0,
1237
+ rtpEndToEndLost: 0,
1238
+ maxRtpJitter: 0,
1239
+ meanRtpJitter: 0,
1240
+ rtpPackets: 0,
1241
+ ssci: 0,
1242
+ rtpJitter: 0,
1243
+ framesDropped: 0,
1244
+ framesReceived: 0,
1245
+ },
1246
+ },
1247
+ ]);
1248
+ assert.deepEqual(mqeData.audioReceive[1].streams, [
1249
+ {
1250
+ common: {
1251
+ codec: 'opus',
1252
+ concealedFrames: 0,
1253
+ csi: [],
1254
+ maxConcealRunLength: 0,
1255
+ optimalBitrate: 0,
1256
+ optimalFrameRate: 0,
1257
+ receivedBitrate: 0.13333333333333333,
1258
+ receivedFrameRate: 0,
1259
+ renderedFrameRate: 0,
1260
+ requestedBitrate: 0,
1261
+ requestedFrameRate: 0,
1262
+ rtpEndToEndLost: 0,
1263
+ maxRtpJitter: 0,
1264
+ meanRtpJitter: 0,
1265
+ rtpPackets: 0,
1266
+ ssci: 0,
1267
+ rtpJitter: 0,
1268
+ framesDropped: 0,
1269
+ framesReceived: 0,
1270
+ },
1271
+ },
1272
+ ]);
1273
+ assert.deepEqual(mqeData.videoTransmit[0].streams, [
1274
+ {
1275
+ common: {
1276
+ codec: 'H264',
1277
+ csi: [],
1278
+ duplicateSsci: 0,
1279
+ requestedBitrate: 0,
1280
+ requestedFrames: 0,
1281
+ rtpPackets: 0,
1282
+ ssci: 0,
1283
+ transmittedBitrate: 0.13333333333333333,
1284
+ transmittedFrameRate: 0,
1285
+ },
1286
+ h264CodecProfile: 'BP',
1287
+ isAvatar: false,
1288
+ isHardwareEncoded: false,
1289
+ localConfigurationChanges: 2,
1290
+ maxFrameQp: 0,
1291
+ maxNoiseLevel: 0,
1292
+ minRegionQp: 0,
1293
+ remoteConfigurationChanges: 0,
1294
+ requestedFrameSize: 0,
1295
+ requestedKeyFrames: 0,
1296
+ transmittedFrameSize: 0,
1297
+ transmittedHeight: 0,
1298
+ transmittedKeyFrames: 0,
1299
+ transmittedKeyFramesClient: 0,
1300
+ transmittedKeyFramesConfigurationChange: 0,
1301
+ transmittedKeyFramesFeedback: 0,
1302
+ transmittedKeyFramesLocalDrop: 0,
1303
+ transmittedKeyFramesOtherLayer: 0,
1304
+ transmittedKeyFramesPeriodic: 0,
1305
+ transmittedKeyFramesSceneChange: 0,
1306
+ transmittedKeyFramesStartup: 0,
1307
+ transmittedKeyFramesUnknown: 0,
1308
+ transmittedWidth: 0,
1309
+ },
1310
+ ]);
1311
+ assert.deepEqual(mqeData.videoTransmit[1].streams, [
1312
+ {
1313
+ common: {
1314
+ codec: 'H264',
1315
+ csi: [],
1316
+ duplicateSsci: 0,
1317
+ requestedBitrate: 0,
1318
+ requestedFrames: 0,
1319
+ rtpPackets: 0,
1320
+ ssci: 0,
1321
+ transmittedBitrate: 0.13333333333333333,
1322
+ transmittedFrameRate: 0,
1323
+ },
1324
+ h264CodecProfile: 'BP',
1325
+ isAvatar: false,
1326
+ isHardwareEncoded: false,
1327
+ localConfigurationChanges: 2,
1328
+ maxFrameQp: 0,
1329
+ maxNoiseLevel: 0,
1330
+ minRegionQp: 0,
1331
+ remoteConfigurationChanges: 0,
1332
+ requestedFrameSize: 0,
1333
+ requestedKeyFrames: 0,
1334
+ transmittedFrameSize: 0,
1335
+ transmittedHeight: 0,
1336
+ transmittedKeyFrames: 0,
1337
+ transmittedKeyFramesClient: 0,
1338
+ transmittedKeyFramesConfigurationChange: 0,
1339
+ transmittedKeyFramesFeedback: 0,
1340
+ transmittedKeyFramesLocalDrop: 0,
1341
+ transmittedKeyFramesOtherLayer: 0,
1342
+ transmittedKeyFramesPeriodic: 0,
1343
+ transmittedKeyFramesSceneChange: 0,
1344
+ transmittedKeyFramesStartup: 0,
1345
+ transmittedKeyFramesUnknown: 0,
1346
+ transmittedWidth: 0,
1347
+ },
1348
+ ]);
1349
+ assert.deepEqual(mqeData.videoReceive[0].streams, [
1350
+ {
1351
+ common: {
1352
+ codec: 'H264',
1353
+ concealedFrames: 0,
1354
+ csi: [],
1355
+ maxConcealRunLength: 0,
1356
+ optimalBitrate: 0,
1357
+ optimalFrameRate: 0,
1358
+ receivedBitrate: 0.13333333333333333,
1359
+ receivedFrameRate: 0,
1360
+ renderedFrameRate: 0,
1361
+ requestedBitrate: 0,
1362
+ requestedFrameRate: 0,
1363
+ rtpEndToEndLost: 0,
1364
+ rtpJitter: 0,
1365
+ rtpPackets: 0,
1366
+ ssci: 0,
1367
+ framesDropped: 0,
1368
+ },
1369
+ h264CodecProfile: 'BP',
1370
+ isActiveSpeaker: true,
1371
+ optimalFrameSize: 0,
1372
+ receivedFrameSize: 3600,
1373
+ receivedHeight: 720,
1374
+ receivedKeyFrames: 0,
1375
+ receivedKeyFramesForRequest: 0,
1376
+ receivedKeyFramesSourceChange: 0,
1377
+ receivedKeyFramesUnknown: 0,
1378
+ receivedWidth: 1280,
1379
+ requestedFrameSize: 0,
1380
+ requestedKeyFrames: 0,
1381
+ },
1382
+ ]);
1383
+ assert.deepEqual(mqeData.videoReceive[1].streams, [
1384
+ {
1385
+ common: {
1386
+ codec: 'H264',
1387
+ concealedFrames: 0,
1388
+ csi: [],
1389
+ maxConcealRunLength: 0,
1390
+ optimalBitrate: 0,
1391
+ optimalFrameRate: 0,
1392
+ receivedBitrate: 0.13333333333333333,
1393
+ receivedFrameRate: 0,
1394
+ renderedFrameRate: 0,
1395
+ requestedBitrate: 0,
1396
+ requestedFrameRate: 0,
1397
+ rtpEndToEndLost: 0,
1398
+ rtpJitter: 0,
1399
+ rtpPackets: 0,
1400
+ ssci: 0,
1401
+ framesDropped: 0,
1402
+ },
1403
+ h264CodecProfile: 'BP',
1404
+ isActiveSpeaker: true,
1405
+ optimalFrameSize: 0,
1406
+ receivedFrameSize: 3600,
1407
+ receivedHeight: 720,
1408
+ receivedKeyFrames: 0,
1409
+ receivedKeyFramesForRequest: 0,
1410
+ receivedKeyFramesSourceChange: 0,
1411
+ receivedKeyFramesUnknown: 0,
1412
+ receivedWidth: 1280,
1413
+ requestedFrameSize: 0,
1414
+ requestedKeyFrames: 0,
1415
+ },
1416
+ ]);
1417
+ });
1418
+
1419
+ it('has three streams for video receivers when three exist', async () => {
1420
+ pc.getTransceiverStats = sinon.stub().resolves({
1421
+ audio: {
1422
+ senders: [fakeStats.audio.senders[0]],
1423
+ receivers: [fakeStats.audio.receivers[0]],
1424
+ },
1425
+ video: {
1426
+ senders: [fakeStats.video.senders[0]],
1427
+ receivers: [
1428
+ fakeStats.video.receivers[0],
1429
+ fakeStats.video.receivers[0],
1430
+ fakeStats.video.receivers[0],
1431
+ ],
1432
+ },
1433
+ screenShareAudio: {
1434
+ senders: [fakeStats.audio.senders[0]],
1435
+ receivers: [fakeStats.audio.receivers[0]],
1436
+ },
1437
+ screenShareVideo: {
1438
+ senders: [fakeStats.video.senders[0]],
1439
+ receivers: [fakeStats.video.receivers[0]],
1440
+ },
1441
+ });
1442
+
1443
+ await startStatsAnalyzer({expected: {receiveVideo: true}});
1444
+
1445
+ await progressTime();
1446
+
1447
+ assert.deepEqual(mqeData.videoReceive[0].streams, [
1448
+ {
1449
+ common: {
1450
+ codec: 'H264',
1451
+ concealedFrames: 0,
1452
+ csi: [],
1453
+ maxConcealRunLength: 0,
1454
+ optimalBitrate: 0,
1455
+ optimalFrameRate: 0,
1456
+ receivedBitrate: 0.13333333333333333,
1457
+ receivedFrameRate: 0,
1458
+ renderedFrameRate: 0,
1459
+ requestedBitrate: 0,
1460
+ requestedFrameRate: 0,
1461
+ rtpEndToEndLost: 0,
1462
+ rtpJitter: 0,
1463
+ rtpPackets: 0,
1464
+ ssci: 0,
1465
+ framesDropped: 0,
1466
+ },
1467
+ h264CodecProfile: 'BP',
1468
+ isActiveSpeaker: true,
1469
+ optimalFrameSize: 0,
1470
+ receivedFrameSize: 3600,
1471
+ receivedHeight: 720,
1472
+ receivedKeyFrames: 0,
1473
+ receivedKeyFramesForRequest: 0,
1474
+ receivedKeyFramesSourceChange: 0,
1475
+ receivedKeyFramesUnknown: 0,
1476
+ receivedWidth: 1280,
1477
+ requestedFrameSize: 0,
1478
+ requestedKeyFrames: 0,
1479
+ },
1480
+ {
1481
+ common: {
1482
+ codec: 'H264',
1483
+ concealedFrames: 0,
1484
+ csi: [],
1485
+ maxConcealRunLength: 0,
1486
+ optimalBitrate: 0,
1487
+ optimalFrameRate: 0,
1488
+ receivedBitrate: 0.13333333333333333,
1489
+ receivedFrameRate: 0,
1490
+ renderedFrameRate: 0,
1491
+ requestedBitrate: 0,
1492
+ requestedFrameRate: 0,
1493
+ rtpEndToEndLost: 0,
1494
+ rtpJitter: 0,
1495
+ rtpPackets: 0,
1496
+ ssci: 0,
1497
+ framesDropped: 0,
1498
+ },
1499
+ h264CodecProfile: 'BP',
1500
+ isActiveSpeaker: true,
1501
+ optimalFrameSize: 0,
1502
+ receivedFrameSize: 3600,
1503
+ receivedHeight: 720,
1504
+ receivedKeyFrames: 0,
1505
+ receivedKeyFramesForRequest: 0,
1506
+ receivedKeyFramesSourceChange: 0,
1507
+ receivedKeyFramesUnknown: 0,
1508
+ receivedWidth: 1280,
1509
+ requestedFrameSize: 0,
1510
+ requestedKeyFrames: 0,
1511
+ },
1512
+ {
1513
+ common: {
1514
+ codec: 'H264',
1515
+ concealedFrames: 0,
1516
+ csi: [],
1517
+ maxConcealRunLength: 0,
1518
+ optimalBitrate: 0,
1519
+ optimalFrameRate: 0,
1520
+ receivedBitrate: 0.13333333333333333,
1521
+ receivedFrameRate: 0,
1522
+ renderedFrameRate: 0,
1523
+ requestedBitrate: 0,
1524
+ requestedFrameRate: 0,
1525
+ rtpEndToEndLost: 0,
1526
+ rtpJitter: 0,
1527
+ rtpPackets: 0,
1528
+ ssci: 0,
1529
+ framesDropped: 0,
1530
+ },
1531
+ h264CodecProfile: 'BP',
1532
+ isActiveSpeaker: true,
1533
+ optimalFrameSize: 0,
1534
+ receivedFrameSize: 3600,
1535
+ receivedHeight: 720,
1536
+ receivedKeyFrames: 0,
1537
+ receivedKeyFramesForRequest: 0,
1538
+ receivedKeyFramesSourceChange: 0,
1539
+ receivedKeyFramesUnknown: 0,
1540
+ receivedWidth: 1280,
1541
+ requestedFrameSize: 0,
1542
+ requestedKeyFrames: 0,
1543
+ },
1544
+ ]);
1545
+ });
277
1546
  });
278
1547
  });
279
1548
  });