@webex/plugin-meetings 3.0.0-beta.1 → 3.0.0-beta.104

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