@webex/plugin-meetings 3.0.0-beta.4 → 3.0.0-beta.40

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