@webex/plugin-meetings 3.0.0-beta.41 → 3.0.0-beta.410

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 (398) hide show
  1. package/README.md +58 -8
  2. package/dist/annotation/annotation.types.js +7 -0
  3. package/dist/annotation/annotation.types.js.map +1 -0
  4. package/dist/annotation/constants.js +49 -0
  5. package/dist/annotation/constants.js.map +1 -0
  6. package/dist/annotation/index.js +342 -0
  7. package/dist/annotation/index.js.map +1 -0
  8. package/dist/breakouts/breakout.js +94 -15
  9. package/dist/breakouts/breakout.js.map +1 -1
  10. package/dist/breakouts/events.js +45 -0
  11. package/dist/breakouts/events.js.map +1 -0
  12. package/dist/breakouts/index.js +625 -123
  13. package/dist/breakouts/index.js.map +1 -1
  14. package/dist/breakouts/utils.js +27 -8
  15. package/dist/breakouts/utils.js.map +1 -1
  16. package/dist/common/errors/no-meeting-info.js +51 -0
  17. package/dist/common/errors/no-meeting-info.js.map +1 -0
  18. package/dist/common/errors/reclaim-host-role-errors.js +158 -0
  19. package/dist/common/errors/reclaim-host-role-errors.js.map +1 -0
  20. package/dist/common/errors/webex-errors.js +48 -7
  21. package/dist/common/errors/webex-errors.js.map +1 -1
  22. package/dist/common/logs/logger-proxy.js +1 -1
  23. package/dist/common/logs/logger-proxy.js.map +1 -1
  24. package/dist/common/logs/request.js +5 -1
  25. package/dist/common/logs/request.js.map +1 -1
  26. package/dist/common/queue.js +24 -9
  27. package/dist/common/queue.js.map +1 -1
  28. package/dist/config.js +6 -10
  29. package/dist/config.js.map +1 -1
  30. package/dist/constants.js +247 -34
  31. package/dist/constants.js.map +1 -1
  32. package/dist/controls-options-manager/enums.js +14 -2
  33. package/dist/controls-options-manager/enums.js.map +1 -1
  34. package/dist/controls-options-manager/index.js +109 -15
  35. package/dist/controls-options-manager/index.js.map +1 -1
  36. package/dist/controls-options-manager/types.js +7 -0
  37. package/dist/controls-options-manager/types.js.map +1 -0
  38. package/dist/controls-options-manager/util.js +309 -18
  39. package/dist/controls-options-manager/util.js.map +1 -1
  40. package/dist/index.js +116 -2
  41. package/dist/index.js.map +1 -1
  42. package/dist/interceptors/index.js +15 -0
  43. package/dist/interceptors/index.js.map +1 -0
  44. package/dist/interceptors/locusRetry.js +93 -0
  45. package/dist/interceptors/locusRetry.js.map +1 -0
  46. package/dist/interpretation/collection.js +23 -0
  47. package/dist/interpretation/collection.js.map +1 -0
  48. package/dist/interpretation/index.js +380 -0
  49. package/dist/interpretation/index.js.map +1 -0
  50. package/dist/interpretation/siLanguage.js +25 -0
  51. package/dist/interpretation/siLanguage.js.map +1 -0
  52. package/dist/locus-info/controlsUtils.js +91 -2
  53. package/dist/locus-info/controlsUtils.js.map +1 -1
  54. package/dist/locus-info/index.js +386 -62
  55. package/dist/locus-info/index.js.map +1 -1
  56. package/dist/locus-info/infoUtils.js +7 -1
  57. package/dist/locus-info/infoUtils.js.map +1 -1
  58. package/dist/locus-info/mediaSharesUtils.js +71 -1
  59. package/dist/locus-info/mediaSharesUtils.js.map +1 -1
  60. package/dist/locus-info/parser.js +249 -72
  61. package/dist/locus-info/parser.js.map +1 -1
  62. package/dist/locus-info/selfUtils.js +89 -14
  63. package/dist/locus-info/selfUtils.js.map +1 -1
  64. package/dist/media/index.js +65 -102
  65. package/dist/media/index.js.map +1 -1
  66. package/dist/media/properties.js +73 -124
  67. package/dist/media/properties.js.map +1 -1
  68. package/dist/mediaQualityMetrics/config.js +135 -330
  69. package/dist/mediaQualityMetrics/config.js.map +1 -1
  70. package/dist/meeting/in-meeting-actions.js +86 -2
  71. package/dist/meeting/in-meeting-actions.js.map +1 -1
  72. package/dist/meeting/index.js +4531 -2994
  73. package/dist/meeting/index.js.map +1 -1
  74. package/dist/meeting/locusMediaRequest.js +292 -0
  75. package/dist/meeting/locusMediaRequest.js.map +1 -0
  76. package/dist/meeting/muteState.js +236 -136
  77. package/dist/meeting/muteState.js.map +1 -1
  78. package/dist/meeting/request.js +189 -155
  79. package/dist/meeting/request.js.map +1 -1
  80. package/dist/meeting/util.js +676 -417
  81. package/dist/meeting/util.js.map +1 -1
  82. package/dist/meeting/voicea-meeting.js +172 -0
  83. package/dist/meeting/voicea-meeting.js.map +1 -0
  84. package/dist/meeting-info/index.js +73 -7
  85. package/dist/meeting-info/index.js.map +1 -1
  86. package/dist/meeting-info/meeting-info-v2.js +201 -57
  87. package/dist/meeting-info/meeting-info-v2.js.map +1 -1
  88. package/dist/meeting-info/util.js +8 -7
  89. package/dist/meeting-info/util.js.map +1 -1
  90. package/dist/meeting-info/utilv2.js +44 -40
  91. package/dist/meeting-info/utilv2.js.map +1 -1
  92. package/dist/meetings/collection.js +39 -0
  93. package/dist/meetings/collection.js.map +1 -1
  94. package/dist/meetings/index.js +484 -119
  95. package/dist/meetings/index.js.map +1 -1
  96. package/dist/meetings/meetings.types.js +7 -0
  97. package/dist/meetings/meetings.types.js.map +1 -0
  98. package/dist/meetings/request.js +2 -0
  99. package/dist/meetings/request.js.map +1 -1
  100. package/dist/meetings/util.js +73 -7
  101. package/dist/meetings/util.js.map +1 -1
  102. package/dist/member/index.js +57 -0
  103. package/dist/member/index.js.map +1 -1
  104. package/dist/member/types.js +25 -0
  105. package/dist/member/types.js.map +1 -0
  106. package/dist/member/util.js +132 -25
  107. package/dist/member/util.js.map +1 -1
  108. package/dist/members/collection.js +10 -0
  109. package/dist/members/collection.js.map +1 -1
  110. package/dist/members/index.js +100 -5
  111. package/dist/members/index.js.map +1 -1
  112. package/dist/members/request.js +106 -38
  113. package/dist/members/request.js.map +1 -1
  114. package/dist/members/types.js +15 -0
  115. package/dist/members/types.js.map +1 -0
  116. package/dist/members/util.js +326 -232
  117. package/dist/members/util.js.map +1 -1
  118. package/dist/metrics/constants.js +18 -1
  119. package/dist/metrics/constants.js.map +1 -1
  120. package/dist/metrics/index.js +1 -446
  121. package/dist/metrics/index.js.map +1 -1
  122. package/dist/multistream/mediaRequestManager.js +223 -32
  123. package/dist/multistream/mediaRequestManager.js.map +1 -1
  124. package/dist/multistream/receiveSlot.js +10 -0
  125. package/dist/multistream/receiveSlot.js.map +1 -1
  126. package/dist/multistream/receiveSlotManager.js +39 -36
  127. package/dist/multistream/receiveSlotManager.js.map +1 -1
  128. package/dist/multistream/remoteMedia.js +3 -1
  129. package/dist/multistream/remoteMedia.js.map +1 -1
  130. package/dist/multistream/remoteMediaGroup.js +76 -5
  131. package/dist/multistream/remoteMediaGroup.js.map +1 -1
  132. package/dist/multistream/remoteMediaManager.js +366 -104
  133. package/dist/multistream/remoteMediaManager.js.map +1 -1
  134. package/dist/multistream/sendSlotManager.js +255 -0
  135. package/dist/multistream/sendSlotManager.js.map +1 -0
  136. package/dist/reachability/clusterReachability.js +356 -0
  137. package/dist/reachability/clusterReachability.js.map +1 -0
  138. package/dist/reachability/index.js +263 -390
  139. package/dist/reachability/index.js.map +1 -1
  140. package/dist/reachability/request.js +6 -4
  141. package/dist/reachability/request.js.map +1 -1
  142. package/dist/reachability/util.js +29 -0
  143. package/dist/reachability/util.js.map +1 -0
  144. package/dist/reconnection-manager/index.js +266 -202
  145. package/dist/reconnection-manager/index.js.map +1 -1
  146. package/dist/recording-controller/index.js +21 -2
  147. package/dist/recording-controller/index.js.map +1 -1
  148. package/dist/recording-controller/util.js +9 -8
  149. package/dist/recording-controller/util.js.map +1 -1
  150. package/dist/roap/index.js +66 -28
  151. package/dist/roap/index.js.map +1 -1
  152. package/dist/roap/request.js +48 -64
  153. package/dist/roap/request.js.map +1 -1
  154. package/dist/roap/turnDiscovery.js +407 -79
  155. package/dist/roap/turnDiscovery.js.map +1 -1
  156. package/dist/rtcMetrics/constants.js +12 -0
  157. package/dist/rtcMetrics/constants.js.map +1 -0
  158. package/dist/rtcMetrics/index.js +179 -0
  159. package/dist/rtcMetrics/index.js.map +1 -0
  160. package/dist/statsAnalyzer/index.js +389 -304
  161. package/dist/statsAnalyzer/index.js.map +1 -1
  162. package/dist/statsAnalyzer/mqaUtil.js +296 -156
  163. package/dist/statsAnalyzer/mqaUtil.js.map +1 -1
  164. package/dist/types/annotation/annotation.types.d.ts +42 -0
  165. package/dist/types/annotation/constants.d.ts +31 -0
  166. package/dist/types/annotation/index.d.ts +117 -0
  167. package/dist/types/breakouts/events.d.ts +8 -0
  168. package/dist/types/breakouts/utils.d.ts +9 -2
  169. package/dist/types/common/errors/no-meeting-info.d.ts +14 -0
  170. package/dist/types/common/errors/reclaim-host-role-errors.d.ts +60 -0
  171. package/dist/types/common/errors/webex-errors.d.ts +25 -1
  172. package/dist/types/common/logs/request.d.ts +2 -0
  173. package/dist/types/common/queue.d.ts +9 -7
  174. package/dist/types/config.d.ts +2 -7
  175. package/dist/types/constants.d.ts +204 -32
  176. package/dist/types/controls-options-manager/enums.d.ts +11 -1
  177. package/dist/types/controls-options-manager/index.d.ts +17 -1
  178. package/dist/types/controls-options-manager/types.d.ts +43 -0
  179. package/dist/types/controls-options-manager/util.d.ts +1 -7
  180. package/dist/types/index.d.ts +6 -5
  181. package/dist/types/interceptors/index.d.ts +2 -0
  182. package/dist/types/interceptors/locusRetry.d.ts +27 -0
  183. package/dist/types/interpretation/collection.d.ts +5 -0
  184. package/dist/types/interpretation/index.d.ts +5 -0
  185. package/dist/types/interpretation/siLanguage.d.ts +5 -0
  186. package/dist/types/locus-info/index.d.ts +57 -4
  187. package/dist/types/locus-info/parser.d.ts +66 -6
  188. package/dist/types/media/index.d.ts +2 -0
  189. package/dist/types/media/properties.d.ts +34 -49
  190. package/dist/types/mediaQualityMetrics/config.d.ts +99 -223
  191. package/dist/types/meeting/in-meeting-actions.d.ts +86 -2
  192. package/dist/types/meeting/index.d.ts +630 -505
  193. package/dist/types/meeting/locusMediaRequest.d.ts +74 -0
  194. package/dist/types/meeting/muteState.d.ts +88 -26
  195. package/dist/types/meeting/request.d.ts +67 -43
  196. package/dist/types/meeting/util.d.ts +117 -1
  197. package/dist/types/meeting/voicea-meeting.d.ts +16 -0
  198. package/dist/types/meeting-info/index.d.ts +13 -1
  199. package/dist/types/meeting-info/meeting-info-v2.d.ts +31 -1
  200. package/dist/types/meetings/collection.d.ts +17 -0
  201. package/dist/types/meetings/index.d.ts +113 -21
  202. package/dist/types/meetings/meetings.types.d.ts +4 -0
  203. package/dist/types/member/index.d.ts +14 -0
  204. package/dist/types/member/types.d.ts +32 -0
  205. package/dist/types/members/collection.d.ts +5 -0
  206. package/dist/types/members/index.d.ts +35 -2
  207. package/dist/types/members/request.d.ts +73 -9
  208. package/dist/types/members/types.d.ts +25 -0
  209. package/dist/types/members/util.d.ts +214 -1
  210. package/dist/types/metrics/constants.d.ts +17 -0
  211. package/dist/types/metrics/index.d.ts +4 -111
  212. package/dist/types/multistream/mediaRequestManager.d.ts +71 -3
  213. package/dist/types/multistream/receiveSlot.d.ts +7 -3
  214. package/dist/types/multistream/receiveSlotManager.d.ts +14 -4
  215. package/dist/types/multistream/remoteMedia.d.ts +3 -31
  216. package/dist/types/multistream/remoteMediaGroup.d.ts +2 -9
  217. package/dist/types/multistream/remoteMediaManager.d.ts +61 -2
  218. package/dist/types/multistream/sendSlotManager.d.ts +69 -0
  219. package/dist/types/reachability/clusterReachability.d.ts +109 -0
  220. package/dist/types/reachability/index.d.ts +60 -95
  221. package/dist/types/reachability/request.d.ts +3 -1
  222. package/dist/types/reachability/util.d.ts +8 -0
  223. package/dist/types/reconnection-manager/index.d.ts +19 -0
  224. package/dist/types/recording-controller/index.d.ts +15 -1
  225. package/dist/types/recording-controller/util.d.ts +5 -4
  226. package/dist/types/roap/index.d.ts +11 -2
  227. package/dist/types/roap/request.d.ts +9 -8
  228. package/dist/types/roap/turnDiscovery.d.ts +90 -9
  229. package/dist/types/rtcMetrics/constants.d.ts +4 -0
  230. package/dist/types/rtcMetrics/index.d.ts +61 -0
  231. package/dist/types/statsAnalyzer/index.d.ts +34 -12
  232. package/dist/types/statsAnalyzer/mqaUtil.d.ts +28 -4
  233. package/dist/types/webinar/collection.d.ts +16 -0
  234. package/dist/types/webinar/index.d.ts +5 -0
  235. package/dist/webinar/collection.js +44 -0
  236. package/dist/webinar/collection.js.map +1 -0
  237. package/dist/webinar/index.js +69 -0
  238. package/dist/webinar/index.js.map +1 -0
  239. package/package.json +22 -19
  240. package/src/annotation/annotation.types.ts +50 -0
  241. package/src/annotation/constants.ts +36 -0
  242. package/src/annotation/index.ts +328 -0
  243. package/src/breakouts/README.md +27 -6
  244. package/src/breakouts/breakout.ts +67 -9
  245. package/src/breakouts/events.ts +56 -0
  246. package/src/breakouts/index.ts +494 -73
  247. package/src/breakouts/utils.ts +26 -8
  248. package/src/common/errors/no-meeting-info.ts +24 -0
  249. package/src/common/errors/reclaim-host-role-errors.ts +134 -0
  250. package/src/common/errors/webex-errors.ts +44 -2
  251. package/src/common/logs/logger-proxy.ts +1 -1
  252. package/src/common/logs/request.ts +5 -1
  253. package/src/common/queue.ts +22 -8
  254. package/src/config.ts +6 -13
  255. package/src/constants.ts +234 -22
  256. package/src/controls-options-manager/enums.ts +12 -0
  257. package/src/controls-options-manager/index.ts +116 -21
  258. package/src/controls-options-manager/types.ts +59 -0
  259. package/src/controls-options-manager/util.ts +294 -14
  260. package/src/index.ts +45 -0
  261. package/src/interceptors/index.ts +3 -0
  262. package/src/interceptors/locusRetry.ts +67 -0
  263. package/src/interpretation/README.md +60 -0
  264. package/src/interpretation/collection.ts +19 -0
  265. package/src/interpretation/index.ts +349 -0
  266. package/src/interpretation/siLanguage.ts +18 -0
  267. package/src/locus-info/controlsUtils.ts +108 -0
  268. package/src/locus-info/index.ts +417 -59
  269. package/src/locus-info/infoUtils.ts +10 -2
  270. package/src/locus-info/mediaSharesUtils.ts +80 -0
  271. package/src/locus-info/parser.ts +258 -47
  272. package/src/locus-info/selfUtils.ts +81 -5
  273. package/src/media/index.ts +100 -108
  274. package/src/media/properties.ts +88 -117
  275. package/src/mediaQualityMetrics/config.ts +103 -238
  276. package/src/meeting/in-meeting-actions.ts +171 -3
  277. package/src/meeting/index.ts +3929 -2622
  278. package/src/meeting/locusMediaRequest.ts +313 -0
  279. package/src/meeting/muteState.ts +237 -136
  280. package/src/meeting/request.ts +173 -122
  281. package/src/meeting/util.ts +690 -395
  282. package/src/meeting/voicea-meeting.ts +122 -0
  283. package/src/meeting-info/index.ts +81 -8
  284. package/src/meeting-info/meeting-info-v2.ts +166 -16
  285. package/src/meeting-info/util.ts +13 -10
  286. package/src/meeting-info/utilv2.ts +47 -37
  287. package/src/meetings/collection.ts +33 -0
  288. package/src/meetings/index.ts +507 -127
  289. package/src/meetings/meetings.types.ts +12 -0
  290. package/src/meetings/request.ts +2 -0
  291. package/src/meetings/util.ts +81 -12
  292. package/src/member/index.ts +57 -0
  293. package/src/member/types.ts +38 -0
  294. package/src/member/util.ts +141 -25
  295. package/src/members/collection.ts +8 -0
  296. package/src/members/index.ts +133 -7
  297. package/src/members/request.ts +97 -17
  298. package/src/members/types.ts +29 -0
  299. package/src/members/util.ts +333 -240
  300. package/src/metrics/constants.ts +17 -0
  301. package/src/metrics/index.ts +1 -469
  302. package/src/multistream/mediaRequestManager.ts +271 -56
  303. package/src/multistream/receiveSlot.ts +11 -4
  304. package/src/multistream/receiveSlotManager.ts +34 -24
  305. package/src/multistream/remoteMedia.ts +5 -3
  306. package/src/multistream/remoteMediaGroup.ts +78 -0
  307. package/src/multistream/remoteMediaManager.ts +248 -45
  308. package/src/multistream/sendSlotManager.ts +198 -0
  309. package/src/reachability/clusterReachability.ts +320 -0
  310. package/src/reachability/index.ts +229 -346
  311. package/src/reachability/request.ts +8 -4
  312. package/src/reachability/util.ts +24 -0
  313. package/src/reconnection-manager/index.ts +128 -97
  314. package/src/recording-controller/index.ts +20 -3
  315. package/src/recording-controller/util.ts +26 -9
  316. package/src/roap/index.ts +76 -25
  317. package/src/roap/request.ts +48 -67
  318. package/src/roap/turnDiscovery.ts +331 -67
  319. package/src/rtcMetrics/constants.ts +3 -0
  320. package/src/rtcMetrics/index.ts +166 -0
  321. package/src/statsAnalyzer/index.ts +496 -419
  322. package/src/statsAnalyzer/mqaUtil.ts +317 -170
  323. package/src/webinar/collection.ts +31 -0
  324. package/src/webinar/index.ts +62 -0
  325. package/test/integration/spec/converged-space-meetings.js +60 -3
  326. package/test/integration/spec/journey.js +321 -262
  327. package/test/integration/spec/space-meeting.js +76 -3
  328. package/test/unit/spec/annotation/index.ts +418 -0
  329. package/test/unit/spec/breakouts/breakout.ts +119 -28
  330. package/test/unit/spec/breakouts/events.ts +89 -0
  331. package/test/unit/spec/breakouts/index.ts +1204 -118
  332. package/test/unit/spec/breakouts/utils.js +27 -2
  333. package/test/unit/spec/common/queue.js +31 -2
  334. package/test/unit/spec/controls-options-manager/index.js +163 -0
  335. package/test/unit/spec/controls-options-manager/util.js +576 -60
  336. package/test/unit/spec/fixture/locus.js +1 -0
  337. package/test/unit/spec/interceptors/locusRetry.ts +131 -0
  338. package/test/unit/spec/interpretation/collection.ts +15 -0
  339. package/test/unit/spec/interpretation/index.ts +625 -0
  340. package/test/unit/spec/interpretation/siLanguage.ts +28 -0
  341. package/test/unit/spec/locus-info/controlsUtils.js +316 -43
  342. package/test/unit/spec/locus-info/index.js +1372 -37
  343. package/test/unit/spec/locus-info/infoUtils.js +37 -15
  344. package/test/unit/spec/locus-info/lib/SeqCmp.json +16 -0
  345. package/test/unit/spec/locus-info/mediaSharesUtils.ts +41 -0
  346. package/test/unit/spec/locus-info/parser.js +116 -35
  347. package/test/unit/spec/locus-info/selfConstant.js +27 -4
  348. package/test/unit/spec/locus-info/selfUtils.js +203 -17
  349. package/test/unit/spec/media/index.ts +178 -81
  350. package/test/unit/spec/media/properties.ts +2 -2
  351. package/test/unit/spec/meeting/in-meeting-actions.ts +85 -3
  352. package/test/unit/spec/meeting/index.js +7835 -2501
  353. package/test/unit/spec/meeting/locusMediaRequest.ts +442 -0
  354. package/test/unit/spec/meeting/muteState.js +549 -207
  355. package/test/unit/spec/meeting/request.js +494 -54
  356. package/test/unit/spec/meeting/utils.js +827 -74
  357. package/test/unit/spec/meeting/voicea-meeting.ts +266 -0
  358. package/test/unit/spec/meeting-info/index.js +300 -0
  359. package/test/unit/spec/meeting-info/meetinginfov2.js +535 -9
  360. package/test/unit/spec/meeting-info/utilv2.js +21 -0
  361. package/test/unit/spec/meetings/collection.js +26 -0
  362. package/test/unit/spec/meetings/index.js +1489 -219
  363. package/test/unit/spec/meetings/utils.js +229 -2
  364. package/test/unit/spec/member/index.js +61 -6
  365. package/test/unit/spec/member/util.js +510 -34
  366. package/test/unit/spec/members/index.js +432 -1
  367. package/test/unit/spec/members/request.js +206 -27
  368. package/test/unit/spec/members/utils.js +210 -0
  369. package/test/unit/spec/metrics/index.js +2 -52
  370. package/test/unit/spec/multistream/mediaRequestManager.ts +782 -114
  371. package/test/unit/spec/multistream/receiveSlot.ts +9 -1
  372. package/test/unit/spec/multistream/receiveSlotManager.ts +32 -30
  373. package/test/unit/spec/multistream/remoteMedia.ts +2 -0
  374. package/test/unit/spec/multistream/remoteMediaGroup.ts +344 -0
  375. package/test/unit/spec/multistream/remoteMediaManager.ts +524 -0
  376. package/test/unit/spec/multistream/sendSlotManager.ts +274 -0
  377. package/test/unit/spec/reachability/clusterReachability.ts +279 -0
  378. package/test/unit/spec/reachability/index.ts +551 -14
  379. package/test/unit/spec/reachability/request.js +3 -1
  380. package/test/unit/spec/reachability/util.ts +40 -0
  381. package/test/unit/spec/reconnection-manager/index.js +171 -11
  382. package/test/unit/spec/recording-controller/index.js +293 -218
  383. package/test/unit/spec/recording-controller/util.js +223 -96
  384. package/test/unit/spec/roap/index.ts +233 -81
  385. package/test/unit/spec/roap/request.ts +100 -62
  386. package/test/unit/spec/roap/turnDiscovery.ts +682 -108
  387. package/test/unit/spec/rtcMetrics/index.ts +122 -0
  388. package/test/unit/spec/stats-analyzer/index.js +1431 -12
  389. package/test/unit/spec/webinar/collection.ts +13 -0
  390. package/test/unit/spec/webinar/index.ts +60 -0
  391. package/test/utils/integrationTestUtils.js +46 -0
  392. package/test/utils/testUtils.js +0 -57
  393. package/test/utils/webex-test-users.js +12 -4
  394. package/dist/metrics/config.js +0 -289
  395. package/dist/metrics/config.js.map +0 -1
  396. package/dist/types/metrics/config.d.ts +0 -169
  397. package/src/index.js +0 -18
  398. package/src/metrics/config.ts +0 -485
