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

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