@webex/plugin-meetings 2.59.8-next.2 → 2.60.0-next.1

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 (433) hide show
  1. package/README.md +46 -8
  2. package/dist/annotation/annotation.types.js +7 -0
  3. package/dist/annotation/annotation.types.js.map +1 -0
  4. package/dist/annotation/constants.js +41 -0
  5. package/dist/annotation/constants.js.map +1 -0
  6. package/dist/annotation/index.js +357 -0
  7. package/dist/annotation/index.js.map +1 -0
  8. package/dist/breakouts/breakout.js +215 -0
  9. package/dist/breakouts/breakout.js.map +1 -0
  10. package/dist/breakouts/collection.js +22 -0
  11. package/dist/breakouts/collection.js.map +1 -0
  12. package/dist/breakouts/edit-lock-error.js +51 -0
  13. package/dist/breakouts/edit-lock-error.js.map +1 -0
  14. package/dist/breakouts/events.js +44 -0
  15. package/dist/breakouts/events.js.map +1 -0
  16. package/dist/breakouts/index.js +1047 -0
  17. package/dist/breakouts/index.js.map +1 -0
  18. package/dist/breakouts/request.js +77 -0
  19. package/dist/breakouts/request.js.map +1 -0
  20. package/dist/breakouts/utils.js +64 -0
  21. package/dist/breakouts/utils.js.map +1 -0
  22. package/dist/common/browser-detection.js +1 -2
  23. package/dist/common/browser-detection.js.map +1 -1
  24. package/dist/common/collection.js +1 -2
  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.js +50 -0
  37. package/dist/common/errors/no-meeting-info.js.map +1 -0
  38. package/dist/common/errors/parameter.js +3 -4
  39. package/dist/common/errors/parameter.js.map +1 -1
  40. package/dist/common/errors/password-error.js +1 -2
  41. package/dist/common/errors/password-error.js.map +1 -1
  42. package/dist/common/errors/permission.js +1 -2
  43. package/dist/common/errors/permission.js.map +1 -1
  44. package/dist/common/errors/reclaim-host-role-errors.js +154 -0
  45. package/dist/common/errors/reclaim-host-role-errors.js.map +1 -0
  46. package/dist/common/errors/reconnection-in-progress.js +1 -2
  47. package/dist/common/errors/reconnection-in-progress.js.map +1 -1
  48. package/dist/common/errors/reconnection.js +1 -2
  49. package/dist/common/errors/reconnection.js.map +1 -1
  50. package/dist/common/errors/stats.js +1 -2
  51. package/dist/common/errors/stats.js.map +1 -1
  52. package/dist/common/errors/webex-errors.js +48 -28
  53. package/dist/common/errors/webex-errors.js.map +1 -1
  54. package/dist/common/errors/webex-meetings-error.js +1 -2
  55. package/dist/common/errors/webex-meetings-error.js.map +1 -1
  56. package/dist/common/events/events-scope.js +1 -2
  57. package/dist/common/events/events-scope.js.map +1 -1
  58. package/dist/common/events/events.js +1 -2
  59. package/dist/common/events/events.js.map +1 -1
  60. package/dist/common/events/trigger-proxy.js +1 -2
  61. package/dist/common/events/trigger-proxy.js.map +1 -1
  62. package/dist/common/events/util.js +1 -2
  63. package/dist/common/events/util.js.map +1 -1
  64. package/dist/common/logs/logger-config.js +1 -2
  65. package/dist/common/logs/logger-config.js.map +1 -1
  66. package/dist/common/logs/logger-proxy.js +2 -3
  67. package/dist/common/logs/logger-proxy.js.map +1 -1
  68. package/dist/common/logs/request.js +8 -5
  69. package/dist/common/logs/request.js.map +1 -1
  70. package/dist/common/queue.js +22 -9
  71. package/dist/common/queue.js.map +1 -1
  72. package/dist/config.js +9 -12
  73. package/dist/config.js.map +1 -1
  74. package/dist/constants.js +437 -433
  75. package/dist/constants.js.map +1 -1
  76. package/dist/controls-options-manager/constants.js +3 -6
  77. package/dist/controls-options-manager/constants.js.map +1 -1
  78. package/dist/controls-options-manager/enums.js +14 -6
  79. package/dist/controls-options-manager/enums.js.map +1 -1
  80. package/dist/controls-options-manager/index.js +126 -37
  81. package/dist/controls-options-manager/index.js.map +1 -1
  82. package/dist/controls-options-manager/types.js +7 -0
  83. package/dist/controls-options-manager/types.js.map +1 -0
  84. package/dist/controls-options-manager/util.js +309 -19
  85. package/dist/controls-options-manager/util.js.map +1 -1
  86. package/dist/index.js +116 -4
  87. package/dist/index.js.map +1 -1
  88. package/dist/interpretation/collection.js +22 -0
  89. package/dist/interpretation/collection.js.map +1 -0
  90. package/dist/interpretation/index.js +365 -0
  91. package/dist/interpretation/index.js.map +1 -0
  92. package/dist/interpretation/siLanguage.js +24 -0
  93. package/dist/interpretation/siLanguage.js.map +1 -0
  94. package/dist/locus-info/controlsUtils.js +95 -6
  95. package/dist/locus-info/controlsUtils.js.map +1 -1
  96. package/dist/locus-info/embeddedAppsUtils.js +3 -4
  97. package/dist/locus-info/embeddedAppsUtils.js.map +1 -1
  98. package/dist/locus-info/fullState.js +1 -2
  99. package/dist/locus-info/fullState.js.map +1 -1
  100. package/dist/locus-info/hostUtils.js +1 -2
  101. package/dist/locus-info/hostUtils.js.map +1 -1
  102. package/dist/locus-info/index.js +408 -67
  103. package/dist/locus-info/index.js.map +1 -1
  104. package/dist/locus-info/infoUtils.js +13 -5
  105. package/dist/locus-info/infoUtils.js.map +1 -1
  106. package/dist/locus-info/mediaSharesUtils.js +58 -3
  107. package/dist/locus-info/mediaSharesUtils.js.map +1 -1
  108. package/dist/locus-info/parser.js +251 -78
  109. package/dist/locus-info/parser.js.map +1 -1
  110. package/dist/locus-info/selfUtils.js +97 -13
  111. package/dist/locus-info/selfUtils.js.map +1 -1
  112. package/dist/media/index.js +106 -319
  113. package/dist/media/index.js.map +1 -1
  114. package/dist/media/properties.js +96 -153
  115. package/dist/media/properties.js.map +1 -1
  116. package/dist/media/util.js +1 -22
  117. package/dist/media/util.js.map +1 -1
  118. package/dist/mediaQualityMetrics/config.js +498 -493
  119. package/dist/mediaQualityMetrics/config.js.map +1 -1
  120. package/dist/meeting/in-meeting-actions.js +90 -3
  121. package/dist/meeting/in-meeting-actions.js.map +1 -1
  122. package/dist/meeting/index.js +4579 -2951
  123. package/dist/meeting/index.js.map +1 -1
  124. package/dist/meeting/locusMediaRequest.js +291 -0
  125. package/dist/meeting/locusMediaRequest.js.map +1 -0
  126. package/dist/meeting/muteState.js +224 -133
  127. package/dist/meeting/muteState.js.map +1 -1
  128. package/dist/meeting/request.js +295 -197
  129. package/dist/meeting/request.js.map +1 -1
  130. package/dist/meeting/request.type.js +7 -0
  131. package/dist/meeting/request.type.js.map +1 -0
  132. package/dist/meeting/state.js +1 -2
  133. package/dist/meeting/state.js.map +1 -1
  134. package/dist/meeting/util.js +602 -432
  135. package/dist/meeting/util.js.map +1 -1
  136. package/dist/meeting-info/collection.js +1 -2
  137. package/dist/meeting-info/collection.js.map +1 -1
  138. package/dist/meeting-info/index.js +74 -7
  139. package/dist/meeting-info/index.js.map +1 -1
  140. package/dist/meeting-info/meeting-info-v2.js +197 -63
  141. package/dist/meeting-info/meeting-info-v2.js.map +1 -1
  142. package/dist/meeting-info/request.js +1 -2
  143. package/dist/meeting-info/request.js.map +1 -1
  144. package/dist/meeting-info/util.js +2 -3
  145. package/dist/meeting-info/util.js.map +1 -1
  146. package/dist/meeting-info/utilv2.js +25 -12
  147. package/dist/meeting-info/utilv2.js.map +1 -1
  148. package/dist/meetings/collection.js +23 -2
  149. package/dist/meetings/collection.js.map +1 -1
  150. package/dist/meetings/index.js +464 -123
  151. package/dist/meetings/index.js.map +1 -1
  152. package/dist/meetings/meetings.types.js +7 -0
  153. package/dist/meetings/meetings.types.js.map +1 -0
  154. package/dist/meetings/request.js +4 -3
  155. package/dist/meetings/request.js.map +1 -1
  156. package/dist/meetings/util.js +107 -6
  157. package/dist/meetings/util.js.map +1 -1
  158. package/dist/member/index.js +54 -2
  159. package/dist/member/index.js.map +1 -1
  160. package/dist/member/member.types.js +3 -4
  161. package/dist/member/member.types.js.map +1 -1
  162. package/dist/member/types.js +23 -0
  163. package/dist/member/types.js.map +1 -0
  164. package/dist/member/util.js +131 -29
  165. package/dist/member/util.js.map +1 -1
  166. package/dist/members/collection.js +11 -2
  167. package/dist/members/collection.js.map +1 -1
  168. package/dist/members/index.js +172 -8
  169. package/dist/members/index.js.map +1 -1
  170. package/dist/members/request.js +108 -41
  171. package/dist/members/request.js.map +1 -1
  172. package/dist/members/types.js +14 -0
  173. package/dist/members/types.js.map +1 -0
  174. package/dist/members/util.js +327 -234
  175. package/dist/members/util.js.map +1 -1
  176. package/dist/metrics/constants.js +14 -7
  177. package/dist/metrics/constants.js.map +1 -1
  178. package/dist/metrics/index.js +4 -452
  179. package/dist/metrics/index.js.map +1 -1
  180. package/dist/multistream/mediaRequestManager.js +344 -0
  181. package/dist/multistream/mediaRequestManager.js.map +1 -0
  182. package/dist/multistream/receiveSlot.js +200 -0
  183. package/dist/multistream/receiveSlot.js.map +1 -0
  184. package/dist/multistream/receiveSlotManager.js +174 -0
  185. package/dist/multistream/receiveSlotManager.js.map +1 -0
  186. package/dist/multistream/remoteMedia.js +268 -0
  187. package/dist/multistream/remoteMedia.js.map +1 -0
  188. package/dist/multistream/remoteMediaGroup.js +267 -0
  189. package/dist/multistream/remoteMediaGroup.js.map +1 -0
  190. package/dist/multistream/remoteMediaManager.js +1211 -0
  191. package/dist/multistream/remoteMediaManager.js.map +1 -0
  192. package/dist/multistream/sendSlotManager.js +236 -0
  193. package/dist/multistream/sendSlotManager.js.map +1 -0
  194. package/dist/networkQualityMonitor/index.js +5 -4
  195. package/dist/networkQualityMonitor/index.js.map +1 -1
  196. package/dist/personal-meeting-room/index.js +2 -3
  197. package/dist/personal-meeting-room/index.js.map +1 -1
  198. package/dist/personal-meeting-room/request.js +2 -3
  199. package/dist/personal-meeting-room/request.js.map +1 -1
  200. package/dist/personal-meeting-room/util.js +1 -2
  201. package/dist/personal-meeting-room/util.js.map +1 -1
  202. package/dist/reachability/index.js +258 -72
  203. package/dist/reachability/index.js.map +1 -1
  204. package/dist/reachability/request.js +18 -10
  205. package/dist/reachability/request.js.map +1 -1
  206. package/dist/reactions/constants.js +12 -0
  207. package/dist/reactions/constants.js.map +1 -0
  208. package/dist/reactions/reactions.js +4 -6
  209. package/dist/reactions/reactions.js.map +1 -1
  210. package/dist/reactions/reactions.type.js +21 -23
  211. package/dist/reactions/reactions.type.js.map +1 -1
  212. package/dist/reconnection-manager/index.js +272 -220
  213. package/dist/reconnection-manager/index.js.map +1 -1
  214. package/dist/recording-controller/enums.js +4 -5
  215. package/dist/recording-controller/enums.js.map +1 -1
  216. package/dist/recording-controller/index.js +57 -46
  217. package/dist/recording-controller/index.js.map +1 -1
  218. package/dist/recording-controller/util.js +10 -10
  219. package/dist/recording-controller/util.js.map +1 -1
  220. package/dist/roap/index.js +101 -235
  221. package/dist/roap/index.js.map +1 -1
  222. package/dist/roap/request.js +126 -180
  223. package/dist/roap/request.js.map +1 -1
  224. package/dist/roap/turnDiscovery.js +115 -105
  225. package/dist/roap/turnDiscovery.js.map +1 -1
  226. package/dist/rtcMetrics/constants.js +11 -0
  227. package/dist/rtcMetrics/constants.js.map +1 -0
  228. package/dist/rtcMetrics/index.js +115 -0
  229. package/dist/rtcMetrics/index.js.map +1 -0
  230. package/dist/statsAnalyzer/global.js +2 -93
  231. package/dist/statsAnalyzer/global.js.map +1 -1
  232. package/dist/statsAnalyzer/index.js +374 -374
  233. package/dist/statsAnalyzer/index.js.map +1 -1
  234. package/dist/statsAnalyzer/mqaUtil.js +100 -66
  235. package/dist/statsAnalyzer/mqaUtil.js.map +1 -1
  236. package/dist/transcription/index.js +1 -2
  237. package/dist/transcription/index.js.map +1 -1
  238. package/dist/webinar/collection.js +43 -0
  239. package/dist/webinar/collection.js.map +1 -0
  240. package/dist/webinar/index.js +68 -0
  241. package/dist/webinar/index.js.map +1 -0
  242. package/package.json +27 -18
  243. package/src/annotation/annotation.types.ts +50 -0
  244. package/src/annotation/constants.ts +36 -0
  245. package/src/annotation/index.ts +328 -0
  246. package/src/breakouts/README.md +220 -0
  247. package/src/breakouts/breakout.ts +188 -0
  248. package/src/breakouts/collection.ts +19 -0
  249. package/src/breakouts/edit-lock-error.ts +25 -0
  250. package/src/breakouts/events.ts +56 -0
  251. package/src/breakouts/index.ts +925 -0
  252. package/src/breakouts/request.ts +55 -0
  253. package/src/breakouts/utils.ts +57 -0
  254. package/src/common/errors/no-meeting-info.ts +24 -0
  255. package/src/common/errors/reclaim-host-role-errors.ts +134 -0
  256. package/src/common/errors/webex-errors.ts +36 -12
  257. package/src/common/logs/logger-proxy.ts +1 -1
  258. package/src/common/logs/request.ts +5 -1
  259. package/src/common/queue.ts +22 -8
  260. package/src/config.ts +7 -9
  261. package/src/constants.ts +263 -89
  262. package/src/controls-options-manager/enums.ts +11 -1
  263. package/src/controls-options-manager/index.ts +116 -21
  264. package/src/controls-options-manager/types.ts +59 -0
  265. package/src/controls-options-manager/util.ts +294 -14
  266. package/src/index.ts +40 -0
  267. package/src/interpretation/README.md +60 -0
  268. package/src/interpretation/collection.ts +19 -0
  269. package/src/interpretation/index.ts +332 -0
  270. package/src/interpretation/siLanguage.ts +18 -0
  271. package/src/locus-info/controlsUtils.ts +110 -0
  272. package/src/locus-info/index.ts +449 -61
  273. package/src/locus-info/infoUtils.ts +14 -2
  274. package/src/locus-info/mediaSharesUtils.ts +64 -0
  275. package/src/locus-info/parser.ts +258 -47
  276. package/src/locus-info/selfUtils.ts +85 -2
  277. package/src/media/index.ts +153 -370
  278. package/src/media/properties.ts +106 -136
  279. package/src/media/util.ts +0 -21
  280. package/src/mediaQualityMetrics/config.ts +379 -377
  281. package/src/meeting/in-meeting-actions.ts +168 -0
  282. package/src/meeting/index.ts +3801 -2457
  283. package/src/meeting/locusMediaRequest.ts +313 -0
  284. package/src/meeting/muteState.ts +224 -138
  285. package/src/meeting/request.ts +207 -127
  286. package/src/meeting/request.type.ts +13 -0
  287. package/src/meeting/util.ts +590 -423
  288. package/src/meeting-info/index.ts +81 -8
  289. package/src/meeting-info/meeting-info-v2.ts +159 -13
  290. package/src/meeting-info/util.ts +1 -1
  291. package/src/meeting-info/utilv2.ts +22 -9
  292. package/src/meetings/collection.ts +20 -0
  293. package/src/meetings/index.ts +466 -124
  294. package/src/meetings/meetings.types.ts +12 -0
  295. package/src/meetings/request.ts +2 -0
  296. package/src/meetings/util.ts +116 -5
  297. package/src/member/index.ts +52 -1
  298. package/src/member/types.ts +38 -0
  299. package/src/member/util.ts +139 -28
  300. package/src/members/collection.ts +8 -0
  301. package/src/members/index.ts +196 -7
  302. package/src/members/request.ts +97 -17
  303. package/src/members/types.ts +29 -0
  304. package/src/members/util.ts +333 -240
  305. package/src/metrics/constants.ts +12 -4
  306. package/src/metrics/index.ts +1 -471
  307. package/src/multistream/mediaRequestManager.ts +440 -0
  308. package/src/multistream/receiveSlot.ts +184 -0
  309. package/src/multistream/receiveSlotManager.ts +166 -0
  310. package/src/multistream/remoteMedia.ts +254 -0
  311. package/src/multistream/remoteMediaGroup.ts +284 -0
  312. package/src/multistream/remoteMediaManager.ts +1145 -0
  313. package/src/multistream/sendSlotManager.ts +170 -0
  314. package/src/networkQualityMonitor/index.ts +6 -6
  315. package/src/reachability/index.ts +238 -45
  316. package/src/reachability/request.ts +17 -8
  317. package/src/reactions/constants.ts +4 -0
  318. package/src/reactions/reactions.ts +4 -4
  319. package/src/reactions/reactions.type.ts +30 -4
  320. package/src/reconnection-manager/index.ts +124 -107
  321. package/src/recording-controller/index.ts +20 -3
  322. package/src/recording-controller/util.ts +26 -9
  323. package/src/roap/index.ts +98 -240
  324. package/src/roap/request.ts +74 -148
  325. package/src/roap/turnDiscovery.ts +62 -56
  326. package/src/rtcMetrics/constants.ts +3 -0
  327. package/src/rtcMetrics/index.ts +100 -0
  328. package/src/statsAnalyzer/global.ts +1 -92
  329. package/src/statsAnalyzer/index.ts +429 -447
  330. package/src/statsAnalyzer/mqaUtil.ts +105 -103
  331. package/src/webinar/collection.ts +31 -0
  332. package/src/webinar/index.ts +62 -0
  333. package/test/integration/spec/converged-space-meetings.js +233 -0
  334. package/test/integration/spec/journey.js +320 -264
  335. package/test/integration/spec/space-meeting.js +77 -4
  336. package/test/unit/spec/annotation/index.ts +418 -0
  337. package/test/unit/spec/breakouts/breakout.ts +237 -0
  338. package/test/unit/spec/breakouts/collection.ts +15 -0
  339. package/test/unit/spec/breakouts/edit-lock-error.ts +30 -0
  340. package/test/unit/spec/breakouts/events.ts +89 -0
  341. package/test/unit/spec/breakouts/index.ts +1790 -0
  342. package/test/unit/spec/breakouts/request.ts +104 -0
  343. package/test/unit/spec/breakouts/utils.js +72 -0
  344. package/test/unit/spec/common/queue.js +31 -2
  345. package/test/unit/spec/controls-options-manager/index.js +163 -0
  346. package/test/unit/spec/controls-options-manager/util.js +576 -60
  347. package/test/unit/spec/fixture/locus.js +1 -0
  348. package/test/unit/spec/interpretation/collection.ts +15 -0
  349. package/test/unit/spec/interpretation/index.ts +589 -0
  350. package/test/unit/spec/interpretation/siLanguage.ts +28 -0
  351. package/test/unit/spec/locus-info/controlsUtils.js +323 -30
  352. package/test/unit/spec/locus-info/index.js +1390 -16
  353. package/test/unit/spec/locus-info/infoUtils.js +54 -16
  354. package/test/unit/spec/locus-info/lib/SeqCmp.json +16 -0
  355. package/test/unit/spec/locus-info/lib/selfConstant.js +48 -0
  356. package/test/unit/spec/locus-info/mediaSharesUtils.ts +32 -0
  357. package/test/unit/spec/locus-info/parser.js +116 -35
  358. package/test/unit/spec/locus-info/selfUtils.js +275 -0
  359. package/test/unit/spec/media/index.ts +274 -0
  360. package/test/unit/spec/media/properties.ts +75 -84
  361. package/test/unit/spec/meeting/in-meeting-actions.ts +82 -0
  362. package/test/unit/spec/meeting/index.js +7420 -3125
  363. package/test/unit/spec/meeting/locusMediaRequest.ts +442 -0
  364. package/test/unit/spec/meeting/muteState.js +407 -212
  365. package/test/unit/spec/meeting/request.js +512 -42
  366. package/test/unit/spec/meeting/utils.js +741 -24
  367. package/test/unit/spec/meeting-info/index.js +300 -0
  368. package/test/unit/spec/meeting-info/meetinginfov2.js +500 -6
  369. package/test/unit/spec/meeting-info/utilv2.js +21 -0
  370. package/test/unit/spec/meetings/collection.js +14 -0
  371. package/test/unit/spec/meetings/index.js +1012 -209
  372. package/test/unit/spec/meetings/utils.js +202 -2
  373. package/test/unit/spec/member/index.js +38 -8
  374. package/test/unit/spec/member/util.js +528 -27
  375. package/test/unit/spec/members/index.js +597 -3
  376. package/test/unit/spec/members/request.js +206 -27
  377. package/test/unit/spec/members/utils.js +210 -0
  378. package/test/unit/spec/metrics/index.js +1 -50
  379. package/test/unit/spec/multistream/mediaRequestManager.ts +1418 -0
  380. package/test/unit/spec/multistream/receiveSlot.ts +163 -0
  381. package/test/unit/spec/multistream/receiveSlotManager.ts +203 -0
  382. package/test/unit/spec/multistream/remoteMedia.ts +255 -0
  383. package/test/unit/spec/multistream/remoteMediaGroup.ts +662 -0
  384. package/test/unit/spec/multistream/remoteMediaManager.ts +1924 -0
  385. package/test/unit/spec/multistream/sendSlotManager.ts +242 -0
  386. package/test/unit/spec/networkQualityMonitor/index.js +4 -4
  387. package/test/unit/spec/reachability/index.ts +598 -24
  388. package/test/unit/spec/reachability/request.js +68 -0
  389. package/test/unit/spec/reconnection-manager/index.js +130 -22
  390. package/test/unit/spec/recording-controller/index.js +293 -218
  391. package/test/unit/spec/recording-controller/util.js +223 -96
  392. package/test/unit/spec/roap/index.ts +200 -77
  393. package/test/unit/spec/roap/request.ts +232 -0
  394. package/test/unit/spec/roap/turnDiscovery.ts +86 -48
  395. package/test/unit/spec/rtcMetrics/index.ts +73 -0
  396. package/test/unit/spec/stats-analyzer/index.js +205 -50
  397. package/test/unit/spec/webinar/collection.ts +13 -0
  398. package/test/unit/spec/webinar/index.ts +60 -0
  399. package/test/utils/constants.js +9 -0
  400. package/test/utils/integrationTestUtils.js +46 -0
  401. package/test/utils/testUtils.js +0 -45
  402. package/test/utils/webex-config.js +4 -0
  403. package/test/utils/webex-test-users.js +7 -3
  404. package/dist/meeting/effectsState.js +0 -260
  405. package/dist/meeting/effectsState.js.map +0 -1
  406. package/dist/metrics/config.js +0 -289
  407. package/dist/metrics/config.js.map +0 -1
  408. package/dist/peer-connection-manager/index.js +0 -671
  409. package/dist/peer-connection-manager/index.js.map +0 -1
  410. package/dist/peer-connection-manager/util.js +0 -110
  411. package/dist/peer-connection-manager/util.js.map +0 -1
  412. package/dist/roap/collection.js +0 -63
  413. package/dist/roap/collection.js.map +0 -1
  414. package/dist/roap/handler.js +0 -279
  415. package/dist/roap/handler.js.map +0 -1
  416. package/dist/roap/state.js +0 -127
  417. package/dist/roap/state.js.map +0 -1
  418. package/dist/roap/util.js +0 -76
  419. package/dist/roap/util.js.map +0 -1
  420. package/src/index.js +0 -15
  421. package/src/meeting/effectsState.ts +0 -209
  422. package/src/metrics/config.ts +0 -485
  423. package/src/peer-connection-manager/index.ts +0 -847
  424. package/src/peer-connection-manager/util.ts +0 -119
  425. package/src/roap/collection.ts +0 -62
  426. package/src/roap/handler.ts +0 -294
  427. package/src/roap/state.ts +0 -156
  428. package/src/roap/util.ts +0 -100
  429. package/test/unit/spec/meeting/effectsState.js +0 -281
  430. package/test/unit/spec/peerconnection-manager/index.js +0 -218
  431. package/test/unit/spec/peerconnection-manager/utils.js +0 -49
  432. package/test/unit/spec/peerconnection-manager/utils.test-fixtures.ts +0 -388
  433. package/test/unit/spec/roap/util.js +0 -30
