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

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