@webex/plugin-meetings 3.0.0-stream-classes.4 → 3.0.0

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 (469) hide show
  1. package/.eslintrc.js +6 -0
  2. package/README.md +12 -0
  3. package/babel.config.js +3 -0
  4. package/dist/annotation/constants.js +12 -20
  5. package/dist/annotation/constants.js.map +1 -1
  6. package/dist/annotation/index.js +25 -10
  7. package/dist/annotation/index.js.map +1 -1
  8. package/dist/breakouts/breakout.js +2 -3
  9. package/dist/breakouts/breakout.js.map +1 -1
  10. package/dist/breakouts/collection.js +1 -2
  11. package/dist/breakouts/collection.js.map +1 -1
  12. package/dist/breakouts/edit-lock-error.js +1 -2
  13. package/dist/breakouts/edit-lock-error.js.map +1 -1
  14. package/dist/breakouts/events.js +1 -2
  15. package/dist/breakouts/events.js.map +1 -1
  16. package/dist/breakouts/index.js +13 -14
  17. package/dist/breakouts/index.js.map +1 -1
  18. package/dist/breakouts/request.js +1 -2
  19. package/dist/breakouts/request.js.map +1 -1
  20. package/dist/breakouts/utils.js +3 -6
  21. package/dist/breakouts/utils.js.map +1 -1
  22. package/dist/common/browser-detection.js +2 -3
  23. package/dist/common/browser-detection.js.map +1 -1
  24. package/dist/common/collection.js +3 -4
  25. package/dist/common/collection.js.map +1 -1
  26. package/dist/common/config.js +1 -2
  27. package/dist/common/config.js.map +1 -1
  28. package/dist/common/errors/captcha-error.js +1 -2
  29. package/dist/common/errors/captcha-error.js.map +1 -1
  30. package/dist/common/errors/intent-to-join.js +1 -2
  31. package/dist/common/errors/intent-to-join.js.map +1 -1
  32. package/dist/common/errors/join-meeting.js +1 -2
  33. package/dist/common/errors/join-meeting.js.map +1 -1
  34. package/dist/common/errors/media.js +1 -2
  35. package/dist/common/errors/media.js.map +1 -1
  36. package/dist/common/errors/no-meeting-info.d.ts +14 -0
  37. package/dist/common/errors/no-meeting-info.js +50 -0
  38. package/dist/common/errors/no-meeting-info.js.map +1 -0
  39. package/dist/common/errors/parameter.js +3 -4
  40. package/dist/common/errors/parameter.js.map +1 -1
  41. package/dist/common/errors/password-error.js +1 -2
  42. package/dist/common/errors/password-error.js.map +1 -1
  43. package/dist/common/errors/permission.js +1 -2
  44. package/dist/common/errors/permission.js.map +1 -1
  45. package/dist/common/errors/reclaim-host-role-errors.d.ts +60 -0
  46. package/dist/common/errors/reclaim-host-role-errors.js +154 -0
  47. package/dist/common/errors/reclaim-host-role-errors.js.map +1 -0
  48. package/dist/common/errors/reconnection-in-progress.js +1 -2
  49. package/dist/common/errors/reconnection-in-progress.js.map +1 -1
  50. package/dist/common/errors/reconnection.js +1 -2
  51. package/dist/common/errors/reconnection.js.map +1 -1
  52. package/dist/common/errors/stats.js +1 -2
  53. package/dist/common/errors/stats.js.map +1 -1
  54. package/dist/{types/common → common}/errors/webex-errors.d.ts +13 -1
  55. package/dist/common/errors/webex-errors.js +35 -16
  56. package/dist/common/errors/webex-errors.js.map +1 -1
  57. package/dist/common/errors/webex-meetings-error.js +1 -2
  58. package/dist/common/errors/webex-meetings-error.js.map +1 -1
  59. package/dist/common/events/events-scope.js +1 -2
  60. package/dist/common/events/events-scope.js.map +1 -1
  61. package/dist/common/events/events.js +1 -2
  62. package/dist/common/events/events.js.map +1 -1
  63. package/dist/common/events/trigger-proxy.js +1 -2
  64. package/dist/common/events/trigger-proxy.js.map +1 -1
  65. package/dist/common/events/util.js +1 -2
  66. package/dist/common/events/util.js.map +1 -1
  67. package/dist/common/logs/logger-config.js +1 -2
  68. package/dist/common/logs/logger-config.js.map +1 -1
  69. package/dist/common/logs/logger-proxy.js +1 -2
  70. package/dist/common/logs/logger-proxy.js.map +1 -1
  71. package/dist/{types/common → common}/logs/request.d.ts +3 -1
  72. package/dist/common/logs/request.js +8 -5
  73. package/dist/common/logs/request.js.map +1 -1
  74. package/dist/common/queue.js +2 -4
  75. package/dist/common/queue.js.map +1 -1
  76. package/dist/{types/config.d.ts → config.d.ts} +1 -1
  77. package/dist/config.js +3 -3
  78. package/dist/config.js.map +1 -1
  79. package/dist/{types/constants.d.ts → constants.d.ts} +72 -15
  80. package/dist/constants.js +254 -371
  81. package/dist/constants.js.map +1 -1
  82. package/dist/controls-options-manager/constants.js +3 -6
  83. package/dist/controls-options-manager/constants.js.map +1 -1
  84. package/dist/controls-options-manager/enums.js +7 -10
  85. package/dist/controls-options-manager/enums.js.map +1 -1
  86. package/dist/controls-options-manager/index.js +27 -32
  87. package/dist/controls-options-manager/index.js.map +1 -1
  88. package/dist/controls-options-manager/util.js +1 -2
  89. package/dist/controls-options-manager/util.js.map +1 -1
  90. package/dist/index.js +8 -5
  91. package/dist/index.js.map +1 -1
  92. package/dist/interceptors/index.d.ts +2 -0
  93. package/dist/interceptors/index.js +15 -0
  94. package/dist/interceptors/index.js.map +1 -0
  95. package/dist/interceptors/locusRetry.d.ts +27 -0
  96. package/dist/interceptors/locusRetry.js +94 -0
  97. package/dist/interceptors/locusRetry.js.map +1 -0
  98. package/dist/interpretation/collection.js +1 -2
  99. package/dist/interpretation/collection.js.map +1 -1
  100. package/dist/interpretation/index.js +2 -3
  101. package/dist/interpretation/index.js.map +1 -1
  102. package/dist/interpretation/siLanguage.js +2 -3
  103. package/dist/interpretation/siLanguage.js.map +1 -1
  104. package/dist/locus-info/controlsUtils.js +12 -13
  105. package/dist/locus-info/controlsUtils.js.map +1 -1
  106. package/dist/locus-info/embeddedAppsUtils.js +3 -4
  107. package/dist/locus-info/embeddedAppsUtils.js.map +1 -1
  108. package/dist/locus-info/fullState.js +1 -2
  109. package/dist/locus-info/fullState.js.map +1 -1
  110. package/dist/locus-info/hostUtils.js +1 -2
  111. package/dist/locus-info/hostUtils.js.map +1 -1
  112. package/dist/{types/locus-info → locus-info}/index.d.ts +1 -1
  113. package/dist/locus-info/index.js +63 -38
  114. package/dist/locus-info/index.js.map +1 -1
  115. package/dist/locus-info/infoUtils.js +3 -4
  116. package/dist/locus-info/infoUtils.js.map +1 -1
  117. package/dist/locus-info/mediaSharesUtils.js +16 -3
  118. package/dist/locus-info/mediaSharesUtils.js.map +1 -1
  119. package/dist/{types/locus-info → locus-info}/parser.d.ts +3 -2
  120. package/dist/locus-info/parser.js +48 -31
  121. package/dist/locus-info/parser.js.map +1 -1
  122. package/dist/locus-info/selfUtils.js +7 -6
  123. package/dist/locus-info/selfUtils.js.map +1 -1
  124. package/dist/media/index.js +15 -10
  125. package/dist/media/index.js.map +1 -1
  126. package/dist/media/properties.js +16 -7
  127. package/dist/media/properties.js.map +1 -1
  128. package/dist/media/util.js +1 -2
  129. package/dist/media/util.js.map +1 -1
  130. package/dist/mediaQualityMetrics/config.d.ts +241 -0
  131. package/dist/mediaQualityMetrics/config.js +135 -339
  132. package/dist/mediaQualityMetrics/config.js.map +1 -1
  133. package/dist/{types/meeting → meeting}/in-meeting-actions.d.ts +4 -0
  134. package/dist/meeting/in-meeting-actions.js +18 -2
  135. package/dist/meeting/in-meeting-actions.js.map +1 -1
  136. package/dist/{types/meeting → meeting}/index.d.ts +331 -44
  137. package/dist/meeting/index.js +2639 -1367
  138. package/dist/meeting/index.js.map +1 -1
  139. package/dist/{types/meeting → meeting}/locusMediaRequest.d.ts +1 -2
  140. package/dist/meeting/locusMediaRequest.js +4 -5
  141. package/dist/meeting/locusMediaRequest.js.map +1 -1
  142. package/dist/meeting/muteState.js +2 -4
  143. package/dist/meeting/muteState.js.map +1 -1
  144. package/dist/{types/meeting → meeting}/request.d.ts +4 -1
  145. package/dist/meeting/request.js +47 -32
  146. package/dist/meeting/request.js.map +1 -1
  147. package/dist/meeting/state.js +1 -2
  148. package/dist/meeting/state.js.map +1 -1
  149. package/dist/{types/meeting → meeting}/util.d.ts +26 -1
  150. package/dist/meeting/util.js +83 -10
  151. package/dist/meeting/util.js.map +1 -1
  152. package/dist/meeting/voicea-meeting.d.ts +16 -0
  153. package/dist/meeting/voicea-meeting.js +169 -0
  154. package/dist/meeting/voicea-meeting.js.map +1 -0
  155. package/dist/meeting-info/collection.js +3 -4
  156. package/dist/meeting-info/collection.js.map +1 -1
  157. package/dist/{types/meeting-info → meeting-info}/index.d.ts +7 -0
  158. package/dist/meeting-info/index.js +53 -27
  159. package/dist/meeting-info/index.js.map +1 -1
  160. package/dist/{types/meeting-info → meeting-info}/meeting-info-v2.d.ts +1 -0
  161. package/dist/meeting-info/meeting-info-v2.js +52 -33
  162. package/dist/meeting-info/meeting-info-v2.js.map +1 -1
  163. package/dist/meeting-info/request.js +1 -2
  164. package/dist/meeting-info/request.js.map +1 -1
  165. package/dist/meeting-info/util.js +8 -8
  166. package/dist/meeting-info/util.js.map +1 -1
  167. package/dist/meeting-info/utilv2.js +12 -9
  168. package/dist/meeting-info/utilv2.js.map +1 -1
  169. package/dist/{types/meetings → meetings}/collection.d.ts +9 -0
  170. package/dist/meetings/collection.js +21 -5
  171. package/dist/meetings/collection.js.map +1 -1
  172. package/dist/{types/meetings → meetings}/index.d.ts +45 -16
  173. package/dist/meetings/index.js +166 -74
  174. package/dist/meetings/index.js.map +1 -1
  175. package/dist/meetings/request.js +2 -3
  176. package/dist/meetings/request.js.map +1 -1
  177. package/dist/meetings/util.js +3 -10
  178. package/dist/meetings/util.js.map +1 -1
  179. package/dist/{types/member → member}/index.d.ts +1 -0
  180. package/dist/member/index.js +10 -3
  181. package/dist/member/index.js.map +1 -1
  182. package/dist/member/member.types.d.ts +11 -0
  183. package/dist/member/member.types.js +17 -0
  184. package/dist/member/member.types.js.map +1 -0
  185. package/dist/member/types.js +6 -8
  186. package/dist/member/types.js.map +1 -1
  187. package/dist/member/util.js +12 -2
  188. package/dist/member/util.js.map +1 -1
  189. package/dist/members/collection.js +1 -2
  190. package/dist/members/collection.js.map +1 -1
  191. package/dist/members/index.js +25 -8
  192. package/dist/members/index.js.map +1 -1
  193. package/dist/members/request.js +2 -3
  194. package/dist/members/request.js.map +1 -1
  195. package/dist/{types/members → members}/types.d.ts +1 -0
  196. package/dist/members/types.js +3 -4
  197. package/dist/members/types.js.map +1 -1
  198. package/dist/{types/members → members}/util.d.ts +6 -1
  199. package/dist/members/util.js +18 -8
  200. package/dist/members/util.js.map +1 -1
  201. package/dist/{types/metrics → metrics}/constants.d.ts +15 -0
  202. package/dist/metrics/constants.js +16 -3
  203. package/dist/metrics/constants.js.map +1 -1
  204. package/dist/metrics/index.js +3 -2
  205. package/dist/metrics/index.js.map +1 -1
  206. package/dist/multistream/mediaRequestManager.js +9 -11
  207. package/dist/multistream/mediaRequestManager.js.map +1 -1
  208. package/dist/multistream/receiveSlot.js +3 -5
  209. package/dist/multistream/receiveSlot.js.map +1 -1
  210. package/dist/multistream/receiveSlotManager.js +7 -9
  211. package/dist/multistream/receiveSlotManager.js.map +1 -1
  212. package/dist/multistream/remoteMedia.js +3 -5
  213. package/dist/multistream/remoteMedia.js.map +1 -1
  214. package/dist/multistream/remoteMediaGroup.js +7 -6
  215. package/dist/multistream/remoteMediaGroup.js.map +1 -1
  216. package/dist/{types/multistream → multistream}/remoteMediaManager.d.ts +9 -1
  217. package/dist/multistream/remoteMediaManager.js +74 -36
  218. package/dist/multistream/remoteMediaManager.js.map +1 -1
  219. package/dist/multistream/sendSlotManager.js +9 -6
  220. package/dist/multistream/sendSlotManager.js.map +1 -1
  221. package/dist/networkQualityMonitor/index.js +1 -2
  222. package/dist/networkQualityMonitor/index.js.map +1 -1
  223. package/dist/personal-meeting-room/index.js +2 -3
  224. package/dist/personal-meeting-room/index.js.map +1 -1
  225. package/dist/personal-meeting-room/request.js +2 -3
  226. package/dist/personal-meeting-room/request.js.map +1 -1
  227. package/dist/personal-meeting-room/util.js +1 -2
  228. package/dist/personal-meeting-room/util.js.map +1 -1
  229. package/dist/reachability/clusterReachability.d.ts +109 -0
  230. package/dist/reachability/clusterReachability.js +357 -0
  231. package/dist/reachability/clusterReachability.js.map +1 -0
  232. package/dist/reachability/index.d.ts +105 -0
  233. package/dist/reachability/index.js +279 -436
  234. package/dist/reachability/index.js.map +1 -1
  235. package/dist/{types/reachability → reachability}/request.d.ts +1 -1
  236. package/dist/reachability/request.js +14 -11
  237. package/dist/reachability/request.js.map +1 -1
  238. package/dist/reachability/util.d.ts +8 -0
  239. package/dist/reachability/util.js +29 -0
  240. package/dist/reachability/util.js.map +1 -0
  241. package/dist/reactions/constants.js +1 -2
  242. package/dist/reactions/constants.js.map +1 -1
  243. package/dist/reactions/reactions.js +2 -4
  244. package/dist/reactions/reactions.js.map +1 -1
  245. package/dist/reactions/reactions.type.js +6 -8
  246. package/dist/reactions/reactions.type.js.map +1 -1
  247. package/dist/{types/reconnection-manager → reconnection-manager}/index.d.ts +10 -0
  248. package/dist/reconnection-manager/index.js +129 -106
  249. package/dist/reconnection-manager/index.js.map +1 -1
  250. package/dist/recording-controller/enums.js +4 -5
  251. package/dist/recording-controller/enums.js.map +1 -1
  252. package/dist/recording-controller/index.js +43 -51
  253. package/dist/recording-controller/index.js.map +1 -1
  254. package/dist/recording-controller/util.js +1 -2
  255. package/dist/recording-controller/util.js.map +1 -1
  256. package/dist/{types/roap → roap}/index.d.ts +2 -1
  257. package/dist/roap/index.js +59 -28
  258. package/dist/roap/index.js.map +1 -1
  259. package/dist/{types/roap → roap}/request.d.ts +2 -1
  260. package/dist/roap/request.js +14 -22
  261. package/dist/roap/request.js.map +1 -1
  262. package/dist/{types/roap → roap}/turnDiscovery.d.ts +21 -4
  263. package/dist/roap/turnDiscovery.js +182 -89
  264. package/dist/roap/turnDiscovery.js.map +1 -1
  265. package/dist/rtcMetrics/constants.js +1 -2
  266. package/dist/rtcMetrics/constants.js.map +1 -1
  267. package/dist/{types/rtcMetrics → rtcMetrics}/index.d.ts +15 -1
  268. package/dist/rtcMetrics/index.js +72 -12
  269. package/dist/rtcMetrics/index.js.map +1 -1
  270. package/dist/statsAnalyzer/global.js +1 -2
  271. package/dist/statsAnalyzer/global.js.map +1 -1
  272. package/dist/{types/statsAnalyzer → statsAnalyzer}/index.d.ts +28 -11
  273. package/dist/statsAnalyzer/index.js +371 -318
  274. package/dist/statsAnalyzer/index.js.map +1 -1
  275. package/dist/statsAnalyzer/mqaUtil.d.ts +48 -0
  276. package/dist/statsAnalyzer/mqaUtil.js +295 -162
  277. package/dist/statsAnalyzer/mqaUtil.js.map +1 -1
  278. package/dist/transcription/index.js +1 -2
  279. package/dist/transcription/index.js.map +1 -1
  280. package/dist/webinar/collection.d.ts +16 -0
  281. package/dist/webinar/collection.js +43 -0
  282. package/dist/webinar/collection.js.map +1 -0
  283. package/dist/webinar/index.d.ts +5 -0
  284. package/dist/webinar/index.js +68 -0
  285. package/dist/webinar/index.js.map +1 -0
  286. package/jest.config.js +3 -0
  287. package/package.json +44 -24
  288. package/process +1 -0
  289. package/src/common/errors/no-meeting-info.ts +24 -0
  290. package/src/common/errors/reclaim-host-role-errors.ts +134 -0
  291. package/src/common/errors/webex-errors.ts +19 -2
  292. package/src/common/logs/request.ts +5 -1
  293. package/src/config.ts +3 -5
  294. package/src/constants.ts +78 -8
  295. package/src/index.ts +4 -0
  296. package/src/interceptors/index.ts +3 -0
  297. package/src/interceptors/locusRetry.ts +67 -0
  298. package/src/locus-info/index.ts +52 -16
  299. package/src/locus-info/mediaSharesUtils.ts +16 -0
  300. package/src/locus-info/parser.ts +47 -21
  301. package/src/media/index.ts +8 -6
  302. package/src/media/properties.ts +17 -2
  303. package/src/mediaQualityMetrics/config.ts +103 -238
  304. package/src/meeting/in-meeting-actions.ts +8 -0
  305. package/src/meeting/index.ts +1692 -627
  306. package/src/meeting/request.ts +19 -1
  307. package/src/meeting/util.ts +102 -1
  308. package/src/meeting/voicea-meeting.ts +122 -0
  309. package/src/meeting-info/index.ts +47 -20
  310. package/src/meeting-info/meeting-info-v2.ts +32 -16
  311. package/src/meeting-info/util.ts +12 -9
  312. package/src/meeting-info/utilv2.ts +25 -15
  313. package/src/meetings/collection.ts +13 -0
  314. package/src/meetings/index.ts +112 -31
  315. package/src/meetings/util.ts +2 -8
  316. package/src/member/index.ts +9 -1
  317. package/src/member/member.types.ts +13 -0
  318. package/src/member/util.ts +14 -0
  319. package/src/members/index.ts +29 -2
  320. package/src/members/types.ts +1 -0
  321. package/src/members/util.ts +15 -1
  322. package/src/metrics/constants.ts +14 -0
  323. package/src/multistream/remoteMediaManager.ts +41 -4
  324. package/src/reachability/clusterReachability.ts +320 -0
  325. package/src/reachability/index.ts +221 -382
  326. package/src/reachability/request.ts +1 -1
  327. package/src/reachability/util.ts +24 -0
  328. package/src/reconnection-manager/index.ts +87 -83
  329. package/src/roap/index.ts +60 -24
  330. package/src/roap/request.ts +4 -17
  331. package/src/roap/turnDiscovery.ts +112 -39
  332. package/src/rtcMetrics/index.ts +71 -5
  333. package/src/statsAnalyzer/index.ts +430 -427
  334. package/src/statsAnalyzer/mqaUtil.ts +317 -168
  335. package/src/webinar/collection.ts +31 -0
  336. package/src/webinar/index.ts +62 -0
  337. package/test/integration/spec/converged-space-meetings.js +7 -7
  338. package/test/integration/spec/journey.js +88 -106
  339. package/test/integration/spec/space-meeting.js +10 -10
  340. package/test/unit/spec/breakouts/breakout.ts +2 -1
  341. package/test/unit/spec/breakouts/index.ts +7 -4
  342. package/test/unit/spec/interceptors/locusRetry.ts +131 -0
  343. package/test/unit/spec/locus-info/index.js +206 -13
  344. package/test/unit/spec/locus-info/lib/SeqCmp.json +16 -0
  345. package/test/unit/spec/locus-info/mediaSharesUtils.ts +10 -0
  346. package/test/unit/spec/locus-info/parser.js +54 -13
  347. package/test/unit/spec/locus-info/selfUtils.js +1 -1
  348. package/test/unit/spec/media/index.ts +25 -4
  349. package/test/unit/spec/media/properties.ts +2 -2
  350. package/test/unit/spec/meeting/in-meeting-actions.ts +4 -0
  351. package/test/unit/spec/meeting/index.js +4354 -1285
  352. package/test/unit/spec/meeting/request.js +63 -12
  353. package/test/unit/spec/meeting/utils.js +145 -10
  354. package/test/unit/spec/meeting/voicea-meeting.ts +266 -0
  355. package/test/unit/spec/meeting-info/index.js +180 -61
  356. package/test/unit/spec/meeting-info/meetinginfov2.js +216 -68
  357. package/test/unit/spec/meetings/collection.js +12 -0
  358. package/test/unit/spec/meetings/index.js +676 -195
  359. package/test/unit/spec/meetings/utils.js +35 -12
  360. package/test/unit/spec/member/index.js +8 -7
  361. package/test/unit/spec/member/util.js +32 -0
  362. package/test/unit/spec/members/index.js +130 -17
  363. package/test/unit/spec/members/utils.js +26 -0
  364. package/test/unit/spec/metrics/index.js +1 -2
  365. package/test/unit/spec/multistream/mediaRequestManager.ts +1 -0
  366. package/test/unit/spec/multistream/remoteMediaManager.ts +10 -2
  367. package/test/unit/spec/reachability/clusterReachability.ts +279 -0
  368. package/test/unit/spec/reachability/index.ts +505 -135
  369. package/test/unit/spec/reachability/util.ts +40 -0
  370. package/test/unit/spec/reconnection-manager/index.js +74 -17
  371. package/test/unit/spec/recording-controller/index.js +0 -1
  372. package/test/unit/spec/roap/index.ts +181 -61
  373. package/test/unit/spec/roap/request.ts +27 -3
  374. package/test/unit/spec/roap/turnDiscovery.ts +363 -102
  375. package/test/unit/spec/rtcMetrics/index.ts +57 -3
  376. package/test/unit/spec/stats-analyzer/index.js +1225 -12
  377. package/test/unit/spec/webinar/collection.ts +13 -0
  378. package/test/unit/spec/webinar/index.ts +60 -0
  379. package/test/utils/integrationTestUtils.js +4 -4
  380. package/test/utils/webex-test-users.js +12 -4
  381. package/dist/types/mediaQualityMetrics/config.d.ts +0 -365
  382. package/dist/types/reachability/index.d.ts +0 -158
  383. package/dist/types/statsAnalyzer/mqaUtil.d.ts +0 -24
  384. /package/dist/{types/annotation → annotation}/annotation.types.d.ts +0 -0
  385. /package/dist/{types/annotation → annotation}/constants.d.ts +0 -0
  386. /package/dist/{types/annotation → annotation}/index.d.ts +0 -0
  387. /package/dist/{types/breakouts → breakouts}/breakout.d.ts +0 -0
  388. /package/dist/{types/breakouts → breakouts}/collection.d.ts +0 -0
  389. /package/dist/{types/breakouts → breakouts}/edit-lock-error.d.ts +0 -0
  390. /package/dist/{types/breakouts → breakouts}/events.d.ts +0 -0
  391. /package/dist/{types/breakouts → breakouts}/index.d.ts +0 -0
  392. /package/dist/{types/breakouts → breakouts}/request.d.ts +0 -0
  393. /package/dist/{types/breakouts → breakouts}/utils.d.ts +0 -0
  394. /package/dist/{types/common → common}/browser-detection.d.ts +0 -0
  395. /package/dist/{types/common → common}/collection.d.ts +0 -0
  396. /package/dist/{types/common → common}/config.d.ts +0 -0
  397. /package/dist/{types/common → common}/errors/captcha-error.d.ts +0 -0
  398. /package/dist/{types/common → common}/errors/intent-to-join.d.ts +0 -0
  399. /package/dist/{types/common → common}/errors/join-meeting.d.ts +0 -0
  400. /package/dist/{types/common → common}/errors/media.d.ts +0 -0
  401. /package/dist/{types/common → common}/errors/parameter.d.ts +0 -0
  402. /package/dist/{types/common → common}/errors/password-error.d.ts +0 -0
  403. /package/dist/{types/common → common}/errors/permission.d.ts +0 -0
  404. /package/dist/{types/common → common}/errors/reconnection-in-progress.d.ts +0 -0
  405. /package/dist/{types/common → common}/errors/reconnection.d.ts +0 -0
  406. /package/dist/{types/common → common}/errors/stats.d.ts +0 -0
  407. /package/dist/{types/common → common}/errors/webex-meetings-error.d.ts +0 -0
  408. /package/dist/{types/common → common}/events/events-scope.d.ts +0 -0
  409. /package/dist/{types/common → common}/events/events.d.ts +0 -0
  410. /package/dist/{types/common → common}/events/trigger-proxy.d.ts +0 -0
  411. /package/dist/{types/common → common}/events/util.d.ts +0 -0
  412. /package/dist/{types/common → common}/logs/logger-config.d.ts +0 -0
  413. /package/dist/{types/common → common}/logs/logger-proxy.d.ts +0 -0
  414. /package/dist/{types/common → common}/queue.d.ts +0 -0
  415. /package/dist/{types/controls-options-manager → controls-options-manager}/constants.d.ts +0 -0
  416. /package/dist/{types/controls-options-manager → controls-options-manager}/enums.d.ts +0 -0
  417. /package/dist/{types/controls-options-manager → controls-options-manager}/index.d.ts +0 -0
  418. /package/dist/{types/controls-options-manager → controls-options-manager}/types.d.ts +0 -0
  419. /package/dist/{types/controls-options-manager → controls-options-manager}/util.d.ts +0 -0
  420. /package/dist/{types/index.d.ts → index.d.ts} +0 -0
  421. /package/dist/{types/interpretation → interpretation}/collection.d.ts +0 -0
  422. /package/dist/{types/interpretation → interpretation}/index.d.ts +0 -0
  423. /package/dist/{types/interpretation → interpretation}/siLanguage.d.ts +0 -0
  424. /package/dist/{types/locus-info → locus-info}/controlsUtils.d.ts +0 -0
  425. /package/dist/{types/locus-info → locus-info}/embeddedAppsUtils.d.ts +0 -0
  426. /package/dist/{types/locus-info → locus-info}/fullState.d.ts +0 -0
  427. /package/dist/{types/locus-info → locus-info}/hostUtils.d.ts +0 -0
  428. /package/dist/{types/locus-info → locus-info}/infoUtils.d.ts +0 -0
  429. /package/dist/{types/locus-info → locus-info}/mediaSharesUtils.d.ts +0 -0
  430. /package/dist/{types/locus-info → locus-info}/selfUtils.d.ts +0 -0
  431. /package/dist/{types/media → media}/index.d.ts +0 -0
  432. /package/dist/{types/media → media}/properties.d.ts +0 -0
  433. /package/dist/{types/media → media}/util.d.ts +0 -0
  434. /package/dist/{types/meeting → meeting}/muteState.d.ts +0 -0
  435. /package/dist/{types/meeting → meeting}/request.type.d.ts +0 -0
  436. /package/dist/{types/meeting → meeting}/state.d.ts +0 -0
  437. /package/dist/{types/meeting-info → meeting-info}/collection.d.ts +0 -0
  438. /package/dist/{types/meeting-info → meeting-info}/request.d.ts +0 -0
  439. /package/dist/{types/meeting-info → meeting-info}/util.d.ts +0 -0
  440. /package/dist/{types/meeting-info → meeting-info}/utilv2.d.ts +0 -0
  441. /package/dist/{types/meetings → meetings}/meetings.types.d.ts +0 -0
  442. /package/dist/{types/meetings → meetings}/request.d.ts +0 -0
  443. /package/dist/{types/meetings → meetings}/util.d.ts +0 -0
  444. /package/dist/{types/member → member}/types.d.ts +0 -0
  445. /package/dist/{types/member → member}/util.d.ts +0 -0
  446. /package/dist/{types/members → members}/collection.d.ts +0 -0
  447. /package/dist/{types/members → members}/index.d.ts +0 -0
  448. /package/dist/{types/members → members}/request.d.ts +0 -0
  449. /package/dist/{types/metrics → metrics}/index.d.ts +0 -0
  450. /package/dist/{types/multistream → multistream}/mediaRequestManager.d.ts +0 -0
  451. /package/dist/{types/multistream → multistream}/receiveSlot.d.ts +0 -0
  452. /package/dist/{types/multistream → multistream}/receiveSlotManager.d.ts +0 -0
  453. /package/dist/{types/multistream → multistream}/remoteMedia.d.ts +0 -0
  454. /package/dist/{types/multistream → multistream}/remoteMediaGroup.d.ts +0 -0
  455. /package/dist/{types/multistream → multistream}/sendSlotManager.d.ts +0 -0
  456. /package/dist/{types/networkQualityMonitor → networkQualityMonitor}/index.d.ts +0 -0
  457. /package/dist/{types/personal-meeting-room → personal-meeting-room}/index.d.ts +0 -0
  458. /package/dist/{types/personal-meeting-room → personal-meeting-room}/request.d.ts +0 -0
  459. /package/dist/{types/personal-meeting-room → personal-meeting-room}/util.d.ts +0 -0
  460. /package/dist/{types/reactions → reactions}/constants.d.ts +0 -0
  461. /package/dist/{types/reactions → reactions}/reactions.d.ts +0 -0
  462. /package/dist/{types/reactions → reactions}/reactions.type.d.ts +0 -0
  463. /package/dist/{types/recording-controller → recording-controller}/enums.d.ts +0 -0
  464. /package/dist/{types/recording-controller → recording-controller}/index.d.ts +0 -0
  465. /package/dist/{types/recording-controller → recording-controller}/util.d.ts +0 -0
  466. /package/dist/{types/rtcMetrics → rtcMetrics}/constants.d.ts +0 -0
  467. /package/dist/{types/statsAnalyzer → statsAnalyzer}/global.d.ts +0 -0
  468. /package/dist/{types/transcription → transcription}/index.d.ts +0 -0
  469. /package/test/unit/spec/locus-info/{selfConstant.js → lib/selfConstant.js} +0 -0
