@webex/plugin-meetings 3.0.0-beta.34 → 3.0.0-beta.340

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 (392) 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 +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/edit-lock-error.js +52 -0
  11. package/dist/breakouts/edit-lock-error.js.map +1 -0
  12. package/dist/breakouts/events.js +45 -0
  13. package/dist/breakouts/events.js.map +1 -0
  14. package/dist/breakouts/index.js +709 -35
  15. package/dist/breakouts/index.js.map +1 -1
  16. package/dist/breakouts/utils.js +45 -1
  17. package/dist/breakouts/utils.js.map +1 -1
  18. package/dist/common/errors/no-meeting-info.js +51 -0
  19. package/dist/common/errors/no-meeting-info.js.map +1 -0
  20. package/dist/common/errors/reclaim-host-role-errors.js +158 -0
  21. package/dist/common/errors/reclaim-host-role-errors.js.map +1 -0
  22. package/dist/common/errors/webex-errors.js +48 -7
  23. package/dist/common/errors/webex-errors.js.map +1 -1
  24. package/dist/common/logs/logger-proxy.js +1 -1
  25. package/dist/common/logs/logger-proxy.js.map +1 -1
  26. package/dist/common/logs/request.js +5 -1
  27. package/dist/common/logs/request.js.map +1 -1
  28. package/dist/common/queue.js +24 -9
  29. package/dist/common/queue.js.map +1 -1
  30. package/dist/config.js +5 -10
  31. package/dist/config.js.map +1 -1
  32. package/dist/constants.js +233 -29
  33. package/dist/constants.js.map +1 -1
  34. package/dist/controls-options-manager/enums.js +14 -2
  35. package/dist/controls-options-manager/enums.js.map +1 -1
  36. package/dist/controls-options-manager/index.js +109 -15
  37. package/dist/controls-options-manager/index.js.map +1 -1
  38. package/dist/controls-options-manager/types.js +7 -0
  39. package/dist/controls-options-manager/types.js.map +1 -0
  40. package/dist/controls-options-manager/util.js +309 -18
  41. package/dist/controls-options-manager/util.js.map +1 -1
  42. package/dist/index.js +112 -1
  43. package/dist/index.js.map +1 -1
  44. package/dist/interpretation/collection.js +23 -0
  45. package/dist/interpretation/collection.js.map +1 -0
  46. package/dist/interpretation/index.js +366 -0
  47. package/dist/interpretation/index.js.map +1 -0
  48. package/dist/interpretation/siLanguage.js +25 -0
  49. package/dist/interpretation/siLanguage.js.map +1 -0
  50. package/dist/locus-info/controlsUtils.js +91 -2
  51. package/dist/locus-info/controlsUtils.js.map +1 -1
  52. package/dist/locus-info/index.js +383 -62
  53. package/dist/locus-info/index.js.map +1 -1
  54. package/dist/locus-info/infoUtils.js +7 -1
  55. package/dist/locus-info/infoUtils.js.map +1 -1
  56. package/dist/locus-info/mediaSharesUtils.js +57 -1
  57. package/dist/locus-info/mediaSharesUtils.js.map +1 -1
  58. package/dist/locus-info/parser.js +249 -72
  59. package/dist/locus-info/parser.js.map +1 -1
  60. package/dist/locus-info/selfUtils.js +89 -14
  61. package/dist/locus-info/selfUtils.js.map +1 -1
  62. package/dist/media/index.js +62 -116
  63. package/dist/media/index.js.map +1 -1
  64. package/dist/media/properties.js +73 -124
  65. package/dist/media/properties.js.map +1 -1
  66. package/dist/mediaQualityMetrics/config.js +1 -204
  67. package/dist/mediaQualityMetrics/config.js.map +1 -1
  68. package/dist/meeting/in-meeting-actions.js +86 -2
  69. package/dist/meeting/in-meeting-actions.js.map +1 -1
  70. package/dist/meeting/index.js +3927 -2960
  71. package/dist/meeting/index.js.map +1 -1
  72. package/dist/meeting/locusMediaRequest.js +292 -0
  73. package/dist/meeting/locusMediaRequest.js.map +1 -0
  74. package/dist/meeting/muteState.js +224 -131
  75. package/dist/meeting/muteState.js.map +1 -1
  76. package/dist/meeting/request.js +260 -196
  77. package/dist/meeting/request.js.map +1 -1
  78. package/dist/meeting/util.js +601 -417
  79. package/dist/meeting/util.js.map +1 -1
  80. package/dist/meeting-info/index.js +73 -7
  81. package/dist/meeting-info/index.js.map +1 -1
  82. package/dist/meeting-info/meeting-info-v2.js +192 -51
  83. package/dist/meeting-info/meeting-info-v2.js.map +1 -1
  84. package/dist/meeting-info/util.js +1 -1
  85. package/dist/meeting-info/util.js.map +1 -1
  86. package/dist/meeting-info/utilv2.js +36 -36
  87. package/dist/meeting-info/utilv2.js.map +1 -1
  88. package/dist/meetings/collection.js +39 -0
  89. package/dist/meetings/collection.js.map +1 -1
  90. package/dist/meetings/index.js +424 -116
  91. package/dist/meetings/index.js.map +1 -1
  92. package/dist/meetings/meetings.types.js +7 -0
  93. package/dist/meetings/meetings.types.js.map +1 -0
  94. package/dist/meetings/request.js +2 -0
  95. package/dist/meetings/request.js.map +1 -1
  96. package/dist/meetings/util.js +72 -6
  97. package/dist/meetings/util.js.map +1 -1
  98. package/dist/member/index.js +58 -0
  99. package/dist/member/index.js.map +1 -1
  100. package/dist/member/types.js +25 -0
  101. package/dist/member/types.js.map +1 -0
  102. package/dist/member/util.js +132 -25
  103. package/dist/member/util.js.map +1 -1
  104. package/dist/members/collection.js +10 -0
  105. package/dist/members/collection.js.map +1 -1
  106. package/dist/members/index.js +102 -6
  107. package/dist/members/index.js.map +1 -1
  108. package/dist/members/request.js +106 -38
  109. package/dist/members/request.js.map +1 -1
  110. package/dist/members/types.js +15 -0
  111. package/dist/members/types.js.map +1 -0
  112. package/dist/members/util.js +326 -232
  113. package/dist/members/util.js.map +1 -1
  114. package/dist/metrics/constants.js +16 -5
  115. package/dist/metrics/constants.js.map +1 -1
  116. package/dist/metrics/index.js +1 -446
  117. package/dist/metrics/index.js.map +1 -1
  118. package/dist/multistream/mediaRequestManager.js +228 -58
  119. package/dist/multistream/mediaRequestManager.js.map +1 -1
  120. package/dist/multistream/receiveSlot.js +29 -16
  121. package/dist/multistream/receiveSlot.js.map +1 -1
  122. package/dist/multistream/receiveSlotManager.js +39 -36
  123. package/dist/multistream/receiveSlotManager.js.map +1 -1
  124. package/dist/multistream/remoteMedia.js +44 -18
  125. package/dist/multistream/remoteMedia.js.map +1 -1
  126. package/dist/multistream/remoteMediaGroup.js +60 -3
  127. package/dist/multistream/remoteMediaGroup.js.map +1 -1
  128. package/dist/multistream/remoteMediaManager.js +209 -59
  129. package/dist/multistream/remoteMediaManager.js.map +1 -1
  130. package/dist/multistream/sendSlotManager.js +233 -0
  131. package/dist/multistream/sendSlotManager.js.map +1 -0
  132. package/dist/reachability/clusterReachability.js +356 -0
  133. package/dist/reachability/clusterReachability.js.map +1 -0
  134. package/dist/reachability/index.js +273 -391
  135. package/dist/reachability/index.js.map +1 -1
  136. package/dist/reachability/request.js +17 -8
  137. package/dist/reachability/request.js.map +1 -1
  138. package/dist/reachability/util.js +29 -0
  139. package/dist/reachability/util.js.map +1 -0
  140. package/dist/reconnection-manager/index.js +214 -170
  141. package/dist/reconnection-manager/index.js.map +1 -1
  142. package/dist/recording-controller/index.js +21 -2
  143. package/dist/recording-controller/index.js.map +1 -1
  144. package/dist/recording-controller/util.js +9 -8
  145. package/dist/recording-controller/util.js.map +1 -1
  146. package/dist/roap/index.js +62 -35
  147. package/dist/roap/index.js.map +1 -1
  148. package/dist/roap/request.js +112 -97
  149. package/dist/roap/request.js.map +1 -1
  150. package/dist/roap/turnDiscovery.js +95 -38
  151. package/dist/roap/turnDiscovery.js.map +1 -1
  152. package/dist/rtcMetrics/constants.js +12 -0
  153. package/dist/rtcMetrics/constants.js.map +1 -0
  154. package/dist/rtcMetrics/index.js +142 -0
  155. package/dist/rtcMetrics/index.js.map +1 -0
  156. package/dist/statsAnalyzer/index.js +181 -214
  157. package/dist/statsAnalyzer/index.js.map +1 -1
  158. package/dist/statsAnalyzer/mqaUtil.js +22 -18
  159. package/dist/statsAnalyzer/mqaUtil.js.map +1 -1
  160. package/dist/types/annotation/annotation.types.d.ts +42 -0
  161. package/dist/types/annotation/constants.d.ts +31 -0
  162. package/dist/types/annotation/index.d.ts +117 -0
  163. package/dist/types/breakouts/edit-lock-error.d.ts +15 -0
  164. package/dist/types/breakouts/events.d.ts +8 -0
  165. package/dist/types/breakouts/utils.d.ts +14 -0
  166. package/dist/types/common/errors/no-meeting-info.d.ts +14 -0
  167. package/dist/types/common/errors/reclaim-host-role-errors.d.ts +60 -0
  168. package/dist/types/common/errors/webex-errors.d.ts +25 -1
  169. package/dist/types/common/logs/request.d.ts +2 -0
  170. package/dist/types/common/queue.d.ts +9 -7
  171. package/dist/types/config.d.ts +2 -7
  172. package/dist/types/constants.d.ts +201 -30
  173. package/dist/types/controls-options-manager/enums.d.ts +11 -1
  174. package/dist/types/controls-options-manager/index.d.ts +17 -1
  175. package/dist/types/controls-options-manager/types.d.ts +43 -0
  176. package/dist/types/controls-options-manager/util.d.ts +1 -7
  177. package/dist/types/index.d.ts +6 -4
  178. package/dist/types/interpretation/collection.d.ts +5 -0
  179. package/dist/types/interpretation/index.d.ts +5 -0
  180. package/dist/types/interpretation/siLanguage.d.ts +5 -0
  181. package/dist/types/locus-info/index.d.ts +57 -4
  182. package/dist/types/locus-info/parser.d.ts +66 -6
  183. package/dist/types/media/index.d.ts +2 -0
  184. package/dist/types/media/properties.d.ts +34 -48
  185. package/dist/types/mediaQualityMetrics/config.d.ts +0 -128
  186. package/dist/types/meeting/in-meeting-actions.d.ts +86 -2
  187. package/dist/types/meeting/index.d.ts +506 -512
  188. package/dist/types/meeting/locusMediaRequest.d.ts +74 -0
  189. package/dist/types/meeting/muteState.d.ts +93 -25
  190. package/dist/types/meeting/request.d.ts +72 -43
  191. package/dist/types/meeting/util.d.ts +101 -1
  192. package/dist/types/meeting-info/index.d.ts +13 -1
  193. package/dist/types/meeting-info/meeting-info-v2.d.ts +31 -1
  194. package/dist/types/meetings/collection.d.ts +17 -0
  195. package/dist/types/meetings/index.d.ts +91 -21
  196. package/dist/types/meetings/meetings.types.d.ts +4 -0
  197. package/dist/types/member/index.d.ts +14 -0
  198. package/dist/types/member/types.d.ts +32 -0
  199. package/dist/types/members/collection.d.ts +5 -0
  200. package/dist/types/members/index.d.ts +35 -2
  201. package/dist/types/members/request.d.ts +73 -9
  202. package/dist/types/members/types.d.ts +25 -0
  203. package/dist/types/members/util.d.ts +214 -1
  204. package/dist/types/metrics/constants.d.ts +15 -4
  205. package/dist/types/metrics/index.d.ts +4 -111
  206. package/dist/types/multistream/mediaRequestManager.d.ts +72 -5
  207. package/dist/types/multistream/receiveSlot.d.ts +13 -11
  208. package/dist/types/multistream/receiveSlotManager.d.ts +14 -4
  209. package/dist/types/multistream/remoteMedia.d.ts +8 -29
  210. package/dist/types/multistream/remoteMediaGroup.d.ts +0 -9
  211. package/dist/types/multistream/remoteMediaManager.d.ts +46 -2
  212. package/dist/types/multistream/sendSlotManager.d.ts +61 -0
  213. package/dist/types/reachability/clusterReachability.d.ts +109 -0
  214. package/dist/types/reachability/index.d.ts +60 -95
  215. package/dist/types/reachability/request.d.ts +7 -3
  216. package/dist/types/reachability/util.d.ts +8 -0
  217. package/dist/types/reconnection-manager/index.d.ts +19 -0
  218. package/dist/types/recording-controller/index.d.ts +15 -1
  219. package/dist/types/recording-controller/util.d.ts +5 -4
  220. package/dist/types/roap/index.d.ts +2 -1
  221. package/dist/types/roap/request.d.ts +15 -11
  222. package/dist/types/roap/turnDiscovery.d.ts +21 -3
  223. package/dist/types/rtcMetrics/constants.d.ts +4 -0
  224. package/dist/types/rtcMetrics/index.d.ts +54 -0
  225. package/dist/types/statsAnalyzer/index.d.ts +29 -11
  226. package/dist/types/webinar/collection.d.ts +16 -0
  227. package/dist/types/webinar/index.d.ts +5 -0
  228. package/dist/webinar/collection.js +44 -0
  229. package/dist/webinar/collection.js.map +1 -0
  230. package/dist/webinar/index.js +69 -0
  231. package/dist/webinar/index.js.map +1 -0
  232. package/package.json +22 -19
  233. package/src/annotation/annotation.types.ts +50 -0
  234. package/src/annotation/constants.ts +36 -0
  235. package/src/annotation/index.ts +328 -0
  236. package/src/breakouts/README.md +42 -12
  237. package/src/breakouts/breakout.ts +67 -9
  238. package/src/breakouts/edit-lock-error.ts +25 -0
  239. package/src/breakouts/events.ts +56 -0
  240. package/src/breakouts/index.ts +592 -20
  241. package/src/breakouts/utils.ts +42 -0
  242. package/src/common/errors/no-meeting-info.ts +24 -0
  243. package/src/common/errors/reclaim-host-role-errors.ts +134 -0
  244. package/src/common/errors/webex-errors.ts +44 -2
  245. package/src/common/logs/logger-proxy.ts +1 -1
  246. package/src/common/logs/request.ts +5 -1
  247. package/src/common/queue.ts +22 -8
  248. package/src/config.ts +4 -9
  249. package/src/constants.ts +224 -20
  250. package/src/controls-options-manager/enums.ts +12 -0
  251. package/src/controls-options-manager/index.ts +116 -21
  252. package/src/controls-options-manager/types.ts +59 -0
  253. package/src/controls-options-manager/util.ts +294 -14
  254. package/src/index.ts +40 -0
  255. package/src/interpretation/README.md +60 -0
  256. package/src/interpretation/collection.ts +19 -0
  257. package/src/interpretation/index.ts +332 -0
  258. package/src/interpretation/siLanguage.ts +18 -0
  259. package/src/locus-info/controlsUtils.ts +108 -0
  260. package/src/locus-info/index.ts +413 -59
  261. package/src/locus-info/infoUtils.ts +10 -2
  262. package/src/locus-info/mediaSharesUtils.ts +64 -0
  263. package/src/locus-info/parser.ts +258 -47
  264. package/src/locus-info/selfUtils.ts +81 -5
  265. package/src/media/index.ts +102 -122
  266. package/src/media/properties.ts +87 -110
  267. package/src/mediaQualityMetrics/config.ts +0 -135
  268. package/src/meeting/in-meeting-actions.ts +171 -3
  269. package/src/meeting/index.ts +3276 -2555
  270. package/src/meeting/locusMediaRequest.ts +313 -0
  271. package/src/meeting/muteState.ts +223 -136
  272. package/src/meeting/request.ts +177 -121
  273. package/src/meeting/util.ts +588 -394
  274. package/src/meeting-info/index.ts +81 -8
  275. package/src/meeting-info/meeting-info-v2.ts +170 -14
  276. package/src/meeting-info/util.ts +1 -1
  277. package/src/meeting-info/utilv2.ts +23 -23
  278. package/src/meetings/collection.ts +33 -0
  279. package/src/meetings/index.ts +454 -125
  280. package/src/meetings/meetings.types.ts +12 -0
  281. package/src/meetings/request.ts +2 -0
  282. package/src/meetings/util.ts +80 -11
  283. package/src/member/index.ts +58 -0
  284. package/src/member/types.ts +38 -0
  285. package/src/member/util.ts +141 -25
  286. package/src/members/collection.ts +8 -0
  287. package/src/members/index.ts +134 -8
  288. package/src/members/request.ts +97 -17
  289. package/src/members/types.ts +29 -0
  290. package/src/members/util.ts +333 -240
  291. package/src/metrics/constants.ts +15 -4
  292. package/src/metrics/index.ts +1 -469
  293. package/src/multistream/mediaRequestManager.ts +277 -82
  294. package/src/multistream/receiveSlot.ts +31 -17
  295. package/src/multistream/receiveSlotManager.ts +34 -24
  296. package/src/multistream/remoteMedia.ts +27 -2
  297. package/src/multistream/remoteMediaGroup.ts +59 -0
  298. package/src/multistream/remoteMediaManager.ts +148 -30
  299. package/src/multistream/sendSlotManager.ts +170 -0
  300. package/src/reachability/clusterReachability.ts +320 -0
  301. package/src/reachability/index.ts +236 -342
  302. package/src/reachability/request.ts +17 -8
  303. package/src/reachability/util.ts +24 -0
  304. package/src/reconnection-manager/index.ts +128 -106
  305. package/src/recording-controller/index.ts +20 -3
  306. package/src/recording-controller/util.ts +26 -9
  307. package/src/roap/index.ts +63 -32
  308. package/src/roap/request.ts +100 -104
  309. package/src/roap/turnDiscovery.ts +48 -26
  310. package/src/rtcMetrics/constants.ts +3 -0
  311. package/src/rtcMetrics/index.ts +124 -0
  312. package/src/statsAnalyzer/index.ts +218 -289
  313. package/src/statsAnalyzer/mqaUtil.ts +28 -30
  314. package/src/webinar/collection.ts +31 -0
  315. package/src/webinar/index.ts +62 -0
  316. package/test/integration/spec/converged-space-meetings.js +60 -3
  317. package/test/integration/spec/journey.js +320 -261
  318. package/test/integration/spec/space-meeting.js +76 -3
  319. package/test/unit/spec/annotation/index.ts +418 -0
  320. package/test/unit/spec/breakouts/breakout.ts +118 -28
  321. package/test/unit/spec/breakouts/edit-lock-error.ts +30 -0
  322. package/test/unit/spec/breakouts/events.ts +89 -0
  323. package/test/unit/spec/breakouts/index.ts +1395 -69
  324. package/test/unit/spec/breakouts/utils.js +52 -1
  325. package/test/unit/spec/common/queue.js +31 -2
  326. package/test/unit/spec/controls-options-manager/index.js +163 -0
  327. package/test/unit/spec/controls-options-manager/util.js +576 -60
  328. package/test/unit/spec/fixture/locus.js +1 -0
  329. package/test/unit/spec/interpretation/collection.ts +15 -0
  330. package/test/unit/spec/interpretation/index.ts +589 -0
  331. package/test/unit/spec/interpretation/siLanguage.ts +28 -0
  332. package/test/unit/spec/locus-info/controlsUtils.js +316 -43
  333. package/test/unit/spec/locus-info/index.js +1304 -33
  334. package/test/unit/spec/locus-info/infoUtils.js +37 -15
  335. package/test/unit/spec/locus-info/lib/SeqCmp.json +16 -0
  336. package/test/unit/spec/locus-info/mediaSharesUtils.ts +32 -0
  337. package/test/unit/spec/locus-info/parser.js +116 -35
  338. package/test/unit/spec/locus-info/selfConstant.js +27 -4
  339. package/test/unit/spec/locus-info/selfUtils.js +208 -17
  340. package/test/unit/spec/media/index.ts +120 -37
  341. package/test/unit/spec/media/properties.ts +2 -2
  342. package/test/unit/spec/meeting/in-meeting-actions.ts +85 -3
  343. package/test/unit/spec/meeting/index.js +5849 -2014
  344. package/test/unit/spec/meeting/locusMediaRequest.ts +442 -0
  345. package/test/unit/spec/meeting/muteState.js +402 -213
  346. package/test/unit/spec/meeting/request.js +483 -49
  347. package/test/unit/spec/meeting/utils.js +679 -64
  348. package/test/unit/spec/meeting-info/index.js +300 -0
  349. package/test/unit/spec/meeting-info/meetinginfov2.js +526 -5
  350. package/test/unit/spec/meeting-info/utilv2.js +21 -0
  351. package/test/unit/spec/meetings/collection.js +26 -0
  352. package/test/unit/spec/meetings/index.js +1231 -212
  353. package/test/unit/spec/meetings/utils.js +202 -2
  354. package/test/unit/spec/member/index.js +61 -6
  355. package/test/unit/spec/member/util.js +510 -34
  356. package/test/unit/spec/members/index.js +432 -1
  357. package/test/unit/spec/members/request.js +206 -27
  358. package/test/unit/spec/members/utils.js +210 -0
  359. package/test/unit/spec/metrics/index.js +1 -50
  360. package/test/unit/spec/multistream/mediaRequestManager.ts +776 -162
  361. package/test/unit/spec/multistream/receiveSlot.ts +28 -20
  362. package/test/unit/spec/multistream/receiveSlotManager.ts +32 -30
  363. package/test/unit/spec/multistream/remoteMedia.ts +30 -0
  364. package/test/unit/spec/multistream/remoteMediaGroup.ts +266 -0
  365. package/test/unit/spec/multistream/remoteMediaManager.ts +326 -0
  366. package/test/unit/spec/multistream/sendSlotManager.ts +242 -0
  367. package/test/unit/spec/reachability/clusterReachability.ts +279 -0
  368. package/test/unit/spec/reachability/index.ts +486 -13
  369. package/test/unit/spec/reachability/request.js +68 -0
  370. package/test/unit/spec/reachability/util.ts +40 -0
  371. package/test/unit/spec/reconnection-manager/index.js +117 -11
  372. package/test/unit/spec/recording-controller/index.js +294 -218
  373. package/test/unit/spec/recording-controller/util.js +223 -96
  374. package/test/unit/spec/roap/index.ts +174 -63
  375. package/test/unit/spec/roap/request.ts +226 -85
  376. package/test/unit/spec/roap/turnDiscovery.ts +76 -34
  377. package/test/unit/spec/rtcMetrics/index.ts +93 -0
  378. package/test/unit/spec/stats-analyzer/index.js +231 -7
  379. package/test/unit/spec/webinar/collection.ts +13 -0
  380. package/test/unit/spec/webinar/index.ts +60 -0
  381. package/test/utils/integrationTestUtils.js +46 -0
  382. package/test/utils/testUtils.js +0 -52
  383. package/dist/meeting/effectsState.js +0 -262
  384. package/dist/meeting/effectsState.js.map +0 -1
  385. package/dist/metrics/config.js +0 -289
  386. package/dist/metrics/config.js.map +0 -1
  387. package/dist/types/meeting/effectsState.d.ts +0 -42
  388. package/dist/types/metrics/config.d.ts +0 -169
  389. package/src/index.js +0 -16
  390. package/src/meeting/effectsState.ts +0 -211
  391. package/src/metrics/config.ts +0 -485
  392. package/test/unit/spec/meeting/effectsState.js +0 -285
