@webex/plugin-meetings 2.59.8-next.2 → 2.60.0-next.1
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.
- package/README.md +46 -8
- package/dist/annotation/annotation.types.js +7 -0
- package/dist/annotation/annotation.types.js.map +1 -0
- package/dist/annotation/constants.js +41 -0
- package/dist/annotation/constants.js.map +1 -0
- package/dist/annotation/index.js +357 -0
- package/dist/annotation/index.js.map +1 -0
- package/dist/breakouts/breakout.js +215 -0
- package/dist/breakouts/breakout.js.map +1 -0
- package/dist/breakouts/collection.js +22 -0
- package/dist/breakouts/collection.js.map +1 -0
- package/dist/breakouts/edit-lock-error.js +51 -0
- package/dist/breakouts/edit-lock-error.js.map +1 -0
- package/dist/breakouts/events.js +44 -0
- package/dist/breakouts/events.js.map +1 -0
- package/dist/breakouts/index.js +1047 -0
- package/dist/breakouts/index.js.map +1 -0
- package/dist/breakouts/request.js +77 -0
- package/dist/breakouts/request.js.map +1 -0
- package/dist/breakouts/utils.js +64 -0
- package/dist/breakouts/utils.js.map +1 -0
- package/dist/common/browser-detection.js +1 -2
- package/dist/common/browser-detection.js.map +1 -1
- package/dist/common/collection.js +1 -2
- package/dist/common/collection.js.map +1 -1
- package/dist/common/config.js +1 -2
- package/dist/common/config.js.map +1 -1
- package/dist/common/errors/captcha-error.js +1 -2
- package/dist/common/errors/captcha-error.js.map +1 -1
- package/dist/common/errors/intent-to-join.js +1 -2
- package/dist/common/errors/intent-to-join.js.map +1 -1
- package/dist/common/errors/join-meeting.js +1 -2
- package/dist/common/errors/join-meeting.js.map +1 -1
- package/dist/common/errors/media.js +1 -2
- package/dist/common/errors/media.js.map +1 -1
- package/dist/common/errors/no-meeting-info.js +50 -0
- package/dist/common/errors/no-meeting-info.js.map +1 -0
- package/dist/common/errors/parameter.js +3 -4
- package/dist/common/errors/parameter.js.map +1 -1
- package/dist/common/errors/password-error.js +1 -2
- package/dist/common/errors/password-error.js.map +1 -1
- package/dist/common/errors/permission.js +1 -2
- package/dist/common/errors/permission.js.map +1 -1
- package/dist/common/errors/reclaim-host-role-errors.js +154 -0
- package/dist/common/errors/reclaim-host-role-errors.js.map +1 -0
- package/dist/common/errors/reconnection-in-progress.js +1 -2
- package/dist/common/errors/reconnection-in-progress.js.map +1 -1
- package/dist/common/errors/reconnection.js +1 -2
- package/dist/common/errors/reconnection.js.map +1 -1
- package/dist/common/errors/stats.js +1 -2
- package/dist/common/errors/stats.js.map +1 -1
- package/dist/common/errors/webex-errors.js +48 -28
- package/dist/common/errors/webex-errors.js.map +1 -1
- package/dist/common/errors/webex-meetings-error.js +1 -2
- package/dist/common/errors/webex-meetings-error.js.map +1 -1
- package/dist/common/events/events-scope.js +1 -2
- package/dist/common/events/events-scope.js.map +1 -1
- package/dist/common/events/events.js +1 -2
- package/dist/common/events/events.js.map +1 -1
- package/dist/common/events/trigger-proxy.js +1 -2
- package/dist/common/events/trigger-proxy.js.map +1 -1
- package/dist/common/events/util.js +1 -2
- package/dist/common/events/util.js.map +1 -1
- package/dist/common/logs/logger-config.js +1 -2
- package/dist/common/logs/logger-config.js.map +1 -1
- package/dist/common/logs/logger-proxy.js +2 -3
- package/dist/common/logs/logger-proxy.js.map +1 -1
- package/dist/common/logs/request.js +8 -5
- package/dist/common/logs/request.js.map +1 -1
- package/dist/common/queue.js +22 -9
- package/dist/common/queue.js.map +1 -1
- package/dist/config.js +9 -12
- package/dist/config.js.map +1 -1
- package/dist/constants.js +437 -433
- package/dist/constants.js.map +1 -1
- package/dist/controls-options-manager/constants.js +3 -6
- package/dist/controls-options-manager/constants.js.map +1 -1
- package/dist/controls-options-manager/enums.js +14 -6
- package/dist/controls-options-manager/enums.js.map +1 -1
- package/dist/controls-options-manager/index.js +126 -37
- package/dist/controls-options-manager/index.js.map +1 -1
- package/dist/controls-options-manager/types.js +7 -0
- package/dist/controls-options-manager/types.js.map +1 -0
- package/dist/controls-options-manager/util.js +309 -19
- package/dist/controls-options-manager/util.js.map +1 -1
- package/dist/index.js +116 -4
- package/dist/index.js.map +1 -1
- package/dist/interpretation/collection.js +22 -0
- package/dist/interpretation/collection.js.map +1 -0
- package/dist/interpretation/index.js +365 -0
- package/dist/interpretation/index.js.map +1 -0
- package/dist/interpretation/siLanguage.js +24 -0
- package/dist/interpretation/siLanguage.js.map +1 -0
- package/dist/locus-info/controlsUtils.js +95 -6
- package/dist/locus-info/controlsUtils.js.map +1 -1
- package/dist/locus-info/embeddedAppsUtils.js +3 -4
- package/dist/locus-info/embeddedAppsUtils.js.map +1 -1
- package/dist/locus-info/fullState.js +1 -2
- package/dist/locus-info/fullState.js.map +1 -1
- package/dist/locus-info/hostUtils.js +1 -2
- package/dist/locus-info/hostUtils.js.map +1 -1
- package/dist/locus-info/index.js +408 -67
- package/dist/locus-info/index.js.map +1 -1
- package/dist/locus-info/infoUtils.js +13 -5
- package/dist/locus-info/infoUtils.js.map +1 -1
- package/dist/locus-info/mediaSharesUtils.js +58 -3
- package/dist/locus-info/mediaSharesUtils.js.map +1 -1
- package/dist/locus-info/parser.js +251 -78
- package/dist/locus-info/parser.js.map +1 -1
- package/dist/locus-info/selfUtils.js +97 -13
- package/dist/locus-info/selfUtils.js.map +1 -1
- package/dist/media/index.js +106 -319
- package/dist/media/index.js.map +1 -1
- package/dist/media/properties.js +96 -153
- package/dist/media/properties.js.map +1 -1
- package/dist/media/util.js +1 -22
- package/dist/media/util.js.map +1 -1
- package/dist/mediaQualityMetrics/config.js +498 -493
- package/dist/mediaQualityMetrics/config.js.map +1 -1
- package/dist/meeting/in-meeting-actions.js +90 -3
- package/dist/meeting/in-meeting-actions.js.map +1 -1
- package/dist/meeting/index.js +4579 -2951
- package/dist/meeting/index.js.map +1 -1
- package/dist/meeting/locusMediaRequest.js +291 -0
- package/dist/meeting/locusMediaRequest.js.map +1 -0
- package/dist/meeting/muteState.js +224 -133
- package/dist/meeting/muteState.js.map +1 -1
- package/dist/meeting/request.js +295 -197
- package/dist/meeting/request.js.map +1 -1
- package/dist/meeting/request.type.js +7 -0
- package/dist/meeting/request.type.js.map +1 -0
- package/dist/meeting/state.js +1 -2
- package/dist/meeting/state.js.map +1 -1
- package/dist/meeting/util.js +602 -432
- package/dist/meeting/util.js.map +1 -1
- package/dist/meeting-info/collection.js +1 -2
- package/dist/meeting-info/collection.js.map +1 -1
- package/dist/meeting-info/index.js +74 -7
- package/dist/meeting-info/index.js.map +1 -1
- package/dist/meeting-info/meeting-info-v2.js +197 -63
- package/dist/meeting-info/meeting-info-v2.js.map +1 -1
- package/dist/meeting-info/request.js +1 -2
- package/dist/meeting-info/request.js.map +1 -1
- package/dist/meeting-info/util.js +2 -3
- package/dist/meeting-info/util.js.map +1 -1
- package/dist/meeting-info/utilv2.js +25 -12
- package/dist/meeting-info/utilv2.js.map +1 -1
- package/dist/meetings/collection.js +23 -2
- package/dist/meetings/collection.js.map +1 -1
- package/dist/meetings/index.js +464 -123
- package/dist/meetings/index.js.map +1 -1
- package/dist/meetings/meetings.types.js +7 -0
- package/dist/meetings/meetings.types.js.map +1 -0
- package/dist/meetings/request.js +4 -3
- package/dist/meetings/request.js.map +1 -1
- package/dist/meetings/util.js +107 -6
- package/dist/meetings/util.js.map +1 -1
- package/dist/member/index.js +54 -2
- package/dist/member/index.js.map +1 -1
- package/dist/member/member.types.js +3 -4
- package/dist/member/member.types.js.map +1 -1
- package/dist/member/types.js +23 -0
- package/dist/member/types.js.map +1 -0
- package/dist/member/util.js +131 -29
- package/dist/member/util.js.map +1 -1
- package/dist/members/collection.js +11 -2
- package/dist/members/collection.js.map +1 -1
- package/dist/members/index.js +172 -8
- package/dist/members/index.js.map +1 -1
- package/dist/members/request.js +108 -41
- package/dist/members/request.js.map +1 -1
- package/dist/members/types.js +14 -0
- package/dist/members/types.js.map +1 -0
- package/dist/members/util.js +327 -234
- package/dist/members/util.js.map +1 -1
- package/dist/metrics/constants.js +14 -7
- package/dist/metrics/constants.js.map +1 -1
- package/dist/metrics/index.js +4 -452
- package/dist/metrics/index.js.map +1 -1
- package/dist/multistream/mediaRequestManager.js +344 -0
- package/dist/multistream/mediaRequestManager.js.map +1 -0
- package/dist/multistream/receiveSlot.js +200 -0
- package/dist/multistream/receiveSlot.js.map +1 -0
- package/dist/multistream/receiveSlotManager.js +174 -0
- package/dist/multistream/receiveSlotManager.js.map +1 -0
- package/dist/multistream/remoteMedia.js +268 -0
- package/dist/multistream/remoteMedia.js.map +1 -0
- package/dist/multistream/remoteMediaGroup.js +267 -0
- package/dist/multistream/remoteMediaGroup.js.map +1 -0
- package/dist/multistream/remoteMediaManager.js +1211 -0
- package/dist/multistream/remoteMediaManager.js.map +1 -0
- package/dist/multistream/sendSlotManager.js +236 -0
- package/dist/multistream/sendSlotManager.js.map +1 -0
- package/dist/networkQualityMonitor/index.js +5 -4
- package/dist/networkQualityMonitor/index.js.map +1 -1
- package/dist/personal-meeting-room/index.js +2 -3
- package/dist/personal-meeting-room/index.js.map +1 -1
- package/dist/personal-meeting-room/request.js +2 -3
- package/dist/personal-meeting-room/request.js.map +1 -1
- package/dist/personal-meeting-room/util.js +1 -2
- package/dist/personal-meeting-room/util.js.map +1 -1
- package/dist/reachability/index.js +258 -72
- package/dist/reachability/index.js.map +1 -1
- package/dist/reachability/request.js +18 -10
- package/dist/reachability/request.js.map +1 -1
- package/dist/reactions/constants.js +12 -0
- package/dist/reactions/constants.js.map +1 -0
- package/dist/reactions/reactions.js +4 -6
- package/dist/reactions/reactions.js.map +1 -1
- package/dist/reactions/reactions.type.js +21 -23
- package/dist/reactions/reactions.type.js.map +1 -1
- package/dist/reconnection-manager/index.js +272 -220
- package/dist/reconnection-manager/index.js.map +1 -1
- package/dist/recording-controller/enums.js +4 -5
- package/dist/recording-controller/enums.js.map +1 -1
- package/dist/recording-controller/index.js +57 -46
- package/dist/recording-controller/index.js.map +1 -1
- package/dist/recording-controller/util.js +10 -10
- package/dist/recording-controller/util.js.map +1 -1
- package/dist/roap/index.js +101 -235
- package/dist/roap/index.js.map +1 -1
- package/dist/roap/request.js +126 -180
- package/dist/roap/request.js.map +1 -1
- package/dist/roap/turnDiscovery.js +115 -105
- package/dist/roap/turnDiscovery.js.map +1 -1
- package/dist/rtcMetrics/constants.js +11 -0
- package/dist/rtcMetrics/constants.js.map +1 -0
- package/dist/rtcMetrics/index.js +115 -0
- package/dist/rtcMetrics/index.js.map +1 -0
- package/dist/statsAnalyzer/global.js +2 -93
- package/dist/statsAnalyzer/global.js.map +1 -1
- package/dist/statsAnalyzer/index.js +374 -374
- package/dist/statsAnalyzer/index.js.map +1 -1
- package/dist/statsAnalyzer/mqaUtil.js +100 -66
- package/dist/statsAnalyzer/mqaUtil.js.map +1 -1
- package/dist/transcription/index.js +1 -2
- package/dist/transcription/index.js.map +1 -1
- package/dist/webinar/collection.js +43 -0
- package/dist/webinar/collection.js.map +1 -0
- package/dist/webinar/index.js +68 -0
- package/dist/webinar/index.js.map +1 -0
- package/package.json +27 -18
- package/src/annotation/annotation.types.ts +50 -0
- package/src/annotation/constants.ts +36 -0
- package/src/annotation/index.ts +328 -0
- package/src/breakouts/README.md +220 -0
- package/src/breakouts/breakout.ts +188 -0
- package/src/breakouts/collection.ts +19 -0
- package/src/breakouts/edit-lock-error.ts +25 -0
- package/src/breakouts/events.ts +56 -0
- package/src/breakouts/index.ts +925 -0
- package/src/breakouts/request.ts +55 -0
- package/src/breakouts/utils.ts +57 -0
- package/src/common/errors/no-meeting-info.ts +24 -0
- package/src/common/errors/reclaim-host-role-errors.ts +134 -0
- package/src/common/errors/webex-errors.ts +36 -12
- package/src/common/logs/logger-proxy.ts +1 -1
- package/src/common/logs/request.ts +5 -1
- package/src/common/queue.ts +22 -8
- package/src/config.ts +7 -9
- package/src/constants.ts +263 -89
- package/src/controls-options-manager/enums.ts +11 -1
- package/src/controls-options-manager/index.ts +116 -21
- package/src/controls-options-manager/types.ts +59 -0
- package/src/controls-options-manager/util.ts +294 -14
- package/src/index.ts +40 -0
- package/src/interpretation/README.md +60 -0
- package/src/interpretation/collection.ts +19 -0
- package/src/interpretation/index.ts +332 -0
- package/src/interpretation/siLanguage.ts +18 -0
- package/src/locus-info/controlsUtils.ts +110 -0
- package/src/locus-info/index.ts +449 -61
- package/src/locus-info/infoUtils.ts +14 -2
- package/src/locus-info/mediaSharesUtils.ts +64 -0
- package/src/locus-info/parser.ts +258 -47
- package/src/locus-info/selfUtils.ts +85 -2
- package/src/media/index.ts +153 -370
- package/src/media/properties.ts +106 -136
- package/src/media/util.ts +0 -21
- package/src/mediaQualityMetrics/config.ts +379 -377
- package/src/meeting/in-meeting-actions.ts +168 -0
- package/src/meeting/index.ts +3801 -2457
- package/src/meeting/locusMediaRequest.ts +313 -0
- package/src/meeting/muteState.ts +224 -138
- package/src/meeting/request.ts +207 -127
- package/src/meeting/request.type.ts +13 -0
- package/src/meeting/util.ts +590 -423
- package/src/meeting-info/index.ts +81 -8
- package/src/meeting-info/meeting-info-v2.ts +159 -13
- package/src/meeting-info/util.ts +1 -1
- package/src/meeting-info/utilv2.ts +22 -9
- package/src/meetings/collection.ts +20 -0
- package/src/meetings/index.ts +466 -124
- package/src/meetings/meetings.types.ts +12 -0
- package/src/meetings/request.ts +2 -0
- package/src/meetings/util.ts +116 -5
- package/src/member/index.ts +52 -1
- package/src/member/types.ts +38 -0
- package/src/member/util.ts +139 -28
- package/src/members/collection.ts +8 -0
- package/src/members/index.ts +196 -7
- package/src/members/request.ts +97 -17
- package/src/members/types.ts +29 -0
- package/src/members/util.ts +333 -240
- package/src/metrics/constants.ts +12 -4
- package/src/metrics/index.ts +1 -471
- package/src/multistream/mediaRequestManager.ts +440 -0
- package/src/multistream/receiveSlot.ts +184 -0
- package/src/multistream/receiveSlotManager.ts +166 -0
- package/src/multistream/remoteMedia.ts +254 -0
- package/src/multistream/remoteMediaGroup.ts +284 -0
- package/src/multistream/remoteMediaManager.ts +1145 -0
- package/src/multistream/sendSlotManager.ts +170 -0
- package/src/networkQualityMonitor/index.ts +6 -6
- package/src/reachability/index.ts +238 -45
- package/src/reachability/request.ts +17 -8
- package/src/reactions/constants.ts +4 -0
- package/src/reactions/reactions.ts +4 -4
- package/src/reactions/reactions.type.ts +30 -4
- package/src/reconnection-manager/index.ts +124 -107
- package/src/recording-controller/index.ts +20 -3
- package/src/recording-controller/util.ts +26 -9
- package/src/roap/index.ts +98 -240
- package/src/roap/request.ts +74 -148
- package/src/roap/turnDiscovery.ts +62 -56
- package/src/rtcMetrics/constants.ts +3 -0
- package/src/rtcMetrics/index.ts +100 -0
- package/src/statsAnalyzer/global.ts +1 -92
- package/src/statsAnalyzer/index.ts +429 -447
- package/src/statsAnalyzer/mqaUtil.ts +105 -103
- package/src/webinar/collection.ts +31 -0
- package/src/webinar/index.ts +62 -0
- package/test/integration/spec/converged-space-meetings.js +233 -0
- package/test/integration/spec/journey.js +320 -264
- package/test/integration/spec/space-meeting.js +77 -4
- package/test/unit/spec/annotation/index.ts +418 -0
- package/test/unit/spec/breakouts/breakout.ts +237 -0
- package/test/unit/spec/breakouts/collection.ts +15 -0
- package/test/unit/spec/breakouts/edit-lock-error.ts +30 -0
- package/test/unit/spec/breakouts/events.ts +89 -0
- package/test/unit/spec/breakouts/index.ts +1790 -0
- package/test/unit/spec/breakouts/request.ts +104 -0
- package/test/unit/spec/breakouts/utils.js +72 -0
- package/test/unit/spec/common/queue.js +31 -2
- package/test/unit/spec/controls-options-manager/index.js +163 -0
- package/test/unit/spec/controls-options-manager/util.js +576 -60
- package/test/unit/spec/fixture/locus.js +1 -0
- package/test/unit/spec/interpretation/collection.ts +15 -0
- package/test/unit/spec/interpretation/index.ts +589 -0
- package/test/unit/spec/interpretation/siLanguage.ts +28 -0
- package/test/unit/spec/locus-info/controlsUtils.js +323 -30
- package/test/unit/spec/locus-info/index.js +1390 -16
- package/test/unit/spec/locus-info/infoUtils.js +54 -16
- package/test/unit/spec/locus-info/lib/SeqCmp.json +16 -0
- package/test/unit/spec/locus-info/lib/selfConstant.js +48 -0
- package/test/unit/spec/locus-info/mediaSharesUtils.ts +32 -0
- package/test/unit/spec/locus-info/parser.js +116 -35
- package/test/unit/spec/locus-info/selfUtils.js +275 -0
- package/test/unit/spec/media/index.ts +274 -0
- package/test/unit/spec/media/properties.ts +75 -84
- package/test/unit/spec/meeting/in-meeting-actions.ts +82 -0
- package/test/unit/spec/meeting/index.js +7420 -3125
- package/test/unit/spec/meeting/locusMediaRequest.ts +442 -0
- package/test/unit/spec/meeting/muteState.js +407 -212
- package/test/unit/spec/meeting/request.js +512 -42
- package/test/unit/spec/meeting/utils.js +741 -24
- package/test/unit/spec/meeting-info/index.js +300 -0
- package/test/unit/spec/meeting-info/meetinginfov2.js +500 -6
- package/test/unit/spec/meeting-info/utilv2.js +21 -0
- package/test/unit/spec/meetings/collection.js +14 -0
- package/test/unit/spec/meetings/index.js +1012 -209
- package/test/unit/spec/meetings/utils.js +202 -2
- package/test/unit/spec/member/index.js +38 -8
- package/test/unit/spec/member/util.js +528 -27
- package/test/unit/spec/members/index.js +597 -3
- package/test/unit/spec/members/request.js +206 -27
- package/test/unit/spec/members/utils.js +210 -0
- package/test/unit/spec/metrics/index.js +1 -50
- package/test/unit/spec/multistream/mediaRequestManager.ts +1418 -0
- package/test/unit/spec/multistream/receiveSlot.ts +163 -0
- package/test/unit/spec/multistream/receiveSlotManager.ts +203 -0
- package/test/unit/spec/multistream/remoteMedia.ts +255 -0
- package/test/unit/spec/multistream/remoteMediaGroup.ts +662 -0
- package/test/unit/spec/multistream/remoteMediaManager.ts +1924 -0
- package/test/unit/spec/multistream/sendSlotManager.ts +242 -0
- package/test/unit/spec/networkQualityMonitor/index.js +4 -4
- package/test/unit/spec/reachability/index.ts +598 -24
- package/test/unit/spec/reachability/request.js +68 -0
- package/test/unit/spec/reconnection-manager/index.js +130 -22
- package/test/unit/spec/recording-controller/index.js +293 -218
- package/test/unit/spec/recording-controller/util.js +223 -96
- package/test/unit/spec/roap/index.ts +200 -77
- package/test/unit/spec/roap/request.ts +232 -0
- package/test/unit/spec/roap/turnDiscovery.ts +86 -48
- package/test/unit/spec/rtcMetrics/index.ts +73 -0
- package/test/unit/spec/stats-analyzer/index.js +205 -50
- package/test/unit/spec/webinar/collection.ts +13 -0
- package/test/unit/spec/webinar/index.ts +60 -0
- package/test/utils/constants.js +9 -0
- package/test/utils/integrationTestUtils.js +46 -0
- package/test/utils/testUtils.js +0 -45
- package/test/utils/webex-config.js +4 -0
- package/test/utils/webex-test-users.js +7 -3
- package/dist/meeting/effectsState.js +0 -260
- package/dist/meeting/effectsState.js.map +0 -1
- package/dist/metrics/config.js +0 -289
- package/dist/metrics/config.js.map +0 -1
- package/dist/peer-connection-manager/index.js +0 -671
- package/dist/peer-connection-manager/index.js.map +0 -1
- package/dist/peer-connection-manager/util.js +0 -110
- package/dist/peer-connection-manager/util.js.map +0 -1
- package/dist/roap/collection.js +0 -63
- package/dist/roap/collection.js.map +0 -1
- package/dist/roap/handler.js +0 -279
- package/dist/roap/handler.js.map +0 -1
- package/dist/roap/state.js +0 -127
- package/dist/roap/state.js.map +0 -1
- package/dist/roap/util.js +0 -76
- package/dist/roap/util.js.map +0 -1
- package/src/index.js +0 -15
- package/src/meeting/effectsState.ts +0 -209
- package/src/metrics/config.ts +0 -485
- package/src/peer-connection-manager/index.ts +0 -847
- package/src/peer-connection-manager/util.ts +0 -119
- package/src/roap/collection.ts +0 -62
- package/src/roap/handler.ts +0 -294
- package/src/roap/state.ts +0 -156
- package/src/roap/util.ts +0 -100
- package/test/unit/spec/meeting/effectsState.js +0 -281
- package/test/unit/spec/peerconnection-manager/index.js +0 -218
- package/test/unit/spec/peerconnection-manager/utils.js +0 -49
- package/test/unit/spec/peerconnection-manager/utils.test-fixtures.ts +0 -388
- package/test/unit/spec/roap/util.js +0 -30
|
@@ -1,18 +1,24 @@
|
|
|
1
1
|
/* eslint-disable prefer-destructuring */
|
|
2
2
|
|
|
3
3
|
import {cloneDeep} from 'lodash';
|
|
4
|
+
import {ConnectionState} from '@webex/internal-media-core';
|
|
4
5
|
|
|
5
6
|
import EventsScope from '../common/events/events-scope';
|
|
6
7
|
import {
|
|
7
8
|
DEFAULT_GET_STATS_FILTER,
|
|
8
|
-
CONNECTION_STATE,
|
|
9
9
|
STATS,
|
|
10
10
|
MQA_INTEVAL,
|
|
11
11
|
NETWORK_TYPE,
|
|
12
12
|
MEDIA_DEVICES,
|
|
13
13
|
_UNKNOWN_,
|
|
14
14
|
} from '../constants';
|
|
15
|
-
import
|
|
15
|
+
import {
|
|
16
|
+
emptyAudioReceive,
|
|
17
|
+
emptyAudioTransmit,
|
|
18
|
+
emptyMqaInterval,
|
|
19
|
+
emptyVideoReceive,
|
|
20
|
+
emptyVideoTransmit,
|
|
21
|
+
} from '../mediaQualityMetrics/config';
|
|
16
22
|
import LoggerProxy from '../common/logs/logger-proxy';
|
|
17
23
|
|
|
18
24
|
import defaultStats from './global';
|
|
@@ -22,6 +28,7 @@ import {
|
|
|
22
28
|
getVideoSenderMqa,
|
|
23
29
|
getVideoReceiverMqa,
|
|
24
30
|
} from './mqaUtil';
|
|
31
|
+
import {ReceiveSlot} from '../multistream/receiveSlot';
|
|
25
32
|
|
|
26
33
|
export const EVENTS = {
|
|
27
34
|
MEDIA_QUALITY: 'MEDIA_QUALITY',
|
|
@@ -31,6 +38,24 @@ export const EVENTS = {
|
|
|
31
38
|
REMOTE_MEDIA_STOPPED: 'REMOTE_MEDIA_STOPPED',
|
|
32
39
|
};
|
|
33
40
|
|
|
41
|
+
const emptySender = {
|
|
42
|
+
trackLabel: '',
|
|
43
|
+
maxPacketLossRatio: 0,
|
|
44
|
+
availableBandwidth: 0,
|
|
45
|
+
bytesSent: 0,
|
|
46
|
+
meanRemoteJitter: [],
|
|
47
|
+
meanRoundTripTime: [],
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const emptyReceiver = {
|
|
51
|
+
availableBandwidth: 0,
|
|
52
|
+
bytesReceived: 0,
|
|
53
|
+
meanRtpJitter: [],
|
|
54
|
+
meanRoundTripTime: [],
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
type ReceiveSlotCallback = (csi: number) => ReceiveSlot | undefined;
|
|
58
|
+
|
|
34
59
|
/**
|
|
35
60
|
* Stats Analyzer class that will emit events based on detected quality
|
|
36
61
|
*
|
|
@@ -44,26 +69,29 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
44
69
|
lastEmittedStartStopEvent: any;
|
|
45
70
|
lastMqaDataSent: any;
|
|
46
71
|
lastStatsResults: any;
|
|
47
|
-
localMQEStats: any;
|
|
48
72
|
meetingMediaStatus: any;
|
|
49
73
|
mqaInterval: NodeJS.Timeout;
|
|
50
74
|
mqaSentCount: any;
|
|
51
75
|
networkQualityMonitor: any;
|
|
52
|
-
|
|
76
|
+
mediaConnection: any;
|
|
53
77
|
statsInterval: NodeJS.Timeout;
|
|
54
78
|
statsResults: any;
|
|
55
79
|
statsStarted: any;
|
|
80
|
+
successfulCandidatePair: any;
|
|
81
|
+
receiveSlotCallback: ReceiveSlotCallback;
|
|
56
82
|
|
|
57
83
|
/**
|
|
58
84
|
* Creates a new instance of StatsAnalyzer
|
|
59
85
|
* @constructor
|
|
60
86
|
* @public
|
|
61
87
|
* @param {Object} config SDK Configuration Object
|
|
88
|
+
* @param {Function} receiveSlotCallback Callback used to access receive slots.
|
|
62
89
|
* @param {Object} networkQualityMonitor class for assessing network characteristics (jitter, packetLoss, latency)
|
|
63
90
|
* @param {Object} statsResults Default properties for stats
|
|
64
91
|
*/
|
|
65
92
|
constructor(
|
|
66
93
|
config: any,
|
|
94
|
+
receiveSlotCallback: ReceiveSlotCallback = () => undefined,
|
|
67
95
|
networkQualityMonitor: object = {},
|
|
68
96
|
statsResults: object = defaultStats
|
|
69
97
|
) {
|
|
@@ -75,147 +103,30 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
75
103
|
this.networkQualityMonitor = networkQualityMonitor;
|
|
76
104
|
this.correlationId = config.correlationId;
|
|
77
105
|
this.mqaSentCount = -1;
|
|
78
|
-
this.lastMqaDataSent = {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
share: {send: {}, recv: {}},
|
|
83
|
-
},
|
|
84
|
-
video: {send: {}, recv: {}},
|
|
85
|
-
audio: {send: {}, recv: {}},
|
|
86
|
-
share: {send: {}, recv: {}},
|
|
87
|
-
};
|
|
88
|
-
this.localMQEStats = {
|
|
89
|
-
audio: {
|
|
90
|
-
RX: {
|
|
91
|
-
packetsLost: [],
|
|
92
|
-
jitter: [],
|
|
93
|
-
latency: [],
|
|
94
|
-
bitRate: [],
|
|
95
|
-
},
|
|
96
|
-
TX: {
|
|
97
|
-
packetsLost: [],
|
|
98
|
-
jitter: [],
|
|
99
|
-
latency: [],
|
|
100
|
-
bitRate: [],
|
|
101
|
-
},
|
|
102
|
-
},
|
|
103
|
-
video: {
|
|
104
|
-
RX: {
|
|
105
|
-
packetsLost: [],
|
|
106
|
-
jitter: [],
|
|
107
|
-
latency: [],
|
|
108
|
-
bitRate: [],
|
|
109
|
-
frameRate: [],
|
|
110
|
-
resolutionWidth: [],
|
|
111
|
-
resolutionHeight: [],
|
|
112
|
-
requestedKeyFrame: [],
|
|
113
|
-
receivedKeyFrame: [],
|
|
114
|
-
},
|
|
115
|
-
TX: {
|
|
116
|
-
packetsLost: [],
|
|
117
|
-
jitter: [],
|
|
118
|
-
latency: [],
|
|
119
|
-
bitRate: [],
|
|
120
|
-
frameRate: [],
|
|
121
|
-
resolutionWidth: [],
|
|
122
|
-
resolutionHeight: [],
|
|
123
|
-
requestedKeyFrame: [],
|
|
124
|
-
receivedKeyFrame: [],
|
|
125
|
-
},
|
|
126
|
-
},
|
|
127
|
-
};
|
|
128
|
-
this.lastEmittedStartStopEvent = {
|
|
129
|
-
audio: {
|
|
130
|
-
local: undefined,
|
|
131
|
-
remote: undefined,
|
|
132
|
-
},
|
|
133
|
-
video: {
|
|
134
|
-
local: undefined,
|
|
135
|
-
remote: undefined,
|
|
136
|
-
},
|
|
137
|
-
share: {
|
|
138
|
-
local: undefined,
|
|
139
|
-
remote: undefined,
|
|
140
|
-
},
|
|
141
|
-
};
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
populateResults(lastMqa) {
|
|
145
|
-
// Audio
|
|
146
|
-
|
|
147
|
-
this.localMQEStats.audio.RX.packetsLost.push(lastMqa.audioReceive[0].common.mediaHopByHopLost);
|
|
148
|
-
this.localMQEStats.audio.RX.jitter.push(lastMqa.audioReceive[0].streams[0].common.rtpJitter);
|
|
149
|
-
this.localMQEStats.audio.RX.latency.push(lastMqa.audioReceive[0].common.roundTripTime);
|
|
150
|
-
this.localMQEStats.audio.RX.bitRate.push(
|
|
151
|
-
lastMqa.audioReceive[0].streams[0].common.receivedBitrate
|
|
152
|
-
);
|
|
153
|
-
|
|
154
|
-
this.localMQEStats.audio.TX.packetsLost.push(lastMqa.audioTransmit[0].common.remoteLossRate);
|
|
155
|
-
this.localMQEStats.audio.TX.jitter.push(lastMqa.audioTransmit[0].common.remoteJitter);
|
|
156
|
-
this.localMQEStats.audio.TX.latency.push(lastMqa.audioTransmit[0].common.roundTripTime);
|
|
157
|
-
this.localMQEStats.audio.TX.bitRate.push(
|
|
158
|
-
lastMqa.audioTransmit[0].streams[0].common.transmittedBitrate
|
|
159
|
-
);
|
|
160
|
-
|
|
161
|
-
// Video
|
|
162
|
-
|
|
163
|
-
this.localMQEStats.video.RX.packetsLost.push(lastMqa.videoReceive[0].common.mediaHopByHopLost);
|
|
164
|
-
this.localMQEStats.video.RX.jitter.push(lastMqa.videoReceive[0].streams[0].common.rtpJitter);
|
|
165
|
-
this.localMQEStats.video.RX.latency.push(
|
|
166
|
-
lastMqa.videoReceive[0].streams[0].common.roundTripTime
|
|
167
|
-
);
|
|
168
|
-
this.localMQEStats.video.RX.bitRate.push(
|
|
169
|
-
lastMqa.videoReceive[0].streams[0].common.receivedBitrate
|
|
170
|
-
);
|
|
171
|
-
this.localMQEStats.video.RX.frameRate.push(
|
|
172
|
-
lastMqa.videoReceive[0].streams[0].common.receivedFrameRate
|
|
173
|
-
);
|
|
174
|
-
this.localMQEStats.video.RX.resolutionWidth.push(
|
|
175
|
-
lastMqa.videoReceive[0].streams[0].receivedWidth
|
|
176
|
-
);
|
|
177
|
-
this.localMQEStats.video.RX.resolutionHeight.push(
|
|
178
|
-
lastMqa.videoReceive[0].streams[0].receivedHeight
|
|
179
|
-
);
|
|
180
|
-
this.localMQEStats.video.RX.requestedKeyFrame.push();
|
|
181
|
-
this.localMQEStats.video.RX.receivedKeyFrame.push();
|
|
182
|
-
|
|
183
|
-
this.localMQEStats.video.TX.packetsLost.push(lastMqa.videoTransmit[0].common.remoteLossRate);
|
|
184
|
-
this.localMQEStats.video.TX.jitter.push(lastMqa.videoTransmit[0].common.remoteJitter);
|
|
185
|
-
this.localMQEStats.video.TX.latency.push(lastMqa.videoTransmit[0].common.roundTripTime);
|
|
186
|
-
this.localMQEStats.video.TX.bitRate.push(
|
|
187
|
-
lastMqa.videoTransmit[0].streams[0].common.transmittedBitrate
|
|
188
|
-
);
|
|
189
|
-
this.localMQEStats.video.TX.frameRate.push(
|
|
190
|
-
lastMqa.videoTransmit[0].streams[0].common.transmittedFrameRate
|
|
191
|
-
);
|
|
192
|
-
this.localMQEStats.video.TX.resolutionWidth.push(
|
|
193
|
-
lastMqa.videoTransmit[0].streams[0].transmittedWidth
|
|
194
|
-
);
|
|
195
|
-
this.localMQEStats.video.TX.resolutionHeight.push(
|
|
196
|
-
lastMqa.videoTransmit[0].streams[0].transmittedHeight
|
|
197
|
-
);
|
|
198
|
-
this.localMQEStats.video.TX.requestedKeyFrame.push(
|
|
199
|
-
lastMqa.videoTransmit[0].streams[0].requestedKeyFrames
|
|
200
|
-
);
|
|
201
|
-
this.localMQEStats.video.TX.receivedKeyFrame.push();
|
|
106
|
+
this.lastMqaDataSent = {};
|
|
107
|
+
this.lastEmittedStartStopEvent = {};
|
|
108
|
+
this.receiveSlotCallback = receiveSlotCallback;
|
|
109
|
+
this.successfulCandidatePair = {};
|
|
202
110
|
}
|
|
203
111
|
|
|
112
|
+
/**
|
|
113
|
+
* Resets cumulative stats arrays.
|
|
114
|
+
*
|
|
115
|
+
* @public
|
|
116
|
+
* @memberof StatsAnalyzer
|
|
117
|
+
* @returns {void}
|
|
118
|
+
*/
|
|
204
119
|
resetStatsResults() {
|
|
205
|
-
this.statsResults.
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
this.statsResults.audio.recv.meanRtpJitter = [];
|
|
210
|
-
|
|
211
|
-
// TODO: currently no values are present
|
|
212
|
-
this.statsResults.video.recv.meanRtpJitter = [];
|
|
213
|
-
this.statsResults.share.recv.meanRtpJitter = [];
|
|
120
|
+
Object.keys(this.statsResults).forEach((mediaType) => {
|
|
121
|
+
if (mediaType.includes('recv')) {
|
|
122
|
+
this.statsResults[mediaType].recv.meanRtpJitter = [];
|
|
123
|
+
}
|
|
214
124
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
125
|
+
if (mediaType.includes('send')) {
|
|
126
|
+
this.statsResults[mediaType].send.meanRemoteJitter = [];
|
|
127
|
+
this.statsResults[mediaType].send.meanRoundTripTime = [];
|
|
128
|
+
}
|
|
129
|
+
});
|
|
219
130
|
}
|
|
220
131
|
|
|
221
132
|
/**
|
|
@@ -231,86 +142,81 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
231
142
|
}
|
|
232
143
|
|
|
233
144
|
/**
|
|
234
|
-
* captures MQA data from
|
|
145
|
+
* captures MQA data from media connection
|
|
235
146
|
*
|
|
236
147
|
* @public
|
|
237
148
|
* @memberof StatsAnalyzer
|
|
238
149
|
* @returns {void}
|
|
239
150
|
*/
|
|
240
|
-
|
|
241
|
-
const
|
|
242
|
-
const audioSender = mqaData.intervals[0].audioTransmit[0];
|
|
243
|
-
const videoReceiver = mqaData.intervals[0].videoReceive[0];
|
|
244
|
-
const videoSender = mqaData.intervals[0].videoTransmit[0];
|
|
245
|
-
const shareSender = mqaData.intervals[0].videoTransmit[1];
|
|
246
|
-
const shareReceiver = mqaData.intervals[0].videoReceive[1];
|
|
247
|
-
|
|
248
|
-
getAudioSenderMqa({
|
|
249
|
-
audioSender,
|
|
250
|
-
statsResults: this.statsResults,
|
|
251
|
-
lastMqaDataSent: this.lastMqaDataSent,
|
|
252
|
-
});
|
|
253
|
-
getAudioReceiverMqa({
|
|
254
|
-
audioReceiver,
|
|
255
|
-
statsResults: this.statsResults,
|
|
256
|
-
lastMqaDataSent: this.lastMqaDataSent,
|
|
257
|
-
});
|
|
258
|
-
|
|
259
|
-
getVideoReceiverMqa({
|
|
260
|
-
videoReceiver,
|
|
261
|
-
statsResults: this.statsResults,
|
|
262
|
-
lastMqaDataSent: this.lastMqaDataSent,
|
|
263
|
-
});
|
|
264
|
-
getVideoSenderMqa({
|
|
265
|
-
videoSender,
|
|
266
|
-
statsResults: this.statsResults,
|
|
267
|
-
lastMqaDataSent: this.lastMqaDataSent,
|
|
268
|
-
});
|
|
151
|
+
sendMqaData() {
|
|
152
|
+
const newMqa = cloneDeep(emptyMqaInterval);
|
|
269
153
|
|
|
270
|
-
|
|
154
|
+
Object.keys(this.statsResults).forEach((mediaType) => {
|
|
155
|
+
if (mediaType.includes('audio-send') || mediaType.includes('audio-share-send')) {
|
|
156
|
+
const audioSender = cloneDeep(emptyAudioTransmit);
|
|
271
157
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
158
|
+
getAudioSenderMqa({
|
|
159
|
+
audioSender,
|
|
160
|
+
statsResults: this.statsResults,
|
|
161
|
+
lastMqaDataSent: this.lastMqaDataSent,
|
|
162
|
+
mediaType,
|
|
163
|
+
});
|
|
164
|
+
newMqa.audioTransmit.push(audioSender);
|
|
165
|
+
} else if (mediaType.includes('audio-recv') || mediaType.includes('audio-share-recv')) {
|
|
166
|
+
const audioReceiver = cloneDeep(emptyAudioReceive);
|
|
167
|
+
|
|
168
|
+
getAudioReceiverMqa({
|
|
169
|
+
audioReceiver,
|
|
170
|
+
statsResults: this.statsResults,
|
|
171
|
+
lastMqaDataSent: this.lastMqaDataSent,
|
|
172
|
+
mediaType,
|
|
173
|
+
});
|
|
174
|
+
newMqa.audioReceive.push(audioReceiver);
|
|
175
|
+
} else if (mediaType.includes('video-send') || mediaType.includes('video-share-send')) {
|
|
176
|
+
const videoSender = cloneDeep(emptyVideoTransmit);
|
|
177
|
+
|
|
178
|
+
getVideoSenderMqa({
|
|
179
|
+
videoSender,
|
|
180
|
+
statsResults: this.statsResults,
|
|
181
|
+
lastMqaDataSent: this.lastMqaDataSent,
|
|
182
|
+
mediaType,
|
|
183
|
+
});
|
|
184
|
+
newMqa.videoTransmit.push(videoSender);
|
|
185
|
+
} else if (mediaType.includes('video-recv') || mediaType.includes('video-share-recv')) {
|
|
186
|
+
const videoReceiver = cloneDeep(emptyVideoReceive);
|
|
187
|
+
|
|
188
|
+
getVideoReceiverMqa({
|
|
189
|
+
videoReceiver,
|
|
190
|
+
statsResults: this.statsResults,
|
|
191
|
+
lastMqaDataSent: this.lastMqaDataSent,
|
|
192
|
+
mediaType,
|
|
193
|
+
});
|
|
194
|
+
newMqa.videoReceive.push(videoReceiver);
|
|
195
|
+
}
|
|
277
196
|
});
|
|
278
197
|
|
|
279
|
-
|
|
280
|
-
videoReceiver: shareReceiver,
|
|
281
|
-
statsResults: this.statsResults,
|
|
282
|
-
lastMqaDataSent: this.lastMqaDataSent,
|
|
283
|
-
isShareStream: true,
|
|
284
|
-
});
|
|
285
|
-
mqaData.intervals[0].intervalMetadata.peerReflexiveIP =
|
|
286
|
-
this.statsResults.connectionType.local.ipAddress[0];
|
|
198
|
+
newMqa.intervalMetadata.peerReflexiveIP = this.statsResults.connectionType.local.ipAddress;
|
|
287
199
|
|
|
288
200
|
// Adding peripheral information
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
}
|
|
201
|
+
newMqa.intervalMetadata.peripherals.push({information: _UNKNOWN_, name: MEDIA_DEVICES.SPEAKER});
|
|
202
|
+
if (this.statsResults['audio-send']) {
|
|
203
|
+
newMqa.intervalMetadata.peripherals.push({
|
|
204
|
+
information: this.statsResults['audio-send'].trackLabel || _UNKNOWN_,
|
|
205
|
+
name: MEDIA_DEVICES.MICROPHONE,
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
if (this.statsResults['video-send']) {
|
|
209
|
+
newMqa.intervalMetadata.peripherals.push({
|
|
210
|
+
information: this.statsResults['video-send'].trackLabel || _UNKNOWN_,
|
|
211
|
+
name: MEDIA_DEVICES.CAMERA,
|
|
212
|
+
});
|
|
213
|
+
}
|
|
302
214
|
|
|
303
|
-
|
|
304
|
-
mqaData.networkType = this.statsResults.connectionType.local.networkType;
|
|
215
|
+
newMqa.networkType = this.statsResults.connectionType.local.networkType;
|
|
305
216
|
|
|
306
217
|
this.mqaSentCount += 1;
|
|
307
218
|
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
// DO Deep copy, for some reason it takes the reference all the time rather then old value set
|
|
311
|
-
this.lastMqaDataSent = cloneDeep(this.statsResults);
|
|
312
|
-
|
|
313
|
-
this.populateResults(mqaData.intervals[0]);
|
|
219
|
+
newMqa.intervalNumber = this.mqaSentCount;
|
|
314
220
|
|
|
315
221
|
this.resetStatsResults();
|
|
316
222
|
|
|
@@ -321,23 +227,23 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
321
227
|
},
|
|
322
228
|
EVENTS.MEDIA_QUALITY,
|
|
323
229
|
{
|
|
324
|
-
data:
|
|
230
|
+
data: newMqa,
|
|
325
231
|
// @ts-ignore
|
|
326
|
-
networkType:
|
|
232
|
+
networkType: newMqa.networkType,
|
|
327
233
|
}
|
|
328
234
|
);
|
|
329
235
|
}
|
|
330
236
|
|
|
331
237
|
/**
|
|
332
|
-
* updated the
|
|
238
|
+
* updated the media connection when changed
|
|
333
239
|
*
|
|
334
240
|
* @private
|
|
335
|
-
* @memberof
|
|
336
|
-
* @param {
|
|
241
|
+
* @memberof StatsAnalyzer
|
|
242
|
+
* @param {RoapMediaConnection} mediaConnection
|
|
337
243
|
* @returns {void}
|
|
338
244
|
*/
|
|
339
|
-
|
|
340
|
-
this.
|
|
245
|
+
updateMediaConnection(mediaConnection: any) {
|
|
246
|
+
this.mediaConnection = mediaConnection;
|
|
341
247
|
}
|
|
342
248
|
|
|
343
249
|
/**
|
|
@@ -345,13 +251,13 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
345
251
|
*
|
|
346
252
|
* @public
|
|
347
253
|
* @memberof StatsAnalyzer
|
|
348
|
-
* @param {
|
|
254
|
+
* @param {RoapMediaConnection} mediaConnection
|
|
349
255
|
* @returns {Promise}
|
|
350
256
|
*/
|
|
351
|
-
public startAnalyzer(
|
|
257
|
+
public startAnalyzer(mediaConnection: any) {
|
|
352
258
|
if (!this.statsStarted) {
|
|
353
259
|
this.statsStarted = true;
|
|
354
|
-
this.
|
|
260
|
+
this.mediaConnection = mediaConnection;
|
|
355
261
|
|
|
356
262
|
return this.getStatsAndParse().then(() => {
|
|
357
263
|
this.statsInterval = setInterval(() => {
|
|
@@ -391,7 +297,7 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
391
297
|
if (sendOneLastMqa) {
|
|
392
298
|
return this.getStatsAndParse().then(() => {
|
|
393
299
|
this.sendMqaData();
|
|
394
|
-
this.
|
|
300
|
+
this.mediaConnection = null;
|
|
395
301
|
});
|
|
396
302
|
}
|
|
397
303
|
|
|
@@ -413,6 +319,37 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
413
319
|
return;
|
|
414
320
|
}
|
|
415
321
|
|
|
322
|
+
// Generate empty stats results
|
|
323
|
+
if (!this.statsResults[type]) {
|
|
324
|
+
this.statsResults[type] = {};
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
if (isSender && !this.statsResults[type].send) {
|
|
328
|
+
this.statsResults[type].send = cloneDeep(emptySender);
|
|
329
|
+
} else if (!isSender && !this.statsResults[type].recv) {
|
|
330
|
+
this.statsResults[type].recv = cloneDeep(emptyReceiver);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
if (!this.statsResults.resolutions[type]) {
|
|
334
|
+
this.statsResults.resolutions[type] = {};
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
if (isSender && !this.statsResults.resolutions[type].send) {
|
|
338
|
+
this.statsResults.resolutions[type].send = cloneDeep(emptySender);
|
|
339
|
+
} else if (!isSender && !this.statsResults.resolutions[type].recv) {
|
|
340
|
+
this.statsResults.resolutions[type].recv = cloneDeep(emptyReceiver);
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
if (!this.statsResults.internal[type]) {
|
|
344
|
+
this.statsResults.internal[type] = {};
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
if (isSender && !this.statsResults.internal[type].send) {
|
|
348
|
+
this.statsResults.internal[type].send = cloneDeep(emptySender);
|
|
349
|
+
} else if (!isSender && !this.statsResults.internal[type].recv) {
|
|
350
|
+
this.statsResults.internal[type].recv = cloneDeep(emptyReceiver);
|
|
351
|
+
}
|
|
352
|
+
|
|
416
353
|
switch (getStatsResult.type) {
|
|
417
354
|
case 'outbound-rtp':
|
|
418
355
|
this.processOutboundRTPResult(getStatsResult, type);
|
|
@@ -447,23 +384,34 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
447
384
|
/**
|
|
448
385
|
* Filters the get stats results for types
|
|
449
386
|
* @private
|
|
450
|
-
* @param {Array}
|
|
387
|
+
* @param {Array} statsItem
|
|
451
388
|
* @param {String} type
|
|
452
389
|
* @param {boolean} isSender
|
|
453
390
|
* @returns {void}
|
|
454
391
|
*/
|
|
455
|
-
|
|
456
|
-
getStatsResults: Array<any>,
|
|
457
|
-
type: string,
|
|
458
|
-
isSender: boolean
|
|
459
|
-
) {
|
|
392
|
+
filterAndParseGetStatsResults(statsItem: any, type: string, isSender: boolean) {
|
|
460
393
|
const {types} = DEFAULT_GET_STATS_FILTER;
|
|
461
394
|
|
|
462
|
-
|
|
395
|
+
// get the successful candidate pair before parsing stats.
|
|
396
|
+
statsItem.report.forEach((report) => {
|
|
397
|
+
if (report.type === 'candidate-pair' && report.state === 'succeeded') {
|
|
398
|
+
this.successfulCandidatePair = report;
|
|
399
|
+
}
|
|
400
|
+
});
|
|
401
|
+
|
|
402
|
+
statsItem.report.forEach((result) => {
|
|
463
403
|
if (types.includes(result.type)) {
|
|
464
404
|
this.parseGetStatsResult(result, type, isSender);
|
|
465
405
|
}
|
|
466
406
|
});
|
|
407
|
+
|
|
408
|
+
if (this.statsResults[type]) {
|
|
409
|
+
this.statsResults[type].direction = statsItem.currentDirection;
|
|
410
|
+
this.statsResults[type].trackLabel = statsItem.localTrackLabel;
|
|
411
|
+
this.statsResults[type].csi = statsItem.csi;
|
|
412
|
+
// reset the successful candidate pair.
|
|
413
|
+
this.successfulCandidatePair = {};
|
|
414
|
+
}
|
|
467
415
|
}
|
|
468
416
|
|
|
469
417
|
/**
|
|
@@ -477,7 +425,7 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
477
425
|
return;
|
|
478
426
|
}
|
|
479
427
|
|
|
480
|
-
if (type
|
|
428
|
+
if (type.includes('audio-send')) {
|
|
481
429
|
this.statsResults[type].send.audioLevel = result.audioLevel;
|
|
482
430
|
this.statsResults[type].send.totalAudioEnergy = result.totalAudioEnergy;
|
|
483
431
|
}
|
|
@@ -512,6 +460,10 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
512
460
|
// eslint-disable-next-line no-param-reassign
|
|
513
461
|
if (currentValue === undefined) currentValue = 0;
|
|
514
462
|
|
|
463
|
+
if (!this.lastEmittedStartStopEvent[mediaType]) {
|
|
464
|
+
this.lastEmittedStartStopEvent[mediaType] = {};
|
|
465
|
+
}
|
|
466
|
+
|
|
515
467
|
const lastEmittedEvent = isLocal
|
|
516
468
|
? this.lastEmittedStartStopEvent[mediaType].local
|
|
517
469
|
: this.lastEmittedStartStopEvent[mediaType].remote;
|
|
@@ -552,21 +504,42 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
552
504
|
*/
|
|
553
505
|
private compareLastStatsResult() {
|
|
554
506
|
if (this.lastStatsResults !== null && this.meetingMediaStatus) {
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
507
|
+
const getCurrentStatsTotals = (keyPrefix: string, value: string): number =>
|
|
508
|
+
Object.keys(this.statsResults)
|
|
509
|
+
.filter((key) => key.startsWith(keyPrefix))
|
|
510
|
+
.reduce((prev, cur) => prev + (this.statsResults[cur]?.recv[value] || 0), 0);
|
|
511
|
+
|
|
512
|
+
const getPreviousStatsTotals = (keyPrefix: string, value: string): number =>
|
|
513
|
+
Object.keys(this.statsResults)
|
|
514
|
+
.filter((key) => key.startsWith(keyPrefix))
|
|
515
|
+
.reduce((prev, cur) => prev + (this.lastStatsResults[cur]?.recv[value] || 0), 0);
|
|
516
|
+
|
|
517
|
+
const getCurrentResolutionsStatsTotals = (keyPrefix: string, value: string): number =>
|
|
518
|
+
Object.keys(this.statsResults)
|
|
519
|
+
.filter((key) => key.startsWith(keyPrefix))
|
|
520
|
+
.reduce((prev, cur) => prev + (this.statsResults.resolutions[cur]?.recv[value] || 0), 0);
|
|
521
|
+
|
|
522
|
+
const getPreviousResolutionsStatsTotals = (keyPrefix: string, value: string): number =>
|
|
523
|
+
Object.keys(this.statsResults)
|
|
524
|
+
.filter((key) => key.startsWith(keyPrefix))
|
|
525
|
+
.reduce(
|
|
526
|
+
(prev, cur) => prev + (this.lastStatsResults.resolutions[cur]?.recv[value] || 0),
|
|
527
|
+
0
|
|
528
|
+
);
|
|
559
529
|
|
|
560
|
-
if (this.meetingMediaStatus.expected.sendAudio) {
|
|
561
|
-
|
|
562
|
-
|
|
530
|
+
if (this.meetingMediaStatus.expected.sendAudio && this.lastStatsResults['audio-send']) {
|
|
531
|
+
// compare audio stats sent
|
|
532
|
+
// NOTE: relies on there being only one sender.
|
|
533
|
+
const currentStats = this.statsResults['audio-send'].send;
|
|
534
|
+
const previousStats = this.lastStatsResults['audio-send'].send;
|
|
563
535
|
|
|
564
536
|
if (
|
|
565
537
|
currentStats.totalPacketsSent === previousStats.totalPacketsSent ||
|
|
566
538
|
currentStats.totalPacketsSent === 0
|
|
567
539
|
) {
|
|
568
540
|
LoggerProxy.logger.info(
|
|
569
|
-
`StatsAnalyzer:index#compareLastStatsResult --> No
|
|
541
|
+
`StatsAnalyzer:index#compareLastStatsResult --> No audio RTP packets sent`,
|
|
542
|
+
currentStats.totalPacketsSent
|
|
570
543
|
);
|
|
571
544
|
} else {
|
|
572
545
|
if (
|
|
@@ -574,19 +547,20 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
574
547
|
currentStats.totalAudioEnergy === 0
|
|
575
548
|
) {
|
|
576
549
|
LoggerProxy.logger.info(
|
|
577
|
-
`StatsAnalyzer:index#compareLastStatsResult --> No
|
|
550
|
+
`StatsAnalyzer:index#compareLastStatsResult --> No audio Energy present`,
|
|
551
|
+
currentStats.totalAudioEnergy
|
|
578
552
|
);
|
|
579
553
|
}
|
|
580
554
|
|
|
581
555
|
if (currentStats.audioLevel === 0) {
|
|
582
556
|
LoggerProxy.logger.info(
|
|
583
|
-
`StatsAnalyzer:index#compareLastStatsResult -->
|
|
557
|
+
`StatsAnalyzer:index#compareLastStatsResult --> audio level is 0 for the user`
|
|
584
558
|
);
|
|
585
559
|
}
|
|
586
560
|
}
|
|
587
561
|
|
|
588
562
|
this.emitStartStopEvents(
|
|
589
|
-
|
|
563
|
+
'audio',
|
|
590
564
|
previousStats.totalPacketsSent,
|
|
591
565
|
currentStats.totalPacketsSent,
|
|
592
566
|
true
|
|
@@ -595,45 +569,47 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
595
569
|
|
|
596
570
|
if (this.meetingMediaStatus.expected.receiveAudio) {
|
|
597
571
|
// compare audio stats received
|
|
598
|
-
|
|
599
|
-
|
|
572
|
+
const currentPacketsReceived = getCurrentStatsTotals('audio-recv', 'totalPacketsReceived');
|
|
573
|
+
const previousPacketsReceived = getPreviousStatsTotals(
|
|
574
|
+
'audio-recv',
|
|
575
|
+
'totalPacketsReceived'
|
|
576
|
+
);
|
|
577
|
+
const currentSamplesReceived = getCurrentStatsTotals('audio-recv', 'totalSamplesReceived');
|
|
578
|
+
const previousSamplesReceived = getPreviousStatsTotals(
|
|
579
|
+
'audio-recv',
|
|
580
|
+
'totalSamplesReceived'
|
|
581
|
+
);
|
|
600
582
|
|
|
601
|
-
if (
|
|
602
|
-
currentStats.totalPacketsReceived === previousStats.totalPacketsReceived ||
|
|
603
|
-
currentStats.totalPacketsReceived === 0
|
|
604
|
-
) {
|
|
583
|
+
if (currentPacketsReceived === previousPacketsReceived || currentPacketsReceived === 0) {
|
|
605
584
|
LoggerProxy.logger.info(
|
|
606
|
-
`StatsAnalyzer:index#compareLastStatsResult --> No
|
|
585
|
+
`StatsAnalyzer:index#compareLastStatsResult --> No audio RTP packets received`,
|
|
586
|
+
currentPacketsReceived
|
|
607
587
|
);
|
|
608
588
|
} else if (
|
|
609
|
-
|
|
610
|
-
|
|
589
|
+
currentSamplesReceived === previousSamplesReceived ||
|
|
590
|
+
currentSamplesReceived === 0
|
|
611
591
|
) {
|
|
612
592
|
LoggerProxy.logger.info(
|
|
613
|
-
`StatsAnalyzer:index#compareLastStatsResult --> No
|
|
593
|
+
`StatsAnalyzer:index#compareLastStatsResult --> No audio samples received`,
|
|
594
|
+
currentSamplesReceived
|
|
614
595
|
);
|
|
615
596
|
}
|
|
616
597
|
|
|
617
|
-
this.emitStartStopEvents(
|
|
618
|
-
mediaType,
|
|
619
|
-
previousStats.totalPacketsReceived,
|
|
620
|
-
currentStats.totalPacketsReceived,
|
|
621
|
-
false
|
|
622
|
-
);
|
|
598
|
+
this.emitStartStopEvents('audio', previousPacketsReceived, currentPacketsReceived, false);
|
|
623
599
|
}
|
|
624
600
|
|
|
625
|
-
|
|
626
|
-
if (this.meetingMediaStatus.expected.sendVideo) {
|
|
601
|
+
if (this.meetingMediaStatus.expected.sendVideo && this.lastStatsResults['video-send']) {
|
|
627
602
|
// compare video stats sent
|
|
628
|
-
currentStats = this.statsResults[
|
|
629
|
-
previousStats = this.lastStatsResults[
|
|
603
|
+
const currentStats = this.statsResults['video-send'].send;
|
|
604
|
+
const previousStats = this.lastStatsResults['video-send'].send;
|
|
630
605
|
|
|
631
606
|
if (
|
|
632
607
|
currentStats.totalPacketsSent === previousStats.totalPacketsSent ||
|
|
633
608
|
currentStats.totalPacketsSent === 0
|
|
634
609
|
) {
|
|
635
610
|
LoggerProxy.logger.info(
|
|
636
|
-
`StatsAnalyzer:index#compareLastStatsResult --> No
|
|
611
|
+
`StatsAnalyzer:index#compareLastStatsResult --> No video RTP packets sent`,
|
|
612
|
+
currentStats.totalPacketsSent
|
|
637
613
|
);
|
|
638
614
|
} else {
|
|
639
615
|
if (
|
|
@@ -641,95 +617,96 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
641
617
|
currentStats.framesEncoded === 0
|
|
642
618
|
) {
|
|
643
619
|
LoggerProxy.logger.info(
|
|
644
|
-
`StatsAnalyzer:index#compareLastStatsResult --> No
|
|
620
|
+
`StatsAnalyzer:index#compareLastStatsResult --> No video Frames Encoded`,
|
|
621
|
+
currentStats.framesEncoded
|
|
645
622
|
);
|
|
646
623
|
}
|
|
647
624
|
|
|
648
625
|
if (
|
|
649
|
-
this.statsResults.resolutions[
|
|
650
|
-
this.lastStatsResults.resolutions[
|
|
651
|
-
this.statsResults.resolutions[
|
|
626
|
+
this.statsResults.resolutions['video-send'].send.framesSent ===
|
|
627
|
+
this.lastStatsResults.resolutions['video-send'].send.framesSent ||
|
|
628
|
+
this.statsResults.resolutions['video-send'].send.framesSent === 0
|
|
652
629
|
) {
|
|
653
630
|
LoggerProxy.logger.info(
|
|
654
|
-
`StatsAnalyzer:index#compareLastStatsResult --> No
|
|
631
|
+
`StatsAnalyzer:index#compareLastStatsResult --> No video Frames sent`,
|
|
632
|
+
this.statsResults.resolutions['video-send'].send.framesSent
|
|
655
633
|
);
|
|
656
634
|
}
|
|
657
635
|
}
|
|
658
636
|
|
|
659
|
-
this.emitStartStopEvents(
|
|
660
|
-
mediaType,
|
|
661
|
-
previousStats.framesSent,
|
|
662
|
-
currentStats.framesSent,
|
|
663
|
-
true
|
|
664
|
-
);
|
|
637
|
+
this.emitStartStopEvents('video', previousStats.framesSent, currentStats.framesSent, true);
|
|
665
638
|
}
|
|
666
639
|
|
|
667
640
|
if (this.meetingMediaStatus.expected.receiveVideo) {
|
|
668
|
-
// compare video stats
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
641
|
+
// compare video stats received
|
|
642
|
+
const currentPacketsReceived = getCurrentStatsTotals('video-recv', 'totalPacketsReceived');
|
|
643
|
+
const previousPacketsReceived = getPreviousStatsTotals(
|
|
644
|
+
'video-recv',
|
|
645
|
+
'totalPacketsReceived'
|
|
646
|
+
);
|
|
647
|
+
const currentFramesReceived = getCurrentResolutionsStatsTotals(
|
|
648
|
+
'video-recv',
|
|
649
|
+
'framesReceived'
|
|
650
|
+
);
|
|
651
|
+
const previousFramesReceived = getPreviousResolutionsStatsTotals(
|
|
652
|
+
'video-recv',
|
|
653
|
+
'framesReceived'
|
|
654
|
+
);
|
|
655
|
+
const currentFramesDecoded = getCurrentStatsTotals('video-recv', 'framesDecoded');
|
|
656
|
+
const previousFramesDecoded = getPreviousStatsTotals('video-recv', 'framesDecoded');
|
|
657
|
+
const currentFramesDropped = getCurrentResolutionsStatsTotals(
|
|
658
|
+
'video-recv',
|
|
659
|
+
'framesDropped'
|
|
660
|
+
);
|
|
661
|
+
const previousFramesDropped = getPreviousResolutionsStatsTotals(
|
|
662
|
+
'video-recv',
|
|
663
|
+
'framesDropped'
|
|
664
|
+
);
|
|
672
665
|
|
|
673
|
-
if (
|
|
674
|
-
currentStats.totalPacketsReceived === previousStats.totalPacketsReceived ||
|
|
675
|
-
currentStats.totalPacketsReceived === 0
|
|
676
|
-
) {
|
|
666
|
+
if (currentPacketsReceived === previousPacketsReceived || currentPacketsReceived === 0) {
|
|
677
667
|
LoggerProxy.logger.info(
|
|
678
|
-
`StatsAnalyzer:index#compareLastStatsResult --> No
|
|
668
|
+
`StatsAnalyzer:index#compareLastStatsResult --> No video RTP packets received`,
|
|
669
|
+
currentPacketsReceived
|
|
679
670
|
);
|
|
680
671
|
} else {
|
|
681
|
-
if (
|
|
682
|
-
this.statsResults.resolutions[mediaType].recv.framesReceived ===
|
|
683
|
-
this.lastStatsResults.resolutions[mediaType].recv.framesReceived ||
|
|
684
|
-
this.statsResults.resolutions[mediaType].recv.framesReceived === 0
|
|
685
|
-
) {
|
|
672
|
+
if (currentFramesReceived === previousFramesReceived || currentFramesReceived === 0) {
|
|
686
673
|
LoggerProxy.logger.info(
|
|
687
|
-
`StatsAnalyzer:index#compareLastStatsResult --> No
|
|
674
|
+
`StatsAnalyzer:index#compareLastStatsResult --> No video frames received`,
|
|
675
|
+
currentFramesReceived
|
|
688
676
|
);
|
|
689
677
|
}
|
|
690
678
|
|
|
691
|
-
if (
|
|
692
|
-
this.statsResults[mediaType].recv.framesDecoded ===
|
|
693
|
-
this.lastStatsResults[mediaType].recv.framesDecoded ||
|
|
694
|
-
this.statsResults.resolutions[mediaType].send.framesDecoded === 0
|
|
695
|
-
) {
|
|
679
|
+
if (currentFramesDecoded === previousFramesDecoded || currentFramesDecoded === 0) {
|
|
696
680
|
LoggerProxy.logger.info(
|
|
697
|
-
`StatsAnalyzer:index#compareLastStatsResult --> No
|
|
681
|
+
`StatsAnalyzer:index#compareLastStatsResult --> No video frames decoded`,
|
|
682
|
+
currentFramesDecoded
|
|
698
683
|
);
|
|
699
684
|
}
|
|
700
685
|
|
|
701
|
-
if (
|
|
702
|
-
this.statsResults.resolutions[mediaType].recv.framesDropped -
|
|
703
|
-
this.lastStatsResults.resolutions[mediaType].recv.framesDropped >
|
|
704
|
-
10
|
|
705
|
-
) {
|
|
686
|
+
if (currentFramesDropped - previousFramesDropped > 10) {
|
|
706
687
|
LoggerProxy.logger.info(
|
|
707
|
-
`StatsAnalyzer:index#compareLastStatsResult -->
|
|
688
|
+
`StatsAnalyzer:index#compareLastStatsResult --> video frames are getting dropped`,
|
|
689
|
+
currentFramesDropped - previousFramesDropped
|
|
708
690
|
);
|
|
709
691
|
}
|
|
710
692
|
}
|
|
711
693
|
|
|
712
|
-
this.emitStartStopEvents(
|
|
713
|
-
mediaType,
|
|
714
|
-
previousStats.framesDecoded,
|
|
715
|
-
currentStats.framesDecoded,
|
|
716
|
-
false
|
|
717
|
-
);
|
|
694
|
+
this.emitStartStopEvents('video', previousFramesDecoded, currentFramesDecoded, false);
|
|
718
695
|
}
|
|
719
696
|
|
|
720
|
-
|
|
721
|
-
if (this.meetingMediaStatus.expected.sendShare) {
|
|
697
|
+
if (this.meetingMediaStatus.expected.sendShare && this.lastStatsResults['video-share-send']) {
|
|
722
698
|
// compare share stats sent
|
|
723
699
|
|
|
724
|
-
currentStats = this.statsResults[
|
|
725
|
-
previousStats = this.lastStatsResults[
|
|
700
|
+
const currentStats = this.statsResults['video-share-send'].send;
|
|
701
|
+
const previousStats = this.lastStatsResults['video-share-send'].send;
|
|
726
702
|
|
|
727
703
|
if (
|
|
728
704
|
currentStats.totalPacketsSent === previousStats.totalPacketsSent ||
|
|
729
705
|
currentStats.totalPacketsSent === 0
|
|
730
706
|
) {
|
|
731
707
|
LoggerProxy.logger.info(
|
|
732
|
-
`StatsAnalyzer:index#compareLastStatsResult --> No
|
|
708
|
+
`StatsAnalyzer:index#compareLastStatsResult --> No share RTP packets sent`,
|
|
709
|
+
currentStats.totalPacketsSent
|
|
733
710
|
);
|
|
734
711
|
} else {
|
|
735
712
|
if (
|
|
@@ -737,61 +714,78 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
737
714
|
currentStats.framesEncoded === 0
|
|
738
715
|
) {
|
|
739
716
|
LoggerProxy.logger.info(
|
|
740
|
-
`StatsAnalyzer:index#compareLastStatsResult --> No
|
|
717
|
+
`StatsAnalyzer:index#compareLastStatsResult --> No share frames getting encoded`,
|
|
718
|
+
currentStats.framesEncoded
|
|
741
719
|
);
|
|
742
720
|
}
|
|
743
721
|
|
|
744
722
|
if (
|
|
745
|
-
this.statsResults.resolutions[
|
|
746
|
-
this.lastStatsResults.resolutions[
|
|
747
|
-
this.statsResults.resolutions[
|
|
723
|
+
this.statsResults.resolutions['video-share-send'].send.framesSent ===
|
|
724
|
+
this.lastStatsResults.resolutions['video-share-send'].send.framesSent ||
|
|
725
|
+
this.statsResults.resolutions['video-share-send'].send.framesSent === 0
|
|
748
726
|
) {
|
|
749
727
|
LoggerProxy.logger.info(
|
|
750
|
-
`StatsAnalyzer:index#compareLastStatsResult --> No
|
|
728
|
+
`StatsAnalyzer:index#compareLastStatsResult --> No share frames sent`,
|
|
729
|
+
this.statsResults.resolutions['video-share-send'].send.framesSent
|
|
751
730
|
);
|
|
752
731
|
}
|
|
753
732
|
}
|
|
733
|
+
}
|
|
754
734
|
|
|
735
|
+
if (this.meetingMediaStatus.expected.sendShare) {
|
|
755
736
|
// TODO:need to check receive share value
|
|
756
|
-
// compare share stats
|
|
757
|
-
|
|
758
|
-
|
|
737
|
+
// compare share stats received
|
|
738
|
+
const currentPacketsReceived = getCurrentStatsTotals(
|
|
739
|
+
'video-share-recv',
|
|
740
|
+
'totalPacketsReceived'
|
|
741
|
+
);
|
|
742
|
+
const previousPacketsReceived = getPreviousStatsTotals(
|
|
743
|
+
'video-share-recv',
|
|
744
|
+
'totalPacketsReceived'
|
|
745
|
+
);
|
|
746
|
+
const currentFramesReceived = getCurrentResolutionsStatsTotals(
|
|
747
|
+
'video-share-recv',
|
|
748
|
+
'framesReceived'
|
|
749
|
+
);
|
|
750
|
+
const previousFramesReceived = getPreviousResolutionsStatsTotals(
|
|
751
|
+
'video-share-recv',
|
|
752
|
+
'framesReceived'
|
|
753
|
+
);
|
|
754
|
+
const currentFramesDecoded = getCurrentStatsTotals('video-share-recv', 'framesDecoded');
|
|
755
|
+
const previousFramesDecoded = getPreviousStatsTotals('video-share-recv', 'framesDecoded');
|
|
756
|
+
const currentFramesDropped = getCurrentResolutionsStatsTotals(
|
|
757
|
+
'video-share-recv',
|
|
758
|
+
'framesDropped'
|
|
759
|
+
);
|
|
760
|
+
const previousFramesDropped = getPreviousResolutionsStatsTotals(
|
|
761
|
+
'video-share-recv',
|
|
762
|
+
'framesDropped'
|
|
763
|
+
);
|
|
759
764
|
|
|
760
|
-
if (
|
|
761
|
-
currentStats.totalPacketsReceived === previousStats.totalPacketsReceived ||
|
|
762
|
-
currentStats.totalPacketsSent === 0
|
|
763
|
-
) {
|
|
765
|
+
if (currentPacketsReceived === previousPacketsReceived || currentPacketsReceived === 0) {
|
|
764
766
|
LoggerProxy.logger.info(
|
|
765
|
-
`StatsAnalyzer:index#compareLastStatsResult --> No
|
|
767
|
+
`StatsAnalyzer:index#compareLastStatsResult --> No share RTP packets received`,
|
|
768
|
+
currentPacketsReceived
|
|
766
769
|
);
|
|
767
770
|
} else {
|
|
768
|
-
if (
|
|
769
|
-
this.statsResults.resolutions[mediaType].recv.framesReceived ===
|
|
770
|
-
this.lastStatsResults.resolutions[mediaType].recv.framesReceived ||
|
|
771
|
-
this.statsResults.resolutions[mediaType].recv.framesReceived === 0
|
|
772
|
-
) {
|
|
771
|
+
if (currentFramesReceived === previousFramesReceived || currentFramesReceived === 0) {
|
|
773
772
|
LoggerProxy.logger.info(
|
|
774
|
-
`StatsAnalyzer:index#compareLastStatsResult --> No
|
|
773
|
+
`StatsAnalyzer:index#compareLastStatsResult --> No share frames received`,
|
|
774
|
+
currentFramesReceived
|
|
775
775
|
);
|
|
776
776
|
}
|
|
777
777
|
|
|
778
|
-
if (
|
|
779
|
-
this.statsResults[mediaType].recv.framesDecoded ===
|
|
780
|
-
this.lastStatsResults[mediaType].recv.framesDecoded ||
|
|
781
|
-
this.statsResults.resolutions[mediaType].send.framesDecoded === 0
|
|
782
|
-
) {
|
|
778
|
+
if (currentFramesDecoded === previousFramesDecoded || currentFramesDecoded === 0) {
|
|
783
779
|
LoggerProxy.logger.info(
|
|
784
|
-
`StatsAnalyzer:index#compareLastStatsResult --> No
|
|
780
|
+
`StatsAnalyzer:index#compareLastStatsResult --> No share frames decoded`,
|
|
781
|
+
currentFramesDecoded
|
|
785
782
|
);
|
|
786
783
|
}
|
|
787
784
|
|
|
788
|
-
if (
|
|
789
|
-
this.statsResults.resolutions[mediaType].recv.framesDropped -
|
|
790
|
-
this.lastStatsResults.resolutions[mediaType].recv.framesDropped >
|
|
791
|
-
10
|
|
792
|
-
) {
|
|
785
|
+
if (currentFramesDropped - previousFramesDropped > 10) {
|
|
793
786
|
LoggerProxy.logger.info(
|
|
794
|
-
`StatsAnalyzer:index#compareLastStatsResult -->
|
|
787
|
+
`StatsAnalyzer:index#compareLastStatsResult --> share frames are getting dropped`,
|
|
788
|
+
currentFramesDropped - previousFramesDropped
|
|
795
789
|
);
|
|
796
790
|
}
|
|
797
791
|
}
|
|
@@ -811,13 +805,16 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
811
805
|
* @returns {Promise}
|
|
812
806
|
*/
|
|
813
807
|
private getStatsAndParse() {
|
|
814
|
-
if (!this.
|
|
808
|
+
if (!this.mediaConnection) {
|
|
815
809
|
return Promise.resolve();
|
|
816
810
|
}
|
|
817
811
|
|
|
818
|
-
if (
|
|
812
|
+
if (
|
|
813
|
+
this.mediaConnection &&
|
|
814
|
+
this.mediaConnection.getConnectionState() === ConnectionState.Failed
|
|
815
|
+
) {
|
|
819
816
|
LoggerProxy.logger.trace(
|
|
820
|
-
'StatsAnalyzer:index#getStatsAndParse -->
|
|
817
|
+
'StatsAnalyzer:index#getStatsAndParse --> media connection is in failed state'
|
|
821
818
|
);
|
|
822
819
|
|
|
823
820
|
return Promise.resolve();
|
|
@@ -825,43 +822,49 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
825
822
|
|
|
826
823
|
LoggerProxy.logger.trace('StatsAnalyzer:index#getStatsAndParse --> Collecting Stats');
|
|
827
824
|
|
|
828
|
-
return
|
|
829
|
-
|
|
830
|
-
this.filterAndParseGetStatsResults(
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
825
|
+
return this.mediaConnection.getTransceiverStats().then((transceiverStats) => {
|
|
826
|
+
transceiverStats.video.receivers.forEach((receiver, i) =>
|
|
827
|
+
this.filterAndParseGetStatsResults(receiver, `video-recv-${i}`, false)
|
|
828
|
+
);
|
|
829
|
+
transceiverStats.audio.receivers.forEach((receiver, i) =>
|
|
830
|
+
this.filterAndParseGetStatsResults(receiver, `audio-recv-${i}`, false)
|
|
831
|
+
);
|
|
832
|
+
transceiverStats.screenShareVideo.receivers.forEach((receiver, i) =>
|
|
833
|
+
this.filterAndParseGetStatsResults(receiver, `video-share-recv-${i}`, false)
|
|
834
|
+
);
|
|
835
|
+
transceiverStats.screenShareAudio.receivers.forEach((receiver, i) =>
|
|
836
|
+
this.filterAndParseGetStatsResults(receiver, `audio-share-recv-${i}`, false)
|
|
837
|
+
);
|
|
838
|
+
|
|
839
|
+
transceiverStats.video.senders.forEach((sender, i) => {
|
|
840
|
+
if (i > 0) {
|
|
841
|
+
throw new Error('Stats Analyzer does not support multiple senders.');
|
|
842
|
+
}
|
|
843
|
+
this.filterAndParseGetStatsResults(sender, 'video-send', true);
|
|
844
|
+
});
|
|
845
|
+
transceiverStats.audio.senders.forEach((sender, i) => {
|
|
846
|
+
if (i > 0) {
|
|
847
|
+
throw new Error('Stats Analyzer does not support multiple senders.');
|
|
848
|
+
}
|
|
849
|
+
this.filterAndParseGetStatsResults(sender, 'audio-send', true);
|
|
850
|
+
});
|
|
851
|
+
transceiverStats.screenShareVideo.senders.forEach((sender, i) => {
|
|
852
|
+
if (i > 0) {
|
|
853
|
+
throw new Error('Stats Analyzer does not support multiple senders.');
|
|
854
|
+
}
|
|
855
|
+
this.filterAndParseGetStatsResults(sender, 'video-share-send', true);
|
|
856
|
+
});
|
|
857
|
+
transceiverStats.screenShareAudio.senders.forEach((sender, i) => {
|
|
858
|
+
if (i > 0) {
|
|
859
|
+
throw new Error('Stats Analyzer does not support multiple senders.');
|
|
860
|
+
}
|
|
861
|
+
this.filterAndParseGetStatsResults(sender, 'audio-share-send', true);
|
|
862
|
+
});
|
|
863
|
+
|
|
862
864
|
this.compareLastStatsResult();
|
|
863
865
|
|
|
864
866
|
// Save the last results to compare with the current
|
|
867
|
+
// DO Deep copy, for some reason it takes the reference all the time rather then old value set
|
|
865
868
|
this.lastStatsResults = JSON.parse(JSON.stringify(this.statsResults));
|
|
866
869
|
|
|
867
870
|
LoggerProxy.logger.trace(
|
|
@@ -874,16 +877,23 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
874
877
|
* Processes OutboundRTP stats result and stores
|
|
875
878
|
* @private
|
|
876
879
|
* @param {*} result
|
|
877
|
-
* @param {*}
|
|
880
|
+
* @param {*} mediaType
|
|
878
881
|
* @returns {void}
|
|
879
882
|
*/
|
|
880
|
-
private processOutboundRTPResult(result: any,
|
|
881
|
-
const mediaType = type || STATS.AUDIO_CORRELATE;
|
|
883
|
+
private processOutboundRTPResult(result: any, mediaType: any) {
|
|
882
884
|
const sendrecvType = STATS.SEND_DIRECTION;
|
|
883
885
|
|
|
884
886
|
if (result.bytesSent) {
|
|
885
887
|
let kilobytes = 0;
|
|
886
888
|
|
|
889
|
+
if (result.frameWidth && result.frameHeight) {
|
|
890
|
+
this.statsResults.resolutions[mediaType][sendrecvType].width = result.frameWidth;
|
|
891
|
+
this.statsResults.resolutions[mediaType][sendrecvType].height = result.frameHeight;
|
|
892
|
+
this.statsResults.resolutions[mediaType][sendrecvType].framesSent = result.framesSent;
|
|
893
|
+
this.statsResults.resolutions[mediaType][sendrecvType].hugeFramesSent =
|
|
894
|
+
result.hugeFramesSent;
|
|
895
|
+
}
|
|
896
|
+
|
|
887
897
|
if (!this.statsResults.internal[mediaType][sendrecvType].prevBytesSent) {
|
|
888
898
|
this.statsResults.internal[mediaType][sendrecvType].prevBytesSent = result.bytesSent;
|
|
889
899
|
}
|
|
@@ -948,15 +958,25 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
948
958
|
* Processes InboundRTP stats result and stores
|
|
949
959
|
* @private
|
|
950
960
|
* @param {*} result
|
|
951
|
-
* @param {*}
|
|
961
|
+
* @param {*} mediaType
|
|
952
962
|
* @returns {void}
|
|
953
963
|
*/
|
|
954
|
-
private processInboundRTPResult(result: any,
|
|
955
|
-
const mediaType = type || STATS.AUDIO_CORRELATE;
|
|
964
|
+
private processInboundRTPResult(result: any, mediaType: any) {
|
|
956
965
|
const sendrecvType = STATS.RECEIVE_DIRECTION;
|
|
957
966
|
|
|
958
967
|
if (result.bytesReceived) {
|
|
959
968
|
let kilobytes = 0;
|
|
969
|
+
const receiveSlot = this.receiveSlotCallback(result.ssrc);
|
|
970
|
+
const idAndCsi = receiveSlot
|
|
971
|
+
? `id: "${receiveSlot.id || ''}"${receiveSlot.csi ? ` and csi: ${receiveSlot.csi}` : ''}`
|
|
972
|
+
: '';
|
|
973
|
+
|
|
974
|
+
if (result.frameWidth && result.frameHeight) {
|
|
975
|
+
this.statsResults.resolutions[mediaType][sendrecvType].width = result.frameWidth;
|
|
976
|
+
this.statsResults.resolutions[mediaType][sendrecvType].height = result.frameHeight;
|
|
977
|
+
this.statsResults.resolutions[mediaType][sendrecvType].framesReceived =
|
|
978
|
+
result.framesReceived;
|
|
979
|
+
}
|
|
960
980
|
|
|
961
981
|
if (!this.statsResults.internal[mediaType][sendrecvType].prevBytesReceived) {
|
|
962
982
|
this.statsResults.internal[mediaType][sendrecvType].prevBytesReceived =
|
|
@@ -1006,10 +1026,12 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
1006
1026
|
result.packetsReceived;
|
|
1007
1027
|
|
|
1008
1028
|
if (this.statsResults[mediaType][sendrecvType].packetsReceived === 0) {
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1029
|
+
if (receiveSlot) {
|
|
1030
|
+
LoggerProxy.logger.info(
|
|
1031
|
+
`StatsAnalyzer:index#processInboundRTPResult --> No packets received for receive slot ${idAndCsi}`,
|
|
1032
|
+
this.statsResults[mediaType][sendrecvType].packetsReceived
|
|
1033
|
+
);
|
|
1034
|
+
}
|
|
1013
1035
|
}
|
|
1014
1036
|
|
|
1015
1037
|
// Check the over all packet Lost ratio
|
|
@@ -1021,7 +1043,7 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
1021
1043
|
: 0;
|
|
1022
1044
|
if (this.statsResults[mediaType][sendrecvType].currentPacketLossRatio > 3) {
|
|
1023
1045
|
LoggerProxy.logger.info(
|
|
1024
|
-
|
|
1046
|
+
`StatsAnalyzer:index#processInboundRTPResult --> Packets getting lost from the receiver with slot ${idAndCsi}`,
|
|
1025
1047
|
this.statsResults[mediaType][sendrecvType].currentPacketLossRatio
|
|
1026
1048
|
);
|
|
1027
1049
|
}
|
|
@@ -1081,73 +1103,40 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
1081
1103
|
if (!result || !result.id) {
|
|
1082
1104
|
return;
|
|
1083
1105
|
}
|
|
1084
|
-
const RemoteCandidateType = {};
|
|
1085
|
-
const RemoteTransport = {};
|
|
1086
|
-
const RemoteIpAddress = {};
|
|
1087
|
-
const RemoteNetworkType = {};
|
|
1088
1106
|
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
const ipType = isRemote ? STATS.REMOTE : STATS.LOCAL;
|
|
1093
|
-
|
|
1094
|
-
if (!RemoteCandidateType[result.id]) {
|
|
1095
|
-
RemoteCandidateType[result.id] = [];
|
|
1096
|
-
}
|
|
1097
|
-
|
|
1098
|
-
if (!RemoteTransport[result.id]) {
|
|
1099
|
-
RemoteTransport[result.id] = [];
|
|
1100
|
-
}
|
|
1101
|
-
|
|
1102
|
-
if (!RemoteIpAddress[result.id]) {
|
|
1103
|
-
RemoteIpAddress[result.id] = [];
|
|
1104
|
-
}
|
|
1105
|
-
if (!RemoteNetworkType[result.id]) {
|
|
1106
|
-
RemoteNetworkType[result.id] = [];
|
|
1107
|
-
}
|
|
1108
|
-
|
|
1109
|
-
if (
|
|
1110
|
-
result.candidateType &&
|
|
1111
|
-
RemoteCandidateType[result.id].indexOf(result.candidateType) === -1
|
|
1112
|
-
) {
|
|
1113
|
-
RemoteCandidateType[result.id].push(result.candidateType);
|
|
1114
|
-
}
|
|
1115
|
-
|
|
1116
|
-
if (result.protocol && RemoteTransport[result.id].indexOf(result.protocol) === -1) {
|
|
1117
|
-
RemoteTransport[result.id].push(result.protocol.toUpperCase());
|
|
1107
|
+
// We only care about the successful local candidate
|
|
1108
|
+
if (this.successfulCandidatePair?.localCandidateId !== result.id) {
|
|
1109
|
+
return;
|
|
1118
1110
|
}
|
|
1119
1111
|
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
) {
|
|
1124
|
-
|
|
1112
|
+
let transport;
|
|
1113
|
+
if (result.relayProtocol) {
|
|
1114
|
+
transport = result.relayProtocol.toUpperCase();
|
|
1115
|
+
} else if (result.protocol) {
|
|
1116
|
+
transport = result.protocol.toUpperCase();
|
|
1125
1117
|
}
|
|
1126
1118
|
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
}
|
|
1119
|
+
const sendRecvType = isSender ? STATS.SEND_DIRECTION : STATS.RECEIVE_DIRECTION;
|
|
1120
|
+
const ipType = isRemote ? STATS.REMOTE : STATS.LOCAL;
|
|
1130
1121
|
|
|
1131
1122
|
this.statsResults.internal.candidates[result.id] = {
|
|
1132
|
-
candidateType:
|
|
1133
|
-
ipAddress:
|
|
1123
|
+
candidateType: result.candidateType,
|
|
1124
|
+
ipAddress: result.ip, // TODO: add ports
|
|
1134
1125
|
portNumber: result.port,
|
|
1135
|
-
networkType:
|
|
1126
|
+
networkType: result.networkType,
|
|
1136
1127
|
priority: result.priority,
|
|
1137
|
-
transport
|
|
1128
|
+
transport,
|
|
1138
1129
|
timestamp: result.time,
|
|
1139
1130
|
id: result.id,
|
|
1140
1131
|
type: result.type,
|
|
1141
1132
|
};
|
|
1142
1133
|
|
|
1143
|
-
this.statsResults.connectionType[ipType].candidateType =
|
|
1144
|
-
this.statsResults.connectionType[ipType].ipAddress =
|
|
1134
|
+
this.statsResults.connectionType[ipType].candidateType = result.candidateType;
|
|
1135
|
+
this.statsResults.connectionType[ipType].ipAddress = result.ipAddress;
|
|
1145
1136
|
|
|
1146
1137
|
this.statsResults.connectionType[ipType].networkType =
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
: RemoteNetworkType[result.id][0];
|
|
1150
|
-
this.statsResults.connectionType[ipType].transport = RemoteTransport[result.id];
|
|
1138
|
+
result.networkType === NETWORK_TYPE.VPN ? NETWORK_TYPE.UNKNOWN : result.networkType;
|
|
1139
|
+
this.statsResults.connectionType[ipType].transport = transport;
|
|
1151
1140
|
|
|
1152
1141
|
this.statsResults[type][sendRecvType].totalRoundTripTime = result.totalRoundTripTime;
|
|
1153
1142
|
};
|
|
@@ -1165,25 +1154,17 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
1165
1154
|
if (!result || result.type !== 'track') {
|
|
1166
1155
|
return;
|
|
1167
1156
|
}
|
|
1168
|
-
if (result.type !== 'track') return;
|
|
1169
1157
|
|
|
1170
1158
|
const sendrecvType =
|
|
1171
1159
|
result.remoteSource === true ? STATS.RECEIVE_DIRECTION : STATS.SEND_DIRECTION;
|
|
1172
1160
|
|
|
1173
|
-
if (result.frameWidth && result.frameHeight) {
|
|
1174
|
-
this.statsResults.resolutions[mediaType][sendrecvType].width = result.frameWidth;
|
|
1175
|
-
this.statsResults.resolutions[mediaType][sendrecvType].height = result.frameHeight;
|
|
1176
|
-
this.statsResults.resolutions[mediaType][sendrecvType].framesSent = result.framesSent;
|
|
1177
|
-
this.statsResults.resolutions[mediaType][sendrecvType].hugeFramesSent = result.hugeFramesSent;
|
|
1178
|
-
}
|
|
1179
|
-
|
|
1180
1161
|
if (sendrecvType === STATS.RECEIVE_DIRECTION) {
|
|
1181
1162
|
this.statsResults.resolutions[mediaType][sendrecvType].framesReceived = result.framesReceived;
|
|
1182
1163
|
this.statsResults.resolutions[mediaType][sendrecvType].framesDecoded = result.framesDecoded;
|
|
1183
1164
|
this.statsResults.resolutions[mediaType][sendrecvType].framesDropped = result.framesDropped;
|
|
1184
1165
|
}
|
|
1185
1166
|
|
|
1186
|
-
if (result.trackIdentifier && mediaType
|
|
1167
|
+
if (result.trackIdentifier && !mediaType.includes('audio')) {
|
|
1187
1168
|
this.statsResults.resolutions[mediaType][sendrecvType].trackIdentifier =
|
|
1188
1169
|
result.trackIdentifier;
|
|
1189
1170
|
|
|
@@ -1209,8 +1190,9 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
1209
1190
|
* @returns {void}
|
|
1210
1191
|
* @memberof StatsAnalyzer
|
|
1211
1192
|
*/
|
|
1212
|
-
|
|
1213
|
-
|
|
1193
|
+
compareSentAndReceived(result, type) {
|
|
1194
|
+
// Don't compare on transceivers without a sender.
|
|
1195
|
+
if (!type || !this.statsResults.internal[type].send) {
|
|
1214
1196
|
return;
|
|
1215
1197
|
}
|
|
1216
1198
|
|