@webex/plugin-meetings 2.60.0 → 2.60.1-next.1

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