@@ -7,6 +7,9 @@ import {ConnectionState} from '@webex/internal-media-core';
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,6 +18,186 @@ 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;
@@ -90,6 +273,8 @@ describe('plugin-meetings', () => {
90
273
  let networkQualityMonitor;
91
274
  let statsAnalyzer;
92
275
  let mqeData;
276
+ let loggerSpy;
277
+ let receiveSlot;
93
278
 
94
279
  let receivedEventsData = {
95
280
  local: {},
@@ -102,6 +287,8 @@ describe('plugin-meetings', () => {
102
287
 
103
288
  let fakeStats;
104
289
 
290
+ const sandbox = sinon.createSandbox();
291
+
105
292
  const resetReceivedEvents = () => {
106
293
  receivedEventsData = {
107
294
  local: {},
@@ -109,8 +296,15 @@ describe('plugin-meetings', () => {
109
296
  };
110
297
  };
111
298
 
299
+ before(() => {
300
+ LoggerConfig.set({enable: false});
301
+ LoggerProxy.set();
302
+ loggerSpy = sandbox.spy(LoggerProxy.logger, 'info');
303
+ });
304
+
112
305
  beforeEach(() => {
113
306
  clock = sinon.useFakeTimers();
307
+ receiveSlot = undefined;
114
308
 
115
309
  resetReceivedEvents();
116
310
 
@@ -119,11 +313,31 @@ describe('plugin-meetings', () => {
119
313
  audio: {
120
314
  senders: [
121
315
  {
316
+ localTrackLabel: 'fake-microphone',
122
317
  report: [
123
318
  {
124
319
  type: 'outbound-rtp',
125
- packetsSent: 0,
126
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',
127
341
  },
128
342
  ],
129
343
  },
@@ -133,8 +347,29 @@ describe('plugin-meetings', () => {
133
347
  report: [
134
348
  {
135
349
  type: 'inbound-rtp',
136
- packetsReceived: 0,
137
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',
138
373
  },
139
374
  ],
140
375
  },
@@ -143,11 +378,32 @@ describe('plugin-meetings', () => {
143
378
  video: {
144
379
  senders: [
145
380
  {
381
+ localTrackLabel: 'fake-camera',
146
382
  report: [
147
383
  {
148
384
  type: 'outbound-rtp',
149
- framesSent: 0,
150
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',
151
407
  },
152
408
  ],
153
409
  },
@@ -157,11 +413,99 @@ describe('plugin-meetings', () => {
157
413
  report: [
158
414
  {
159
415
  type: 'inbound-rtp',
416
+ bytesReceived: 1,
417
+ frameHeight: 720,
418
+ frameWidth: 1280,
160
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',
161
484
  bytesReceived: 1,
162
485
  frameHeight: 720,
163
486
  frameWidth: 1280,
164
- framesReceived: 1,
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',
165
509
  },
166
510
  ],
167
511
  },
@@ -181,19 +525,19 @@ describe('plugin-meetings', () => {
181
525
  receivers: [fakeStats.video.receivers[0]],
182
526
  },
183
527
  screenShareAudio: {
184
- senders: [],
185
- receivers: [],
528
+ senders: [fakeStats.audio.senders[0]],
529
+ receivers: [fakeStats.audio.receivers[0]],
186
530
  },
187
531
  screenShareVideo: {
188
- senders: [],
189
- receivers: [],
532
+ senders: [fakeStats.share.senders[0]],
533
+ receivers: [fakeStats.share.receivers[0]],
190
534
  },
191
535
  }),
192
536
  };
193
537
 
194
538
  networkQualityMonitor = new NetworkQualityMonitor(initialConfig);
195
539
 
196
- statsAnalyzer = new StatsAnalyzer(initialConfig, () => ({}), networkQualityMonitor);
540
+ statsAnalyzer = new StatsAnalyzer(initialConfig, () => receiveSlot, networkQualityMonitor);
197
541
 
198
542
  statsAnalyzer.on(EVENTS.LOCAL_MEDIA_STARTED, (data) => {
199
543
  receivedEventsData.local.started = data;
@@ -213,18 +557,39 @@ describe('plugin-meetings', () => {
213
557
  });
214
558
 
215
559
  afterEach(() => {
560
+ sandbox.reset();
216
561
  clock.restore();
217
562
  });
218
563
 
219
- const startStatsAnalyzer = async (mediaStatus) => {
564
+ const startStatsAnalyzer = async (mediaStatus, lastEmittedEvents) => {
220
565
  statsAnalyzer.updateMediaStatus(mediaStatus);
221
566
  statsAnalyzer.startAnalyzer(pc);
567
+ statsAnalyzer.lastEmittedStartStopEvent = lastEmittedEvents || {};
222
568
 
223
569
  await testUtils.flushPromises();
224
570
  };
225
571
 
226
- const progressTime = async () => {
227
- 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);
228
593
  await testUtils.flushPromises();
229
594
  };
230
595
 
@@ -237,6 +602,17 @@ describe('plugin-meetings', () => {
237
602
  };
238
603
 
239
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
+
240
616
  assert.strictEqual(mqeData.videoReceive[0].streams[0].receivedFrameSize, 3600);
241
617
  assert.strictEqual(mqeData.videoReceive[0].streams[0].receivedHeight, 720);
242
618
  assert.strictEqual(mqeData.videoReceive[0].streams[0].receivedWidth, 1280);
@@ -282,6 +658,26 @@ describe('plugin-meetings', () => {
282
658
  checkReceivedEvent({expected: {local: {stopped: {type: 'video'}}}});
283
659
  });
284
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
+
285
681
  it('emits REMOTE_MEDIA_STARTED and REMOTE_MEDIA_STOPPED events for audio', async () => {
286
682
  await startStatsAnalyzer({expected: {receiveAudio: true}});
287
683
 
@@ -322,6 +718,26 @@ describe('plugin-meetings', () => {
322
718
  checkReceivedEvent({expected: {remote: {stopped: {type: 'video'}}}});
323
719
  });
324
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
+
325
741
  it('emits the correct MEDIA_QUALITY events', async () => {
326
742
  await startStatsAnalyzer({expected: {receiveVideo: true}});
327
743
 
@@ -330,6 +746,803 @@ describe('plugin-meetings', () => {
330
746
  // Check that the mqe data has been emitted and is correctly computed.
331
747
  checkMqeData();
332
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
+ });
333
1546
  });
334
1547
  });
335
1548
  });