@webex/plugin-meetings 3.0.0-beta.2 → 3.0.0-beta.200

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