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

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