@@ -1,18 +1,24 @@
1
1
  /* eslint-disable prefer-destructuring */
2
2
 
3
3
  import {cloneDeep} from 'lodash';
4
+ import {ConnectionState} from '@webex/internal-media-core';
4
5
 
5
6
  import EventsScope from '../common/events/events-scope';
6
7
  import {
7
8
  DEFAULT_GET_STATS_FILTER,
8
- CONNECTION_STATE,
9
9
  STATS,
10
10
  MQA_INTEVAL,
11
11
  NETWORK_TYPE,
12
12
  MEDIA_DEVICES,
13
13
  _UNKNOWN_,
14
14
  } from '../constants';
15
- import mqaData from '../mediaQualityMetrics/config';
15
+ import {
16
+ emptyAudioReceive,
17
+ emptyAudioTransmit,
18
+ emptyMqaInterval,
19
+ emptyVideoReceive,
20
+ emptyVideoTransmit,
21
+ } from '../mediaQualityMetrics/config';
16
22
  import LoggerProxy from '../common/logs/logger-proxy';
17
23
 
18
24
  import defaultStats from './global';
@@ -22,6 +28,7 @@ import {
22
28
  getVideoSenderMqa,
23
29
  getVideoReceiverMqa,
24
30
  } from './mqaUtil';