@@ -1,13 +1,13 @@
1
1
  /* eslint-disable prefer-destructuring */
2
2
 
3
- import {cloneDeep} from 'lodash';
3
+ import {cloneDeep, isEmpty} from 'lodash';
4
4
  import {ConnectionState} from '@webex/internal-media-core';
5
5
 
6
6
  import EventsScope from '../common/events/events-scope';
7
7
  import {
8
8
  DEFAULT_GET_STATS_FILTER,
9
9
  STATS,
10
- MQA_INTEVAL,
10
+ MQA_INTERVAL,
11
11
  NETWORK_TYPE,
12
12
  MEDIA_DEVICES,
13
13
  _UNKNOWN_,
@@ -18,6 +18,10 @@ import {
18
18
  emptyMqaInterval,
19
19
  emptyVideoReceive,
20
20
  emptyVideoTransmit,
21
+ emptyAudioReceiveStream,
22
+ emptyAudioTransmitStream,
23
+ emptyVideoReceiveStream,
24
+ emptyVideoTransmitStream,
21
25
  } from '../mediaQualityMetrics/config';
22
26
  import LoggerProxy from '../common/logs/logger-proxy';
23
27
 
@@ -27,7 +31,12 @@ import {
27
31
  getAudioReceiverMqa,
28
32
  getVideoSenderMqa,
29
33
  getVideoReceiverMqa,
34
+ getAudioSenderStreamMqa,
35
+ getAudioReceiverStreamMqa,
36
+ getVideoSenderStreamMqa,
37
+ getVideoReceiverStreamMqa,
30
38
  } from './mqaUtil';
39
+ import {ReceiveSlot} from '../multistream/receiveSlot';
31
40
 
32
41
  export const EVENTS = {
33
42
  MEDIA_QUALITY: 'MEDIA_QUALITY',
@@ -53,6 +62,11 @@ const emptyReceiver = {
53
62
  meanRoundTripTime: [],
54
63
  };
55
64
 
65
+ type ReceiveSlotCallback = (csi: number) => ReceiveSlot | undefined;
66
+ type MediaStatus = {
67
+ actual?: any;
68
+ expected?: any;
69
+ };
56
70
  /**
57
71
  * Stats Analyzer class that will emit events based on detected quality
58
72
  *
@@ -74,17 +88,22 @@ export class StatsAnalyzer extends EventsScope {
74
88
  statsInterval: NodeJS.Timeout;
75
89
  statsResults: any;
76
90
  statsStarted: any;
91
+ successfulCandidatePair: any;
92
+ localIpAddress: string; // Returns the local IP address for diagnostics. this is the local IP of the interface used for the current media connection a host can have many local Ip Addresses
93
+ receiveSlotCallback: ReceiveSlotCallback;
77
94
 
78
95
  /**
79
96
  * Creates a new instance of StatsAnalyzer
80
97
  * @constructor
81
98
  * @public
82
99
  * @param {Object} config SDK Configuration Object
100
+ * @param {Function} receiveSlotCallback Callback used to access receive slots.
83
101
  * @param {Object} networkQualityMonitor class for assessing network characteristics (jitter, packetLoss, latency)
84
102
  * @param {Object} statsResults Default properties for stats
85
103
  */
86
104
  constructor(
87
105
  config: any,
106
+ receiveSlotCallback: ReceiveSlotCallback = () => undefined,
88
107
  networkQualityMonitor: object = {},
89
108
  statsResults: object = defaultStats
90
109
  ) {
@@ -98,6 +117,9 @@ export class StatsAnalyzer extends EventsScope {
98
117
  this.mqaSentCount = -1;
99
118
  this.lastMqaDataSent = {};
100
119
  this.lastEmittedStartStopEvent = {};
120
+ this.receiveSlotCallback = receiveSlotCallback;
121
+ this.successfulCandidatePair = {};
122
+ this.localIpAddress = '';
101
123
  }
102
124
 
103
125
  /**
@@ -128,8 +150,17 @@ export class StatsAnalyzer extends EventsScope {
128
150
  * @memberof StatsAnalyzer
129
151
  * @returns {void}
130
152
  */
131
- public updateMediaStatus(status: object) {
132
- this.meetingMediaStatus = status;
153
+ public updateMediaStatus(status: MediaStatus) {
154
+ this.meetingMediaStatus = {
155
+ actual: {
156
+ ...this.meetingMediaStatus?.actual,
157
+ ...status?.actual,
158
+ },
159
+ expected: {
160
+ ...this.meetingMediaStatus?.expected,
161
+ ...status?.expected,
162
+ },
163
+ };
133
164
  }
134
165
 
135
166
  /**
@@ -142,65 +173,215 @@ export class StatsAnalyzer extends EventsScope {
142
173
  sendMqaData() {
143
174
  const newMqa = cloneDeep(emptyMqaInterval);
144
175
 
176
+ // Fill in empty stats items for lastMqaDataSent
177
+ Object.keys(this.statsResults).forEach((mediaType) => {
178
+ if (!this.lastMqaDataSent[mediaType]) {
179
+ this.lastMqaDataSent[mediaType] = {};
180
+ }
181
+
182
+ if (!this.lastMqaDataSent[mediaType].send && mediaType.includes('-send')) {
183
+ this.lastMqaDataSent[mediaType].send = {};
184
+ }
185
+
186
+ if (!this.lastMqaDataSent[mediaType].recv && mediaType.includes('-recv')) {
187
+ this.lastMqaDataSent[mediaType].recv = {};
188
+ }
189
+ });
190
+
191
+ // Create stats the first level, totals for senders and receivers
192
+ const audioSender = cloneDeep(emptyAudioTransmit);
193
+ const audioShareSender = cloneDeep(emptyAudioTransmit);
194
+ const audioReceiver = cloneDeep(emptyAudioReceive);
195
+ const audioShareReceiver = cloneDeep(emptyAudioReceive);
196
+ const videoSender = cloneDeep(emptyVideoTransmit);
197
+ const videoShareSender = cloneDeep(emptyVideoTransmit);
198
+ const videoReceiver = cloneDeep(emptyVideoReceive);
199
+ const videoShareReceiver = cloneDeep(emptyVideoReceive);
200
+
201
+ getAudioSenderMqa({
202
+ audioSender,
203
+ statsResults: this.statsResults,
204
+ lastMqaDataSent: this.lastMqaDataSent,
205
+ baseMediaType: 'audio-send',
206
+ });
207
+ newMqa.audioTransmit.push(audioSender);
208
+
209
+ getAudioSenderMqa({
210
+ audioSender: audioShareSender,
211
+ statsResults: this.statsResults,
212
+ lastMqaDataSent: this.lastMqaDataSent,
213
+ baseMediaType: 'audio-share-send',
214
+ });
215
+ newMqa.audioTransmit.push(audioShareSender);
216
+
217
+ getAudioReceiverMqa({
218
+ audioReceiver,
219
+ statsResults: this.statsResults,
220
+ lastMqaDataSent: this.lastMqaDataSent,
221
+ baseMediaType: 'audio-recv',
222
+ });
223
+ newMqa.audioReceive.push(audioReceiver);
224
+
225
+ getAudioReceiverMqa({
226
+ audioReceiver: audioShareReceiver,
227
+ statsResults: this.statsResults,
228
+ lastMqaDataSent: this.lastMqaDataSent,
229
+ baseMediaType: 'audio-share-recv',
230
+ });
231
+ newMqa.audioReceive.push(audioShareReceiver);
232
+
233
+ getVideoSenderMqa({
234
+ videoSender,
235
+ statsResults: this.statsResults,
236
+ lastMqaDataSent: this.lastMqaDataSent,
237
+ baseMediaType: 'video-send',
238
+ });
239
+ newMqa.videoTransmit.push(videoSender);
240
+
241
+ getVideoSenderMqa({
242
+ videoSender: videoShareSender,
243
+ statsResults: this.statsResults,
244
+ lastMqaDataSent: this.lastMqaDataSent,
245
+ baseMediaType: 'video-share-send',
246
+ });
247
+ newMqa.videoTransmit.push(videoShareSender);
248
+
249
+ getVideoReceiverMqa({
250
+ videoReceiver,
251
+ statsResults: this.statsResults,
252
+ lastMqaDataSent: this.lastMqaDataSent,
253
+ baseMediaType: 'video-recv',
254
+ });
255
+ newMqa.videoReceive.push(videoReceiver);
256
+
257
+ getVideoReceiverMqa({
258
+ videoReceiver: videoShareReceiver,
259
+ statsResults: this.statsResults,
260
+ lastMqaDataSent: this.lastMqaDataSent,
261
+ baseMediaType: 'video-share-recv',
262
+ });
263
+ newMqa.videoReceive.push(videoShareReceiver);
264
+
265
+ // Add stats for individual streams
145
266
  Object.keys(this.statsResults).forEach((mediaType) => {
146
- if (mediaType.includes('audio-send') || mediaType.includes('audio-share-send')) {
147
- const audioSender = cloneDeep(emptyAudioTransmit);
267
+ if (mediaType.startsWith('audio-send')) {
268
+ const audioSenderStream = cloneDeep(emptyAudioTransmitStream);
269
+
270
+ getAudioSenderStreamMqa({
271
+ audioSenderStream,
272
+ statsResults: this.statsResults,
273
+ lastMqaDataSent: this.lastMqaDataSent,
274
+ mediaType,
275
+ });
276
+ newMqa.audioTransmit[0].streams.push(audioSenderStream);
277
+
278
+ this.lastMqaDataSent[mediaType].send = cloneDeep(this.statsResults[mediaType].send);
279
+ } else if (mediaType.startsWith('audio-share-send')) {
280
+ const audioSenderStream = cloneDeep(emptyAudioTransmitStream);
281
+
282
+ getAudioSenderStreamMqa({
283
+ audioSenderStream,
284
+ statsResults: this.statsResults,
285
+ lastMqaDataSent: this.lastMqaDataSent,
286
+ mediaType,
287
+ });
288
+ newMqa.audioTransmit[1].streams.push(audioSenderStream);
289
+
290
+ this.lastMqaDataSent[mediaType].send = cloneDeep(this.statsResults[mediaType].send);
291
+ } else if (mediaType.startsWith('audio-recv')) {
292
+ const audioReceiverStream = cloneDeep(emptyAudioReceiveStream);
293
+
294
+ getAudioReceiverStreamMqa({
295
+ audioReceiverStream,
296
+ statsResults: this.statsResults,
297
+ lastMqaDataSent: this.lastMqaDataSent,
298
+ mediaType,
299
+ });
300
+ newMqa.audioReceive[0].streams.push(audioReceiverStream);
301
+
302
+ this.lastMqaDataSent[mediaType].recv = cloneDeep(this.statsResults[mediaType].recv);
303
+ } else if (mediaType.startsWith('audio-share-recv')) {
304
+ const audioReceiverStream = cloneDeep(emptyAudioReceiveStream);
305
+
306
+ getAudioReceiverStreamMqa({
307
+ audioReceiverStream,
308
+ statsResults: this.statsResults,
309
+ lastMqaDataSent: this.lastMqaDataSent,
310
+ mediaType,
311
+ });
312
+ newMqa.audioReceive[1].streams.push(audioReceiverStream);
313
+
314
+ this.lastMqaDataSent[mediaType].recv = cloneDeep(this.statsResults[mediaType].recv);
315
+ } else if (mediaType.startsWith('video-send-layer')) {
316
+ // We only want the stream-specific stats we get with video-send-layer-0, video-send-layer-1, etc.
317
+ const videoSenderStream = cloneDeep(emptyVideoTransmitStream);
148
318
 
149
- getAudioSenderMqa({
150
- audioSender,
319
+ getVideoSenderStreamMqa({
320
+ videoSenderStream,
151
321
  statsResults: this.statsResults,
152
322
  lastMqaDataSent: this.lastMqaDataSent,
153
323
  mediaType,
154
324
  });
155
- newMqa.audioTransmit.push(audioSender);
156
- } else if (mediaType.includes('audio-recv') || mediaType.includes('audio-share-recv')) {
157
- const audioReceiver = cloneDeep(emptyAudioReceive);
325
+ newMqa.videoTransmit[0].streams.push(videoSenderStream);
158
326
 
159
- getAudioReceiverMqa({
160
- audioReceiver,
327
+ this.lastMqaDataSent[mediaType].send = cloneDeep(this.statsResults[mediaType].send);
328
+ } else if (mediaType.startsWith('video-share-send')) {
329
+ const videoSenderStream = cloneDeep(emptyVideoTransmitStream);
330
+
331
+ getVideoSenderStreamMqa({
332
+ videoSenderStream,
161
333
  statsResults: this.statsResults,
162
334
  lastMqaDataSent: this.lastMqaDataSent,
163
335
  mediaType,
164
336
  });
165
- newMqa.audioReceive.push(audioReceiver);
166
- } else if (mediaType.includes('video-send') || mediaType.includes('video-share-send')) {
167
- const videoSender = cloneDeep(emptyVideoTransmit);
337
+ newMqa.videoTransmit[1].streams.push(videoSenderStream);
338
+
339
+ this.lastMqaDataSent[mediaType].send = cloneDeep(this.statsResults[mediaType].send);
340
+ } else if (mediaType.startsWith('video-recv')) {
341
+ const videoReceiverStream = cloneDeep(emptyVideoReceiveStream);
168
342
 
169
- getVideoSenderMqa({
170
- videoSender,
343
+ getVideoReceiverStreamMqa({
344
+ videoReceiverStream,
171
345
  statsResults: this.statsResults,
172
346
  lastMqaDataSent: this.lastMqaDataSent,
173
347
  mediaType,
174
348
  });
175
- newMqa.videoTransmit.push(videoSender);
176
- } else if (mediaType.includes('video-recv') || mediaType.includes('video-share-recv')) {
177
- const videoReceiver = cloneDeep(emptyVideoReceive);
349
+ newMqa.videoReceive[0].streams.push(videoReceiverStream);
178
350
 
179
- getVideoReceiverMqa({
180
- videoReceiver,
351
+ this.lastMqaDataSent[mediaType].recv = cloneDeep(this.statsResults[mediaType].recv);
352
+ } else if (mediaType.startsWith('video-share-recv')) {
353
+ const videoReceiverStream = cloneDeep(emptyVideoReceiveStream);
354
+
355
+ getVideoReceiverStreamMqa({
356
+ videoReceiverStream,
181
357
  statsResults: this.statsResults,
182
358
  lastMqaDataSent: this.lastMqaDataSent,
183
359
  mediaType,
184
360
  });
185
- newMqa.videoReceive.push(videoReceiver);
361
+ newMqa.videoReceive[1].streams.push(videoReceiverStream);
362
+
363
+ this.lastMqaDataSent[mediaType].recv = cloneDeep(this.statsResults[mediaType].recv);
186
364
  }
187
365
  });
188
366
 
189
- newMqa.intervalMetadata.peerReflexiveIP = this.statsResults.connectionType.local.ipAddress[0];
367
+ newMqa.intervalMetadata.peerReflexiveIP = this.statsResults.connectionType.local.ipAddress;
190
368
 
191
369
  // Adding peripheral information
192
- newMqa.intervalMetadata.peripherals = [];
193
-
194
370
  newMqa.intervalMetadata.peripherals.push({information: _UNKNOWN_, name: MEDIA_DEVICES.SPEAKER});
195
371
  if (this.statsResults['audio-send']) {
196
372
  newMqa.intervalMetadata.peripherals.push({
197
- information: this.statsResults['audio-send']?.trackLabel,
373
+ information: this.statsResults['audio-send'].trackLabel || _UNKNOWN_,
198
374
  name: MEDIA_DEVICES.MICROPHONE,
199
375
  });
200
376
  }
201
- if (this.statsResults['video-send']) {
377
+
378
+ const existingVideoSender = Object.keys(this.statsResults).find((item) =>
379
+ item.includes('video-send')
380
+ );
381
+
382
+ if (existingVideoSender) {
202
383
  newMqa.intervalMetadata.peripherals.push({
203
- information: this.statsResults['video-send']?.trackLabel,
384
+ information: this.statsResults[existingVideoSender].trackLabel || _UNKNOWN_,
204
385
  name: MEDIA_DEVICES.CAMERA,
205
386
  });
206
387
  }
@@ -239,6 +420,16 @@ export class StatsAnalyzer extends EventsScope {
239
420
  this.mediaConnection = mediaConnection;
240
421
  }
241
422
 
423
+ /**
424
+ * Returns the local IP address for diagnostics.
425
+ * this is the local IP of the interface used for the current media connection
426
+ * a host can have many local Ip Addresses
427
+ * @returns {string | undefined} The local IP address.
428
+ */
429
+ getLocalIpAddress(): string {
430
+ return this.localIpAddress;
431
+ }
432
+
242
433
  /**
243
434
  * Starts the stats analyzer on interval
244
435
  *
@@ -260,7 +451,7 @@ export class StatsAnalyzer extends EventsScope {
260
451
  this.sendMqaData();
261
452
  this.mqaInterval = setInterval(() => {
262
453
  this.sendMqaData();
263
- }, MQA_INTEVAL);
454
+ }, MQA_INTERVAL);
264
455
  });
265
456
  }
266
457
 
@@ -293,7 +484,6 @@ export class StatsAnalyzer extends EventsScope {
293
484
  this.mediaConnection = null;
294
485
  });
295
486
  }
296
- this.mediaConnection = null;
297
487
 
298
488
  return Promise.resolve();
299
489
  }
@@ -324,26 +514,6 @@ export class StatsAnalyzer extends EventsScope {
324
514
  this.statsResults[type].recv = cloneDeep(emptyReceiver);
325
515
  }
326
516
 
327
- if (!this.statsResults.resolutions[type]) {
328
- this.statsResults.resolutions[type] = {};
329
- }
330
-
331
- if (isSender && !this.statsResults.resolutions[type].send) {
332
- this.statsResults.resolutions[type].send = cloneDeep(emptySender);
333
- } else if (!isSender && !this.statsResults.resolutions[type].recv) {
334
- this.statsResults.resolutions[type].recv = cloneDeep(emptyReceiver);
335
- }
336
-
337
- if (!this.statsResults.internal[type]) {
338
- this.statsResults.internal[type] = {};
339
- }
340
-
341
- if (isSender && !this.statsResults.internal[type].send) {
342
- this.statsResults.internal[type].send = cloneDeep(emptySender);
343
- } else if (!isSender && !this.statsResults.internal[type].recv) {
344
- this.statsResults.internal[type].recv = cloneDeep(emptyReceiver);
345
- }
346
-
347
517
  switch (getStatsResult.type) {
348
518
  case 'outbound-rtp':
349
519
  this.processOutboundRTPResult(getStatsResult, type);
@@ -351,13 +521,9 @@ export class StatsAnalyzer extends EventsScope {
351
521
  case 'inbound-rtp':
352
522
  this.processInboundRTPResult(getStatsResult, type);
353
523
  break;
354
- case 'track':
355
- this.processTrackResult(getStatsResult, type);
356
- break;
357
524
  case 'remote-inbound-rtp':
358
525
  case 'remote-outbound-rtp':
359
- // @ts-ignore
360
- this.compareSentAndReceived(getStatsResult, type, isSender);
526
+ this.compareSentAndReceived(getStatsResult, type);
361
527
  break;
362
528
  case 'remotecandidate':
363
529
  case 'remote-candidate':
@@ -367,7 +533,6 @@ export class StatsAnalyzer extends EventsScope {
367
533
  this.parseCandidate(getStatsResult, type, isSender, false);
368
534
  break;
369
535
  case 'media-source':
370
- // @ts-ignore
371
536
  this.parseAudioSource(getStatsResult, type);
372
537
  break;
373
538
  default:
@@ -386,9 +551,28 @@ export class StatsAnalyzer extends EventsScope {
386
551
  filterAndParseGetStatsResults(statsItem: any, type: string, isSender: boolean) {
387
552
  const {types} = DEFAULT_GET_STATS_FILTER;
388
553
 
554
+ // get the successful candidate pair before parsing stats.
555
+ statsItem.report.forEach((report) => {
556
+ if (report.type === 'candidate-pair' && report.state === 'succeeded') {
557
+ this.successfulCandidatePair = report;
558
+ }
559
+ });
560
+
561
+ let videoSenderIndex = 0;
389
562
  statsItem.report.forEach((result) => {
390
563
  if (types.includes(result.type)) {
391
- this.parseGetStatsResult(result, type, isSender);
564
+ // if the video sender has multiple streams in the report, it is a new stream object.
565
+ if (type === 'video-send' && result.type === 'outbound-rtp') {
566
+ const newType = `video-send-layer-${videoSenderIndex}`;
567
+ this.parseGetStatsResult(result, newType, isSender);
568
+ videoSenderIndex += 1;
569
+
570
+ this.statsResults[newType].direction = statsItem.currentDirection;
571
+ this.statsResults[newType].trackLabel = statsItem.localTrackLabel;
572
+ this.statsResults[newType].csi = statsItem.csi;
573
+ } else {
574
+ this.parseGetStatsResult(result, type, isSender);
575
+ }
392
576
  }
393
577
  });
394
578
 
@@ -396,6 +580,12 @@ export class StatsAnalyzer extends EventsScope {
396
580
  this.statsResults[type].direction = statsItem.currentDirection;
397
581
  this.statsResults[type].trackLabel = statsItem.localTrackLabel;
398
582
  this.statsResults[type].csi = statsItem.csi;
583
+ this.extractAndSetLocalIpAddressInfoForDiagnostics(
584
+ this.successfulCandidatePair?.localCandidateId,
585
+ this.statsResults?.candidates
586
+ );
587
+ // reset the successful candidate pair.
588
+ this.successfulCandidatePair = {};
399
589
  }
400
590
  }
401
591
 
@@ -492,50 +682,53 @@ export class StatsAnalyzer extends EventsScope {
492
682
  const getCurrentStatsTotals = (keyPrefix: string, value: string): number =>
493
683
  Object.keys(this.statsResults)
494
684
  .filter((key) => key.startsWith(keyPrefix))
495
- .reduce((prev, cur) => prev + (this.statsResults[cur]?.recv[value] || 0), 0);
685
+ .reduce(
686
+ (prev, cur) =>
687
+ prev +
688
+ (this.statsResults[cur]?.[keyPrefix.includes('send') ? 'send' : 'recv'][value] || 0),
689
+ 0
690
+ );
496
691
 
497
692
  const getPreviousStatsTotals = (keyPrefix: string, value: string): number =>
498
- Object.keys(this.statsResults)
499
- .filter((key) => key.startsWith(keyPrefix))
500
- .reduce((prev, cur) => prev + (this.lastStatsResults[cur]?.recv[value] || 0), 0);
501
-
502
- const getCurrentResolutionsStatsTotals = (keyPrefix: string, value: string): number =>
503
- Object.keys(this.statsResults)
504
- .filter((key) => key.startsWith(keyPrefix))
505
- .reduce((prev, cur) => prev + (this.statsResults.resolutions[cur]?.recv[value] || 0), 0);
506
-
507
- const getPreviousResolutionsStatsTotals = (keyPrefix: string, value: string): number =>
508
693
  Object.keys(this.statsResults)
509
694
  .filter((key) => key.startsWith(keyPrefix))
510
695
  .reduce(
511
- (prev, cur) => prev + (this.lastStatsResults.resolutions[cur]?.recv[value] || 0),
696
+ (prev, cur) =>
697
+ prev +
698
+ (this.lastStatsResults[cur]?.[keyPrefix.includes('send') ? 'send' : 'recv'][value] ||
699
+ 0),
512
700
  0
513
701
  );
514
702
 
515
- if (this.meetingMediaStatus.expected.sendAudio && this.lastStatsResults['audio-send']) {
703
+ // Audio Transmit
704
+ if (this.lastStatsResults['audio-send']) {
516
705
  // compare audio stats sent
517
706
  // NOTE: relies on there being only one sender.
518
707
  const currentStats = this.statsResults['audio-send'].send;
519
708
  const previousStats = this.lastStatsResults['audio-send'].send;
520
709
 
521
710
  if (
522
- currentStats.totalPacketsSent === previousStats.totalPacketsSent ||
711
+ (this.meetingMediaStatus.expected.sendAudio &&
712
+ currentStats.totalPacketsSent === previousStats.totalPacketsSent) ||
523
713
  currentStats.totalPacketsSent === 0
524
714
  ) {
525
715
  LoggerProxy.logger.info(
526
- `StatsAnalyzer:index#compareLastStatsResult --> No audio RTP packets sent`
716
+ `StatsAnalyzer:index#compareLastStatsResult --> No audio RTP packets sent`,
717
+ currentStats.totalPacketsSent
527
718
  );
528
719
  } else {
529
720
  if (
530
- currentStats.totalAudioEnergy === previousStats.totalAudioEnergy ||
721
+ (this.meetingMediaStatus.expected.sendAudio &&
722
+ currentStats.totalAudioEnergy === previousStats.totalAudioEnergy) ||
531
723
  currentStats.totalAudioEnergy === 0
532
724
  ) {
533
725
  LoggerProxy.logger.info(
534
- `StatsAnalyzer:index#compareLastStatsResult --> No audio Energy present`
726
+ `StatsAnalyzer:index#compareLastStatsResult --> No audio Energy present`,
727
+ currentStats.totalAudioEnergy
535
728
  );
536
729
  }
537
730
 
538
- if (currentStats.audioLevel === 0) {
731
+ if (this.meetingMediaStatus.expected.sendAudio && currentStats.audioLevel === 0) {
539
732
  LoggerProxy.logger.info(
540
733
  `StatsAnalyzer:index#compareLastStatsResult --> audio level is 0 for the user`
541
734
  );
@@ -550,217 +743,141 @@ export class StatsAnalyzer extends EventsScope {
550
743
  );
551
744
  }
552
745
 
553
- if (this.meetingMediaStatus.expected.receiveAudio) {
554
- // compare audio stats received
555
- const currentPacketsReceived = getCurrentStatsTotals('audio-recv', 'totalPacketsReceived');
556
- const previousPacketsReceived = getPreviousStatsTotals(
557
- 'audio-recv',
558
- 'totalPacketsReceived'
559
- );
560
- const currentSamplesReceived = getCurrentStatsTotals('audio-recv', 'totalSamplesReceived');
561
- const previousSamplesReceived = getPreviousStatsTotals(
562
- 'audio-recv',
563
- 'totalSamplesReceived'
564
- );
746
+ // Audio Receive
747
+ const currentAudioPacketsReceived = getCurrentStatsTotals(
748
+ 'audio-recv',
749
+ 'totalPacketsReceived'
750
+ );
751
+ const previousAudioPacketsReceived = getPreviousStatsTotals(
752
+ 'audio-recv',
753
+ 'totalPacketsReceived'
754
+ );
565
755
 
566
- if (currentPacketsReceived === previousPacketsReceived || currentPacketsReceived === 0) {
567
- LoggerProxy.logger.info(
568
- `StatsAnalyzer:index#compareLastStatsResult --> No audio RTP packets received`
569
- );
570
- } else if (
571
- currentSamplesReceived === previousSamplesReceived ||
572
- currentSamplesReceived === 0
573
- ) {
574
- LoggerProxy.logger.info(
575
- `StatsAnalyzer:index#compareLastStatsResult --> No audio samples received`
576
- );
577
- }
756
+ this.emitStartStopEvents(
757
+ 'audio',
758
+ previousAudioPacketsReceived,
759
+ currentAudioPacketsReceived,
760
+ false
761
+ );
578
762
 
579
- this.emitStartStopEvents('audio', previousPacketsReceived, currentPacketsReceived, false);
580
- }
763
+ const currentTotalPacketsSent = getCurrentStatsTotals('video-send', 'totalPacketsSent');
764
+ const previousTotalPacketsSent = getPreviousStatsTotals('video-send', 'totalPacketsSent');
765
+
766
+ const currentFramesEncoded = getCurrentStatsTotals('video-send', 'framesEncoded');
767
+ const previousFramesEncoded = getPreviousStatsTotals('video-send', 'framesEncoded');
768
+
769
+ const currentFramesSent = getCurrentStatsTotals('video-send', 'framesSent');
770
+ const previousFramesSent = getPreviousStatsTotals('video-send', 'framesSent');
581
771
 
582
- if (this.meetingMediaStatus.expected.sendVideo && this.lastStatsResults['video-send']) {
772
+ const doesVideoSendExist = Object.keys(this.lastStatsResults).some((item) =>
773
+ item.includes('video-send')
774
+ );
775
+
776
+ // Video Transmit
777
+ if (doesVideoSendExist) {
583
778
  // compare video stats sent
584
- const currentStats = this.statsResults['video-send'].send;
585
- const previousStats = this.lastStatsResults['video-send'].send;
586
779
 
587
780
  if (
588
- currentStats.totalPacketsSent === previousStats.totalPacketsSent ||
589
- currentStats.totalPacketsSent === 0
781
+ this.meetingMediaStatus.expected.sendVideo &&
782
+ (currentTotalPacketsSent === previousTotalPacketsSent || currentTotalPacketsSent === 0)
590
783
  ) {
591
784
  LoggerProxy.logger.info(
592
- `StatsAnalyzer:index#compareLastStatsResult --> No video RTP packets sent`
785
+ `StatsAnalyzer:index#compareLastStatsResult --> No video RTP packets sent`,
786
+ currentTotalPacketsSent
593
787
  );
594
788
  } else {
595
789
  if (
596
- currentStats.framesEncoded === previousStats.framesEncoded ||
597
- currentStats.framesEncoded === 0
790
+ this.meetingMediaStatus.expected.sendVideo &&
791
+ (currentFramesEncoded === previousFramesEncoded || currentFramesEncoded === 0)
598
792
  ) {
599
793
  LoggerProxy.logger.info(
600
- `StatsAnalyzer:index#compareLastStatsResult --> No video Frames Encoded`
794
+ `StatsAnalyzer:index#compareLastStatsResult --> No video Frames Encoded`,
795
+ currentFramesEncoded
601
796
  );
602
797
  }
603
798
 
604
799
  if (
605
- this.statsResults.resolutions['video-send'].send.framesSent ===
606
- this.lastStatsResults.resolutions['video-send'].send.framesSent ||
607
- this.statsResults.resolutions['video-send'].send.framesSent === 0
800
+ this.meetingMediaStatus.expected.sendVideo &&
801
+ (currentFramesSent === previousFramesSent || currentFramesSent === 0)
608
802
  ) {
609
803
  LoggerProxy.logger.info(
610
- `StatsAnalyzer:index#compareLastStatsResult --> No video Frames sent`
804
+ `StatsAnalyzer:index#compareLastStatsResult --> No video Frames sent`,
805
+ currentFramesSent
611
806
  );
612
807
  }
613
808
  }
614
809
 
615
- this.emitStartStopEvents('video', previousStats.framesSent, currentStats.framesSent, true);
810
+ this.emitStartStopEvents('video', previousFramesSent, currentFramesSent, true);
616
811
  }
617
812
 
618
- if (this.meetingMediaStatus.expected.receiveVideo) {
619
- // compare video stats received
620
- const currentPacketsReceived = getCurrentStatsTotals('video-recv', 'totalPacketsReceived');
621
- const previousPacketsReceived = getPreviousStatsTotals(
622
- 'video-recv',
623
- 'totalPacketsReceived'
624
- );
625
- const currentFramesReceived = getCurrentResolutionsStatsTotals(
626
- 'video-recv',
627
- 'framesReceived'
628
- );
629
- const previousFramesReceived = getPreviousResolutionsStatsTotals(
630
- 'video-recv',
631
- 'framesReceived'
632
- );
633
- const currentFramesDecoded = getCurrentStatsTotals('video-recv', 'framesDecoded');
634
- const previousFramesDecoded = getPreviousStatsTotals('video-recv', 'framesDecoded');
635
- const currentFramesDropped = getCurrentResolutionsStatsTotals(
636
- 'video-recv',
637
- 'framesDropped'
638
- );
639
- const previousFramesDropped = getPreviousResolutionsStatsTotals(
640
- 'video-recv',
641
- 'framesDropped'
642
- );
813
+ // Video Receive
814
+ const currentVideoFramesDecoded = getCurrentStatsTotals('video-recv', 'framesDecoded');
815
+ const previousVideoFramesDecoded = getPreviousStatsTotals('video-recv', 'framesDecoded');
643
816
 
644
- if (currentPacketsReceived === previousPacketsReceived || currentPacketsReceived === 0) {
645
- LoggerProxy.logger.info(
646
- `StatsAnalyzer:index#compareLastStatsResult --> No video RTP packets received`
647
- );
648
- } else {
649
- if (currentFramesReceived === previousFramesReceived || currentFramesReceived === 0) {
650
- LoggerProxy.logger.info(
651
- `StatsAnalyzer:index#compareLastStatsResult --> No video frames received`
652
- );
653
- }
654
-
655
- if (currentFramesDecoded === previousFramesDecoded || currentFramesDecoded === 0) {
656
- LoggerProxy.logger.info(
657
- `StatsAnalyzer:index#compareLastStatsResult --> No video frames decoded`
658
- );
659
- }
660
-
661
- if (currentFramesDropped - previousFramesDropped > 10) {
662
- LoggerProxy.logger.info(
663
- `StatsAnalyzer:index#compareLastStatsResult --> video frames are getting dropped`
664
- );
665
- }
666
- }
667
-
668
- this.emitStartStopEvents('video', previousFramesDecoded, currentFramesDecoded, false);
669
- }
817
+ this.emitStartStopEvents(
818
+ 'video',
819
+ previousVideoFramesDecoded,
820
+ currentVideoFramesDecoded,
821
+ false
822
+ );
670
823
 
671
- if (this.meetingMediaStatus.expected.sendShare && this.lastStatsResults['video-share-send']) {
824
+ // Share Transmit
825
+ if (this.lastStatsResults['video-share-send']) {
672
826
  // compare share stats sent
673
827
 
674
828
  const currentStats = this.statsResults['video-share-send'].send;
675
829
  const previousStats = this.lastStatsResults['video-share-send'].send;
676
830
 
677
831
  if (
678
- currentStats.totalPacketsSent === previousStats.totalPacketsSent ||
679
- currentStats.totalPacketsSent === 0
832
+ this.meetingMediaStatus.expected.sendShare &&
833
+ (currentStats.totalPacketsSent === previousStats.totalPacketsSent ||
834
+ currentStats.totalPacketsSent === 0)
680
835
  ) {
681
836
  LoggerProxy.logger.info(
682
- `StatsAnalyzer:index#compareLastStatsResult --> No share RTP packets sent`
837
+ `StatsAnalyzer:index#compareLastStatsResult --> No share RTP packets sent`,
838
+ currentStats.totalPacketsSent
683
839
  );
684
840
  } else {
685
841
  if (
686
- currentStats.framesEncoded === previousStats.framesEncoded ||
687
- currentStats.framesEncoded === 0
842
+ this.meetingMediaStatus.expected.sendShare &&
843
+ (currentStats.framesEncoded === previousStats.framesEncoded ||
844
+ currentStats.framesEncoded === 0)
688
845
  ) {
689
846
  LoggerProxy.logger.info(
690
- `StatsAnalyzer:index#compareLastStatsResult --> No share frames getting encoded`
847
+ `StatsAnalyzer:index#compareLastStatsResult --> No share frames getting encoded`,
848
+ currentStats.framesEncoded
691
849
  );
692
850
  }
693
851
 
694
852
  if (
695
- this.statsResults.resolutions['video-share-send'].send.framesSent ===
696
- this.lastStatsResults.resolutions['video-share-send'].send.framesSent ||
697
- this.statsResults.resolutions['video-share-send'].send.framesSent === 0
853
+ this.meetingMediaStatus.expected.sendShare &&
854
+ (this.statsResults['video-share-send'].send.framesSent ===
855
+ this.lastStatsResults['video-share-send'].send.framesSent ||
856
+ this.statsResults['video-share-send'].send.framesSent === 0)
698
857
  ) {
699
858
  LoggerProxy.logger.info(
700
- `StatsAnalyzer:index#compareLastStatsResult --> No share frames sent`
859
+ `StatsAnalyzer:index#compareLastStatsResult --> No share frames sent`,
860
+ this.statsResults['video-share-send'].send.framesSent
701
861
  );
702
862
  }
703
863
  }
704
- }
705
-
706
- if (this.meetingMediaStatus.expected.sendShare) {
707
- // TODO:need to check receive share value
708
- // compare share stats received
709
- const currentPacketsReceived = getCurrentStatsTotals(
710
- 'video-share-recv',
711
- 'totalPacketsReceived'
712
- );
713
- const previousPacketsReceived = getPreviousStatsTotals(
714
- 'video-share-recv',
715
- 'totalPacketsReceived'
716
- );
717
- const currentFramesReceived = getCurrentResolutionsStatsTotals(
718
- 'video-share-recv',
719
- 'framesReceived'
720
- );
721
- const previousFramesReceived = getPreviousResolutionsStatsTotals(
722
- 'video-share-recv',
723
- 'framesReceived'
724
- );
725
- const currentFramesDecoded = getCurrentStatsTotals('video-share-recv', 'framesDecoded');
726
- const previousFramesDecoded = getPreviousStatsTotals('video-share-recv', 'framesDecoded');
727
- const currentFramesDropped = getCurrentResolutionsStatsTotals(
728
- 'video-share-recv',
729
- 'framesDropped'
730
- );
731
- const previousFramesDropped = getPreviousResolutionsStatsTotals(
732
- 'video-share-recv',
733
- 'framesDropped'
734
- );
735
-
736
- if (currentPacketsReceived === previousPacketsReceived || currentPacketsReceived === 0) {
737
- LoggerProxy.logger.info(
738
- `StatsAnalyzer:index#compareLastStatsResult --> No share RTP packets received`
739
- );
740
- } else {
741
- if (currentFramesReceived === previousFramesReceived || currentFramesReceived === 0) {
742
- LoggerProxy.logger.info(
743
- `StatsAnalyzer:index#compareLastStatsResult --> No share frames received`
744
- );
745
- }
746
864
 
747
- if (currentFramesDecoded === previousFramesDecoded || currentFramesDecoded === 0) {
748
- LoggerProxy.logger.info(
749
- `StatsAnalyzer:index#compareLastStatsResult --> No share frames decoded`
750
- );
751
- }
865
+ this.emitStartStopEvents('share', previousStats.framesSent, currentStats.framesSent, true);
866
+ }
752
867
 
753
- if (currentFramesDropped - previousFramesDropped > 10) {
754
- LoggerProxy.logger.info(
755
- `StatsAnalyzer:index#compareLastStatsResult --> share frames are getting dropped`
756
- );
757
- }
758
- }
868
+ // Share receive
869
+ const currentShareFramesDecoded = getCurrentStatsTotals('video-share-recv', 'framesDecoded');
870
+ const previousShareFramesDecoded = getPreviousStatsTotals(
871
+ 'video-share-recv',
872
+ 'framesDecoded'
873
+ );
759
874
 
760
- // we are not calling emitStartStopEvents() for sending or receiving share because sharing is often started and stopped
761
- // in meetings and this.meetingMediaStatus.expected values can be out of sync with the actual packet flow
762
- // so we would send "sharing stopped" events incorrectly
763
- }
875
+ this.emitStartStopEvents(
876
+ 'share',
877
+ previousShareFramesDecoded,
878
+ currentShareFramesDecoded,
879
+ false
880
+ );
764
881
  }
765
882
  }
766
883
 
@@ -851,43 +968,20 @@ export class StatsAnalyzer extends EventsScope {
851
968
  const sendrecvType = STATS.SEND_DIRECTION;
852
969
 
853
970
  if (result.bytesSent) {
854
- let kilobytes = 0;
971
+ const kilobytes = 0;
855
972
 
856
- if (!this.statsResults.internal[mediaType][sendrecvType].prevBytesSent) {
857
- this.statsResults.internal[mediaType][sendrecvType].prevBytesSent = result.bytesSent;
858
- }
859
- if (!this.statsResults.internal[mediaType][sendrecvType].framesEncoded) {
860
- this.statsResults.internal[mediaType][sendrecvType].framesEncoded = result.framesEncoded;
973
+ if (result.frameWidth && result.frameHeight) {
974
+ this.statsResults[mediaType][sendrecvType].width = result.frameWidth;
975
+ this.statsResults[mediaType][sendrecvType].height = result.frameHeight;
976
+ this.statsResults[mediaType][sendrecvType].framesSent = result.framesSent;
977
+ this.statsResults[mediaType][sendrecvType].hugeFramesSent = result.hugeFramesSent;
861
978
  }
862
- if (!this.statsResults.internal[mediaType][sendrecvType].keyFramesEncoded) {
863
- this.statsResults.internal[mediaType][sendrecvType].keyFramesEncoded =
864
- result.keyFramesEncoded;
865
- }
866
-
867
- const bytes =
868
- result.bytesSent - this.statsResults.internal[mediaType][sendrecvType].prevBytesSent;
869
-
870
- this.statsResults.internal[mediaType][sendrecvType].prevBytesSent = result.bytesSent;
871
-
872
- kilobytes = bytes / 1024;
873
979
 
874
980
  this.statsResults[mediaType][sendrecvType].availableBandwidth = kilobytes.toFixed(1);
875
- this.statsResults[mediaType].bytesSent = kilobytes;
876
-
877
- this.statsResults[mediaType][sendrecvType].framesEncoded =
878
- result.framesEncoded - this.statsResults.internal[mediaType][sendrecvType].framesEncoded;
879
- this.statsResults[mediaType][sendrecvType].keyFramesEncoded =
880
- result.keyFramesEncoded -
881
- this.statsResults.internal[mediaType][sendrecvType].keyFramesEncoded;
882
- this.statsResults.internal[mediaType].outboundRtpId = result.id;
883
-
884
- if (!this.statsResults.internal[mediaType][sendrecvType].packetsSent) {
885
- this.statsResults.internal[mediaType][sendrecvType].packetsSent = result.packetsSent;
886
- }
887
981
 
888
- this.statsResults[mediaType][sendrecvType].packetsSent =
889
- result.packetsSent - this.statsResults.internal[mediaType][sendrecvType].packetsSent;
890
- this.statsResults.internal[mediaType][sendrecvType].packetsSent = result.packetsSent;
982
+ this.statsResults[mediaType][sendrecvType].framesEncoded = result.framesEncoded;
983
+ this.statsResults[mediaType][sendrecvType].keyFramesEncoded = result.keyFramesEncoded;
984
+ this.statsResults[mediaType][sendrecvType].packetsSent = result.packetsSent;
891
985
 
892
986
  // Data saved to send MQA metrics
893
987
 
@@ -925,75 +1019,92 @@ export class StatsAnalyzer extends EventsScope {
925
1019
 
926
1020
  if (result.bytesReceived) {
927
1021
  let kilobytes = 0;
1022
+ const receiveSlot = this.receiveSlotCallback(result.ssrc);
1023
+ const sourceState = receiveSlot?.sourceState;
1024
+ const idAndCsi = receiveSlot
1025
+ ? `id: "${receiveSlot.id || ''}"${receiveSlot.csi ? ` and csi: ${receiveSlot.csi}` : ''}`
1026
+ : '';
928
1027
 
929
- if (!this.statsResults.internal[mediaType][sendrecvType].prevBytesReceived) {
930
- this.statsResults.internal[mediaType][sendrecvType].prevBytesReceived =
931
- result.bytesReceived;
932
- }
1028
+ const bytes =
1029
+ result.bytesReceived - this.statsResults[mediaType][sendrecvType].totalBytesReceived;
933
1030
 
934
- if (!this.statsResults.internal[mediaType][sendrecvType].pliCount) {
935
- this.statsResults.internal[mediaType][sendrecvType].pliCount = result.pliCount;
936
- }
1031
+ kilobytes = bytes / 1024;
1032
+ this.statsResults[mediaType][sendrecvType].availableBandwidth = kilobytes.toFixed(1);
937
1033
 
938
- if (!this.statsResults.internal[mediaType][sendrecvType].packetsLost) {
939
- this.statsResults.internal[mediaType][sendrecvType].packetsLost = result.packetsLost;
1034
+ let currentPacketsLost =
1035
+ result.packetsLost - this.statsResults[mediaType][sendrecvType].totalPacketsLost;
1036
+ if (currentPacketsLost < 0) {
1037
+ currentPacketsLost = 0;
940
1038
  }
1039
+ const packetsReceivedDiff =
1040
+ result.packetsReceived - this.statsResults[mediaType][sendrecvType].totalPacketsReceived;
1041
+ this.statsResults[mediaType][sendrecvType].totalPacketsReceived = result.packetsReceived;
941
1042
 
942
- if (!this.statsResults.internal[mediaType][sendrecvType].totalPacketsReceived) {
943
- this.statsResults.internal[mediaType][sendrecvType].totalPacketsReceived =
944
- result.packetsReceived;
1043
+ if (packetsReceivedDiff === 0) {
1044
+ if (receiveSlot && sourceState === 'live') {
1045
+ LoggerProxy.logger.info(
1046
+ `StatsAnalyzer:index#processInboundRTPResult --> No packets received for mediaType: ${mediaType}, receive slot ${idAndCsi}. Total packets received on slot: `,
1047
+ result.packetsReceived
1048
+ );
1049
+ }
945
1050
  }
946
1051
 
947
- if (!this.statsResults.internal[mediaType][sendrecvType].lastPacketReceivedTimestamp) {
948
- this.statsResults.internal[mediaType][sendrecvType].lastPacketReceivedTimestamp =
949
- result.lastPacketReceivedTimestamp;
950
- }
1052
+ if (mediaType.startsWith('video') || mediaType.startsWith('share')) {
1053
+ const videoFramesReceivedDiff =
1054
+ result.framesReceived - this.statsResults[mediaType][sendrecvType].framesReceived;
951
1055
 
952
- const bytes =
953
- result.bytesReceived -
954
- this.statsResults.internal[mediaType][sendrecvType].prevBytesReceived;
1056
+ if (videoFramesReceivedDiff === 0) {
1057
+ if (receiveSlot && sourceState === 'live') {
1058
+ LoggerProxy.logger.info(
1059
+ `StatsAnalyzer:index#processInboundRTPResult --> No frames received for mediaType: ${mediaType}, receive slot ${idAndCsi}. Total frames received on slot: `,
1060
+ result.framesReceived
1061
+ );
1062
+ }
1063
+ }
955
1064
 
956
- this.statsResults.internal[mediaType][sendrecvType].prevBytesReceived = result.bytesReceived;
1065
+ const videoFramesDecodedDiff =
1066
+ result.framesDecoded - this.statsResults[mediaType][sendrecvType].framesDecoded;
957
1067
 
958
- kilobytes = bytes / 1024;
959
- this.statsResults[mediaType][sendrecvType].availableBandwidth = kilobytes.toFixed(1);
960
- this.statsResults[mediaType].bytesReceived = kilobytes.toFixed(1);
961
-
962
- this.statsResults[mediaType][sendrecvType].pliCount =
963
- result.pliCount - this.statsResults.internal[mediaType][sendrecvType].pliCount;
964
- this.statsResults[mediaType][sendrecvType].currentPacketsLost =
965
- result.packetsLost - this.statsResults.internal[mediaType][sendrecvType].packetsLost;
966
- if (this.statsResults[mediaType][sendrecvType].currentPacketsLost < 0) {
967
- this.statsResults[mediaType][sendrecvType].currentPacketsLost = 0;
968
- }
1068
+ if (videoFramesDecodedDiff === 0) {
1069
+ if (receiveSlot && sourceState === 'live') {
1070
+ LoggerProxy.logger.info(
1071
+ `StatsAnalyzer:index#processInboundRTPResult --> No frames decoded for mediaType: ${mediaType}, receive slot ${idAndCsi}. Total frames decoded on slot: `,
1072
+ result.framesDecoded
1073
+ );
1074
+ }
1075
+ }
969
1076
 
970
- this.statsResults[mediaType][sendrecvType].packetsReceived =
971
- result.packetsReceived -
972
- this.statsResults.internal[mediaType][sendrecvType].totalPacketsReceived;
973
- this.statsResults.internal[mediaType][sendrecvType].totalPacketsReceived =
974
- result.packetsReceived;
1077
+ const videoFramesDroppedDiff =
1078
+ result.framesDropped - this.statsResults[mediaType][sendrecvType].framesDropped;
975
1079
 
976
- if (this.statsResults[mediaType][sendrecvType].packetsReceived === 0) {
977
- LoggerProxy.logger.info(
978
- `StatsAnalyzer:index#processInboundRTPResult --> No packets received for ${mediaType} `,
979
- this.statsResults[mediaType][sendrecvType].packetsReceived
980
- );
1080
+ if (videoFramesDroppedDiff > 10) {
1081
+ if (receiveSlot && sourceState === 'live') {
1082
+ LoggerProxy.logger.info(
1083
+ `StatsAnalyzer:index#processInboundRTPResult --> Frames dropped for mediaType: ${mediaType}, receive slot ${idAndCsi}. Total frames dropped on slot: `,
1084
+ result.framesDropped
1085
+ );
1086
+ }
1087
+ }
981
1088
  }
982
1089
 
983
1090
  // Check the over all packet Lost ratio
984
1091
  this.statsResults[mediaType][sendrecvType].currentPacketLossRatio =
985
- this.statsResults[mediaType][sendrecvType].currentPacketsLost > 0
986
- ? this.statsResults[mediaType][sendrecvType].currentPacketsLost /
987
- (this.statsResults[mediaType][sendrecvType].packetsReceived +
988
- this.statsResults[mediaType][sendrecvType].currentPacketsLost)
1092
+ currentPacketsLost > 0
1093
+ ? currentPacketsLost / (packetsReceivedDiff + currentPacketsLost)
989
1094
  : 0;
990
1095
  if (this.statsResults[mediaType][sendrecvType].currentPacketLossRatio > 3) {
991
1096
  LoggerProxy.logger.info(
992
- 'StatsAnalyzer:index#processInboundRTPResult --> Packets getting lost from the receiver ',
1097
+ `StatsAnalyzer:index#processInboundRTPResult --> Packets getting lost from the receiver with slot ${idAndCsi}`,
993
1098
  this.statsResults[mediaType][sendrecvType].currentPacketLossRatio
994
1099
  );
995
1100
  }
996
1101
 
1102
+ if (result.frameWidth && result.frameHeight) {
1103
+ this.statsResults[mediaType][sendrecvType].width = result.frameWidth;
1104
+ this.statsResults[mediaType][sendrecvType].height = result.frameHeight;
1105
+ this.statsResults[mediaType][sendrecvType].framesReceived = result.framesReceived;
1106
+ }
1107
+
997
1108
  // TODO: check the packet loss value is negative values here
998
1109
 
999
1110
  if (result.packetsLost) {
@@ -1011,6 +1122,7 @@ export class StatsAnalyzer extends EventsScope {
1011
1122
  this.statsResults[mediaType][sendrecvType].totalPliCount = result.pliCount;
1012
1123
  this.statsResults[mediaType][sendrecvType].framesDecoded = result.framesDecoded;
1013
1124
  this.statsResults[mediaType][sendrecvType].keyFramesDecoded = result.keyFramesDecoded;
1125
+ this.statsResults[mediaType][sendrecvType].framesDropped = result.framesDropped;
1014
1126
 
1015
1127
  this.statsResults[mediaType][sendrecvType].decoderImplementation =
1016
1128
  result.decoderImplementation;
@@ -1035,6 +1147,48 @@ export class StatsAnalyzer extends EventsScope {
1035
1147
  }
1036
1148
  }
1037
1149
 
1150
+ /**
1151
+ * extracts the local Ip address from the statsResult object by looking at stats results candidates
1152
+ * and matches that ID with the successful candidate pair. It looks at the type of local candidate it is
1153
+ * and then extracts the IP address from the relatedAddress or address property based on conditions known in webrtc
1154
+ * note, there are known incompatibilities and it is possible for this to set undefined, or for the IP address to be the public IP address
1155
+ * for example, firefox does not set the relayProtocol, and if the user is behind a NAT it might be the public IP
1156
+ * @private
1157
+ * @param {string} successfulCandidatePairId - The ID of the successful candidate pair.
1158
+ * @param {Object} candidates - the stats result candidates
1159
+ * @returns {void}
1160
+ */
1161
+ extractAndSetLocalIpAddressInfoForDiagnostics = (
1162
+ successfulCandidatePairId: string,
1163
+ candidates: {[key: string]: Record<string, unknown>}
1164
+ ) => {
1165
+ let newIpAddress = '';
1166
+ if (successfulCandidatePairId && !isEmpty(candidates)) {
1167
+ const localCandidate = candidates[successfulCandidatePairId];
1168
+ if (localCandidate) {
1169
+ if (localCandidate.candidateType === 'host') {
1170
+ // if it's a host candidate, use the address property - it will be the local IP
1171
+ newIpAddress = `${localCandidate.address}`;
1172
+ } else if (localCandidate.candidateType === 'prflx') {
1173
+ // if it's a peer reflexive candidate and we're not using a relay (there is no relayProtocol set)
1174
+ // then look at the relatedAddress - it will be the local
1175
+ //
1176
+ // Firefox doesn't populate the relayProtocol property
1177
+ if (!localCandidate.relayProtocol) {
1178
+ newIpAddress = `${localCandidate.relatedAddress}`;
1179
+ } else {
1180
+ // if it's a peer reflexive candidate and we are using a relay -
1181
+ // in that case the relatedAddress will be the IP of the TURN server (Linus),
1182
+ // so we can only look at the address, but it might be local IP or public IP,
1183
+ // depending on if the user is behind a NAT or not
1184
+ newIpAddress = `${localCandidate.address}`;
1185
+ }
1186
+ }
1187
+ }
1188
+ }
1189
+ this.localIpAddress = newIpAddress;
1190
+ };
1191
+
1038
1192
  /**
1039
1193
  * Processes remote and local candidate result and stores
1040
1194
  * @private
@@ -1049,125 +1203,53 @@ export class StatsAnalyzer extends EventsScope {
1049
1203
  if (!result || !result.id) {
1050
1204
  return;
1051
1205
  }
1052
- const RemoteCandidateType = {};
1053
- const RemoteTransport = {};
1054
- const RemoteIpAddress = {};
1055
- const RemoteNetworkType = {};
1056
-
1057
- if (!result.id) return;
1058
-
1059
- const sendRecvType = isSender ? STATS.SEND_DIRECTION : STATS.RECEIVE_DIRECTION;
1060
- const ipType = isRemote ? STATS.REMOTE : STATS.LOCAL;
1061
-
1062
- if (!RemoteCandidateType[result.id]) {
1063
- RemoteCandidateType[result.id] = [];
1064
- }
1065
-
1066
- if (!RemoteTransport[result.id]) {
1067
- RemoteTransport[result.id] = [];
1068
- }
1069
1206
 
1070
- if (!RemoteIpAddress[result.id]) {
1071
- RemoteIpAddress[result.id] = [];
1072
- }
1073
- if (!RemoteNetworkType[result.id]) {
1074
- RemoteNetworkType[result.id] = [];
1075
- }
1076
-
1077
- if (
1078
- result.candidateType &&
1079
- RemoteCandidateType[result.id].indexOf(result.candidateType) === -1
1080
- ) {
1081
- RemoteCandidateType[result.id].push(result.candidateType);
1207
+ // We only care about the successful local candidate
1208
+ if (this.successfulCandidatePair?.localCandidateId !== result.id) {
1209
+ return;
1082
1210
  }
1083
1211
 
1084
- if (result.protocol && RemoteTransport[result.id].indexOf(result.protocol) === -1) {
1085
- RemoteTransport[result.id].push(result.protocol.toUpperCase());
1212
+ let transport;
1213
+ if (result.relayProtocol) {
1214
+ transport = result.relayProtocol.toUpperCase();
1215
+ } else if (result.protocol) {
1216
+ transport = result.protocol.toUpperCase();
1086
1217
  }
1087
1218
 
1088
- if (
1089
- result.ip &&
1090
- RemoteIpAddress[result.id].indexOf(`${result.ip}:${result.portNumber}`) === -1
1091
- ) {
1092
- RemoteIpAddress[result.id].push(`${result.ip}`); // TODO: Add ports
1093
- }
1219
+ const sendRecvType = isSender ? STATS.SEND_DIRECTION : STATS.RECEIVE_DIRECTION;
1220
+ const ipType = isRemote ? STATS.REMOTE : STATS.LOCAL;
1094
1221
 
1095
- if (result.networkType && RemoteNetworkType[result.id].indexOf(result.networkType) === -1) {
1096
- RemoteNetworkType[result.id].push(result.networkType);
1222
+ if (!this.statsResults.candidates) {
1223
+ this.statsResults.candidates = {};
1097
1224
  }
1098
1225
 
1099
- this.statsResults.internal.candidates[result.id] = {
1100
- candidateType: RemoteCandidateType[result.id],
1101
- ipAddress: RemoteIpAddress[result.id],
1226
+ this.statsResults.candidates[result.id] = {
1227
+ candidateType: result.candidateType,
1228
+ ipAddress: result.ip, // TODO: add ports
1229
+ relatedAddress: result.relatedAddress,
1230
+ relatedPort: result.relatedPort,
1231
+ relayProtocol: result.relayProtocol,
1232
+ protocol: result.protocol,
1233
+ address: result.address,
1102
1234
  portNumber: result.port,
1103
- networkType: RemoteNetworkType[result.id],
1235
+ networkType: result.networkType,
1104
1236
  priority: result.priority,
1105
- transport: RemoteTransport[result.id],
1237
+ transport,
1106
1238
  timestamp: result.time,
1107
1239
  id: result.id,
1108
1240
  type: result.type,
1109
1241
  };
1110
1242
 
1111
- this.statsResults.connectionType[ipType].candidateType = RemoteCandidateType[result.id];
1112
- this.statsResults.connectionType[ipType].ipAddress = RemoteIpAddress[result.id];
1243
+ this.statsResults.connectionType[ipType].candidateType = result.candidateType;
1244
+ this.statsResults.connectionType[ipType].ipAddress = result.ipAddress;
1113
1245
 
1114
1246
  this.statsResults.connectionType[ipType].networkType =
1115
- RemoteNetworkType[result.id][0] === NETWORK_TYPE.VPN
1116
- ? NETWORK_TYPE.UNKNOWN
1117
- : RemoteNetworkType[result.id][0];
1118
- this.statsResults.connectionType[ipType].transport = RemoteTransport[result.id];
1247
+ result.networkType === NETWORK_TYPE.VPN ? NETWORK_TYPE.UNKNOWN : result.networkType;
1248
+ this.statsResults.connectionType[ipType].transport = transport;
1119
1249
 
1120
1250
  this.statsResults[type][sendRecvType].totalRoundTripTime = result.totalRoundTripTime;
1121
1251
  };
1122
1252
 
1123
- /**
1124
- * Process Track results
1125
- *
1126
- * @private
1127
- * @param {*} result
1128
- * @param {*} mediaType
1129
- * @returns {void}
1130
- * @memberof StatsAnalyzer
1131
- */
1132
- private processTrackResult(result: any, mediaType: any) {
1133
- if (!result || result.type !== 'track') {
1134
- return;
1135
- }
1136
-
1137
- const sendrecvType =
1138
- result.remoteSource === true ? STATS.RECEIVE_DIRECTION : STATS.SEND_DIRECTION;
1139
-
1140
- if (result.frameWidth && result.frameHeight) {
1141
- this.statsResults.resolutions[mediaType][sendrecvType].width = result.frameWidth;
1142
- this.statsResults.resolutions[mediaType][sendrecvType].height = result.frameHeight;
1143
- this.statsResults.resolutions[mediaType][sendrecvType].framesSent = result.framesSent;
1144
- this.statsResults.resolutions[mediaType][sendrecvType].hugeFramesSent = result.hugeFramesSent;
1145
- }
1146
-
1147
- if (sendrecvType === STATS.RECEIVE_DIRECTION) {
1148
- this.statsResults.resolutions[mediaType][sendrecvType].framesReceived = result.framesReceived;
1149
- this.statsResults.resolutions[mediaType][sendrecvType].framesDecoded = result.framesDecoded;
1150
- this.statsResults.resolutions[mediaType][sendrecvType].framesDropped = result.framesDropped;
1151
- }
1152
-
1153
- if (result.trackIdentifier && !mediaType.includes('audio')) {
1154
- this.statsResults.resolutions[mediaType][sendrecvType].trackIdentifier =
1155
- result.trackIdentifier;
1156
-
1157
- const jitterBufferDelay = result && result.jitterBufferDelay;
1158
- const jitterBufferEmittedCount = result && result.jitterBufferEmittedCount;
1159
-
1160
- this.statsResults.resolutions[mediaType][sendrecvType].avgJitterDelay =
1161
- jitterBufferEmittedCount && +jitterBufferDelay / +jitterBufferEmittedCount;
1162
-
1163
- // Used to calculate the jitter
1164
- this.statsResults.resolutions[mediaType][sendrecvType].jitterBufferDelay =
1165
- result.jitterBufferDelay;
1166
- this.statsResults.resolutions[mediaType][sendrecvType].jitterBufferEmittedCount =
1167
- result.jitterBufferEmittedCount;
1168
- }
1169
- }
1170
-
1171
1253
  /**
1172
1254
  *
1173
1255
  * @private
@@ -1178,20 +1260,15 @@ export class StatsAnalyzer extends EventsScope {
1178
1260
  */
1179
1261
  compareSentAndReceived(result, type) {
1180
1262
  // Don't compare on transceivers without a sender.
1181
- if (!type || !this.statsResults.internal[type].send) {
1263
+ if (!type || !this.statsResults[type].send) {
1182
1264
  return;
1183
1265
  }
1184
1266
 
1185
1267
  const mediaType = type;
1186
1268
 
1187
- if (!this.statsResults.internal[mediaType].send.totalPacketsLostOnReceiver) {
1188
- this.statsResults.internal[mediaType].send.totalPacketsLostOnReceiver = result.packetsLost;
1189
- }
1190
-
1191
1269
  const currentPacketLoss =
1192
- result.packetsLost - this.statsResults.internal[mediaType].send.totalPacketsLostOnReceiver;
1270
+ result.packetsLost - this.statsResults[mediaType].send.totalPacketsLostOnReceiver;
1193
1271
 
1194
- this.statsResults.internal[mediaType].send.totalPacketsLostOnReceiver = result.packetsLost;
1195
1272
  this.statsResults[mediaType].send.packetsLostOnReceiver = currentPacketLoss;
1196
1273
  this.statsResults[mediaType].send.totalPacketsLostOnReceiver = result.packetsLost;
1197
1274