@@ -1,6 +1,6 @@
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';
@@ -28,6 +28,7 @@ import {
28
28
  getVideoSenderMqa,
29
29
  getVideoReceiverMqa,
30
30
  } from './mqaUtil';
31
+ import {ReceiveSlot} from '../multistream/receiveSlot';
31
32
 
32
33
  export const EVENTS = {
33
34
  MEDIA_QUALITY: 'MEDIA_QUALITY',
@@ -53,6 +54,8 @@ const emptyReceiver = {
53
54
  meanRoundTripTime: [],
54
55
  };
55
56
 
57
+ type ReceiveSlotCallback = (csi: number) => ReceiveSlot | undefined;
58
+
56
59
  /**
57
60
  * Stats Analyzer class that will emit events based on detected quality
58
61
  *
@@ -74,17 +77,22 @@ export class StatsAnalyzer extends EventsScope {
74
77
  statsInterval: NodeJS.Timeout;
75
78
  statsResults: any;
76
79
  statsStarted: any;
80
+ successfulCandidatePair: any;
81
+ 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
82
+ receiveSlotCallback: ReceiveSlotCallback;
77
83
 
78
84
  /**
79
85
  * Creates a new instance of StatsAnalyzer
80
86
  * @constructor
81
87
  * @public
82
88
  * @param {Object} config SDK Configuration Object
89
+ * @param {Function} receiveSlotCallback Callback used to access receive slots.
83
90
  * @param {Object} networkQualityMonitor class for assessing network characteristics (jitter, packetLoss, latency)
84
91
  * @param {Object} statsResults Default properties for stats
85
92
  */
86
93
  constructor(
87
94
  config: any,
95
+ receiveSlotCallback: ReceiveSlotCallback = () => undefined,
88
96
  networkQualityMonitor: object = {},
89
97
  statsResults: object = defaultStats
90
98
  ) {
@@ -98,6 +106,9 @@ export class StatsAnalyzer extends EventsScope {
98
106
  this.mqaSentCount = -1;
99
107
  this.lastMqaDataSent = {};
100
108
  this.lastEmittedStartStopEvent = {};
109
+ this.receiveSlotCallback = receiveSlotCallback;
110
+ this.successfulCandidatePair = {};
111
+ this.localIpAddress = '';
101
112
  }
102
113
 
103
114
  /**
@@ -143,6 +154,18 @@ export class StatsAnalyzer extends EventsScope {
143
154
  const newMqa = cloneDeep(emptyMqaInterval);
144
155
 
145
156
  Object.keys(this.statsResults).forEach((mediaType) => {
157
+ if (!this.lastMqaDataSent[mediaType]) {
158
+ this.lastMqaDataSent[mediaType] = {};
159
+ }
160
+
161
+ if (!this.lastMqaDataSent[mediaType].send && mediaType.includes('-send')) {
162
+ this.lastMqaDataSent[mediaType].send = {};
163
+ }
164
+
165
+ if (!this.lastMqaDataSent[mediaType].recv && mediaType.includes('-recv')) {
166
+ this.lastMqaDataSent[mediaType].recv = {};
167
+ }
168
+
146
169
  if (mediaType.includes('audio-send') || mediaType.includes('audio-share-send')) {
147
170
  const audioSender = cloneDeep(emptyAudioTransmit);
148
171
 
@@ -153,6 +176,8 @@ export class StatsAnalyzer extends EventsScope {
153
176
  mediaType,
154
177
  });
155
178
  newMqa.audioTransmit.push(audioSender);
179
+
180
+ this.lastMqaDataSent[mediaType].send = cloneDeep(this.statsResults[mediaType].send);
156
181
  } else if (mediaType.includes('audio-recv') || mediaType.includes('audio-share-recv')) {
157
182
  const audioReceiver = cloneDeep(emptyAudioReceive);
158
183
 
@@ -163,6 +188,8 @@ export class StatsAnalyzer extends EventsScope {
163
188
  mediaType,
164
189
  });
165
190
  newMqa.audioReceive.push(audioReceiver);
191
+
192
+ this.lastMqaDataSent[mediaType].recv = cloneDeep(this.statsResults[mediaType].recv);
166
193
  } else if (mediaType.includes('video-send') || mediaType.includes('video-share-send')) {
167
194
  const videoSender = cloneDeep(emptyVideoTransmit);
168
195
 
@@ -173,6 +200,8 @@ export class StatsAnalyzer extends EventsScope {
173
200
  mediaType,
174
201
  });
175
202
  newMqa.videoTransmit.push(videoSender);
203
+
204
+ this.lastMqaDataSent[mediaType].send = cloneDeep(this.statsResults[mediaType].send);
176
205
  } else if (mediaType.includes('video-recv') || mediaType.includes('video-share-recv')) {
177
206
  const videoReceiver = cloneDeep(emptyVideoReceive);
178
207
 
@@ -183,24 +212,24 @@ export class StatsAnalyzer extends EventsScope {
183
212
  mediaType,
184
213
  });
185
214
  newMqa.videoReceive.push(videoReceiver);
215
+
216
+ this.lastMqaDataSent[mediaType].recv = cloneDeep(this.statsResults[mediaType].recv);
186
217
  }
187
218
  });
188
219
 
189
- newMqa.intervalMetadata.peerReflexiveIP = this.statsResults.connectionType.local.ipAddress[0];
220
+ newMqa.intervalMetadata.peerReflexiveIP = this.statsResults.connectionType.local.ipAddress;
190
221
 
191
222
  // Adding peripheral information
192
- newMqa.intervalMetadata.peripherals = [];
193
-
194
223
  newMqa.intervalMetadata.peripherals.push({information: _UNKNOWN_, name: MEDIA_DEVICES.SPEAKER});
195
224
  if (this.statsResults['audio-send']) {
196
225
  newMqa.intervalMetadata.peripherals.push({
197
- information: this.statsResults['audio-send']?.trackLabel,
226
+ information: this.statsResults['audio-send'].trackLabel || _UNKNOWN_,
198
227
  name: MEDIA_DEVICES.MICROPHONE,
199
228
  });
200
229
  }
201
230
  if (this.statsResults['video-send']) {
202
231
  newMqa.intervalMetadata.peripherals.push({
203
- information: this.statsResults['video-send']?.trackLabel,
232
+ information: this.statsResults['video-send'].trackLabel || _UNKNOWN_,
204
233
  name: MEDIA_DEVICES.CAMERA,
205
234
  });
206
235
  }
@@ -239,6 +268,16 @@ export class StatsAnalyzer extends EventsScope {
239
268
  this.mediaConnection = mediaConnection;
240
269
  }
241
270
 
271
+ /**
272
+ * Returns the local IP address for diagnostics.
273
+ * this is the local IP of the interface used for the current media connection
274
+ * a host can have many local Ip Addresses
275
+ * @returns {string | undefined} The local IP address.
276
+ */
277
+ getLocalIpAddress(): string {
278
+ return this.localIpAddress;
279
+ }
280
+
242
281
  /**
243
282
  * Starts the stats analyzer on interval
244
283
  *
@@ -293,7 +332,6 @@ export class StatsAnalyzer extends EventsScope {
293
332
  this.mediaConnection = null;
294
333
  });
295
334
  }
296
- this.mediaConnection = null;
297
335
 
298
336
  return Promise.resolve();
299
337
  }
@@ -324,26 +362,6 @@ export class StatsAnalyzer extends EventsScope {
324
362
  this.statsResults[type].recv = cloneDeep(emptyReceiver);
325
363
  }
326
364
 
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
365
  switch (getStatsResult.type) {
348
366
  case 'outbound-rtp':
349
367
  this.processOutboundRTPResult(getStatsResult, type);
@@ -351,13 +369,9 @@ export class StatsAnalyzer extends EventsScope {
351
369
  case 'inbound-rtp':
352
370
  this.processInboundRTPResult(getStatsResult, type);
353
371
  break;
354
- case 'track':
355
- this.processTrackResult(getStatsResult, type);
356
- break;
357
372
  case 'remote-inbound-rtp':
358
373
  case 'remote-outbound-rtp':
359
- // @ts-ignore
360
- this.compareSentAndReceived(getStatsResult, type, isSender);
374
+ this.compareSentAndReceived(getStatsResult, type);
361
375
  break;
362
376
  case 'remotecandidate':
363
377
  case 'remote-candidate':
@@ -386,6 +400,13 @@ export class StatsAnalyzer extends EventsScope {
386
400
  filterAndParseGetStatsResults(statsItem: any, type: string, isSender: boolean) {
387
401
  const {types} = DEFAULT_GET_STATS_FILTER;
388
402
 
403
+ // get the successful candidate pair before parsing stats.
404
+ statsItem.report.forEach((report) => {
405
+ if (report.type === 'candidate-pair' && report.state === 'succeeded') {
406
+ this.successfulCandidatePair = report;
407
+ }
408
+ });
409
+
389
410
  statsItem.report.forEach((result) => {
390
411
  if (types.includes(result.type)) {
391
412
  this.parseGetStatsResult(result, type, isSender);
@@ -396,6 +417,12 @@ export class StatsAnalyzer extends EventsScope {
396
417
  this.statsResults[type].direction = statsItem.currentDirection;
397
418
  this.statsResults[type].trackLabel = statsItem.localTrackLabel;
398
419
  this.statsResults[type].csi = statsItem.csi;
420
+ this.extractAndSetLocalIpAddressInfoForDiagnostics(
421
+ this.successfulCandidatePair?.localCandidateId,
422
+ this.statsResults?.candidates
423
+ );
424
+ // reset the successful candidate pair.
425
+ this.successfulCandidatePair = {};
399
426
  }
400
427
  }
401
428
 
@@ -492,25 +519,12 @@ export class StatsAnalyzer extends EventsScope {
492
519
  const getCurrentStatsTotals = (keyPrefix: string, value: string): number =>
493
520
  Object.keys(this.statsResults)
494
521
  .filter((key) => key.startsWith(keyPrefix))
495
- .reduce((prev, cur) => prev + (this.statsResults[cur].recv[value] || 0), 0);
522
+ .reduce((prev, cur) => prev + (this.statsResults[cur]?.recv[value] || 0), 0);
496
523
 
497
524
  const getPreviousStatsTotals = (keyPrefix: string, value: string): number =>
498
525
  Object.keys(this.statsResults)
499
526
  .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
- Object.keys(this.statsResults)
509
- .filter((key) => key.startsWith(keyPrefix))
510
- .reduce(
511
- (prev, cur) => prev + (this.lastStatsResults.resolutions[cur].recv[value] || 0),
512
- 0
513
- );
527
+ .reduce((prev, cur) => prev + (this.lastStatsResults[cur]?.recv[value] || 0), 0);
514
528
 
515
529
  if (this.meetingMediaStatus.expected.sendAudio && this.lastStatsResults['audio-send']) {
516
530
  // compare audio stats sent
@@ -523,7 +537,8 @@ export class StatsAnalyzer extends EventsScope {
523
537
  currentStats.totalPacketsSent === 0
524
538
  ) {
525
539
  LoggerProxy.logger.info(
526
- `StatsAnalyzer:index#compareLastStatsResult --> No audio RTP packets sent`
540
+ `StatsAnalyzer:index#compareLastStatsResult --> No audio RTP packets sent`,
541
+ currentStats.totalPacketsSent
527
542
  );
528
543
  } else {
529
544
  if (
@@ -531,7 +546,8 @@ export class StatsAnalyzer extends EventsScope {
531
546
  currentStats.totalAudioEnergy === 0
532
547
  ) {
533
548
  LoggerProxy.logger.info(
534
- `StatsAnalyzer:index#compareLastStatsResult --> No audio Energy present`
549
+ `StatsAnalyzer:index#compareLastStatsResult --> No audio Energy present`,
550
+ currentStats.totalAudioEnergy
535
551
  );
536
552
  }
537
553
 
@@ -565,14 +581,16 @@ export class StatsAnalyzer extends EventsScope {
565
581
 
566
582
  if (currentPacketsReceived === previousPacketsReceived || currentPacketsReceived === 0) {
567
583
  LoggerProxy.logger.info(
568
- `StatsAnalyzer:index#compareLastStatsResult --> No audio RTP packets received`
584
+ `StatsAnalyzer:index#compareLastStatsResult --> No audio RTP packets received`,
585
+ currentPacketsReceived
569
586
  );
570
587
  } else if (
571
588
  currentSamplesReceived === previousSamplesReceived ||
572
589
  currentSamplesReceived === 0
573
590
  ) {
574
591
  LoggerProxy.logger.info(
575
- `StatsAnalyzer:index#compareLastStatsResult --> No audio samples received`
592
+ `StatsAnalyzer:index#compareLastStatsResult --> No audio samples received`,
593
+ currentSamplesReceived
576
594
  );
577
595
  }
578
596
 
@@ -589,7 +607,8 @@ export class StatsAnalyzer extends EventsScope {
589
607
  currentStats.totalPacketsSent === 0
590
608
  ) {
591
609
  LoggerProxy.logger.info(
592
- `StatsAnalyzer:index#compareLastStatsResult --> No video RTP packets sent`
610
+ `StatsAnalyzer:index#compareLastStatsResult --> No video RTP packets sent`,
611
+ currentStats.totalPacketsSent
593
612
  );
594
613
  } else {
595
614
  if (
@@ -597,17 +616,19 @@ export class StatsAnalyzer extends EventsScope {
597
616
  currentStats.framesEncoded === 0
598
617
  ) {
599
618
  LoggerProxy.logger.info(
600
- `StatsAnalyzer:index#compareLastStatsResult --> No video Frames Encoded`
619
+ `StatsAnalyzer:index#compareLastStatsResult --> No video Frames Encoded`,
620
+ currentStats.framesEncoded
601
621
  );
602
622
  }
603
623
 
604
624
  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
625
+ this.statsResults['video-send'].send.framesSent ===
626
+ this.lastStatsResults['video-send'].send.framesSent ||
627
+ this.statsResults['video-send'].send.framesSent === 0
608
628
  ) {
609
629
  LoggerProxy.logger.info(
610
- `StatsAnalyzer:index#compareLastStatsResult --> No video Frames sent`
630
+ `StatsAnalyzer:index#compareLastStatsResult --> No video Frames sent`,
631
+ this.statsResults['video-send'].send.framesSent
611
632
  );
612
633
  }
613
634
  }
@@ -622,45 +643,37 @@ export class StatsAnalyzer extends EventsScope {
622
643
  'video-recv',
623
644
  'totalPacketsReceived'
624
645
  );
625
- const currentFramesReceived = getCurrentResolutionsStatsTotals(
626
- 'video-recv',
627
- 'framesReceived'
628
- );
629
- const previousFramesReceived = getPreviousResolutionsStatsTotals(
630
- 'video-recv',
631
- 'framesReceived'
632
- );
646
+ const currentFramesReceived = getCurrentStatsTotals('video-recv', 'framesReceived');
647
+ const previousFramesReceived = getPreviousStatsTotals('video-recv', 'framesReceived');
633
648
  const currentFramesDecoded = getCurrentStatsTotals('video-recv', 'framesDecoded');
634
649
  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
- );
650
+ const currentFramesDropped = getCurrentStatsTotals('video-recv', 'framesDropped');
651
+ const previousFramesDropped = getPreviousStatsTotals('video-recv', 'framesDropped');
643
652
 
644
653
  if (currentPacketsReceived === previousPacketsReceived || currentPacketsReceived === 0) {
645
654
  LoggerProxy.logger.info(
646
- `StatsAnalyzer:index#compareLastStatsResult --> No video RTP packets received`
655
+ `StatsAnalyzer:index#compareLastStatsResult --> No video RTP packets received`,
656
+ currentPacketsReceived
647
657
  );
648
658
  } else {
649
659
  if (currentFramesReceived === previousFramesReceived || currentFramesReceived === 0) {
650
660
  LoggerProxy.logger.info(
651
- `StatsAnalyzer:index#compareLastStatsResult --> No video frames received`
661
+ `StatsAnalyzer:index#compareLastStatsResult --> No video frames received`,
662
+ currentFramesReceived
652
663
  );
653
664
  }
654
665
 
655
666
  if (currentFramesDecoded === previousFramesDecoded || currentFramesDecoded === 0) {
656
667
  LoggerProxy.logger.info(
657
- `StatsAnalyzer:index#compareLastStatsResult --> No video frames decoded`
668
+ `StatsAnalyzer:index#compareLastStatsResult --> No video frames decoded`,
669
+ currentFramesDecoded
658
670
  );
659
671
  }
660
672
 
661
673
  if (currentFramesDropped - previousFramesDropped > 10) {
662
674
  LoggerProxy.logger.info(
663
- `StatsAnalyzer:index#compareLastStatsResult --> video frames are getting dropped`
675
+ `StatsAnalyzer:index#compareLastStatsResult --> video frames are getting dropped`,
676
+ currentFramesDropped - previousFramesDropped
664
677
  );
665
678
  }
666
679
  }
@@ -679,7 +692,8 @@ export class StatsAnalyzer extends EventsScope {
679
692
  currentStats.totalPacketsSent === 0
680
693
  ) {
681
694
  LoggerProxy.logger.info(
682
- `StatsAnalyzer:index#compareLastStatsResult --> No share RTP packets sent`
695
+ `StatsAnalyzer:index#compareLastStatsResult --> No share RTP packets sent`,
696
+ currentStats.totalPacketsSent
683
697
  );
684
698
  } else {
685
699
  if (
@@ -687,17 +701,19 @@ export class StatsAnalyzer extends EventsScope {
687
701
  currentStats.framesEncoded === 0
688
702
  ) {
689
703
  LoggerProxy.logger.info(
690
- `StatsAnalyzer:index#compareLastStatsResult --> No share frames getting encoded`
704
+ `StatsAnalyzer:index#compareLastStatsResult --> No share frames getting encoded`,
705
+ currentStats.framesEncoded
691
706
  );
692
707
  }
693
708
 
694
709
  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
710
+ this.statsResults['video-share-send'].send.framesSent ===
711
+ this.lastStatsResults['video-share-send'].send.framesSent ||
712
+ this.statsResults['video-share-send'].send.framesSent === 0
698
713
  ) {
699
714
  LoggerProxy.logger.info(
700
- `StatsAnalyzer:index#compareLastStatsResult --> No share frames sent`
715
+ `StatsAnalyzer:index#compareLastStatsResult --> No share frames sent`,
716
+ this.statsResults['video-share-send'].send.framesSent
701
717
  );
702
718
  }
703
719
  }
@@ -714,45 +730,37 @@ export class StatsAnalyzer extends EventsScope {
714
730
  'video-share-recv',
715
731
  'totalPacketsReceived'
716
732
  );
717
- const currentFramesReceived = getCurrentResolutionsStatsTotals(
718
- 'video-share-recv',
719
- 'framesReceived'
720
- );
721
- const previousFramesReceived = getPreviousResolutionsStatsTotals(
722
- 'video-share-recv',
723
- 'framesReceived'
724
- );
733
+ const currentFramesReceived = getCurrentStatsTotals('video-share-recv', 'framesReceived');
734
+ const previousFramesReceived = getPreviousStatsTotals('video-share-recv', 'framesReceived');
725
735
  const currentFramesDecoded = getCurrentStatsTotals('video-share-recv', 'framesDecoded');
726
736
  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
- );
737
+ const currentFramesDropped = getCurrentStatsTotals('video-share-recv', 'framesDropped');
738
+ const previousFramesDropped = getPreviousStatsTotals('video-share-recv', 'framesDropped');
735
739
 
736
740
  if (currentPacketsReceived === previousPacketsReceived || currentPacketsReceived === 0) {
737
741
  LoggerProxy.logger.info(
738
- `StatsAnalyzer:index#compareLastStatsResult --> No share RTP packets received`
742
+ `StatsAnalyzer:index#compareLastStatsResult --> No share RTP packets received`,
743
+ currentPacketsReceived
739
744
  );
740
745
  } else {
741
746
  if (currentFramesReceived === previousFramesReceived || currentFramesReceived === 0) {
742
747
  LoggerProxy.logger.info(
743
- `StatsAnalyzer:index#compareLastStatsResult --> No share frames received`
748
+ `StatsAnalyzer:index#compareLastStatsResult --> No share frames received`,
749
+ currentFramesReceived
744
750
  );
745
751
  }
746
752
 
747
753
  if (currentFramesDecoded === previousFramesDecoded || currentFramesDecoded === 0) {
748
754
  LoggerProxy.logger.info(
749
- `StatsAnalyzer:index#compareLastStatsResult --> No share frames decoded`
755
+ `StatsAnalyzer:index#compareLastStatsResult --> No share frames decoded`,
756
+ currentFramesDecoded
750
757
  );
751
758
  }
752
759
 
753
760
  if (currentFramesDropped - previousFramesDropped > 10) {
754
761
  LoggerProxy.logger.info(
755
- `StatsAnalyzer:index#compareLastStatsResult --> share frames are getting dropped`
762
+ `StatsAnalyzer:index#compareLastStatsResult --> share frames are getting dropped`,
763
+ currentFramesDropped - previousFramesDropped
756
764
  );
757
765
  }
758
766
  }
@@ -851,43 +859,20 @@ export class StatsAnalyzer extends EventsScope {
851
859
  const sendrecvType = STATS.SEND_DIRECTION;
852
860
 
853
861
  if (result.bytesSent) {
854
- let kilobytes = 0;
862
+ const kilobytes = 0;
855
863
 
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;
861
- }
862
- if (!this.statsResults.internal[mediaType][sendrecvType].keyFramesEncoded) {
863
- this.statsResults.internal[mediaType][sendrecvType].keyFramesEncoded =
864
- result.keyFramesEncoded;
864
+ if (result.frameWidth && result.frameHeight) {
865
+ this.statsResults[mediaType][sendrecvType].width = result.frameWidth;
866
+ this.statsResults[mediaType][sendrecvType].height = result.frameHeight;
867
+ this.statsResults[mediaType][sendrecvType].framesSent = result.framesSent;
868
+ this.statsResults[mediaType][sendrecvType].hugeFramesSent = result.hugeFramesSent;
865
869
  }
866
870
 
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
-
874
871
  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
872
 
888
- this.statsResults[mediaType][sendrecvType].packetsSent =
889
- result.packetsSent - this.statsResults.internal[mediaType][sendrecvType].packetsSent;
890
- this.statsResults.internal[mediaType][sendrecvType].packetsSent = result.packetsSent;
873
+ this.statsResults[mediaType][sendrecvType].framesEncoded = result.framesEncoded;
874
+ this.statsResults[mediaType][sendrecvType].keyFramesEncoded = result.keyFramesEncoded;
875
+ this.statsResults[mediaType][sendrecvType].packetsSent = result.packetsSent;
891
876
 
892
877
  // Data saved to send MQA metrics
893
878
 
@@ -925,71 +910,50 @@ export class StatsAnalyzer extends EventsScope {
925
910
 
926
911
  if (result.bytesReceived) {
927
912
  let kilobytes = 0;
928
-
929
- if (!this.statsResults.internal[mediaType][sendrecvType].prevBytesReceived) {
930
- this.statsResults.internal[mediaType][sendrecvType].prevBytesReceived =
931
- result.bytesReceived;
932
- }
933
-
934
- if (!this.statsResults.internal[mediaType][sendrecvType].pliCount) {
935
- this.statsResults.internal[mediaType][sendrecvType].pliCount = result.pliCount;
936
- }
937
-
938
- if (!this.statsResults.internal[mediaType][sendrecvType].packetsLost) {
939
- this.statsResults.internal[mediaType][sendrecvType].packetsLost = result.packetsLost;
940
- }
941
-
942
- if (!this.statsResults.internal[mediaType][sendrecvType].totalPacketsReceived) {
943
- this.statsResults.internal[mediaType][sendrecvType].totalPacketsReceived =
944
- result.packetsReceived;
945
- }
946
-
947
- if (!this.statsResults.internal[mediaType][sendrecvType].lastPacketReceivedTimestamp) {
948
- this.statsResults.internal[mediaType][sendrecvType].lastPacketReceivedTimestamp =
949
- result.lastPacketReceivedTimestamp;
913
+ const receiveSlot = this.receiveSlotCallback(result.ssrc);
914
+ const idAndCsi = receiveSlot
915
+ ? `id: "${receiveSlot.id || ''}"${receiveSlot.csi ? ` and csi: ${receiveSlot.csi}` : ''}`
916
+ : '';
917
+
918
+ if (result.frameWidth && result.frameHeight) {
919
+ this.statsResults[mediaType][sendrecvType].width = result.frameWidth;
920
+ this.statsResults[mediaType][sendrecvType].height = result.frameHeight;
921
+ this.statsResults[mediaType][sendrecvType].framesReceived = result.framesReceived;
950
922
  }
951
923
 
952
924
  const bytes =
953
- result.bytesReceived -
954
- this.statsResults.internal[mediaType][sendrecvType].prevBytesReceived;
955
-
956
- this.statsResults.internal[mediaType][sendrecvType].prevBytesReceived = result.bytesReceived;
925
+ result.bytesReceived - this.statsResults[mediaType][sendrecvType].totalBytesReceived;
957
926
 
958
927
  kilobytes = bytes / 1024;
959
928
  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;
929
+
930
+ let currentPacketsLost =
931
+ result.packetsLost - this.statsResults[mediaType][sendrecvType].totalPacketsLost;
932
+ if (currentPacketsLost < 0) {
933
+ currentPacketsLost = 0;
968
934
  }
969
935
 
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;
936
+ const currentPacketsReceived =
937
+ result.packetsReceived - this.statsResults[mediaType][sendrecvType].totalPacketsReceived;
938
+ this.statsResults[mediaType][sendrecvType].totalPacketsReceived = result.packetsReceived;
975
939
 
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
- );
940
+ if (currentPacketsReceived === 0) {
941
+ if (receiveSlot) {
942
+ LoggerProxy.logger.info(
943
+ `StatsAnalyzer:index#processInboundRTPResult --> No packets received for receive slot ${idAndCsi}`,
944
+ currentPacketsReceived
945
+ );
946
+ }
981
947
  }
982
948
 
983
949
  // Check the over all packet Lost ratio
984
950
  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)
951
+ currentPacketsLost > 0
952
+ ? currentPacketsLost / (currentPacketsReceived + currentPacketsLost)
989
953
  : 0;
990
954
  if (this.statsResults[mediaType][sendrecvType].currentPacketLossRatio > 3) {
991
955
  LoggerProxy.logger.info(
992
- 'StatsAnalyzer:index#processInboundRTPResult --> Packets getting lost from the receiver ',
956
+ `StatsAnalyzer:index#processInboundRTPResult --> Packets getting lost from the receiver with slot ${idAndCsi}`,
993
957
  this.statsResults[mediaType][sendrecvType].currentPacketLossRatio
994
958
  );
995
959
  }
@@ -1035,6 +999,48 @@ export class StatsAnalyzer extends EventsScope {
1035
999
  }
1036
1000
  }
1037
1001
 
1002
+ /**
1003
+ * extracts the local Ip address from the statsResult object by looking at stats results candidates
1004
+ * and matches that ID with the successful candidate pair. It looks at the type of local candidate it is
1005
+ * and then extracts the IP address from the relatedAddress or address property based on conditions known in webrtc
1006
+ * 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
1007
+ * for example, firefox does not set the relayProtocol, and if the user is behind a NAT it might be the public IP
1008
+ * @private
1009
+ * @param {string} successfulCandidatePairId - The ID of the successful candidate pair.
1010
+ * @param {Object} candidates - the stats result candidates
1011
+ * @returns {void}
1012
+ */
1013
+ extractAndSetLocalIpAddressInfoForDiagnostics = (
1014
+ successfulCandidatePairId: string,
1015
+ candidates: {[key: string]: Record<string, unknown>}
1016
+ ) => {
1017
+ let newIpAddress = '';
1018
+ if (successfulCandidatePairId && !isEmpty(candidates)) {
1019
+ const localCandidate = candidates[successfulCandidatePairId];
1020
+ if (localCandidate) {
1021
+ if (localCandidate.candidateType === 'host') {
1022
+ // if it's a host candidate, use the address property - it will be the local IP
1023
+ newIpAddress = `${localCandidate.address}`;
1024
+ } else if (localCandidate.candidateType === 'prflx') {
1025
+ // if it's a peer reflexive candidate and we're not using a relay (there is no relayProtocol set)
1026
+ // then look at the relatedAddress - it will be the local
1027
+ //
1028
+ // Firefox doesn't populate the relayProtocol property
1029
+ if (!localCandidate.relayProtocol) {
1030
+ newIpAddress = `${localCandidate.relatedAddress}`;
1031
+ } else {
1032
+ // if it's a peer reflexive candidate and we are using a relay -
1033
+ // in that case the relatedAddress will be the IP of the TURN server (Linus),
1034
+ // so we can only look at the address, but it might be local IP or public IP,
1035
+ // depending on if the user is behind a NAT or not
1036
+ newIpAddress = `${localCandidate.address}`;
1037
+ }
1038
+ }
1039
+ }
1040
+ }
1041
+ this.localIpAddress = newIpAddress;
1042
+ };
1043
+
1038
1044
  /**
1039
1045
  * Processes remote and local candidate result and stores
1040
1046
  * @private
@@ -1049,125 +1055,53 @@ export class StatsAnalyzer extends EventsScope {
1049
1055
  if (!result || !result.id) {
1050
1056
  return;
1051
1057
  }
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
-
1070
- if (!RemoteIpAddress[result.id]) {
1071
- RemoteIpAddress[result.id] = [];
1072
- }
1073
- if (!RemoteNetworkType[result.id]) {
1074
- RemoteNetworkType[result.id] = [];
1075
- }
1076
1058
 
1077
- if (
1078
- result.candidateType &&
1079
- RemoteCandidateType[result.id].indexOf(result.candidateType) === -1
1080
- ) {
1081
- RemoteCandidateType[result.id].push(result.candidateType);
1059
+ // We only care about the successful local candidate
1060
+ if (this.successfulCandidatePair?.localCandidateId !== result.id) {
1061
+ return;
1082
1062
  }
1083
1063
 
1084
- if (result.protocol && RemoteTransport[result.id].indexOf(result.protocol) === -1) {
1085
- RemoteTransport[result.id].push(result.protocol.toUpperCase());
1064
+ let transport;
1065
+ if (result.relayProtocol) {
1066
+ transport = result.relayProtocol.toUpperCase();
1067
+ } else if (result.protocol) {
1068
+ transport = result.protocol.toUpperCase();
1086
1069
  }
1087
1070
 
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
- }
1071
+ const sendRecvType = isSender ? STATS.SEND_DIRECTION : STATS.RECEIVE_DIRECTION;
1072
+ const ipType = isRemote ? STATS.REMOTE : STATS.LOCAL;
1094
1073
 
1095
- if (result.networkType && RemoteNetworkType[result.id].indexOf(result.networkType) === -1) {
1096
- RemoteNetworkType[result.id].push(result.networkType);
1074
+ if (!this.statsResults.candidates) {
1075
+ this.statsResults.candidates = {};
1097
1076
  }
1098
1077
 
1099
- this.statsResults.internal.candidates[result.id] = {
1100
- candidateType: RemoteCandidateType[result.id],
1101
- ipAddress: RemoteIpAddress[result.id],
1078
+ this.statsResults.candidates[result.id] = {
1079
+ candidateType: result.candidateType,
1080
+ ipAddress: result.ip, // TODO: add ports
1081
+ relatedAddress: result.relatedAddress,
1082
+ relatedPort: result.relatedPort,
1083
+ relayProtocol: result.relayProtocol,
1084
+ protocol: result.protocol,
1085
+ address: result.address,
1102
1086
  portNumber: result.port,
1103
- networkType: RemoteNetworkType[result.id],
1087
+ networkType: result.networkType,
1104
1088
  priority: result.priority,
1105
- transport: RemoteTransport[result.id],
1089
+ transport,
1106
1090
  timestamp: result.time,
1107
1091
  id: result.id,
1108
1092
  type: result.type,
1109
1093
  };
1110
1094
 
1111
- this.statsResults.connectionType[ipType].candidateType = RemoteCandidateType[result.id];
1112
- this.statsResults.connectionType[ipType].ipAddress = RemoteIpAddress[result.id];
1095
+ this.statsResults.connectionType[ipType].candidateType = result.candidateType;
1096
+ this.statsResults.connectionType[ipType].ipAddress = result.ipAddress;
1113
1097
 
1114
1098
  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];
1099
+ result.networkType === NETWORK_TYPE.VPN ? NETWORK_TYPE.UNKNOWN : result.networkType;
1100
+ this.statsResults.connectionType[ipType].transport = transport;
1119
1101
 
1120
1102
  this.statsResults[type][sendRecvType].totalRoundTripTime = result.totalRoundTripTime;
1121
1103
  };
1122
1104
 
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
1105
  /**
1172
1106
  *
1173
1107
  * @private
@@ -1178,20 +1112,15 @@ export class StatsAnalyzer extends EventsScope {
1178
1112
  */
1179
1113
  compareSentAndReceived(result, type) {
1180
1114
  // Don't compare on transceivers without a sender.
1181
- if (!type || !this.statsResults.internal[type].send) {
1115
+ if (!type || !this.statsResults[type].send) {
1182
1116
  return;
1183
1117
  }
1184
1118
 
1185
1119
  const mediaType = type;
1186
1120
 
1187
- if (!this.statsResults.internal[mediaType].send.totalPacketsLostOnReceiver) {
1188
- this.statsResults.internal[mediaType].send.totalPacketsLostOnReceiver = result.packetsLost;
1189
- }
1190
-
1191
1121
  const currentPacketLoss =
1192
- result.packetsLost - this.statsResults.internal[mediaType].send.totalPacketsLostOnReceiver;
1122
+ result.packetsLost - this.statsResults[mediaType].send.totalPacketsLostOnReceiver;
1193
1123
 
1194
- this.statsResults.internal[mediaType].send.totalPacketsLostOnReceiver = result.packetsLost;
1195
1124
  this.statsResults[mediaType].send.packetsLostOnReceiver = currentPacketLoss;
1196
1125
  this.statsResults[mediaType].send.totalPacketsLostOnReceiver = result.packetsLost;
1197
1126