31
+ import {ReceiveSlot} from '../multistream/receiveSlot';
25
32
 
26
33
  export const EVENTS = {
27
34
  MEDIA_QUALITY: 'MEDIA_QUALITY',
@@ -31,6 +38,24 @@ export const EVENTS = {
31
38
  REMOTE_MEDIA_STOPPED: 'REMOTE_MEDIA_STOPPED',
32
39
  };
33
40
 
41
+ const emptySender = {
42
+ trackLabel: '',
43
+ maxPacketLossRatio: 0,
44
+ availableBandwidth: 0,
45
+ bytesSent: 0,
46
+ meanRemoteJitter: [],
47
+ meanRoundTripTime: [],
48
+ };
49
+
50
+ const emptyReceiver = {
51
+ availableBandwidth: 0,
52
+ bytesReceived: 0,
53
+ meanRtpJitter: [],
54
+ meanRoundTripTime: [],
55
+ };
56
+
57
+ type ReceiveSlotCallback = (csi: number) => ReceiveSlot | undefined;
58
+
34
59
  /**
35
60
  * Stats Analyzer class that will emit events based on detected quality
36
61
  *
@@ -44,26 +69,29 @@ export class StatsAnalyzer extends EventsScope {
44
69
  lastEmittedStartStopEvent: any;
45
70
  lastMqaDataSent: any;
46
71
  lastStatsResults: any;
47
- localMQEStats: any;
48
72
  meetingMediaStatus: any;
49
73
  mqaInterval: NodeJS.Timeout;
50
74
  mqaSentCount: any;
51
75
  networkQualityMonitor: any;
52
- peerConnection: any;
76
+ mediaConnection: any;
53
77
  statsInterval: NodeJS.Timeout;
54
78
  statsResults: any;
55
79
  statsStarted: any;
80
+ successfulCandidatePair: any;
81
+ receiveSlotCallback: ReceiveSlotCallback;
56
82
 
57
83
  /**
58
84
  * Creates a new instance of StatsAnalyzer
59
85
  * @constructor
60
86
  * @public
61
87
  * @param {Object} config SDK Configuration Object
88
+ * @param {Function} receiveSlotCallback Callback used to access receive slots.
62
89
  * @param {Object} networkQualityMonitor class for assessing network characteristics (jitter, packetLoss, latency)
63
90
  * @param {Object} statsResults Default properties for stats
64
91
  */
65
92
  constructor(
66
93
  config: any,
94
+ receiveSlotCallback: ReceiveSlotCallback = () => undefined,
67
95
  networkQualityMonitor: object = {},
68
96
  statsResults: object = defaultStats
69
97
  ) {
@@ -75,147 +103,30 @@ export class StatsAnalyzer extends EventsScope {
75
103
  this.networkQualityMonitor = networkQualityMonitor;
76
104
  this.correlationId = config.correlationId;
77
105
  this.mqaSentCount = -1;
78
- this.lastMqaDataSent = {
79
- resolutions: {
80
- video: {send: {}, recv: {}},
81
- audio: {send: {}, recv: {}},
82
- share: {send: {}, recv: {}},
83
- },
84
- video: {send: {}, recv: {}},
85
- audio: {send: {}, recv: {}},
86
- share: {send: {}, recv: {}},
87
- };
88
- this.localMQEStats = {
89
- audio: {
90
- RX: {
91
- packetsLost: [],
92
- jitter: [],
93
- latency: [],
94
- bitRate: [],
95
- },
96
- TX: {
97
- packetsLost: [],
98
- jitter: [],
99
- latency: [],
100
- bitRate: [],
101
- },
102
- },
103
- video: {
104
- RX: {
105
- packetsLost: [],
106
- jitter: [],
107
- latency: [],
108
- bitRate: [],
109
- frameRate: [],
110
- resolutionWidth: [],
111
- resolutionHeight: [],
112
- requestedKeyFrame: [],
113
- receivedKeyFrame: [],
114
- },
115
- TX: {
116
- packetsLost: [],
117
- jitter: [],
118
- latency: [],
119
- bitRate: [],
120
- frameRate: [],
121
- resolutionWidth: [],
122
- resolutionHeight: [],
123
- requestedKeyFrame: [],
124
- receivedKeyFrame: [],
125
- },
126
- },
127
- };
128
- this.lastEmittedStartStopEvent = {
129
- audio: {
130
- local: undefined,
131
- remote: undefined,
132
- },
133
- video: {
134
- local: undefined,
135
- remote: undefined,
136
- },
137
- share: {
138
- local: undefined,
139
- remote: undefined,
140
- },
141
- };
142
- }
143
-
144
- populateResults(lastMqa) {
145
- // Audio
146
-
147
- this.localMQEStats.audio.RX.packetsLost.push(lastMqa.audioReceive[0].common.mediaHopByHopLost);
148
- this.localMQEStats.audio.RX.jitter.push(lastMqa.audioReceive[0].streams[0].common.rtpJitter);
149
- this.localMQEStats.audio.RX.latency.push(lastMqa.audioReceive[0].common.roundTripTime);
150
- this.localMQEStats.audio.RX.bitRate.push(
151
- lastMqa.audioReceive[0].streams[0].common.receivedBitrate
152
- );
153
-
154
- this.localMQEStats.audio.TX.packetsLost.push(lastMqa.audioTransmit[0].common.remoteLossRate);
155
- this.localMQEStats.audio.TX.jitter.push(lastMqa.audioTransmit[0].common.remoteJitter);
156
- this.localMQEStats.audio.TX.latency.push(lastMqa.audioTransmit[0].common.roundTripTime);
157
- this.localMQEStats.audio.TX.bitRate.push(
158
- lastMqa.audioTransmit[0].streams[0].common.transmittedBitrate
159
- );
160
-
161
- // Video
162
-
163
- this.localMQEStats.video.RX.packetsLost.push(lastMqa.videoReceive[0].common.mediaHopByHopLost);
164
- this.localMQEStats.video.RX.jitter.push(lastMqa.videoReceive[0].streams[0].common.rtpJitter);
165
- this.localMQEStats.video.RX.latency.push(
166
- lastMqa.videoReceive[0].streams[0].common.roundTripTime
167
- );
168
- this.localMQEStats.video.RX.bitRate.push(
169
- lastMqa.videoReceive[0].streams[0].common.receivedBitrate
170
- );
171
- this.localMQEStats.video.RX.frameRate.push(
172
- lastMqa.videoReceive[0].streams[0].common.receivedFrameRate
173
- );
174
- this.localMQEStats.video.RX.resolutionWidth.push(
175
- lastMqa.videoReceive[0].streams[0].receivedWidth
176
- );
177
- this.localMQEStats.video.RX.resolutionHeight.push(
178
- lastMqa.videoReceive[0].streams[0].receivedHeight
179
- );
180
- this.localMQEStats.video.RX.requestedKeyFrame.push();
181
- this.localMQEStats.video.RX.receivedKeyFrame.push();
182
-
183
- this.localMQEStats.video.TX.packetsLost.push(lastMqa.videoTransmit[0].common.remoteLossRate);
184
- this.localMQEStats.video.TX.jitter.push(lastMqa.videoTransmit[0].common.remoteJitter);
185
- this.localMQEStats.video.TX.latency.push(lastMqa.videoTransmit[0].common.roundTripTime);
186
- this.localMQEStats.video.TX.bitRate.push(
187
- lastMqa.videoTransmit[0].streams[0].common.transmittedBitrate
188
- );
189
- this.localMQEStats.video.TX.frameRate.push(
190
- lastMqa.videoTransmit[0].streams[0].common.transmittedFrameRate
191
- );
192
- this.localMQEStats.video.TX.resolutionWidth.push(
193
- lastMqa.videoTransmit[0].streams[0].transmittedWidth
194
- );
195
- this.localMQEStats.video.TX.resolutionHeight.push(
196
- lastMqa.videoTransmit[0].streams[0].transmittedHeight
197
- );
198
- this.localMQEStats.video.TX.requestedKeyFrame.push(
199
- lastMqa.videoTransmit[0].streams[0].requestedKeyFrames
200
- );
201
- this.localMQEStats.video.TX.receivedKeyFrame.push();
106
+ this.lastMqaDataSent = {};
107
+ this.lastEmittedStartStopEvent = {};
108
+ this.receiveSlotCallback = receiveSlotCallback;
109
+ this.successfulCandidatePair = {};
202
110
  }
203
111
 
112
+ /**
113
+ * Resets cumulative stats arrays.
114
+ *
115
+ * @public
116
+ * @memberof StatsAnalyzer
117
+ * @returns {void}
118
+ */
204
119
  resetStatsResults() {
205
- this.statsResults.audio.send.meanRemoteJitter = [];
206
- this.statsResults.video.send.meanRemoteJitter = [];
207
- this.statsResults.share.send.meanRemoteJitter = [];
208
-
209
- this.statsResults.audio.recv.meanRtpJitter = [];
210
-
211
- // TODO: currently no values are present
212
- this.statsResults.video.recv.meanRtpJitter = [];
213
- this.statsResults.share.recv.meanRtpJitter = [];
120
+ Object.keys(this.statsResults).forEach((mediaType) => {
121
+ if (mediaType.includes('recv')) {
122
+ this.statsResults[mediaType].recv.meanRtpJitter = [];
123
+ }
214
124
 
215
- // Reset the roundTripTime
216
- this.statsResults.audio.send.meanRoundTripTime = [];
217
- this.statsResults.video.send.meanRoundTripTime = [];
218
- this.statsResults.share.send.meanRoundTripTime = [];
125
+ if (mediaType.includes('send')) {
126
+ this.statsResults[mediaType].send.meanRemoteJitter = [];
127
+ this.statsResults[mediaType].send.meanRoundTripTime = [];
128
+ }
129
+ });
219
130
  }
220
131
 
221
132
  /**
@@ -231,86 +142,81 @@ export class StatsAnalyzer extends EventsScope {
231
142
  }
232
143
 
233
144
  /**
234
- * captures MQA data from peerconnection
145
+ * captures MQA data from media connection
235
146
  *
236
147
  * @public
237
148
  * @memberof StatsAnalyzer
238
149
  * @returns {void}
239
150
  */
240
- public sendMqaData() {
241
- const audioReceiver = mqaData.intervals[0].audioReceive[0];
242
- const audioSender = mqaData.intervals[0].audioTransmit[0];
243
- const videoReceiver = mqaData.intervals[0].videoReceive[0];
244
- const videoSender = mqaData.intervals[0].videoTransmit[0];
245
- const shareSender = mqaData.intervals[0].videoTransmit[1];
246
- const shareReceiver = mqaData.intervals[0].videoReceive[1];
247
-
248
- getAudioSenderMqa({
249
- audioSender,
250
- statsResults: this.statsResults,
251
- lastMqaDataSent: this.lastMqaDataSent,
252
- });
253
- getAudioReceiverMqa({
254
- audioReceiver,
255
- statsResults: this.statsResults,
256
- lastMqaDataSent: this.lastMqaDataSent,
257
- });
258
-
259
- getVideoReceiverMqa({
260
- videoReceiver,
261
- statsResults: this.statsResults,
262
- lastMqaDataSent: this.lastMqaDataSent,
263
- });
264
- getVideoSenderMqa({
265
- videoSender,
266
- statsResults: this.statsResults,
267
- lastMqaDataSent: this.lastMqaDataSent,
268
- });
151
+ sendMqaData() {
152
+ const newMqa = cloneDeep(emptyMqaInterval);
269
153
 
270
- // Capture mqa for share scenario
154
+ Object.keys(this.statsResults).forEach((mediaType) => {
155
+ if (mediaType.includes('audio-send') || mediaType.includes('audio-share-send')) {
156
+ const audioSender = cloneDeep(emptyAudioTransmit);
271
157
 
272
- getVideoSenderMqa({
273
- videoSender: shareSender,
274
- statsResults: this.statsResults,
275
- lastMqaDataSent: this.lastMqaDataSent,
276
- isShareStream: true,
158
+ getAudioSenderMqa({
159
+ audioSender,
160
+ statsResults: this.statsResults,
161
+ lastMqaDataSent: this.lastMqaDataSent,
162
+ mediaType,
163
+ });
164
+ newMqa.audioTransmit.push(audioSender);
165
+ } else if (mediaType.includes('audio-recv') || mediaType.includes('audio-share-recv')) {
166
+ const audioReceiver = cloneDeep(emptyAudioReceive);
167
+
168
+ getAudioReceiverMqa({
169
+ audioReceiver,
170
+ statsResults: this.statsResults,
171
+ lastMqaDataSent: this.lastMqaDataSent,
172
+ mediaType,
173
+ });
174
+ newMqa.audioReceive.push(audioReceiver);
175
+ } else if (mediaType.includes('video-send') || mediaType.includes('video-share-send')) {
176
+ const videoSender = cloneDeep(emptyVideoTransmit);
177
+
178
+ getVideoSenderMqa({
179
+ videoSender,
180
+ statsResults: this.statsResults,
181
+ lastMqaDataSent: this.lastMqaDataSent,
182
+ mediaType,
183
+ });
184
+ newMqa.videoTransmit.push(videoSender);
185
+ } else if (mediaType.includes('video-recv') || mediaType.includes('video-share-recv')) {
186
+ const videoReceiver = cloneDeep(emptyVideoReceive);
187
+
188
+ getVideoReceiverMqa({
189
+ videoReceiver,
190
+ statsResults: this.statsResults,
191
+ lastMqaDataSent: this.lastMqaDataSent,
192
+ mediaType,
193
+ });
194
+ newMqa.videoReceive.push(videoReceiver);
195
+ }
277
196
  });
278
197
 
279
- getVideoReceiverMqa({
280
- videoReceiver: shareReceiver,
281
- statsResults: this.statsResults,
282
- lastMqaDataSent: this.lastMqaDataSent,
283
- isShareStream: true,
284
- });
285
- mqaData.intervals[0].intervalMetadata.peerReflexiveIP =
286
- this.statsResults.connectionType.local.ipAddress[0];
198
+ newMqa.intervalMetadata.peerReflexiveIP = this.statsResults.connectionType.local.ipAddress;
287
199
 
288
200
  // Adding peripheral information
289
- mqaData.intervals[0].intervalMetadata.peripherals = [];
290
- mqaData.intervals[0].intervalMetadata.peripherals.push({
291
- information: _UNKNOWN_,
292
- name: MEDIA_DEVICES.SPEAKER,
293
- });
294
- mqaData.intervals[0].intervalMetadata.peripherals.push({
295
- information: this.peerConnection?.audioTransceiver?.sender?.track?.label || _UNKNOWN_,
296
- name: MEDIA_DEVICES.MICROPHONE,
297
- });
298
- mqaData.intervals[0].intervalMetadata.peripherals.push({
299
- information: this.peerConnection?.videoTransceiver?.sender?.track?.label || _UNKNOWN_,
300
- name: MEDIA_DEVICES.CAMERA,
301
- });
201
+ newMqa.intervalMetadata.peripherals.push({information: _UNKNOWN_, name: MEDIA_DEVICES.SPEAKER});
202
+ if (this.statsResults['audio-send']) {
203
+ newMqa.intervalMetadata.peripherals.push({
204
+ information: this.statsResults['audio-send'].trackLabel || _UNKNOWN_,
205
+ name: MEDIA_DEVICES.MICROPHONE,
206
+ });
207
+ }
208
+ if (this.statsResults['video-send']) {
209
+ newMqa.intervalMetadata.peripherals.push({
210
+ information: this.statsResults['video-send'].trackLabel || _UNKNOWN_,
211
+ name: MEDIA_DEVICES.CAMERA,
212
+ });
213
+ }
302
214
 
303
- // @ts-ignore
304
- mqaData.networkType = this.statsResults.connectionType.local.networkType;
215
+ newMqa.networkType = this.statsResults.connectionType.local.networkType;
305
216
 
306
217
  this.mqaSentCount += 1;
307
218
 
308
- mqaData.intervals[0].intervalNumber = this.mqaSentCount;
309
-
310
- // DO Deep copy, for some reason it takes the reference all the time rather then old value set
311
- this.lastMqaDataSent = cloneDeep(this.statsResults);
312
-
313
- this.populateResults(mqaData.intervals[0]);
219
+ newMqa.intervalNumber = this.mqaSentCount;
314
220
 
315
221
  this.resetStatsResults();
316
222
 
@@ -321,23 +227,23 @@ export class StatsAnalyzer extends EventsScope {
321
227
  },
322
228
  EVENTS.MEDIA_QUALITY,
323
229
  {
324
- data: mqaData.intervals[0],
230
+ data: newMqa,
325
231
  // @ts-ignore
326
- networkType: mqaData.networkType,
232
+ networkType: newMqa.networkType,
327
233
  }
328
234
  );
329
235
  }
330
236
 
331
237
  /**
332
- * updated the peerconnection when changed
238
+ * updated the media connection when changed
333
239
  *
334
240
  * @private
335
- * @memberof updatePeerconnection
336
- * @param {PeerConnection} peerConnection
241
+ * @memberof StatsAnalyzer
242
+ * @param {RoapMediaConnection} mediaConnection
337
243
  * @returns {void}
338
244
  */
339
- updatePeerconnection(peerConnection: any) {
340
- this.peerConnection = peerConnection;
245
+ updateMediaConnection(mediaConnection: any) {
246
+ this.mediaConnection = mediaConnection;
341
247
  }
342
248
 
343
249
  /**
@@ -345,13 +251,13 @@ export class StatsAnalyzer extends EventsScope {
345
251
  *
346
252
  * @public
347
253
  * @memberof StatsAnalyzer
348
- * @param {PeerConnection} peerConnection
254
+ * @param {RoapMediaConnection} mediaConnection
349
255
  * @returns {Promise}
350
256
  */
351
- public startAnalyzer(peerConnection: any) {
257
+ public startAnalyzer(mediaConnection: any) {
352
258
  if (!this.statsStarted) {
353
259
  this.statsStarted = true;
354
- this.peerConnection = peerConnection;
260
+ this.mediaConnection = mediaConnection;
355
261
 
356
262
  return this.getStatsAndParse().then(() => {
357
263
  this.statsInterval = setInterval(() => {
@@ -391,7 +297,7 @@ export class StatsAnalyzer extends EventsScope {
391
297
  if (sendOneLastMqa) {
392
298
  return this.getStatsAndParse().then(() => {
393
299
  this.sendMqaData();
394
- this.peerConnection = null;
300
+ this.mediaConnection = null;
395
301
  });
396
302
  }
397
303
 
@@ -413,6 +319,37 @@ export class StatsAnalyzer extends EventsScope {
413
319
  return;
414
320
  }
415
321
 
322
+ // Generate empty stats results
323
+ if (!this.statsResults[type]) {
324
+ this.statsResults[type] = {};
325
+ }
326
+
327
+ if (isSender && !this.statsResults[type].send) {
328
+ this.statsResults[type].send = cloneDeep(emptySender);
329
+ } else if (!isSender && !this.statsResults[type].recv) {
330
+ this.statsResults[type].recv = cloneDeep(emptyReceiver);
331
+ }
332
+
333
+ if (!this.statsResults.resolutions[type]) {
334
+ this.statsResults.resolutions[type] = {};
335
+ }
336
+
337
+ if (isSender && !this.statsResults.resolutions[type].send) {
338
+ this.statsResults.resolutions[type].send = cloneDeep(emptySender);
339
+ } else if (!isSender && !this.statsResults.resolutions[type].recv) {
340
+ this.statsResults.resolutions[type].recv = cloneDeep(emptyReceiver);
341
+ }
342
+
343
+ if (!this.statsResults.internal[type]) {
344
+ this.statsResults.internal[type] = {};
345
+ }
346
+
347
+ if (isSender && !this.statsResults.internal[type].send) {
348
+ this.statsResults.internal[type].send = cloneDeep(emptySender);
349
+ } else if (!isSender && !this.statsResults.internal[type].recv) {
350
+ this.statsResults.internal[type].recv = cloneDeep(emptyReceiver);
351
+ }
352
+
416
353
  switch (getStatsResult.type) {
417
354
  case 'outbound-rtp':
418
355
  this.processOutboundRTPResult(getStatsResult, type);
@@ -447,23 +384,34 @@ export class StatsAnalyzer extends EventsScope {
447
384
  /**
448
385
  * Filters the get stats results for types
449
386
  * @private
450
- * @param {Array} getStatsResults
387
+ * @param {Array} statsItem
451
388
  * @param {String} type
452
389
  * @param {boolean} isSender
453
390
  * @returns {void}
454
391
  */
455
- private filterAndParseGetStatsResults(
456
- getStatsResults: Array<any>,
457
- type: string,
458
- isSender: boolean
459
- ) {
392
+ filterAndParseGetStatsResults(statsItem: any, type: string, isSender: boolean) {
460
393
  const {types} = DEFAULT_GET_STATS_FILTER;
461
394
 
462
- getStatsResults.forEach((result) => {
395
+ // get the successful candidate pair before parsing stats.
396
+ statsItem.report.forEach((report) => {
397
+ if (report.type === 'candidate-pair' && report.state === 'succeeded') {
398
+ this.successfulCandidatePair = report;
399
+ }
400
+ });
401
+
402
+ statsItem.report.forEach((result) => {
463
403
  if (types.includes(result.type)) {
464
404
  this.parseGetStatsResult(result, type, isSender);
465
405
  }
466
406
  });
407
+
408
+ if (this.statsResults[type]) {
409
+ this.statsResults[type].direction = statsItem.currentDirection;
410
+ this.statsResults[type].trackLabel = statsItem.localTrackLabel;
411
+ this.statsResults[type].csi = statsItem.csi;
412
+ // reset the successful candidate pair.
413
+ this.successfulCandidatePair = {};
414
+ }
467
415
  }
468
416
 
469
417
  /**
@@ -477,7 +425,7 @@ export class StatsAnalyzer extends EventsScope {
477
425
  return;
478
426
  }
479
427
 
480
- if (type === STATS.AUDIO_CORRELATE) {
428
+ if (type.includes('audio-send')) {
481
429
  this.statsResults[type].send.audioLevel = result.audioLevel;
482
430
  this.statsResults[type].send.totalAudioEnergy = result.totalAudioEnergy;
483
431
  }
@@ -512,6 +460,10 @@ export class StatsAnalyzer extends EventsScope {
512
460
  // eslint-disable-next-line no-param-reassign
513
461
  if (currentValue === undefined) currentValue = 0;
514
462
 
463
+ if (!this.lastEmittedStartStopEvent[mediaType]) {
464
+ this.lastEmittedStartStopEvent[mediaType] = {};
465
+ }
466
+
515
467
  const lastEmittedEvent = isLocal
516
468
  ? this.lastEmittedStartStopEvent[mediaType].local
517
469
  : this.lastEmittedStartStopEvent[mediaType].remote;
@@ -552,21 +504,42 @@ export class StatsAnalyzer extends EventsScope {
552
504
  */
553
505
  private compareLastStatsResult() {
554
506
  if (this.lastStatsResults !== null && this.meetingMediaStatus) {
555
- // compare audio stats sent
556
- let mediaType = STATS.AUDIO_CORRELATE;
557
- let currentStats = null;
558
- let previousStats = null;
507
+ const getCurrentStatsTotals = (keyPrefix: string, value: string): number =>
508
+ Object.keys(this.statsResults)
509
+ .filter((key) => key.startsWith(keyPrefix))
510
+ .reduce((prev, cur) => prev + (this.statsResults[cur]?.recv[value] || 0), 0);
511
+
512
+ const getPreviousStatsTotals = (keyPrefix: string, value: string): number =>
513
+ Object.keys(this.statsResults)
514
+ .filter((key) => key.startsWith(keyPrefix))
515
+ .reduce((prev, cur) => prev + (this.lastStatsResults[cur]?.recv[value] || 0), 0);
516
+
517
+ const getCurrentResolutionsStatsTotals = (keyPrefix: string, value: string): number =>
518
+ Object.keys(this.statsResults)
519
+ .filter((key) => key.startsWith(keyPrefix))
520
+ .reduce((prev, cur) => prev + (this.statsResults.resolutions[cur]?.recv[value] || 0), 0);
521
+
522
+ const getPreviousResolutionsStatsTotals = (keyPrefix: string, value: string): number =>
523
+ Object.keys(this.statsResults)
524
+ .filter((key) => key.startsWith(keyPrefix))
525
+ .reduce(
526
+ (prev, cur) => prev + (this.lastStatsResults.resolutions[cur]?.recv[value] || 0),
527
+ 0
528
+ );
559
529
 
560
- if (this.meetingMediaStatus.expected.sendAudio) {
561
- currentStats = this.statsResults[mediaType].send;
562
- previousStats = this.lastStatsResults[mediaType].send;
530
+ if (this.meetingMediaStatus.expected.sendAudio && this.lastStatsResults['audio-send']) {
531
+ // compare audio stats sent
532
+ // NOTE: relies on there being only one sender.
533
+ const currentStats = this.statsResults['audio-send'].send;
534
+ const previousStats = this.lastStatsResults['audio-send'].send;
563
535
 
564
536
  if (
565
537
  currentStats.totalPacketsSent === previousStats.totalPacketsSent ||
566
538
  currentStats.totalPacketsSent === 0
567
539
  ) {
568
540
  LoggerProxy.logger.info(
569
- `StatsAnalyzer:index#compareLastStatsResult --> No ${mediaType} RTP packets sent`
541
+ `StatsAnalyzer:index#compareLastStatsResult --> No audio RTP packets sent`,
542
+ currentStats.totalPacketsSent
570
543
  );
571
544
  } else {
572
545
  if (
@@ -574,19 +547,20 @@ export class StatsAnalyzer extends EventsScope {
574
547
  currentStats.totalAudioEnergy === 0
575
548
  ) {
576
549
  LoggerProxy.logger.info(
577
- `StatsAnalyzer:index#compareLastStatsResult --> No ${mediaType} Energy present`
550
+ `StatsAnalyzer:index#compareLastStatsResult --> No audio Energy present`,
551
+ currentStats.totalAudioEnergy
578
552
  );
579
553
  }
580
554
 
581
555
  if (currentStats.audioLevel === 0) {
582
556
  LoggerProxy.logger.info(
583
- `StatsAnalyzer:index#compareLastStatsResult --> ${mediaType} level is 0 for the user`
557
+ `StatsAnalyzer:index#compareLastStatsResult --> audio level is 0 for the user`
584
558
  );
585
559
  }
586
560
  }
587
561
 
588
562
  this.emitStartStopEvents(
589
- mediaType,
563
+ 'audio',
590
564
  previousStats.totalPacketsSent,
591
565
  currentStats.totalPacketsSent,
592
566
  true
@@ -595,45 +569,47 @@ export class StatsAnalyzer extends EventsScope {
595
569
 
596
570
  if (this.meetingMediaStatus.expected.receiveAudio) {
597
571
  // compare audio stats received
598
- currentStats = this.statsResults[mediaType].recv;
599
- previousStats = this.lastStatsResults[mediaType].recv;
572
+ const currentPacketsReceived = getCurrentStatsTotals('audio-recv', 'totalPacketsReceived');
573
+ const previousPacketsReceived = getPreviousStatsTotals(
574
+ 'audio-recv',
575
+ 'totalPacketsReceived'
576
+ );
577
+ const currentSamplesReceived = getCurrentStatsTotals('audio-recv', 'totalSamplesReceived');
578
+ const previousSamplesReceived = getPreviousStatsTotals(
579
+ 'audio-recv',
580
+ 'totalSamplesReceived'
581
+ );
600
582
 
601
- if (
602
- currentStats.totalPacketsReceived === previousStats.totalPacketsReceived ||
603
- currentStats.totalPacketsReceived === 0
604
- ) {
583
+ if (currentPacketsReceived === previousPacketsReceived || currentPacketsReceived === 0) {
605
584
  LoggerProxy.logger.info(
606
- `StatsAnalyzer:index#compareLastStatsResult --> No ${mediaType} RTP packets received`
585
+ `StatsAnalyzer:index#compareLastStatsResult --> No audio RTP packets received`,
586
+ currentPacketsReceived
607
587
  );
608
588
  } else if (
609
- currentStats.totalSamplesReceived === previousStats.totalSamplesReceived ||
610
- currentStats.totalSamplesReceived === 0
589
+ currentSamplesReceived === previousSamplesReceived ||
590
+ currentSamplesReceived === 0
611
591
  ) {
612
592
  LoggerProxy.logger.info(
613
- `StatsAnalyzer:index#compareLastStatsResult --> No ${mediaType} samples received`
593
+ `StatsAnalyzer:index#compareLastStatsResult --> No audio samples received`,
594
+ currentSamplesReceived
614
595
  );
615
596
  }
616
597
 
617
- this.emitStartStopEvents(
618
- mediaType,
619
- previousStats.totalPacketsReceived,
620
- currentStats.totalPacketsReceived,
621
- false
622
- );
598
+ this.emitStartStopEvents('audio', previousPacketsReceived, currentPacketsReceived, false);
623
599
  }
624
600
 
625
- mediaType = STATS.VIDEO_CORRELATE;
626
- if (this.meetingMediaStatus.expected.sendVideo) {
601
+ if (this.meetingMediaStatus.expected.sendVideo && this.lastStatsResults['video-send']) {
627
602
  // compare video stats sent
628
- currentStats = this.statsResults[mediaType].send;
629
- previousStats = this.lastStatsResults[mediaType].send;
603
+ const currentStats = this.statsResults['video-send'].send;
604
+ const previousStats = this.lastStatsResults['video-send'].send;
630
605
 
631
606
  if (
632
607
  currentStats.totalPacketsSent === previousStats.totalPacketsSent ||
633
608
  currentStats.totalPacketsSent === 0
634
609
  ) {
635
610
  LoggerProxy.logger.info(
636
- `StatsAnalyzer:index#compareLastStatsResult --> No ${mediaType} RTP packets sent`
611
+ `StatsAnalyzer:index#compareLastStatsResult --> No video RTP packets sent`,
612
+ currentStats.totalPacketsSent
637
613
  );
638
614
  } else {
639
615
  if (
@@ -641,95 +617,96 @@ export class StatsAnalyzer extends EventsScope {
641
617
  currentStats.framesEncoded === 0
642
618
  ) {
643
619
  LoggerProxy.logger.info(
644
- `StatsAnalyzer:index#compareLastStatsResult --> No ${mediaType} Frames Encoded`
620
+ `StatsAnalyzer:index#compareLastStatsResult --> No video Frames Encoded`,
621
+ currentStats.framesEncoded
645
622
  );
646
623
  }
647
624
 
648
625
  if (
649
- this.statsResults.resolutions[mediaType].send.framesSent ===
650
- this.lastStatsResults.resolutions[mediaType].send.framesSent ||
651
- this.statsResults.resolutions[mediaType].send.framesSent === 0
626
+ this.statsResults.resolutions['video-send'].send.framesSent ===
627
+ this.lastStatsResults.resolutions['video-send'].send.framesSent ||
628
+ this.statsResults.resolutions['video-send'].send.framesSent === 0
652
629
  ) {
653
630
  LoggerProxy.logger.info(
654
- `StatsAnalyzer:index#compareLastStatsResult --> No ${mediaType} Frames sent`
631
+ `StatsAnalyzer:index#compareLastStatsResult --> No video Frames sent`,
632
+ this.statsResults.resolutions['video-send'].send.framesSent
655
633
  );
656
634
  }
657
635
  }
658
636
 
659
- this.emitStartStopEvents(
660
- mediaType,
661
- previousStats.framesSent,
662
- currentStats.framesSent,
663
- true
664
- );
637
+ this.emitStartStopEvents('video', previousStats.framesSent, currentStats.framesSent, true);
665
638
  }
666
639
 
667
640
  if (this.meetingMediaStatus.expected.receiveVideo) {
668
- // compare video stats reveived
669
-
670
- currentStats = this.statsResults[mediaType].recv;
671
- previousStats = this.lastStatsResults[mediaType].recv;
641
+ // compare video stats received
642
+ const currentPacketsReceived = getCurrentStatsTotals('video-recv', 'totalPacketsReceived');
643
+ const previousPacketsReceived = getPreviousStatsTotals(
644
+ 'video-recv',
645
+ 'totalPacketsReceived'
646
+ );
647
+ const currentFramesReceived = getCurrentResolutionsStatsTotals(
648
+ 'video-recv',
649
+ 'framesReceived'
650
+ );
651
+ const previousFramesReceived = getPreviousResolutionsStatsTotals(
652
+ 'video-recv',
653
+ 'framesReceived'
654
+ );
655
+ const currentFramesDecoded = getCurrentStatsTotals('video-recv', 'framesDecoded');
656
+ const previousFramesDecoded = getPreviousStatsTotals('video-recv', 'framesDecoded');
657
+ const currentFramesDropped = getCurrentResolutionsStatsTotals(
658
+ 'video-recv',
659
+ 'framesDropped'
660
+ );
661
+ const previousFramesDropped = getPreviousResolutionsStatsTotals(
662
+ 'video-recv',
663
+ 'framesDropped'
664
+ );
672
665
 
673
- if (
674
- currentStats.totalPacketsReceived === previousStats.totalPacketsReceived ||
675
- currentStats.totalPacketsReceived === 0
676
- ) {
666
+ if (currentPacketsReceived === previousPacketsReceived || currentPacketsReceived === 0) {
677
667
  LoggerProxy.logger.info(
678
- `StatsAnalyzer:index#compareLastStatsResult --> No ${mediaType} RTP packets received`
668
+ `StatsAnalyzer:index#compareLastStatsResult --> No video RTP packets received`,
669
+ currentPacketsReceived
679
670
  );
680
671
  } else {
681
- if (
682
- this.statsResults.resolutions[mediaType].recv.framesReceived ===
683
- this.lastStatsResults.resolutions[mediaType].recv.framesReceived ||
684
- this.statsResults.resolutions[mediaType].recv.framesReceived === 0
685
- ) {
672
+ if (currentFramesReceived === previousFramesReceived || currentFramesReceived === 0) {
686
673
  LoggerProxy.logger.info(
687
- `StatsAnalyzer:index#compareLastStatsResult --> No ${mediaType} frames received`
674
+ `StatsAnalyzer:index#compareLastStatsResult --> No video frames received`,
675
+ currentFramesReceived
688
676
  );
689
677
  }
690
678
 
691
- if (
692
- this.statsResults[mediaType].recv.framesDecoded ===
693
- this.lastStatsResults[mediaType].recv.framesDecoded ||
694
- this.statsResults.resolutions[mediaType].send.framesDecoded === 0
695
- ) {
679
+ if (currentFramesDecoded === previousFramesDecoded || currentFramesDecoded === 0) {
696
680
  LoggerProxy.logger.info(
697
- `StatsAnalyzer:index#compareLastStatsResult --> No ${mediaType} frames decoded`
681
+ `StatsAnalyzer:index#compareLastStatsResult --> No video frames decoded`,
682
+ currentFramesDecoded
698
683
  );
699
684
  }
700
685
 
701
- if (
702
- this.statsResults.resolutions[mediaType].recv.framesDropped -
703
- this.lastStatsResults.resolutions[mediaType].recv.framesDropped >
704
- 10
705
- ) {
686
+ if (currentFramesDropped - previousFramesDropped > 10) {
706
687
  LoggerProxy.logger.info(
707
- `StatsAnalyzer:index#compareLastStatsResult --> ${mediaType} frames are getting dropped`
688
+ `StatsAnalyzer:index#compareLastStatsResult --> video frames are getting dropped`,
689
+ currentFramesDropped - previousFramesDropped
708
690
  );
709
691
  }
710
692
  }
711
693
 
712
- this.emitStartStopEvents(
713
- mediaType,
714
- previousStats.framesDecoded,
715
- currentStats.framesDecoded,
716
- false
717
- );
694
+ this.emitStartStopEvents('video', previousFramesDecoded, currentFramesDecoded, false);
718
695
  }
719
696
 
720
- mediaType = STATS.SHARE_CORRELATE;
721
- if (this.meetingMediaStatus.expected.sendShare) {
697
+ if (this.meetingMediaStatus.expected.sendShare && this.lastStatsResults['video-share-send']) {
722
698
  // compare share stats sent
723
699
 
724
- currentStats = this.statsResults[mediaType].send;
725
- previousStats = this.lastStatsResults[mediaType].send;
700
+ const currentStats = this.statsResults['video-share-send'].send;
701
+ const previousStats = this.lastStatsResults['video-share-send'].send;
726
702
 
727
703
  if (
728
704
  currentStats.totalPacketsSent === previousStats.totalPacketsSent ||
729
705
  currentStats.totalPacketsSent === 0
730
706
  ) {
731
707
  LoggerProxy.logger.info(
732
- `StatsAnalyzer:index#compareLastStatsResult --> No ${mediaType} RTP packets sent`
708
+ `StatsAnalyzer:index#compareLastStatsResult --> No share RTP packets sent`,
709
+ currentStats.totalPacketsSent
733
710
  );
734
711
  } else {
735
712
  if (
@@ -737,61 +714,78 @@ export class StatsAnalyzer extends EventsScope {
737
714
  currentStats.framesEncoded === 0
738
715
  ) {
739
716
  LoggerProxy.logger.info(
740
- `StatsAnalyzer:index#compareLastStatsResult --> No ${mediaType} frames getting encoded`
717
+ `StatsAnalyzer:index#compareLastStatsResult --> No share frames getting encoded`,
718
+ currentStats.framesEncoded
741
719
  );
742
720
  }
743
721
 
744
722
  if (
745
- this.statsResults.resolutions[mediaType].send.framesSent ===
746
- this.lastStatsResults.resolutions[mediaType].send.framesSent ||
747
- this.statsResults.resolutions[mediaType].send.framesSent === 0
723
+ this.statsResults.resolutions['video-share-send'].send.framesSent ===
724
+ this.lastStatsResults.resolutions['video-share-send'].send.framesSent ||
725
+ this.statsResults.resolutions['video-share-send'].send.framesSent === 0
748
726
  ) {
749
727
  LoggerProxy.logger.info(
750
- `StatsAnalyzer:index#compareLastStatsResult --> No ${mediaType} frames sent`
728
+ `StatsAnalyzer:index#compareLastStatsResult --> No share frames sent`,
729
+ this.statsResults.resolutions['video-share-send'].send.framesSent
751
730
  );
752
731
  }
753
732
  }
733
+ }
754
734
 
735
+ if (this.meetingMediaStatus.expected.sendShare) {
755
736
  // TODO:need to check receive share value
756
- // compare share stats reveived
757
- currentStats = this.statsResults[mediaType].recv;
758
- previousStats = this.lastStatsResults[mediaType].recv;
737
+ // compare share stats received
738
+ const currentPacketsReceived = getCurrentStatsTotals(
739
+ 'video-share-recv',
740
+ 'totalPacketsReceived'
741
+ );
742
+ const previousPacketsReceived = getPreviousStatsTotals(
743
+ 'video-share-recv',
744
+ 'totalPacketsReceived'
745
+ );
746
+ const currentFramesReceived = getCurrentResolutionsStatsTotals(
747
+ 'video-share-recv',
748
+ 'framesReceived'
749
+ );
750
+ const previousFramesReceived = getPreviousResolutionsStatsTotals(
751
+ 'video-share-recv',
752
+ 'framesReceived'
753
+ );
754
+ const currentFramesDecoded = getCurrentStatsTotals('video-share-recv', 'framesDecoded');
755
+ const previousFramesDecoded = getPreviousStatsTotals('video-share-recv', 'framesDecoded');
756
+ const currentFramesDropped = getCurrentResolutionsStatsTotals(
757
+ 'video-share-recv',
758
+ 'framesDropped'
759
+ );
760
+ const previousFramesDropped = getPreviousResolutionsStatsTotals(
761
+ 'video-share-recv',
762
+ 'framesDropped'
763
+ );
759
764
 
760
- if (
761
- currentStats.totalPacketsReceived === previousStats.totalPacketsReceived ||
762
- currentStats.totalPacketsSent === 0
763
- ) {
765
+ if (currentPacketsReceived === previousPacketsReceived || currentPacketsReceived === 0) {
764
766
  LoggerProxy.logger.info(
765
- `StatsAnalyzer:index#compareLastStatsResult --> No ${mediaType} RTP packets received`
767
+ `StatsAnalyzer:index#compareLastStatsResult --> No share RTP packets received`,
768
+ currentPacketsReceived
766
769
  );
767
770
  } else {
768
- if (
769
- this.statsResults.resolutions[mediaType].recv.framesReceived ===
770
- this.lastStatsResults.resolutions[mediaType].recv.framesReceived ||
771
- this.statsResults.resolutions[mediaType].recv.framesReceived === 0
772
- ) {
771
+ if (currentFramesReceived === previousFramesReceived || currentFramesReceived === 0) {
773
772
  LoggerProxy.logger.info(
774
- `StatsAnalyzer:index#compareLastStatsResult --> No ${mediaType} frames received`
773
+ `StatsAnalyzer:index#compareLastStatsResult --> No share frames received`,
774
+ currentFramesReceived
775
775
  );
776
776
  }
777
777
 
778
- if (
779
- this.statsResults[mediaType].recv.framesDecoded ===
780
- this.lastStatsResults[mediaType].recv.framesDecoded ||
781
- this.statsResults.resolutions[mediaType].send.framesDecoded === 0
782
- ) {
778
+ if (currentFramesDecoded === previousFramesDecoded || currentFramesDecoded === 0) {
783
779
  LoggerProxy.logger.info(
784
- `StatsAnalyzer:index#compareLastStatsResult --> No ${mediaType} frames decoded`
780
+ `StatsAnalyzer:index#compareLastStatsResult --> No share frames decoded`,
781
+ currentFramesDecoded
785
782
  );
786
783
  }
787
784
 
788
- if (
789
- this.statsResults.resolutions[mediaType].recv.framesDropped -
790
- this.lastStatsResults.resolutions[mediaType].recv.framesDropped >
791
- 10
792
- ) {
785
+ if (currentFramesDropped - previousFramesDropped > 10) {
793
786
  LoggerProxy.logger.info(
794
- `StatsAnalyzer:index#compareLastStatsResult --> ${mediaType} frames are getting dropped`
787
+ `StatsAnalyzer:index#compareLastStatsResult --> share frames are getting dropped`,
788
+ currentFramesDropped - previousFramesDropped
795
789
  );
796
790
  }
797
791
  }
@@ -811,13 +805,16 @@ export class StatsAnalyzer extends EventsScope {
811
805
  * @returns {Promise}
812
806
  */
813
807
  private getStatsAndParse() {
814
- if (!this.peerConnection) {
808
+ if (!this.mediaConnection) {
815
809
  return Promise.resolve();
816
810
  }
817
811
 
818
- if (this.peerConnection && this.peerConnection.connectionState === CONNECTION_STATE.FAILED) {
812
+ if (
813
+ this.mediaConnection &&
814
+ this.mediaConnection.getConnectionState() === ConnectionState.Failed
815
+ ) {
819
816
  LoggerProxy.logger.trace(
820
- 'StatsAnalyzer:index#getStatsAndParse --> PeerConnection is in failed state'
817
+ 'StatsAnalyzer:index#getStatsAndParse --> media connection is in failed state'
821
818
  );
822
819
 
823
820
  return Promise.resolve();
@@ -825,43 +822,49 @@ export class StatsAnalyzer extends EventsScope {
825
822
 
826
823
  LoggerProxy.logger.trace('StatsAnalyzer:index#getStatsAndParse --> Collecting Stats');
827
824
 
828
- return Promise.all([
829
- this.peerConnection.videoTransceiver.sender.getStats().then((res) => {
830
- this.filterAndParseGetStatsResults(res, STATS.VIDEO_CORRELATE, true);
831
- }),
832
-
833
- this.peerConnection.videoTransceiver.receiver.getStats().then((res) => {
834
- this.filterAndParseGetStatsResults(res, STATS.VIDEO_CORRELATE, false);
835
- }),
836
-
837
- this.peerConnection.audioTransceiver.sender.getStats().then((res) => {
838
- this.filterAndParseGetStatsResults(res, STATS.AUDIO_CORRELATE, true);
839
- }),
840
-
841
- this.peerConnection.audioTransceiver.receiver.getStats().then((res) => {
842
- this.filterAndParseGetStatsResults(res, STATS.AUDIO_CORRELATE, false);
843
- }),
844
-
845
- // TODO: add checks for screen share
846
- this.peerConnection.shareTransceiver.sender.getStats().then((res) => {
847
- this.filterAndParseGetStatsResults(res, STATS.SHARE_CORRELATE, true);
848
- }),
849
-
850
- this.peerConnection.shareTransceiver.receiver.getStats().then((res) => {
851
- this.filterAndParseGetStatsResults(res, STATS.SHARE_CORRELATE, false);
852
- }),
853
- ]).then(() => {
854
- this.statsResults[STATS.AUDIO_CORRELATE].direction =
855
- this.peerConnection.audioTransceiver.currentDirection;
856
- this.statsResults[STATS.VIDEO_CORRELATE].direction =
857
- this.peerConnection.videoTransceiver.currentDirection;
858
- this.statsResults[STATS.SHARE_CORRELATE].direction =
859
- this.peerConnection.shareTransceiver.currentDirection;
860
-
861
- // Process Stats results every 5 seconds
825
+ return this.mediaConnection.getTransceiverStats().then((transceiverStats) => {
826
+ transceiverStats.video.receivers.forEach((receiver, i) =>
827
+ this.filterAndParseGetStatsResults(receiver, `video-recv-${i}`, false)
828
+ );
829
+ transceiverStats.audio.receivers.forEach((receiver, i) =>
830
+ this.filterAndParseGetStatsResults(receiver, `audio-recv-${i}`, false)
831
+ );
832
+ transceiverStats.screenShareVideo.receivers.forEach((receiver, i) =>
833
+ this.filterAndParseGetStatsResults(receiver, `video-share-recv-${i}`, false)
834
+ );
835
+ transceiverStats.screenShareAudio.receivers.forEach((receiver, i) =>
836
+ this.filterAndParseGetStatsResults(receiver, `audio-share-recv-${i}`, false)
837
+ );
838
+
839
+ transceiverStats.video.senders.forEach((sender, i) => {
840
+ if (i > 0) {
841
+ throw new Error('Stats Analyzer does not support multiple senders.');
842
+ }
843
+ this.filterAndParseGetStatsResults(sender, 'video-send', true);
844
+ });
845
+ transceiverStats.audio.senders.forEach((sender, i) => {
846
+ if (i > 0) {
847
+ throw new Error('Stats Analyzer does not support multiple senders.');
848
+ }
849
+ this.filterAndParseGetStatsResults(sender, 'audio-send', true);
850
+ });
851
+ transceiverStats.screenShareVideo.senders.forEach((sender, i) => {
852
+ if (i > 0) {
853
+ throw new Error('Stats Analyzer does not support multiple senders.');
854
+ }
855
+ this.filterAndParseGetStatsResults(sender, 'video-share-send', true);
856
+ });
857
+ transceiverStats.screenShareAudio.senders.forEach((sender, i) => {
858
+ if (i > 0) {
859
+ throw new Error('Stats Analyzer does not support multiple senders.');
860
+ }
861
+ this.filterAndParseGetStatsResults(sender, 'audio-share-send', true);
862
+ });
863
+
862
864
  this.compareLastStatsResult();
863
865
 
864
866
  // Save the last results to compare with the current
867
+ // DO Deep copy, for some reason it takes the reference all the time rather then old value set
865
868
  this.lastStatsResults = JSON.parse(JSON.stringify(this.statsResults));
866
869
 
867
870
  LoggerProxy.logger.trace(
@@ -874,16 +877,23 @@ export class StatsAnalyzer extends EventsScope {
874
877
  * Processes OutboundRTP stats result and stores
875
878
  * @private
876
879
  * @param {*} result
877
- * @param {*} type
880
+ * @param {*} mediaType
878
881
  * @returns {void}
879
882
  */
880
- private processOutboundRTPResult(result: any, type: any) {
881
- const mediaType = type || STATS.AUDIO_CORRELATE;
883
+ private processOutboundRTPResult(result: any, mediaType: any) {
882
884
  const sendrecvType = STATS.SEND_DIRECTION;
883
885
 
884
886
  if (result.bytesSent) {
885
887
  let kilobytes = 0;
886
888
 
889
+ if (result.frameWidth && result.frameHeight) {
890
+ this.statsResults.resolutions[mediaType][sendrecvType].width = result.frameWidth;
891
+ this.statsResults.resolutions[mediaType][sendrecvType].height = result.frameHeight;
892
+ this.statsResults.resolutions[mediaType][sendrecvType].framesSent = result.framesSent;
893
+ this.statsResults.resolutions[mediaType][sendrecvType].hugeFramesSent =
894
+ result.hugeFramesSent;
895
+ }
896
+
887
897
  if (!this.statsResults.internal[mediaType][sendrecvType].prevBytesSent) {
888
898
  this.statsResults.internal[mediaType][sendrecvType].prevBytesSent = result.bytesSent;
889
899
  }
@@ -948,15 +958,25 @@ export class StatsAnalyzer extends EventsScope {
948
958
  * Processes InboundRTP stats result and stores
949
959
  * @private
950
960
  * @param {*} result
951
- * @param {*} type
961
+ * @param {*} mediaType
952
962
  * @returns {void}
953
963
  */
954
- private processInboundRTPResult(result: any, type: any) {
955
- const mediaType = type || STATS.AUDIO_CORRELATE;
964
+ private processInboundRTPResult(result: any, mediaType: any) {
956
965
  const sendrecvType = STATS.RECEIVE_DIRECTION;
957
966
 
958
967
  if (result.bytesReceived) {
959
968
  let kilobytes = 0;
969
+ const receiveSlot = this.receiveSlotCallback(result.ssrc);
970
+ const idAndCsi = receiveSlot
971
+ ? `id: "${receiveSlot.id || ''}"${receiveSlot.csi ? ` and csi: ${receiveSlot.csi}` : ''}`
972
+ : '';
973
+
974
+ if (result.frameWidth && result.frameHeight) {
975
+ this.statsResults.resolutions[mediaType][sendrecvType].width = result.frameWidth;
976
+ this.statsResults.resolutions[mediaType][sendrecvType].height = result.frameHeight;
977
+ this.statsResults.resolutions[mediaType][sendrecvType].framesReceived =
978
+ result.framesReceived;
979
+ }
960
980
 
961
981
  if (!this.statsResults.internal[mediaType][sendrecvType].prevBytesReceived) {
962
982
  this.statsResults.internal[mediaType][sendrecvType].prevBytesReceived =
@@ -1006,10 +1026,12 @@ export class StatsAnalyzer extends EventsScope {
1006
1026
  result.packetsReceived;
1007
1027
 
1008
1028
  if (this.statsResults[mediaType][sendrecvType].packetsReceived === 0) {
1009
- LoggerProxy.logger.info(
1010
- `StatsAnalyzer:index#processInboundRTPResult --> No packets received for ${mediaType} `,
1011
- this.statsResults[mediaType][sendrecvType].packetsReceived
1012
- );
1029
+ if (receiveSlot) {
1030
+ LoggerProxy.logger.info(
1031
+ `StatsAnalyzer:index#processInboundRTPResult --> No packets received for receive slot ${idAndCsi}`,
1032
+ this.statsResults[mediaType][sendrecvType].packetsReceived
1033
+ );
1034
+ }
1013
1035
  }
1014
1036
 
1015
1037
  // Check the over all packet Lost ratio
@@ -1021,7 +1043,7 @@ export class StatsAnalyzer extends EventsScope {
1021
1043
  : 0;
1022
1044
  if (this.statsResults[mediaType][sendrecvType].currentPacketLossRatio > 3) {
1023
1045
  LoggerProxy.logger.info(
1024
- 'StatsAnalyzer:index#processInboundRTPResult --> Packets getting lost from the receiver ',
1046
+ `StatsAnalyzer:index#processInboundRTPResult --> Packets getting lost from the receiver with slot ${idAndCsi}`,
1025
1047
  this.statsResults[mediaType][sendrecvType].currentPacketLossRatio
1026
1048
  );
1027
1049
  }
@@ -1081,73 +1103,40 @@ export class StatsAnalyzer extends EventsScope {
1081
1103
  if (!result || !result.id) {
1082
1104
  return;
1083
1105
  }
1084
- const RemoteCandidateType = {};
1085
- const RemoteTransport = {};
1086
- const RemoteIpAddress = {};
1087
- const RemoteNetworkType = {};
1088
1106
 
1089
- if (!result.id) return;
1090
-
1091
- const sendRecvType = isSender ? STATS.SEND_DIRECTION : STATS.RECEIVE_DIRECTION;
1092
- const ipType = isRemote ? STATS.REMOTE : STATS.LOCAL;
1093
-
1094
- if (!RemoteCandidateType[result.id]) {
1095
- RemoteCandidateType[result.id] = [];
1096
- }
1097
-
1098
- if (!RemoteTransport[result.id]) {
1099
- RemoteTransport[result.id] = [];
1100
- }
1101
-
1102
- if (!RemoteIpAddress[result.id]) {
1103
- RemoteIpAddress[result.id] = [];
1104
- }
1105
- if (!RemoteNetworkType[result.id]) {
1106
- RemoteNetworkType[result.id] = [];
1107
- }
1108
-
1109
- if (
1110
- result.candidateType &&
1111
- RemoteCandidateType[result.id].indexOf(result.candidateType) === -1
1112
- ) {
1113
- RemoteCandidateType[result.id].push(result.candidateType);
1114
- }
1115
-
1116
- if (result.protocol && RemoteTransport[result.id].indexOf(result.protocol) === -1) {
1117
- RemoteTransport[result.id].push(result.protocol.toUpperCase());
1107
+ // We only care about the successful local candidate
1108
+ if (this.successfulCandidatePair?.localCandidateId !== result.id) {
1109
+ return;
1118
1110
  }
1119
1111
 
1120
- if (
1121
- result.ip &&
1122
- RemoteIpAddress[result.id].indexOf(`${result.ip}:${result.portNumber}`) === -1
1123
- ) {
1124
- RemoteIpAddress[result.id].push(`${result.ip}`); // TODO: Add ports
1112
+ let transport;
1113
+ if (result.relayProtocol) {
1114
+ transport = result.relayProtocol.toUpperCase();
1115
+ } else if (result.protocol) {
1116
+ transport = result.protocol.toUpperCase();
1125
1117
  }
1126
1118
 
1127
- if (result.networkType && RemoteNetworkType[result.id].indexOf(result.networkType) === -1) {
1128
- RemoteNetworkType[result.id].push(result.networkType);
1129
- }
1119
+ const sendRecvType = isSender ? STATS.SEND_DIRECTION : STATS.RECEIVE_DIRECTION;
1120
+ const ipType = isRemote ? STATS.REMOTE : STATS.LOCAL;
1130
1121
 
1131
1122
  this.statsResults.internal.candidates[result.id] = {
1132
- candidateType: RemoteCandidateType[result.id],
1133
- ipAddress: RemoteIpAddress[result.id],
1123
+ candidateType: result.candidateType,
1124
+ ipAddress: result.ip, // TODO: add ports
1134
1125
  portNumber: result.port,
1135
- networkType: RemoteNetworkType[result.id],
1126
+ networkType: result.networkType,
1136
1127
  priority: result.priority,
1137
- transport: RemoteTransport[result.id],
1128
+ transport,
1138
1129
  timestamp: result.time,
1139
1130
  id: result.id,
1140
1131
  type: result.type,
1141
1132
  };
1142
1133
 
1143
- this.statsResults.connectionType[ipType].candidateType = RemoteCandidateType[result.id];
1144
- this.statsResults.connectionType[ipType].ipAddress = RemoteIpAddress[result.id];
1134
+ this.statsResults.connectionType[ipType].candidateType = result.candidateType;
1135
+ this.statsResults.connectionType[ipType].ipAddress = result.ipAddress;
1145
1136
 
1146
1137
  this.statsResults.connectionType[ipType].networkType =
1147
- RemoteNetworkType[result.id][0] === NETWORK_TYPE.VPN
1148
- ? NETWORK_TYPE.UNKNOWN
1149
- : RemoteNetworkType[result.id][0];
1150
- this.statsResults.connectionType[ipType].transport = RemoteTransport[result.id];
1138
+ result.networkType === NETWORK_TYPE.VPN ? NETWORK_TYPE.UNKNOWN : result.networkType;
1139
+ this.statsResults.connectionType[ipType].transport = transport;
1151
1140
 
1152
1141
  this.statsResults[type][sendRecvType].totalRoundTripTime = result.totalRoundTripTime;
1153
1142
  };
@@ -1165,25 +1154,17 @@ export class StatsAnalyzer extends EventsScope {
1165
1154
  if (!result || result.type !== 'track') {
1166
1155
  return;
1167
1156
  }
1168
- if (result.type !== 'track') return;
1169
1157
 
1170
1158
  const sendrecvType =
1171
1159
  result.remoteSource === true ? STATS.RECEIVE_DIRECTION : STATS.SEND_DIRECTION;
1172
1160
 
1173
- if (result.frameWidth && result.frameHeight) {
1174
- this.statsResults.resolutions[mediaType][sendrecvType].width = result.frameWidth;
1175
- this.statsResults.resolutions[mediaType][sendrecvType].height = result.frameHeight;
1176
- this.statsResults.resolutions[mediaType][sendrecvType].framesSent = result.framesSent;
1177
- this.statsResults.resolutions[mediaType][sendrecvType].hugeFramesSent = result.hugeFramesSent;
1178
- }
1179
-
1180
1161
  if (sendrecvType === STATS.RECEIVE_DIRECTION) {
1181
1162
  this.statsResults.resolutions[mediaType][sendrecvType].framesReceived = result.framesReceived;
1182
1163
  this.statsResults.resolutions[mediaType][sendrecvType].framesDecoded = result.framesDecoded;
1183
1164
  this.statsResults.resolutions[mediaType][sendrecvType].framesDropped = result.framesDropped;
1184
1165
  }
1185
1166
 
1186
- if (result.trackIdentifier && mediaType !== STATS.AUDIO_CORRELATE) {
1167
+ if (result.trackIdentifier && !mediaType.includes('audio')) {
1187
1168
  this.statsResults.resolutions[mediaType][sendrecvType].trackIdentifier =
1188
1169
  result.trackIdentifier;
1189
1170
 
@@ -1209,8 +1190,9 @@ export class StatsAnalyzer extends EventsScope {
1209
1190
  * @returns {void}
1210
1191
  * @memberof StatsAnalyzer
1211
1192
  */
1212
- private compareSentAndReceived(result: any, type: any) {
1213
- if (!type) {
1193
+ compareSentAndReceived(result, type) {
1194
+ // Don't compare on transceivers without a sender.
1195
+ if (!type || !this.statsResults.internal[type].send) {
1214
1196
  return;
1215
1197
  }
1216
1198