@webex/plugin-meetings 3.0.0-beta.39 → 3.0.0-beta.391
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 +58 -8
- package/dist/annotation/annotation.types.js +7 -0
- package/dist/annotation/annotation.types.js.map +1 -0
- package/dist/annotation/constants.js +49 -0
- package/dist/annotation/constants.js.map +1 -0
- package/dist/annotation/index.js +342 -0
- package/dist/annotation/index.js.map +1 -0
- package/dist/breakouts/breakout.js +94 -15
- package/dist/breakouts/breakout.js.map +1 -1
- package/dist/breakouts/events.js +45 -0
- package/dist/breakouts/events.js.map +1 -0
- package/dist/breakouts/index.js +671 -81
- package/dist/breakouts/index.js.map +1 -1
- package/dist/breakouts/utils.js +45 -1
- package/dist/breakouts/utils.js.map +1 -1
- package/dist/common/errors/no-meeting-info.js +51 -0
- package/dist/common/errors/no-meeting-info.js.map +1 -0
- package/dist/common/errors/reclaim-host-role-errors.js +158 -0
- package/dist/common/errors/reclaim-host-role-errors.js.map +1 -0
- package/dist/common/errors/webex-errors.js +48 -7
- package/dist/common/errors/webex-errors.js.map +1 -1
- package/dist/common/logs/logger-proxy.js +1 -1
- package/dist/common/logs/logger-proxy.js.map +1 -1
- package/dist/common/logs/request.js +5 -1
- package/dist/common/logs/request.js.map +1 -1
- package/dist/common/queue.js +24 -9
- package/dist/common/queue.js.map +1 -1
- package/dist/config.js +5 -10
- package/dist/config.js.map +1 -1
- package/dist/constants.js +242 -33
- package/dist/constants.js.map +1 -1
- package/dist/controls-options-manager/enums.js +14 -2
- package/dist/controls-options-manager/enums.js.map +1 -1
- package/dist/controls-options-manager/index.js +109 -15
- 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 -18
- package/dist/controls-options-manager/util.js.map +1 -1
- package/dist/index.js +110 -2
- package/dist/index.js.map +1 -1
- package/dist/interceptors/index.js +15 -0
- package/dist/interceptors/index.js.map +1 -0
- package/dist/interceptors/locusRetry.js +93 -0
- package/dist/interceptors/locusRetry.js.map +1 -0
- package/dist/interpretation/collection.js +23 -0
- package/dist/interpretation/collection.js.map +1 -0
- package/dist/interpretation/index.js +380 -0
- package/dist/interpretation/index.js.map +1 -0
- package/dist/interpretation/siLanguage.js +25 -0
- package/dist/interpretation/siLanguage.js.map +1 -0
- package/dist/locus-info/controlsUtils.js +91 -2
- package/dist/locus-info/controlsUtils.js.map +1 -1
- package/dist/locus-info/index.js +386 -62
- package/dist/locus-info/index.js.map +1 -1
- package/dist/locus-info/infoUtils.js +7 -1
- package/dist/locus-info/infoUtils.js.map +1 -1
- package/dist/locus-info/mediaSharesUtils.js +71 -1
- package/dist/locus-info/mediaSharesUtils.js.map +1 -1
- package/dist/locus-info/parser.js +249 -72
- package/dist/locus-info/parser.js.map +1 -1
- package/dist/locus-info/selfUtils.js +89 -14
- package/dist/locus-info/selfUtils.js.map +1 -1
- package/dist/media/index.js +65 -102
- package/dist/media/index.js.map +1 -1
- package/dist/media/properties.js +73 -124
- package/dist/media/properties.js.map +1 -1
- package/dist/mediaQualityMetrics/config.js +135 -330
- package/dist/mediaQualityMetrics/config.js.map +1 -1
- package/dist/meeting/in-meeting-actions.js +86 -2
- package/dist/meeting/in-meeting-actions.js.map +1 -1
- package/dist/meeting/index.js +4075 -2827
- package/dist/meeting/index.js.map +1 -1
- package/dist/meeting/locusMediaRequest.js +292 -0
- package/dist/meeting/locusMediaRequest.js.map +1 -0
- package/dist/meeting/muteState.js +224 -136
- package/dist/meeting/muteState.js.map +1 -1
- package/dist/meeting/request.js +177 -152
- package/dist/meeting/request.js.map +1 -1
- package/dist/meeting/util.js +672 -417
- package/dist/meeting/util.js.map +1 -1
- package/dist/meeting-info/index.js +73 -7
- package/dist/meeting-info/index.js.map +1 -1
- package/dist/meeting-info/meeting-info-v2.js +192 -51
- package/dist/meeting-info/meeting-info-v2.js.map +1 -1
- package/dist/meeting-info/util.js +1 -1
- package/dist/meeting-info/util.js.map +1 -1
- package/dist/meeting-info/utilv2.js +36 -36
- package/dist/meeting-info/utilv2.js.map +1 -1
- package/dist/meetings/collection.js +39 -0
- package/dist/meetings/collection.js.map +1 -1
- package/dist/meetings/index.js +484 -119
- 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 +2 -0
- package/dist/meetings/request.js.map +1 -1
- package/dist/meetings/util.js +73 -7
- package/dist/meetings/util.js.map +1 -1
- package/dist/member/index.js +58 -0
- package/dist/member/index.js.map +1 -1
- package/dist/member/types.js +25 -0
- package/dist/member/types.js.map +1 -0
- package/dist/member/util.js +132 -25
- package/dist/member/util.js.map +1 -1
- package/dist/members/collection.js +10 -0
- package/dist/members/collection.js.map +1 -1
- package/dist/members/index.js +102 -6
- package/dist/members/index.js.map +1 -1
- package/dist/members/request.js +106 -38
- package/dist/members/request.js.map +1 -1
- package/dist/members/types.js +15 -0
- package/dist/members/types.js.map +1 -0
- package/dist/members/util.js +326 -232
- package/dist/members/util.js.map +1 -1
- package/dist/metrics/constants.js +18 -1
- package/dist/metrics/constants.js.map +1 -1
- package/dist/metrics/index.js +1 -446
- package/dist/metrics/index.js.map +1 -1
- package/dist/multistream/mediaRequestManager.js +223 -32
- package/dist/multistream/mediaRequestManager.js.map +1 -1
- package/dist/multistream/receiveSlot.js +10 -0
- package/dist/multistream/receiveSlot.js.map +1 -1
- package/dist/multistream/receiveSlotManager.js +39 -36
- package/dist/multistream/receiveSlotManager.js.map +1 -1
- package/dist/multistream/remoteMedia.js +3 -1
- package/dist/multistream/remoteMedia.js.map +1 -1
- package/dist/multistream/remoteMediaGroup.js +76 -5
- package/dist/multistream/remoteMediaGroup.js.map +1 -1
- package/dist/multistream/remoteMediaManager.js +366 -104
- package/dist/multistream/remoteMediaManager.js.map +1 -1
- package/dist/multistream/sendSlotManager.js +255 -0
- package/dist/multistream/sendSlotManager.js.map +1 -0
- package/dist/reachability/clusterReachability.js +356 -0
- package/dist/reachability/clusterReachability.js.map +1 -0
- package/dist/reachability/index.js +263 -390
- package/dist/reachability/index.js.map +1 -1
- package/dist/reachability/request.js +6 -4
- package/dist/reachability/request.js.map +1 -1
- package/dist/reachability/util.js +29 -0
- package/dist/reachability/util.js.map +1 -0
- package/dist/reconnection-manager/index.js +266 -202
- package/dist/reconnection-manager/index.js.map +1 -1
- package/dist/recording-controller/index.js +21 -2
- package/dist/recording-controller/index.js.map +1 -1
- package/dist/recording-controller/util.js +9 -8
- package/dist/recording-controller/util.js.map +1 -1
- package/dist/roap/index.js +51 -28
- package/dist/roap/index.js.map +1 -1
- package/dist/roap/request.js +48 -64
- package/dist/roap/request.js.map +1 -1
- package/dist/roap/turnDiscovery.js +220 -70
- package/dist/roap/turnDiscovery.js.map +1 -1
- package/dist/rtcMetrics/constants.js +12 -0
- package/dist/rtcMetrics/constants.js.map +1 -0
- package/dist/rtcMetrics/index.js +179 -0
- package/dist/rtcMetrics/index.js.map +1 -0
- package/dist/statsAnalyzer/index.js +357 -295
- package/dist/statsAnalyzer/index.js.map +1 -1
- package/dist/statsAnalyzer/mqaUtil.js +296 -156
- package/dist/statsAnalyzer/mqaUtil.js.map +1 -1
- package/dist/types/annotation/annotation.types.d.ts +42 -0
- package/dist/types/annotation/constants.d.ts +31 -0
- package/dist/types/annotation/index.d.ts +117 -0
- package/dist/types/breakouts/events.d.ts +8 -0
- package/dist/types/breakouts/utils.d.ts +14 -0
- package/dist/types/common/errors/no-meeting-info.d.ts +14 -0
- package/dist/types/common/errors/reclaim-host-role-errors.d.ts +60 -0
- package/dist/types/common/errors/webex-errors.d.ts +25 -1
- package/dist/types/common/logs/request.d.ts +2 -0
- package/dist/types/common/queue.d.ts +9 -7
- package/dist/types/config.d.ts +2 -7
- package/dist/types/constants.d.ts +203 -31
- package/dist/types/controls-options-manager/enums.d.ts +11 -1
- package/dist/types/controls-options-manager/index.d.ts +17 -1
- package/dist/types/controls-options-manager/types.d.ts +43 -0
- package/dist/types/controls-options-manager/util.d.ts +1 -7
- package/dist/types/index.d.ts +6 -5
- package/dist/types/interceptors/index.d.ts +2 -0
- package/dist/types/interceptors/locusRetry.d.ts +27 -0
- package/dist/types/interpretation/collection.d.ts +5 -0
- package/dist/types/interpretation/index.d.ts +5 -0
- package/dist/types/interpretation/siLanguage.d.ts +5 -0
- package/dist/types/locus-info/index.d.ts +57 -4
- package/dist/types/locus-info/parser.d.ts +66 -6
- package/dist/types/media/index.d.ts +2 -0
- package/dist/types/media/properties.d.ts +34 -49
- package/dist/types/mediaQualityMetrics/config.d.ts +99 -223
- package/dist/types/meeting/in-meeting-actions.d.ts +86 -2
- package/dist/types/meeting/index.d.ts +567 -496
- package/dist/types/meeting/locusMediaRequest.d.ts +74 -0
- package/dist/types/meeting/muteState.d.ts +93 -25
- package/dist/types/meeting/request.d.ts +64 -43
- package/dist/types/meeting/util.d.ts +117 -1
- package/dist/types/meeting-info/index.d.ts +13 -1
- package/dist/types/meeting-info/meeting-info-v2.d.ts +31 -1
- package/dist/types/meetings/collection.d.ts +17 -0
- package/dist/types/meetings/index.d.ts +113 -21
- package/dist/types/meetings/meetings.types.d.ts +4 -0
- package/dist/types/member/index.d.ts +14 -0
- package/dist/types/member/types.d.ts +32 -0
- package/dist/types/members/collection.d.ts +5 -0
- package/dist/types/members/index.d.ts +35 -2
- package/dist/types/members/request.d.ts +73 -9
- package/dist/types/members/types.d.ts +25 -0
- package/dist/types/members/util.d.ts +214 -1
- package/dist/types/metrics/constants.d.ts +17 -0
- package/dist/types/metrics/index.d.ts +4 -111
- package/dist/types/multistream/mediaRequestManager.d.ts +72 -3
- package/dist/types/multistream/receiveSlot.d.ts +7 -3
- package/dist/types/multistream/receiveSlotManager.d.ts +14 -4
- package/dist/types/multistream/remoteMedia.d.ts +3 -31
- package/dist/types/multistream/remoteMediaGroup.d.ts +2 -9
- package/dist/types/multistream/remoteMediaManager.d.ts +62 -2
- package/dist/types/multistream/sendSlotManager.d.ts +70 -0
- package/dist/types/reachability/clusterReachability.d.ts +109 -0
- package/dist/types/reachability/index.d.ts +60 -95
- package/dist/types/reachability/request.d.ts +3 -1
- package/dist/types/reachability/util.d.ts +8 -0
- package/dist/types/reconnection-manager/index.d.ts +19 -0
- package/dist/types/recording-controller/index.d.ts +15 -1
- package/dist/types/recording-controller/util.d.ts +5 -4
- package/dist/types/roap/index.d.ts +2 -1
- package/dist/types/roap/request.d.ts +9 -8
- package/dist/types/roap/turnDiscovery.d.ts +39 -5
- package/dist/types/rtcMetrics/constants.d.ts +4 -0
- package/dist/types/rtcMetrics/index.d.ts +61 -0
- package/dist/types/statsAnalyzer/index.d.ts +34 -12
- package/dist/types/statsAnalyzer/mqaUtil.d.ts +28 -4
- package/dist/types/webinar/collection.d.ts +16 -0
- package/dist/types/webinar/index.d.ts +5 -0
- package/dist/webinar/collection.js +44 -0
- package/dist/webinar/collection.js.map +1 -0
- package/dist/webinar/index.js +69 -0
- package/dist/webinar/index.js.map +1 -0
- package/package.json +22 -19
- 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 +35 -11
- package/src/breakouts/breakout.ts +67 -9
- package/src/breakouts/events.ts +56 -0
- package/src/breakouts/index.ts +558 -59
- package/src/breakouts/utils.ts +42 -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 +44 -2
- 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 +4 -9
- package/src/constants.ts +229 -21
- package/src/controls-options-manager/enums.ts +12 -0
- 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 +44 -0
- package/src/interceptors/index.ts +3 -0
- package/src/interceptors/locusRetry.ts +67 -0
- package/src/interpretation/README.md +60 -0
- package/src/interpretation/collection.ts +19 -0
- package/src/interpretation/index.ts +349 -0
- package/src/interpretation/siLanguage.ts +18 -0
- package/src/locus-info/controlsUtils.ts +108 -0
- package/src/locus-info/index.ts +417 -59
- package/src/locus-info/infoUtils.ts +10 -2
- package/src/locus-info/mediaSharesUtils.ts +80 -0
- package/src/locus-info/parser.ts +258 -47
- package/src/locus-info/selfUtils.ts +81 -5
- package/src/media/index.ts +100 -108
- package/src/media/properties.ts +88 -117
- package/src/mediaQualityMetrics/config.ts +103 -238
- package/src/meeting/in-meeting-actions.ts +171 -3
- package/src/meeting/index.ts +3411 -2435
- package/src/meeting/locusMediaRequest.ts +313 -0
- package/src/meeting/muteState.ts +223 -136
- package/src/meeting/request.ts +155 -120
- package/src/meeting/util.ts +685 -395
- package/src/meeting-info/index.ts +81 -8
- package/src/meeting-info/meeting-info-v2.ts +170 -14
- package/src/meeting-info/util.ts +1 -1
- package/src/meeting-info/utilv2.ts +23 -23
- package/src/meetings/collection.ts +33 -0
- package/src/meetings/index.ts +507 -127
- package/src/meetings/meetings.types.ts +12 -0
- package/src/meetings/request.ts +2 -0
- package/src/meetings/util.ts +81 -12
- package/src/member/index.ts +58 -0
- package/src/member/types.ts +38 -0
- package/src/member/util.ts +141 -25
- package/src/members/collection.ts +8 -0
- package/src/members/index.ts +134 -8
- 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 +17 -0
- package/src/metrics/index.ts +1 -469
- package/src/multistream/mediaRequestManager.ts +271 -56
- package/src/multistream/receiveSlot.ts +11 -4
- package/src/multistream/receiveSlotManager.ts +34 -24
- package/src/multistream/remoteMedia.ts +5 -3
- package/src/multistream/remoteMediaGroup.ts +78 -0
- package/src/multistream/remoteMediaManager.ts +248 -44
- package/src/multistream/sendSlotManager.ts +199 -0
- package/src/reachability/clusterReachability.ts +320 -0
- package/src/reachability/index.ts +229 -346
- package/src/reachability/request.ts +8 -4
- package/src/reachability/util.ts +24 -0
- package/src/reconnection-manager/index.ts +128 -97
- package/src/recording-controller/index.ts +20 -3
- package/src/recording-controller/util.ts +26 -9
- package/src/roap/index.ts +52 -23
- package/src/roap/request.ts +48 -67
- package/src/roap/turnDiscovery.ts +147 -49
- package/src/rtcMetrics/constants.ts +3 -0
- package/src/rtcMetrics/index.ts +166 -0
- package/src/statsAnalyzer/index.ts +457 -416
- package/src/statsAnalyzer/mqaUtil.ts +317 -170
- package/src/webinar/collection.ts +31 -0
- package/src/webinar/index.ts +62 -0
- package/test/integration/spec/converged-space-meetings.js +60 -3
- package/test/integration/spec/journey.js +320 -261
- package/test/integration/spec/space-meeting.js +76 -3
- package/test/unit/spec/annotation/index.ts +418 -0
- package/test/unit/spec/breakouts/breakout.ts +118 -28
- package/test/unit/spec/breakouts/events.ts +89 -0
- package/test/unit/spec/breakouts/index.ts +1349 -114
- package/test/unit/spec/breakouts/utils.js +52 -1
- 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/interceptors/locusRetry.ts +131 -0
- package/test/unit/spec/interpretation/collection.ts +15 -0
- package/test/unit/spec/interpretation/index.ts +625 -0
- package/test/unit/spec/interpretation/siLanguage.ts +28 -0
- package/test/unit/spec/locus-info/controlsUtils.js +316 -43
- package/test/unit/spec/locus-info/index.js +1363 -37
- package/test/unit/spec/locus-info/infoUtils.js +37 -15
- package/test/unit/spec/locus-info/lib/SeqCmp.json +16 -0
- package/test/unit/spec/locus-info/mediaSharesUtils.ts +41 -0
- package/test/unit/spec/locus-info/parser.js +116 -35
- package/test/unit/spec/locus-info/selfConstant.js +27 -4
- package/test/unit/spec/locus-info/selfUtils.js +208 -17
- package/test/unit/spec/media/index.ts +173 -81
- package/test/unit/spec/media/properties.ts +2 -2
- package/test/unit/spec/meeting/in-meeting-actions.ts +85 -3
- package/test/unit/spec/meeting/index.js +6821 -2172
- package/test/unit/spec/meeting/locusMediaRequest.ts +442 -0
- package/test/unit/spec/meeting/muteState.js +402 -212
- package/test/unit/spec/meeting/request.js +473 -54
- package/test/unit/spec/meeting/utils.js +773 -67
- package/test/unit/spec/meeting-info/index.js +300 -0
- package/test/unit/spec/meeting-info/meetinginfov2.js +526 -5
- package/test/unit/spec/meeting-info/utilv2.js +21 -0
- package/test/unit/spec/meetings/collection.js +26 -0
- package/test/unit/spec/meetings/index.js +1415 -213
- package/test/unit/spec/meetings/utils.js +229 -2
- package/test/unit/spec/member/index.js +61 -6
- package/test/unit/spec/member/util.js +510 -34
- package/test/unit/spec/members/index.js +432 -1
- 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 +781 -114
- package/test/unit/spec/multistream/receiveSlot.ts +9 -1
- package/test/unit/spec/multistream/receiveSlotManager.ts +32 -30
- package/test/unit/spec/multistream/remoteMedia.ts +2 -0
- package/test/unit/spec/multistream/remoteMediaGroup.ts +345 -0
- package/test/unit/spec/multistream/remoteMediaManager.ts +525 -0
- package/test/unit/spec/multistream/sendSlotManager.ts +274 -0
- package/test/unit/spec/reachability/clusterReachability.ts +279 -0
- package/test/unit/spec/reachability/index.ts +551 -14
- package/test/unit/spec/reachability/request.js +3 -1
- package/test/unit/spec/reachability/util.ts +40 -0
- package/test/unit/spec/reconnection-manager/index.js +171 -11
- package/test/unit/spec/recording-controller/index.js +294 -218
- package/test/unit/spec/recording-controller/util.js +223 -96
- package/test/unit/spec/roap/index.ts +180 -83
- package/test/unit/spec/roap/request.ts +100 -62
- package/test/unit/spec/roap/turnDiscovery.ts +388 -96
- package/test/unit/spec/rtcMetrics/index.ts +122 -0
- package/test/unit/spec/stats-analyzer/index.js +1252 -12
- package/test/unit/spec/webinar/collection.ts +13 -0
- package/test/unit/spec/webinar/index.ts +60 -0
- package/test/utils/integrationTestUtils.js +46 -0
- package/test/utils/testUtils.js +0 -57
- package/test/utils/webex-test-users.js +12 -4
- package/dist/metrics/config.js +0 -289
- package/dist/metrics/config.js.map +0 -1
- package/dist/types/metrics/config.d.ts +0 -169
- package/src/index.js +0 -18
- package/src/metrics/config.ts +0 -485
|
@@ -7,6 +7,9 @@ import {ConnectionState} from '@webex/internal-media-core';
|
|
|
7
7
|
import {StatsAnalyzer, EVENTS} from '../../../../src/statsAnalyzer';
|
|
8
8
|
import NetworkQualityMonitor from '../../../../src/networkQualityMonitor';
|
|
9
9
|
import testUtils from '../../../utils/testUtils';
|
|
10
|
+
import {MEDIA_DEVICES, MQA_INTERVAL, _UNKNOWN_} from '@webex/plugin-meetings/src/constants';
|
|
11
|
+
import LoggerProxy from '../../../../src/common/logs/logger-proxy';
|
|
12
|
+
import LoggerConfig from '../../../../src/common/logs/logger-config';
|
|
10
13
|
|
|
11
14
|
const {assert} = chai;
|
|
12
15
|
|
|
@@ -15,6 +18,186 @@ sinon.assert.expose(chai.assert, {prefix: ''});
|
|
|
15
18
|
|
|
16
19
|
describe('plugin-meetings', () => {
|
|
17
20
|
describe('StatsAnalyzer', () => {
|
|
21
|
+
describe('parseStatsResult', () => {
|
|
22
|
+
const sandbox = sinon.createSandbox();
|
|
23
|
+
let statsAnalyzer;
|
|
24
|
+
|
|
25
|
+
const initialConfig = {};
|
|
26
|
+
const defaultStats = {};
|
|
27
|
+
|
|
28
|
+
beforeEach(() => {
|
|
29
|
+
const networkQualityMonitor = new NetworkQualityMonitor(initialConfig);
|
|
30
|
+
|
|
31
|
+
statsAnalyzer = new StatsAnalyzer(
|
|
32
|
+
initialConfig,
|
|
33
|
+
() => ({}),
|
|
34
|
+
networkQualityMonitor,
|
|
35
|
+
defaultStats
|
|
36
|
+
);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
afterEach(() => {
|
|
40
|
+
sandbox.reset();
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('should call processOutboundRTPResult', () => {
|
|
44
|
+
const calledSpy = sandbox.spy(statsAnalyzer, 'processOutboundRTPResult');
|
|
45
|
+
statsAnalyzer.parseGetStatsResult({type: 'outbound-rtp'}, 'video-send');
|
|
46
|
+
assert(calledSpy.calledOnce);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('should call processInboundRTPResult', () => {
|
|
50
|
+
const calledSpy = sandbox.spy(statsAnalyzer, 'processInboundRTPResult');
|
|
51
|
+
statsAnalyzer.parseGetStatsResult({type: 'inbound-rtp'}, 'video-recv');
|
|
52
|
+
assert(calledSpy.calledOnce);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('should call compareSentAndReceived', () => {
|
|
56
|
+
const calledSpy = sandbox.spy(statsAnalyzer, 'compareSentAndReceived');
|
|
57
|
+
statsAnalyzer.parseGetStatsResult({type: 'remote-outbound-rtp'}, 'video-send');
|
|
58
|
+
assert(calledSpy.calledOnce);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('should call parseCandidate', () => {
|
|
62
|
+
const calledSpy = sandbox.spy(statsAnalyzer, 'parseCandidate');
|
|
63
|
+
statsAnalyzer.parseGetStatsResult({type: 'local-candidate'}, 'video-send');
|
|
64
|
+
assert(calledSpy.calledOnce);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('processOutboundRTPResult should create the correct stats results', () => {
|
|
68
|
+
// establish the `statsResults` object.
|
|
69
|
+
statsAnalyzer.parseGetStatsResult({type: 'none'}, 'audio-send', true);
|
|
70
|
+
|
|
71
|
+
statsAnalyzer.processOutboundRTPResult(
|
|
72
|
+
{
|
|
73
|
+
bytesSent: 50000,
|
|
74
|
+
codecId: 'RTCCodec_1_Outbound_111',
|
|
75
|
+
headerBytesSent: 25000,
|
|
76
|
+
id: 'RTCOutboundRTPAudioStream_123456789',
|
|
77
|
+
kind: 'audio',
|
|
78
|
+
mediaSourceId: 'RTCAudioSource_2',
|
|
79
|
+
mediaType: 'audio',
|
|
80
|
+
nackCount: 1,
|
|
81
|
+
packetsSent: 3600,
|
|
82
|
+
remoteId: 'RTCRemoteInboundRtpAudioStream_123456789',
|
|
83
|
+
retransmittedBytesSent: 100,
|
|
84
|
+
retransmittedPacketsSent: 2,
|
|
85
|
+
ssrc: 123456789,
|
|
86
|
+
targetBitrate: 256000,
|
|
87
|
+
timestamp: 1707341489336,
|
|
88
|
+
trackId: 'RTCMediaStreamTrack_sender_2',
|
|
89
|
+
transportId: 'RTCTransport_0_1',
|
|
90
|
+
type: 'outbound-rtp',
|
|
91
|
+
},
|
|
92
|
+
'audio-send',
|
|
93
|
+
true
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
assert.strictEqual(statsAnalyzer.statsResults['audio-send'].send.headerBytesSent, 25000);
|
|
97
|
+
assert.strictEqual(statsAnalyzer.statsResults['audio-send'].send.totalBytesSent, 50000);
|
|
98
|
+
assert.strictEqual(statsAnalyzer.statsResults['audio-send'].send.totalNackCount, 1);
|
|
99
|
+
assert.strictEqual(statsAnalyzer.statsResults['audio-send'].send.totalPacketsSent, 3600);
|
|
100
|
+
assert.strictEqual(
|
|
101
|
+
statsAnalyzer.statsResults['audio-send'].send.retransmittedPacketsSent,
|
|
102
|
+
2
|
|
103
|
+
);
|
|
104
|
+
assert.strictEqual(
|
|
105
|
+
statsAnalyzer.statsResults['audio-send'].send.retransmittedBytesSent,
|
|
106
|
+
100
|
|
107
|
+
);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it('processInboundRTPResult should create the correct stats results', () => {
|
|
111
|
+
// establish the `statsResults` object.
|
|
112
|
+
statsAnalyzer.parseGetStatsResult({type: 'none'}, 'audio-recv-1', false);
|
|
113
|
+
|
|
114
|
+
statsAnalyzer.processInboundRTPResult(
|
|
115
|
+
{
|
|
116
|
+
audioLevel: 0,
|
|
117
|
+
bytesReceived: 509,
|
|
118
|
+
codecId: 'RTCCodec_6_Inbound_111',
|
|
119
|
+
concealedSamples: 200000,
|
|
120
|
+
concealmentEvents: 13,
|
|
121
|
+
fecPacketsDiscarded: 1,
|
|
122
|
+
fecPacketsReceived: 1,
|
|
123
|
+
headerBytesReceived: 250,
|
|
124
|
+
id: 'RTCInboundRTPAudioStream_123456789',
|
|
125
|
+
insertedSamplesForDeceleration: 0,
|
|
126
|
+
jitter: 0.012,
|
|
127
|
+
jitterBufferDelay: 1000,
|
|
128
|
+
jitterBufferEmittedCount: 10000,
|
|
129
|
+
kind: 'audio',
|
|
130
|
+
lastPacketReceivedTimestamp: 1707341488529,
|
|
131
|
+
mediaType: 'audio',
|
|
132
|
+
packetsDiscarded: 0,
|
|
133
|
+
packetsLost: 0,
|
|
134
|
+
packetsReceived: 12,
|
|
135
|
+
remoteId: 'RTCRemoteOutboundRTPAudioStream_123456789',
|
|
136
|
+
removedSamplesForAcceleration: 0,
|
|
137
|
+
silentConcealedSamples: 200000,
|
|
138
|
+
ssrc: 123456789,
|
|
139
|
+
timestamp: 1707341489419,
|
|
140
|
+
totalAudioEnergy: 133,
|
|
141
|
+
totalSamplesDuration: 7,
|
|
142
|
+
totalSamplesReceived: 300000,
|
|
143
|
+
trackId: 'RTCMediaStreamTrack_receiver_76',
|
|
144
|
+
transportId: 'RTCTransport_0_1',
|
|
145
|
+
type: 'inbound-rtp',
|
|
146
|
+
},
|
|
147
|
+
'audio-recv-1',
|
|
148
|
+
false
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
assert.strictEqual(
|
|
152
|
+
statsAnalyzer.statsResults['audio-recv-1'].recv.totalPacketsReceived,
|
|
153
|
+
12
|
|
154
|
+
);
|
|
155
|
+
assert.strictEqual(statsAnalyzer.statsResults['audio-recv-1'].recv.fecPacketsDiscarded, 1);
|
|
156
|
+
assert.strictEqual(statsAnalyzer.statsResults['audio-recv-1'].recv.fecPacketsReceived, 1);
|
|
157
|
+
assert.strictEqual(statsAnalyzer.statsResults['audio-recv-1'].recv.totalBytesReceived, 509);
|
|
158
|
+
assert.strictEqual(
|
|
159
|
+
statsAnalyzer.statsResults['audio-recv-1'].recv.headerBytesReceived,
|
|
160
|
+
250
|
|
161
|
+
);
|
|
162
|
+
assert.strictEqual(statsAnalyzer.statsResults['audio-recv-1'].recv.audioLevel, 0);
|
|
163
|
+
assert.strictEqual(statsAnalyzer.statsResults['audio-recv-1'].recv.totalAudioEnergy, 133);
|
|
164
|
+
assert.strictEqual(
|
|
165
|
+
statsAnalyzer.statsResults['audio-recv-1'].recv.totalSamplesReceived,
|
|
166
|
+
300000
|
|
167
|
+
);
|
|
168
|
+
assert.strictEqual(statsAnalyzer.statsResults['audio-recv-1'].recv.totalSamplesDecoded, 0);
|
|
169
|
+
assert.strictEqual(
|
|
170
|
+
statsAnalyzer.statsResults['audio-recv-1'].recv.concealedSamples,
|
|
171
|
+
200000
|
|
172
|
+
);
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
it('parseAudioSource should create the correct stats results', () => {
|
|
176
|
+
// establish the `statsResults` object.
|
|
177
|
+
statsAnalyzer.parseGetStatsResult({type: 'none'}, 'audio-send', true);
|
|
178
|
+
|
|
179
|
+
statsAnalyzer.parseAudioSource(
|
|
180
|
+
{
|
|
181
|
+
audioLevel: 0.03,
|
|
182
|
+
echoReturnLoss: -30,
|
|
183
|
+
echoReturnLossEnhancement: 0.17,
|
|
184
|
+
id: 'RTCAudioSource_2',
|
|
185
|
+
kind: 'audio',
|
|
186
|
+
timestamp: 1707341488160.012,
|
|
187
|
+
totalAudioEnergy: 0.001,
|
|
188
|
+
totalSamplesDuration: 4.5,
|
|
189
|
+
trackIdentifier: '2207e5bf-c595-4301-93f7-283994d8143f',
|
|
190
|
+
type: 'media-source',
|
|
191
|
+
},
|
|
192
|
+
'audio-send',
|
|
193
|
+
true
|
|
194
|
+
);
|
|
195
|
+
|
|
196
|
+
assert.strictEqual(statsAnalyzer.statsResults['audio-send'].send.audioLevel, 0.03);
|
|
197
|
+
assert.strictEqual(statsAnalyzer.statsResults['audio-send'].send.totalAudioEnergy, 0.001);
|
|
198
|
+
});
|
|
199
|
+
});
|
|
200
|
+
|
|
18
201
|
describe('compareSentAndReceived()', () => {
|
|
19
202
|
let statsAnalyzer;
|
|
20
203
|
let sandBoxSpy;
|
|
@@ -53,7 +236,12 @@ describe('plugin-meetings', () => {
|
|
|
53
236
|
beforeEach(() => {
|
|
54
237
|
const networkQualityMonitor = new NetworkQualityMonitor(initialConfig);
|
|
55
238
|
|
|
56
|
-
statsAnalyzer = new StatsAnalyzer(
|
|
239
|
+
statsAnalyzer = new StatsAnalyzer(
|
|
240
|
+
initialConfig,
|
|
241
|
+
() => ({}),
|
|
242
|
+
networkQualityMonitor,
|
|
243
|
+
defaultStats
|
|
244
|
+
);
|
|
57
245
|
|
|
58
246
|
sandBoxSpy = sandbox.spy(
|
|
59
247
|
statsAnalyzer.networkQualityMonitor,
|
|
@@ -84,6 +272,9 @@ describe('plugin-meetings', () => {
|
|
|
84
272
|
let pc;
|
|
85
273
|
let networkQualityMonitor;
|
|
86
274
|
let statsAnalyzer;
|
|
275
|
+
let mqeData;
|
|
276
|
+
let loggerSpy;
|
|
277
|
+
let receiveSlot;
|
|
87
278
|
|
|
88
279
|
let receivedEventsData = {
|
|
89
280
|
local: {},
|
|
@@ -96,6 +287,8 @@ describe('plugin-meetings', () => {
|
|
|
96
287
|
|
|
97
288
|
let fakeStats;
|
|
98
289
|
|
|
290
|
+
const sandbox = sinon.createSandbox();
|
|
291
|
+
|
|
99
292
|
const resetReceivedEvents = () => {
|
|
100
293
|
receivedEventsData = {
|
|
101
294
|
local: {},
|
|
@@ -103,8 +296,15 @@ describe('plugin-meetings', () => {
|
|
|
103
296
|
};
|
|
104
297
|
};
|
|
105
298
|
|
|
299
|
+
before(() => {
|
|
300
|
+
LoggerConfig.set({enable: false});
|
|
301
|
+
LoggerProxy.set();
|
|
302
|
+
loggerSpy = sandbox.spy(LoggerProxy.logger, 'info');
|
|
303
|
+
});
|
|
304
|
+
|
|
106
305
|
beforeEach(() => {
|
|
107
306
|
clock = sinon.useFakeTimers();
|
|
307
|
+
receiveSlot = undefined;
|
|
108
308
|
|
|
109
309
|
resetReceivedEvents();
|
|
110
310
|
|
|
@@ -113,11 +313,31 @@ describe('plugin-meetings', () => {
|
|
|
113
313
|
audio: {
|
|
114
314
|
senders: [
|
|
115
315
|
{
|
|
316
|
+
localTrackLabel: 'fake-microphone',
|
|
116
317
|
report: [
|
|
117
318
|
{
|
|
118
319
|
type: 'outbound-rtp',
|
|
119
|
-
packetsSent: 0,
|
|
120
320
|
bytesSent: 1,
|
|
321
|
+
packetsSent: 0,
|
|
322
|
+
},
|
|
323
|
+
{
|
|
324
|
+
type: 'remote-inbound-rtp',
|
|
325
|
+
packetsLost: 0,
|
|
326
|
+
},
|
|
327
|
+
{
|
|
328
|
+
type: 'candidate-pair',
|
|
329
|
+
state: 'succeeded',
|
|
330
|
+
localCandidateId: 'fake-candidate-id',
|
|
331
|
+
},
|
|
332
|
+
{
|
|
333
|
+
type: 'candidate-pair',
|
|
334
|
+
state: 'failed',
|
|
335
|
+
localCandidateId: 'bad-candidate-id',
|
|
336
|
+
},
|
|
337
|
+
{
|
|
338
|
+
type: 'local-candidate',
|
|
339
|
+
id: 'fake-candidate-id',
|
|
340
|
+
protocol: 'tcp',
|
|
121
341
|
},
|
|
122
342
|
],
|
|
123
343
|
},
|
|
@@ -127,8 +347,29 @@ describe('plugin-meetings', () => {
|
|
|
127
347
|
report: [
|
|
128
348
|
{
|
|
129
349
|
type: 'inbound-rtp',
|
|
130
|
-
packetsReceived: 0,
|
|
131
350
|
bytesReceived: 1,
|
|
351
|
+
fecPacketsDiscarded: 0,
|
|
352
|
+
fecPacketsReceived: 0,
|
|
353
|
+
packetsLost: 0,
|
|
354
|
+
packetsReceived: 0,
|
|
355
|
+
},
|
|
356
|
+
{
|
|
357
|
+
type: 'remote-outbound-rtp',
|
|
358
|
+
},
|
|
359
|
+
{
|
|
360
|
+
type: 'candidate-pair',
|
|
361
|
+
state: 'succeeded',
|
|
362
|
+
localCandidateId: 'fake-candidate-id',
|
|
363
|
+
},
|
|
364
|
+
{
|
|
365
|
+
type: 'candidate-pair',
|
|
366
|
+
state: 'failed',
|
|
367
|
+
localCandidateId: 'bad-candidate-id',
|
|
368
|
+
},
|
|
369
|
+
{
|
|
370
|
+
type: 'local-candidate',
|
|
371
|
+
id: 'fake-candidate-id',
|
|
372
|
+
protocol: 'tcp',
|
|
132
373
|
},
|
|
133
374
|
],
|
|
134
375
|
},
|
|
@@ -137,11 +378,32 @@ describe('plugin-meetings', () => {
|
|
|
137
378
|
video: {
|
|
138
379
|
senders: [
|
|
139
380
|
{
|
|
381
|
+
localTrackLabel: 'fake-camera',
|
|
140
382
|
report: [
|
|
141
383
|
{
|
|
142
384
|
type: 'outbound-rtp',
|
|
143
|
-
framesSent: 0,
|
|
144
385
|
bytesSent: 1,
|
|
386
|
+
framesSent: 0,
|
|
387
|
+
packetsSent: 0,
|
|
388
|
+
},
|
|
389
|
+
{
|
|
390
|
+
type: 'remote-inbound-rtp',
|
|
391
|
+
packetsLost: 0,
|
|
392
|
+
},
|
|
393
|
+
{
|
|
394
|
+
type: 'candidate-pair',
|
|
395
|
+
state: 'succeeded',
|
|
396
|
+
localCandidateId: 'fake-candidate-id',
|
|
397
|
+
},
|
|
398
|
+
{
|
|
399
|
+
type: 'candidate-pair',
|
|
400
|
+
state: 'failed',
|
|
401
|
+
localCandidateId: 'bad-candidate-id',
|
|
402
|
+
},
|
|
403
|
+
{
|
|
404
|
+
type: 'local-candidate',
|
|
405
|
+
id: 'fake-candidate-id',
|
|
406
|
+
protocol: 'tcp',
|
|
145
407
|
},
|
|
146
408
|
],
|
|
147
409
|
},
|
|
@@ -151,8 +413,99 @@ describe('plugin-meetings', () => {
|
|
|
151
413
|
report: [
|
|
152
414
|
{
|
|
153
415
|
type: 'inbound-rtp',
|
|
416
|
+
bytesReceived: 1,
|
|
417
|
+
frameHeight: 720,
|
|
418
|
+
frameWidth: 1280,
|
|
154
419
|
framesDecoded: 0,
|
|
420
|
+
framesReceived: 0,
|
|
421
|
+
packetsLost: 0,
|
|
422
|
+
packetsReceived: 0,
|
|
423
|
+
},
|
|
424
|
+
{
|
|
425
|
+
type: 'remote-outbound-rtp',
|
|
426
|
+
},
|
|
427
|
+
{
|
|
428
|
+
type: 'candidate-pair',
|
|
429
|
+
state: 'succeeded',
|
|
430
|
+
localCandidateId: 'fake-candidate-id',
|
|
431
|
+
},
|
|
432
|
+
{
|
|
433
|
+
type: 'candidate-pair',
|
|
434
|
+
state: 'failed',
|
|
435
|
+
localCandidateId: 'bad-candidate-id',
|
|
436
|
+
},
|
|
437
|
+
{
|
|
438
|
+
type: 'local-candidate',
|
|
439
|
+
id: 'fake-candidate-id',
|
|
440
|
+
protocol: 'tcp',
|
|
441
|
+
},
|
|
442
|
+
],
|
|
443
|
+
},
|
|
444
|
+
],
|
|
445
|
+
},
|
|
446
|
+
share: {
|
|
447
|
+
senders: [
|
|
448
|
+
{
|
|
449
|
+
localTrackLabel: 'fake-share',
|
|
450
|
+
report: [
|
|
451
|
+
{
|
|
452
|
+
type: 'outbound-rtp',
|
|
453
|
+
bytesSent: 1,
|
|
454
|
+
framesSent: 0,
|
|
455
|
+
packetsSent: 0,
|
|
456
|
+
},
|
|
457
|
+
{
|
|
458
|
+
type: 'remote-inbound-rtp',
|
|
459
|
+
packetsLost: 0,
|
|
460
|
+
},
|
|
461
|
+
{
|
|
462
|
+
type: 'candidate-pair',
|
|
463
|
+
state: 'succeeded',
|
|
464
|
+
localCandidateId: 'fake-candidate-id',
|
|
465
|
+
},
|
|
466
|
+
{
|
|
467
|
+
type: 'candidate-pair',
|
|
468
|
+
state: 'failed',
|
|
469
|
+
localCandidateId: 'bad-candidate-id',
|
|
470
|
+
},
|
|
471
|
+
{
|
|
472
|
+
type: 'local-candidate',
|
|
473
|
+
id: 'fake-candidate-id',
|
|
474
|
+
protocol: 'tcp',
|
|
475
|
+
},
|
|
476
|
+
],
|
|
477
|
+
},
|
|
478
|
+
],
|
|
479
|
+
receivers: [
|
|
480
|
+
{
|
|
481
|
+
report: [
|
|
482
|
+
{
|
|
483
|
+
type: 'inbound-rtp',
|
|
155
484
|
bytesReceived: 1,
|
|
485
|
+
frameHeight: 720,
|
|
486
|
+
frameWidth: 1280,
|
|
487
|
+
framesDecoded: 0,
|
|
488
|
+
framesReceived: 0,
|
|
489
|
+
packetsLost: 0,
|
|
490
|
+
packetsReceived: 0,
|
|
491
|
+
},
|
|
492
|
+
{
|
|
493
|
+
type: 'remote-outbound-rtp',
|
|
494
|
+
},
|
|
495
|
+
{
|
|
496
|
+
type: 'candidate-pair',
|
|
497
|
+
state: 'succeeded',
|
|
498
|
+
localCandidateId: 'fake-candidate-id',
|
|
499
|
+
},
|
|
500
|
+
{
|
|
501
|
+
type: 'candidate-pair',
|
|
502
|
+
state: 'failed',
|
|
503
|
+
localCandidateId: 'bad-candidate-id',
|
|
504
|
+
},
|
|
505
|
+
{
|
|
506
|
+
type: 'local-candidate',
|
|
507
|
+
id: 'fake-candidate-id',
|
|
508
|
+
protocol: 'tcp',
|
|
156
509
|
},
|
|
157
510
|
],
|
|
158
511
|
},
|
|
@@ -172,19 +525,19 @@ describe('plugin-meetings', () => {
|
|
|
172
525
|
receivers: [fakeStats.video.receivers[0]],
|
|
173
526
|
},
|
|
174
527
|
screenShareAudio: {
|
|
175
|
-
senders: [],
|
|
176
|
-
receivers: [],
|
|
528
|
+
senders: [fakeStats.audio.senders[0]],
|
|
529
|
+
receivers: [fakeStats.audio.receivers[0]],
|
|
177
530
|
},
|
|
178
531
|
screenShareVideo: {
|
|
179
|
-
senders: [],
|
|
180
|
-
receivers: [],
|
|
532
|
+
senders: [fakeStats.share.senders[0]],
|
|
533
|
+
receivers: [fakeStats.share.receivers[0]],
|
|
181
534
|
},
|
|
182
535
|
}),
|
|
183
536
|
};
|
|
184
537
|
|
|
185
538
|
networkQualityMonitor = new NetworkQualityMonitor(initialConfig);
|
|
186
539
|
|
|
187
|
-
statsAnalyzer = new StatsAnalyzer(initialConfig, networkQualityMonitor);
|
|
540
|
+
statsAnalyzer = new StatsAnalyzer(initialConfig, () => receiveSlot, networkQualityMonitor);
|
|
188
541
|
|
|
189
542
|
statsAnalyzer.on(EVENTS.LOCAL_MEDIA_STARTED, (data) => {
|
|
190
543
|
receivedEventsData.local.started = data;
|
|
@@ -198,21 +551,45 @@ describe('plugin-meetings', () => {
|
|
|
198
551
|
statsAnalyzer.on(EVENTS.REMOTE_MEDIA_STOPPED, (data) => {
|
|
199
552
|
receivedEventsData.remote.stopped = data;
|
|
200
553
|
});
|
|
554
|
+
statsAnalyzer.on(EVENTS.MEDIA_QUALITY, ({data}) => {
|
|
555
|
+
mqeData = data;
|
|
556
|
+
});
|
|
201
557
|
});
|
|
202
558
|
|
|
203
559
|
afterEach(() => {
|
|
560
|
+
sandbox.reset();
|
|
204
561
|
clock.restore();
|
|
205
562
|
});
|
|
206
563
|
|
|
207
|
-
const startStatsAnalyzer = async (mediaStatus) => {
|
|
564
|
+
const startStatsAnalyzer = async (mediaStatus, lastEmittedEvents) => {
|
|
208
565
|
statsAnalyzer.updateMediaStatus(mediaStatus);
|
|
209
566
|
statsAnalyzer.startAnalyzer(pc);
|
|
567
|
+
statsAnalyzer.lastEmittedStartStopEvent = lastEmittedEvents || {};
|
|
210
568
|
|
|
211
569
|
await testUtils.flushPromises();
|
|
212
570
|
};
|
|
213
571
|
|
|
214
|
-
const
|
|
215
|
-
|
|
572
|
+
const mergeProperties = (
|
|
573
|
+
target,
|
|
574
|
+
properties,
|
|
575
|
+
keyValue = 'fake-candidate-id',
|
|
576
|
+
matchKey = 'type',
|
|
577
|
+
matchValue = 'local-candidate'
|
|
578
|
+
) => {
|
|
579
|
+
for (let key in target) {
|
|
580
|
+
if (target.hasOwnProperty(key)) {
|
|
581
|
+
if (typeof target[key] === 'object') {
|
|
582
|
+
mergeProperties(target[key], properties, keyValue, matchKey, matchValue);
|
|
583
|
+
}
|
|
584
|
+
if (key === 'id' && target[key] === keyValue && target[matchKey] === matchValue) {
|
|
585
|
+
Object.assign(target, properties);
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
};
|
|
590
|
+
|
|
591
|
+
const progressTime = async (time = initialConfig.analyzerInterval) => {
|
|
592
|
+
await clock.tickAsync(time);
|
|
216
593
|
await testUtils.flushPromises();
|
|
217
594
|
};
|
|
218
595
|
|
|
@@ -224,6 +601,23 @@ describe('plugin-meetings', () => {
|
|
|
224
601
|
assert.deepEqual(receivedEventsData.remote.stopped, expected.remote?.stopped);
|
|
225
602
|
};
|
|
226
603
|
|
|
604
|
+
const checkMqeData = () => {
|
|
605
|
+
for (const data of [
|
|
606
|
+
mqeData.audioTransmit,
|
|
607
|
+
mqeData.audioReceive,
|
|
608
|
+
mqeData.videoTransmit,
|
|
609
|
+
mqeData.videoReceive,
|
|
610
|
+
]) {
|
|
611
|
+
assert.strictEqual(data.length, 2);
|
|
612
|
+
assert.strictEqual(data[0].common.common.isMain, true);
|
|
613
|
+
assert.strictEqual(data[1].common.common.isMain, false);
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
assert.strictEqual(mqeData.videoReceive[0].streams[0].receivedFrameSize, 3600);
|
|
617
|
+
assert.strictEqual(mqeData.videoReceive[0].streams[0].receivedHeight, 720);
|
|
618
|
+
assert.strictEqual(mqeData.videoReceive[0].streams[0].receivedWidth, 1280);
|
|
619
|
+
};
|
|
620
|
+
|
|
227
621
|
it('emits LOCAL_MEDIA_STARTED and LOCAL_MEDIA_STOPPED events for audio', async () => {
|
|
228
622
|
await startStatsAnalyzer({expected: {sendAudio: true}});
|
|
229
623
|
|
|
@@ -264,6 +658,26 @@ describe('plugin-meetings', () => {
|
|
|
264
658
|
checkReceivedEvent({expected: {local: {stopped: {type: 'video'}}}});
|
|
265
659
|
});
|
|
266
660
|
|
|
661
|
+
it('emits LOCAL_MEDIA_STARTED and LOCAL_MEDIA_STOPPED events for share', async () => {
|
|
662
|
+
await startStatsAnalyzer({expected: {sendShare: true}});
|
|
663
|
+
|
|
664
|
+
// check that we haven't received any events yet
|
|
665
|
+
checkReceivedEvent({expected: {}});
|
|
666
|
+
|
|
667
|
+
// setup a mock to return some values higher the previous ones
|
|
668
|
+
fakeStats.share.senders[0].report[0].framesSent += 1;
|
|
669
|
+
|
|
670
|
+
await progressTime();
|
|
671
|
+
|
|
672
|
+
// check that we got the LOCAL_MEDIA_STARTED event for audio
|
|
673
|
+
checkReceivedEvent({expected: {local: {started: {type: 'share'}}}});
|
|
674
|
+
|
|
675
|
+
// now advance the clock and the mock still returns same values, so only "stopped" event should be triggered
|
|
676
|
+
resetReceivedEvents();
|
|
677
|
+
await progressTime();
|
|
678
|
+
checkReceivedEvent({expected: {local: {stopped: {type: 'share'}}}});
|
|
679
|
+
});
|
|
680
|
+
|
|
267
681
|
it('emits REMOTE_MEDIA_STARTED and REMOTE_MEDIA_STOPPED events for audio', async () => {
|
|
268
682
|
await startStatsAnalyzer({expected: {receiveAudio: true}});
|
|
269
683
|
|
|
@@ -303,6 +717,832 @@ describe('plugin-meetings', () => {
|
|
|
303
717
|
|
|
304
718
|
checkReceivedEvent({expected: {remote: {stopped: {type: 'video'}}}});
|
|
305
719
|
});
|
|
720
|
+
|
|
721
|
+
it('emits REMOTE_MEDIA_STARTED and REMOTE_MEDIA_STOPPED events for share', async () => {
|
|
722
|
+
await startStatsAnalyzer({expected: {receiveShare: true}});
|
|
723
|
+
|
|
724
|
+
// check that we haven't received any events yet
|
|
725
|
+
checkReceivedEvent({expected: {}});
|
|
726
|
+
|
|
727
|
+
// setup a mock to return some values higher the previous ones
|
|
728
|
+
fakeStats.share.receivers[0].report[0].framesDecoded += 1;
|
|
729
|
+
|
|
730
|
+
await progressTime();
|
|
731
|
+
// check that we got the REMOTE_MEDIA_STARTED event for video
|
|
732
|
+
checkReceivedEvent({expected: {remote: {started: {type: 'share'}}}});
|
|
733
|
+
|
|
734
|
+
// now advance the clock and the mock still returns same values, so only "stopped" event should be triggered
|
|
735
|
+
resetReceivedEvents();
|
|
736
|
+
await progressTime();
|
|
737
|
+
|
|
738
|
+
checkReceivedEvent({expected: {remote: {stopped: {type: 'share'}}}});
|
|
739
|
+
});
|
|
740
|
+
|
|
741
|
+
it('emits the correct MEDIA_QUALITY events', async () => {
|
|
742
|
+
await startStatsAnalyzer({expected: {receiveVideo: true}});
|
|
743
|
+
|
|
744
|
+
await progressTime();
|
|
745
|
+
|
|
746
|
+
// Check that the mqe data has been emitted and is correctly computed.
|
|
747
|
+
checkMqeData();
|
|
748
|
+
});
|
|
749
|
+
|
|
750
|
+
it('emits the correct transportType in MEDIA_QUALITY events', async () => {
|
|
751
|
+
await startStatsAnalyzer({expected: {receiveVideo: true}});
|
|
752
|
+
|
|
753
|
+
await progressTime();
|
|
754
|
+
|
|
755
|
+
assert.strictEqual(mqeData.audioTransmit[0].common.transportType, 'TCP');
|
|
756
|
+
assert.strictEqual(mqeData.videoReceive[0].common.transportType, 'TCP');
|
|
757
|
+
});
|
|
758
|
+
|
|
759
|
+
it('emits the correct transportType in MEDIA_QUALITY events when using a TURN server', async () => {
|
|
760
|
+
fakeStats.audio.senders[0].report[4].relayProtocol = 'tls';
|
|
761
|
+
fakeStats.video.senders[0].report[4].relayProtocol = 'tls';
|
|
762
|
+
fakeStats.audio.receivers[0].report[4].relayProtocol = 'tls';
|
|
763
|
+
fakeStats.video.receivers[0].report[4].relayProtocol = 'tls';
|
|
764
|
+
|
|
765
|
+
await startStatsAnalyzer({expected: {receiveVideo: true}});
|
|
766
|
+
|
|
767
|
+
await progressTime();
|
|
768
|
+
|
|
769
|
+
assert.strictEqual(mqeData.audioTransmit[0].common.transportType, 'TLS');
|
|
770
|
+
assert.strictEqual(mqeData.videoReceive[0].common.transportType, 'TLS');
|
|
771
|
+
});
|
|
772
|
+
|
|
773
|
+
it('emits the correct peripherals in MEDIA_QUALITY events', async () => {
|
|
774
|
+
await startStatsAnalyzer({expected: {receiveVideo: true}});
|
|
775
|
+
|
|
776
|
+
await progressTime();
|
|
777
|
+
|
|
778
|
+
assert.strictEqual(
|
|
779
|
+
mqeData.intervalMetadata.peripherals.find((val) => val.name === MEDIA_DEVICES.MICROPHONE)
|
|
780
|
+
.information,
|
|
781
|
+
'fake-microphone'
|
|
782
|
+
);
|
|
783
|
+
assert.strictEqual(
|
|
784
|
+
mqeData.intervalMetadata.peripherals.find((val) => val.name === MEDIA_DEVICES.CAMERA)
|
|
785
|
+
.information,
|
|
786
|
+
'fake-camera'
|
|
787
|
+
);
|
|
788
|
+
});
|
|
789
|
+
|
|
790
|
+
it('emits the correct peripherals in MEDIA_QUALITY events when localTrackLabel is undefined', async () => {
|
|
791
|
+
fakeStats.audio.senders[0].localTrackLabel = undefined;
|
|
792
|
+
fakeStats.video.senders[0].localTrackLabel = undefined;
|
|
793
|
+
|
|
794
|
+
await startStatsAnalyzer({expected: {receiveVideo: true}});
|
|
795
|
+
|
|
796
|
+
await progressTime();
|
|
797
|
+
|
|
798
|
+
assert.strictEqual(
|
|
799
|
+
mqeData.intervalMetadata.peripherals.find((val) => val.name === MEDIA_DEVICES.MICROPHONE)
|
|
800
|
+
.information,
|
|
801
|
+
_UNKNOWN_
|
|
802
|
+
);
|
|
803
|
+
assert.strictEqual(
|
|
804
|
+
mqeData.intervalMetadata.peripherals.find((val) => val.name === MEDIA_DEVICES.CAMERA)
|
|
805
|
+
.information,
|
|
806
|
+
_UNKNOWN_
|
|
807
|
+
);
|
|
808
|
+
});
|
|
809
|
+
|
|
810
|
+
it('emits the correct transmittedFrameRate/receivedFrameRate', async () => {
|
|
811
|
+
it('at the start of the stats analyzer', async () => {
|
|
812
|
+
await startStatsAnalyzer();
|
|
813
|
+
assert.strictEqual(mqeData.videoTransmit[0].streams[0].common.transmittedFrameRate, 0);
|
|
814
|
+
assert.strictEqual(mqeData.videoReceive[0].streams[0].common.receivedFrameRate, 0);
|
|
815
|
+
});
|
|
816
|
+
|
|
817
|
+
it('after frames are sent and received', async () => {
|
|
818
|
+
fakeStats.video.senders[0].report[0].framesSent += 300;
|
|
819
|
+
fakeStats.video.receivers[0].report[0].framesReceived += 300;
|
|
820
|
+
await progressTime(MQA_INTERVAL);
|
|
821
|
+
|
|
822
|
+
// 300 frames in 60 seconds = 5 frames per second
|
|
823
|
+
assert.strictEqual(mqeData.videoTransmit[0].streams[0].common.transmittedFrameRate, 5);
|
|
824
|
+
assert.strictEqual(mqeData.videoReceive[0].streams[0].common.receivedFrameRate, 5);
|
|
825
|
+
});
|
|
826
|
+
});
|
|
827
|
+
|
|
828
|
+
it('emits the correct rtpPackets', async () => {
|
|
829
|
+
it('at the start of the stats analyzer', async () => {
|
|
830
|
+
await startStatsAnalyzer();
|
|
831
|
+
assert.strictEqual(mqeData.audioTransmit[0].common.rtpPackets, 0);
|
|
832
|
+
assert.strictEqual(mqeData.audioTransmit[0].streams[0].common.rtpPackets, 0);
|
|
833
|
+
assert.strictEqual(mqeData.audioReceive[0].common.rtpPackets, 0);
|
|
834
|
+
assert.strictEqual(mqeData.audioReceive[0].streams[0].common.rtpPackets, 0);
|
|
835
|
+
assert.strictEqual(mqeData.videoTransmit[0].common.rtpPackets, 0);
|
|
836
|
+
assert.strictEqual(mqeData.videoTransmit[0].streams[0].common.rtpPackets, 0);
|
|
837
|
+
assert.strictEqual(mqeData.videoReceive[0].common.rtpPackets, 0);
|
|
838
|
+
assert.strictEqual(mqeData.videoReceive[0].streams[0].common.rtpPackets, 0);
|
|
839
|
+
});
|
|
840
|
+
|
|
841
|
+
it('after packets are sent', async () => {
|
|
842
|
+
fakeStats.audio.senders[0].report[0].packetsSent += 5;
|
|
843
|
+
fakeStats.video.senders[0].report[0].packetsSent += 5;
|
|
844
|
+
await progressTime(MQA_INTERVAL);
|
|
845
|
+
|
|
846
|
+
assert.strictEqual(mqeData.audioTransmit[0].common.rtpPackets, 5);
|
|
847
|
+
assert.strictEqual(mqeData.audioTransmit[0].streams[0].common.rtpPackets, 5);
|
|
848
|
+
assert.strictEqual(mqeData.videoTransmit[0].common.rtpPackets, 5);
|
|
849
|
+
assert.strictEqual(mqeData.videoTransmit[0].streams[0].common.rtpPackets, 5);
|
|
850
|
+
});
|
|
851
|
+
|
|
852
|
+
it('after packets are received', async () => {
|
|
853
|
+
fakeStats.audio.senders[0].report[0].packetsSent += 10;
|
|
854
|
+
fakeStats.video.senders[0].report[0].packetsSent += 10;
|
|
855
|
+
fakeStats.audio.receivers[0].report[0].packetsReceived += 10;
|
|
856
|
+
fakeStats.video.receivers[0].report[0].packetsReceived += 10;
|
|
857
|
+
await progressTime(MQA_INTERVAL);
|
|
858
|
+
|
|
859
|
+
assert.strictEqual(mqeData.audioReceive[0].common.rtpPackets, 10);
|
|
860
|
+
assert.strictEqual(mqeData.audioReceive[0].streams[0].common.rtpPackets, 10);
|
|
861
|
+
assert.strictEqual(mqeData.videoReceive[0].common.rtpPackets, 10);
|
|
862
|
+
assert.strictEqual(mqeData.videoReceive[0].streams[0].common.rtpPackets, 10);
|
|
863
|
+
});
|
|
864
|
+
});
|
|
865
|
+
|
|
866
|
+
it('emits the correct fecPackets', async () => {
|
|
867
|
+
it('at the start of the stats analyzer', async () => {
|
|
868
|
+
await startStatsAnalyzer();
|
|
869
|
+
assert.strictEqual(mqeData.audioReceive[0].common.fecPackets, 0);
|
|
870
|
+
});
|
|
871
|
+
|
|
872
|
+
it('after FEC packets are received', async () => {
|
|
873
|
+
fakeStats.audio.receivers[0].report[0].fecPacketsReceived += 5;
|
|
874
|
+
await progressTime(MQA_INTERVAL);
|
|
875
|
+
|
|
876
|
+
assert.strictEqual(mqeData.audioReceive[0].common.fecPackets, 5);
|
|
877
|
+
});
|
|
878
|
+
|
|
879
|
+
it('after FEC packets are received and some FEC packets are discarded', async () => {
|
|
880
|
+
fakeStats.audio.receivers[0].report[0].fecPacketsReceived += 15;
|
|
881
|
+
fakeStats.audio.receivers[0].report[0].fecPacketsDiscarded += 5;
|
|
882
|
+
await progressTime(MQA_INTERVAL);
|
|
883
|
+
|
|
884
|
+
assert.strictEqual(mqeData.audioReceive[0].common.fecPackets, 10);
|
|
885
|
+
});
|
|
886
|
+
});
|
|
887
|
+
|
|
888
|
+
it('emits the correct mediaHopByHopLost/rtpHopByHopLost', async () => {
|
|
889
|
+
it('at the start of the stats analyzer', async () => {
|
|
890
|
+
await startStatsAnalyzer();
|
|
891
|
+
assert.strictEqual(mqeData.audioReceive[0].common.mediaHopByHopLost, 0);
|
|
892
|
+
assert.strictEqual(mqeData.audioReceive[0].common.rtpHopByHopLost, 0);
|
|
893
|
+
assert.strictEqual(mqeData.videoReceive[0].common.mediaHopByHopLost, 0);
|
|
894
|
+
assert.strictEqual(mqeData.videoReceive[0].common.rtpHopByHopLost, 0);
|
|
895
|
+
});
|
|
896
|
+
|
|
897
|
+
it('after packets are lost', async () => {
|
|
898
|
+
fakeStats.audio.receivers[0].report[0].packetsLost += 5;
|
|
899
|
+
fakeStats.video.receivers[0].report[0].packetsLost += 5;
|
|
900
|
+
await progressTime(MQA_INTERVAL);
|
|
901
|
+
|
|
902
|
+
assert.strictEqual(mqeData.audioReceive[0].common.mediaHopByHopLost, 5);
|
|
903
|
+
assert.strictEqual(mqeData.audioReceive[0].common.rtpHopByHopLost, 5);
|
|
904
|
+
assert.strictEqual(mqeData.videoReceive[0].common.mediaHopByHopLost, 5);
|
|
905
|
+
assert.strictEqual(mqeData.videoReceive[0].common.rtpHopByHopLost, 5);
|
|
906
|
+
});
|
|
907
|
+
});
|
|
908
|
+
|
|
909
|
+
it('emits the correct remoteLossRate', async () => {
|
|
910
|
+
it('at the start of the stats analyzer', async () => {
|
|
911
|
+
await startStatsAnalyzer();
|
|
912
|
+
assert.strictEqual(mqeData.audioTransmit[0].common.remoteLossRate, 0);
|
|
913
|
+
assert.strictEqual(mqeData.videoTransmit[0].common.remoteLossRate, 0);
|
|
914
|
+
});
|
|
915
|
+
|
|
916
|
+
it('after packets are sent', async () => {
|
|
917
|
+
fakeStats.audio.senders[0].report[0].packetsSent += 100;
|
|
918
|
+
fakeStats.video.senders[0].report[0].packetsSent += 100;
|
|
919
|
+
await progressTime(MQA_INTERVAL);
|
|
920
|
+
|
|
921
|
+
assert.strictEqual(mqeData.audioTransmit[0].common.remoteLossRate, 0);
|
|
922
|
+
assert.strictEqual(mqeData.videoTransmit[0].common.remoteLossRate, 0);
|
|
923
|
+
});
|
|
924
|
+
|
|
925
|
+
it('after packets are sent and some packets are lost', async () => {
|
|
926
|
+
fakeStats.audio.senders[0].report[0].packetsSent += 200;
|
|
927
|
+
fakeStats.audio.senders[0].report[1].packetsLost += 10;
|
|
928
|
+
fakeStats.video.senders[0].report[0].packetsSent += 200;
|
|
929
|
+
fakeStats.video.senders[0].report[1].packetsLost += 10;
|
|
930
|
+
await progressTime(MQA_INTERVAL);
|
|
931
|
+
|
|
932
|
+
assert.strictEqual(mqeData.audioTransmit[0].common.remoteLossRate, 5);
|
|
933
|
+
assert.strictEqual(mqeData.videoTransmit[0].common.remoteLossRate, 5);
|
|
934
|
+
});
|
|
935
|
+
});
|
|
936
|
+
|
|
937
|
+
it('has the correct localIpAddress set when the candidateType is host', async () => {
|
|
938
|
+
await startStatsAnalyzer();
|
|
939
|
+
|
|
940
|
+
await progressTime();
|
|
941
|
+
assert.strictEqual(statsAnalyzer.getLocalIpAddress(), '');
|
|
942
|
+
mergeProperties(fakeStats, {address: 'test', candidateType: 'host'});
|
|
943
|
+
await progressTime();
|
|
944
|
+
assert.strictEqual(statsAnalyzer.getLocalIpAddress(), 'test');
|
|
945
|
+
});
|
|
946
|
+
|
|
947
|
+
it('has the correct localIpAddress set when the candidateType is prflx and relayProtocol is set', async () => {
|
|
948
|
+
await startStatsAnalyzer();
|
|
949
|
+
|
|
950
|
+
await progressTime();
|
|
951
|
+
assert.strictEqual(statsAnalyzer.getLocalIpAddress(), '');
|
|
952
|
+
mergeProperties(fakeStats, {
|
|
953
|
+
relayProtocol: 'test',
|
|
954
|
+
address: 'test2',
|
|
955
|
+
candidateType: 'prflx',
|
|
956
|
+
});
|
|
957
|
+
await progressTime();
|
|
958
|
+
assert.strictEqual(statsAnalyzer.getLocalIpAddress(), 'test2');
|
|
959
|
+
});
|
|
960
|
+
|
|
961
|
+
it('has the correct localIpAddress set when the candidateType is prflx and relayProtocol is not set', async () => {
|
|
962
|
+
await startStatsAnalyzer();
|
|
963
|
+
|
|
964
|
+
await progressTime();
|
|
965
|
+
assert.strictEqual(statsAnalyzer.getLocalIpAddress(), '');
|
|
966
|
+
mergeProperties(fakeStats, {
|
|
967
|
+
relatedAddress: 'relatedAddress',
|
|
968
|
+
address: 'test2',
|
|
969
|
+
candidateType: 'prflx',
|
|
970
|
+
});
|
|
971
|
+
await progressTime();
|
|
972
|
+
assert.strictEqual(statsAnalyzer.getLocalIpAddress(), 'relatedAddress');
|
|
973
|
+
});
|
|
974
|
+
|
|
975
|
+
it('has no localIpAddress set when the candidateType is invalid', async () => {
|
|
976
|
+
await startStatsAnalyzer();
|
|
977
|
+
|
|
978
|
+
await progressTime();
|
|
979
|
+
assert.strictEqual(statsAnalyzer.getLocalIpAddress(), '');
|
|
980
|
+
mergeProperties(fakeStats, {candidateType: 'invalid'});
|
|
981
|
+
await progressTime();
|
|
982
|
+
assert.strictEqual(statsAnalyzer.getLocalIpAddress(), '');
|
|
983
|
+
});
|
|
984
|
+
|
|
985
|
+
it('logs a message when audio send packets do not increase', async () => {
|
|
986
|
+
await startStatsAnalyzer(
|
|
987
|
+
{expected: {sendAudio: true}},
|
|
988
|
+
{audio: {local: EVENTS.LOCAL_MEDIA_STARTED}}
|
|
989
|
+
);
|
|
990
|
+
|
|
991
|
+
// don't increase the packets when time progresses.
|
|
992
|
+
await progressTime();
|
|
993
|
+
|
|
994
|
+
assert(
|
|
995
|
+
loggerSpy.calledWith(
|
|
996
|
+
'StatsAnalyzer:index#compareLastStatsResult --> No audio RTP packets sent'
|
|
997
|
+
)
|
|
998
|
+
);
|
|
999
|
+
});
|
|
1000
|
+
|
|
1001
|
+
it('does not log a message when audio send packets increase', async () => {
|
|
1002
|
+
await startStatsAnalyzer(
|
|
1003
|
+
{expected: {sendAudio: true}},
|
|
1004
|
+
{audio: {local: EVENTS.LOCAL_MEDIA_STOPPED}}
|
|
1005
|
+
);
|
|
1006
|
+
|
|
1007
|
+
fakeStats.audio.senders[0].report[0].packetsSent += 5;
|
|
1008
|
+
await progressTime();
|
|
1009
|
+
|
|
1010
|
+
assert(
|
|
1011
|
+
loggerSpy.neverCalledWith(
|
|
1012
|
+
'StatsAnalyzer:index#compareLastStatsResult --> No audio RTP packets sent'
|
|
1013
|
+
)
|
|
1014
|
+
);
|
|
1015
|
+
});
|
|
1016
|
+
|
|
1017
|
+
it('logs a message when video send packets do not increase', async () => {
|
|
1018
|
+
await startStatsAnalyzer(
|
|
1019
|
+
{expected: {sendVideo: true}},
|
|
1020
|
+
{video: {local: EVENTS.LOCAL_MEDIA_STARTED}}
|
|
1021
|
+
);
|
|
1022
|
+
|
|
1023
|
+
// don't increase the packets when time progresses.
|
|
1024
|
+
await progressTime();
|
|
1025
|
+
|
|
1026
|
+
assert(
|
|
1027
|
+
loggerSpy.calledWith(
|
|
1028
|
+
'StatsAnalyzer:index#compareLastStatsResult --> No video RTP packets sent'
|
|
1029
|
+
)
|
|
1030
|
+
);
|
|
1031
|
+
});
|
|
1032
|
+
|
|
1033
|
+
it('does not log a message when video send packets increase', async () => {
|
|
1034
|
+
await startStatsAnalyzer(
|
|
1035
|
+
{expected: {sendVideo: true}},
|
|
1036
|
+
{video: {local: EVENTS.LOCAL_MEDIA_STOPPED}}
|
|
1037
|
+
);
|
|
1038
|
+
|
|
1039
|
+
fakeStats.video.senders[0].report[0].packetsSent += 5;
|
|
1040
|
+
await progressTime();
|
|
1041
|
+
|
|
1042
|
+
assert(
|
|
1043
|
+
loggerSpy.neverCalledWith(
|
|
1044
|
+
'StatsAnalyzer:index#compareLastStatsResult --> No video RTP packets sent'
|
|
1045
|
+
)
|
|
1046
|
+
);
|
|
1047
|
+
});
|
|
1048
|
+
|
|
1049
|
+
it('logs a message when share send packets do not increase', async () => {
|
|
1050
|
+
await startStatsAnalyzer(
|
|
1051
|
+
{expected: {sendShare: true}},
|
|
1052
|
+
{share: {local: EVENTS.LOCAL_MEDIA_STARTED}}
|
|
1053
|
+
);
|
|
1054
|
+
|
|
1055
|
+
// don't increase the packets when time progresses.
|
|
1056
|
+
await progressTime();
|
|
1057
|
+
|
|
1058
|
+
assert(
|
|
1059
|
+
loggerSpy.calledWith(
|
|
1060
|
+
'StatsAnalyzer:index#compareLastStatsResult --> No share RTP packets sent'
|
|
1061
|
+
)
|
|
1062
|
+
);
|
|
1063
|
+
});
|
|
1064
|
+
|
|
1065
|
+
it('does not log a message when share send packets increase', async () => {
|
|
1066
|
+
await startStatsAnalyzer(
|
|
1067
|
+
{expected: {sendShare: true}},
|
|
1068
|
+
{share: {local: EVENTS.LOCAL_MEDIA_STOPPED}}
|
|
1069
|
+
);
|
|
1070
|
+
|
|
1071
|
+
fakeStats.share.senders[0].report[0].packetsSent += 5;
|
|
1072
|
+
await progressTime();
|
|
1073
|
+
|
|
1074
|
+
assert(
|
|
1075
|
+
loggerSpy.neverCalledWith(
|
|
1076
|
+
'StatsAnalyzer:index#compareLastStatsResult --> No share RTP packets sent'
|
|
1077
|
+
)
|
|
1078
|
+
);
|
|
1079
|
+
});
|
|
1080
|
+
|
|
1081
|
+
['avatar', 'invalid', 'no source', 'bandwidth limited', 'policy violation'].forEach(
|
|
1082
|
+
(sourceState) => {
|
|
1083
|
+
it(`does not log a message when no packets are recieved for a receive slot with sourceState "${sourceState}"`, async () => {
|
|
1084
|
+
receiveSlot = {
|
|
1085
|
+
sourceState,
|
|
1086
|
+
csi: 2,
|
|
1087
|
+
id: '4',
|
|
1088
|
+
};
|
|
1089
|
+
|
|
1090
|
+
await startStatsAnalyzer();
|
|
1091
|
+
|
|
1092
|
+
// don't increase the packets when time progresses.
|
|
1093
|
+
await progressTime();
|
|
1094
|
+
|
|
1095
|
+
assert.neverCalledWith(
|
|
1096
|
+
loggerSpy,
|
|
1097
|
+
'StatsAnalyzer:index#processInboundRTPResult --> No packets received for receive slot id: "4" and csi: 2. Total packets received on slot: ',
|
|
1098
|
+
0
|
|
1099
|
+
);
|
|
1100
|
+
});
|
|
1101
|
+
}
|
|
1102
|
+
);
|
|
1103
|
+
|
|
1104
|
+
it(`logs a message if no packets are sent`, async () => {
|
|
1105
|
+
receiveSlot = {
|
|
1106
|
+
sourceState: 'live',
|
|
1107
|
+
csi: 2,
|
|
1108
|
+
id: '4',
|
|
1109
|
+
};
|
|
1110
|
+
await startStatsAnalyzer();
|
|
1111
|
+
|
|
1112
|
+
// don't increase the packets when time progresses.
|
|
1113
|
+
await progressTime();
|
|
1114
|
+
|
|
1115
|
+
assert.calledWith(
|
|
1116
|
+
loggerSpy,
|
|
1117
|
+
'StatsAnalyzer:index#processInboundRTPResult --> No packets received for mediaType: video-recv-0, receive slot id: "4" and csi: 2. Total packets received on slot: ',
|
|
1118
|
+
0
|
|
1119
|
+
);
|
|
1120
|
+
|
|
1121
|
+
assert.calledWith(
|
|
1122
|
+
loggerSpy,
|
|
1123
|
+
'StatsAnalyzer:index#processInboundRTPResult --> No frames received for mediaType: video-recv-0, receive slot id: "4" and csi: 2. Total frames received on slot: ',
|
|
1124
|
+
0
|
|
1125
|
+
);
|
|
1126
|
+
|
|
1127
|
+
assert.calledWith(
|
|
1128
|
+
loggerSpy,
|
|
1129
|
+
'StatsAnalyzer:index#processInboundRTPResult --> No frames decoded for mediaType: video-recv-0, receive slot id: "4" and csi: 2. Total frames decoded on slot: ',
|
|
1130
|
+
0
|
|
1131
|
+
);
|
|
1132
|
+
|
|
1133
|
+
assert.calledWith(
|
|
1134
|
+
loggerSpy,
|
|
1135
|
+
'StatsAnalyzer:index#processInboundRTPResult --> No packets received for mediaType: audio-recv-0, receive slot id: "4" and csi: 2. Total packets received on slot: ',
|
|
1136
|
+
0
|
|
1137
|
+
);
|
|
1138
|
+
|
|
1139
|
+
assert.calledWith(
|
|
1140
|
+
loggerSpy,
|
|
1141
|
+
'StatsAnalyzer:index#processInboundRTPResult --> No packets received for mediaType: video-share-recv-0, receive slot id: "4" and csi: 2. Total packets received on slot: ',
|
|
1142
|
+
0
|
|
1143
|
+
);
|
|
1144
|
+
|
|
1145
|
+
assert.calledWith(
|
|
1146
|
+
loggerSpy,
|
|
1147
|
+
'StatsAnalyzer:index#processInboundRTPResult --> No frames received for mediaType: video-share-recv-0, receive slot id: "4" and csi: 2. Total frames received on slot: ',
|
|
1148
|
+
0
|
|
1149
|
+
);
|
|
1150
|
+
assert.calledWith(
|
|
1151
|
+
loggerSpy,
|
|
1152
|
+
'StatsAnalyzer:index#processInboundRTPResult --> No frames decoded for mediaType: video-share-recv-0, receive slot id: "4" and csi: 2. Total frames decoded on slot: ',
|
|
1153
|
+
0
|
|
1154
|
+
);
|
|
1155
|
+
assert.calledWith(
|
|
1156
|
+
loggerSpy,
|
|
1157
|
+
'StatsAnalyzer:index#processInboundRTPResult --> No packets received for mediaType: audio-share-recv-0, receive slot id: "4" and csi: 2. Total packets received on slot: ',
|
|
1158
|
+
0
|
|
1159
|
+
);
|
|
1160
|
+
});
|
|
1161
|
+
|
|
1162
|
+
it(`does not log a message if receiveSlot is undefined`, async () => {
|
|
1163
|
+
await startStatsAnalyzer();
|
|
1164
|
+
|
|
1165
|
+
// don't increase the packets when time progresses.
|
|
1166
|
+
await progressTime();
|
|
1167
|
+
|
|
1168
|
+
assert.neverCalledWith(
|
|
1169
|
+
loggerSpy,
|
|
1170
|
+
'StatsAnalyzer:index#processInboundRTPResult --> No packets received for receive slot "". Total packets received on slot: ',
|
|
1171
|
+
0
|
|
1172
|
+
);
|
|
1173
|
+
});
|
|
1174
|
+
|
|
1175
|
+
it('has the correct number of senders and receivers (2)', async () => {
|
|
1176
|
+
await startStatsAnalyzer({expected: {receiveVideo: true}});
|
|
1177
|
+
|
|
1178
|
+
await progressTime();
|
|
1179
|
+
|
|
1180
|
+
assert.lengthOf(mqeData.audioTransmit, 2);
|
|
1181
|
+
assert.lengthOf(mqeData.audioReceive, 2);
|
|
1182
|
+
assert.lengthOf(mqeData.videoTransmit, 2);
|
|
1183
|
+
assert.lengthOf(mqeData.videoReceive, 2);
|
|
1184
|
+
});
|
|
1185
|
+
|
|
1186
|
+
it('has one stream per sender/reciever', async () => {
|
|
1187
|
+
await startStatsAnalyzer({expected: {receiveVideo: true}});
|
|
1188
|
+
|
|
1189
|
+
await progressTime();
|
|
1190
|
+
|
|
1191
|
+
assert.deepEqual(mqeData.audioTransmit[0].streams, [
|
|
1192
|
+
{
|
|
1193
|
+
common: {
|
|
1194
|
+
codec: 'opus',
|
|
1195
|
+
csi: [],
|
|
1196
|
+
requestedBitrate: 0,
|
|
1197
|
+
requestedFrames: 0,
|
|
1198
|
+
rtpPackets: 0,
|
|
1199
|
+
ssci: 0,
|
|
1200
|
+
transmittedBitrate: 0.13333333333333333,
|
|
1201
|
+
transmittedFrameRate: 0,
|
|
1202
|
+
},
|
|
1203
|
+
transmittedKeyFrames: 0,
|
|
1204
|
+
requestedKeyFrames: 0,
|
|
1205
|
+
},
|
|
1206
|
+
]);
|
|
1207
|
+
assert.deepEqual(mqeData.audioTransmit[1].streams, [
|
|
1208
|
+
{
|
|
1209
|
+
common: {
|
|
1210
|
+
codec: 'opus',
|
|
1211
|
+
csi: [],
|
|
1212
|
+
requestedBitrate: 0,
|
|
1213
|
+
requestedFrames: 0,
|
|
1214
|
+
rtpPackets: 0,
|
|
1215
|
+
ssci: 0,
|
|
1216
|
+
transmittedBitrate: 0.13333333333333333,
|
|
1217
|
+
transmittedFrameRate: 0,
|
|
1218
|
+
},
|
|
1219
|
+
transmittedKeyFrames: 0,
|
|
1220
|
+
requestedKeyFrames: 0,
|
|
1221
|
+
},
|
|
1222
|
+
]);
|
|
1223
|
+
assert.deepEqual(mqeData.audioReceive[0].streams, [
|
|
1224
|
+
{
|
|
1225
|
+
common: {
|
|
1226
|
+
codec: 'opus',
|
|
1227
|
+
concealedFrames: 0,
|
|
1228
|
+
csi: [],
|
|
1229
|
+
maxConcealRunLength: 0,
|
|
1230
|
+
optimalBitrate: 0,
|
|
1231
|
+
optimalFrameRate: 0,
|
|
1232
|
+
receivedBitrate: 0.13333333333333333,
|
|
1233
|
+
receivedFrameRate: 0,
|
|
1234
|
+
renderedFrameRate: 0,
|
|
1235
|
+
requestedBitrate: 0,
|
|
1236
|
+
requestedFrameRate: 0,
|
|
1237
|
+
rtpEndToEndLost: 0,
|
|
1238
|
+
maxRtpJitter: 0,
|
|
1239
|
+
meanRtpJitter: 0,
|
|
1240
|
+
rtpPackets: 0,
|
|
1241
|
+
ssci: 0,
|
|
1242
|
+
rtpJitter: 0,
|
|
1243
|
+
framesDropped: 0,
|
|
1244
|
+
framesReceived: 0,
|
|
1245
|
+
},
|
|
1246
|
+
},
|
|
1247
|
+
]);
|
|
1248
|
+
assert.deepEqual(mqeData.audioReceive[1].streams, [
|
|
1249
|
+
{
|
|
1250
|
+
common: {
|
|
1251
|
+
codec: 'opus',
|
|
1252
|
+
concealedFrames: 0,
|
|
1253
|
+
csi: [],
|
|
1254
|
+
maxConcealRunLength: 0,
|
|
1255
|
+
optimalBitrate: 0,
|
|
1256
|
+
optimalFrameRate: 0,
|
|
1257
|
+
receivedBitrate: 0.13333333333333333,
|
|
1258
|
+
receivedFrameRate: 0,
|
|
1259
|
+
renderedFrameRate: 0,
|
|
1260
|
+
requestedBitrate: 0,
|
|
1261
|
+
requestedFrameRate: 0,
|
|
1262
|
+
rtpEndToEndLost: 0,
|
|
1263
|
+
maxRtpJitter: 0,
|
|
1264
|
+
meanRtpJitter: 0,
|
|
1265
|
+
rtpPackets: 0,
|
|
1266
|
+
ssci: 0,
|
|
1267
|
+
rtpJitter: 0,
|
|
1268
|
+
framesDropped: 0,
|
|
1269
|
+
framesReceived: 0,
|
|
1270
|
+
},
|
|
1271
|
+
},
|
|
1272
|
+
]);
|
|
1273
|
+
assert.deepEqual(mqeData.videoTransmit[0].streams, [
|
|
1274
|
+
{
|
|
1275
|
+
common: {
|
|
1276
|
+
codec: 'H264',
|
|
1277
|
+
csi: [],
|
|
1278
|
+
duplicateSsci: 0,
|
|
1279
|
+
requestedBitrate: 0,
|
|
1280
|
+
requestedFrames: 0,
|
|
1281
|
+
rtpPackets: 0,
|
|
1282
|
+
ssci: 0,
|
|
1283
|
+
transmittedBitrate: 0.13333333333333333,
|
|
1284
|
+
transmittedFrameRate: 0,
|
|
1285
|
+
},
|
|
1286
|
+
h264CodecProfile: 'BP',
|
|
1287
|
+
isAvatar: false,
|
|
1288
|
+
isHardwareEncoded: false,
|
|
1289
|
+
localConfigurationChanges: 2,
|
|
1290
|
+
maxFrameQp: 0,
|
|
1291
|
+
maxNoiseLevel: 0,
|
|
1292
|
+
minRegionQp: 0,
|
|
1293
|
+
remoteConfigurationChanges: 0,
|
|
1294
|
+
requestedFrameSize: 0,
|
|
1295
|
+
requestedKeyFrames: 0,
|
|
1296
|
+
transmittedFrameSize: 0,
|
|
1297
|
+
transmittedHeight: 0,
|
|
1298
|
+
transmittedKeyFrames: 0,
|
|
1299
|
+
transmittedKeyFramesClient: 0,
|
|
1300
|
+
transmittedKeyFramesConfigurationChange: 0,
|
|
1301
|
+
transmittedKeyFramesFeedback: 0,
|
|
1302
|
+
transmittedKeyFramesLocalDrop: 0,
|
|
1303
|
+
transmittedKeyFramesOtherLayer: 0,
|
|
1304
|
+
transmittedKeyFramesPeriodic: 0,
|
|
1305
|
+
transmittedKeyFramesSceneChange: 0,
|
|
1306
|
+
transmittedKeyFramesStartup: 0,
|
|
1307
|
+
transmittedKeyFramesUnknown: 0,
|
|
1308
|
+
transmittedWidth: 0,
|
|
1309
|
+
},
|
|
1310
|
+
]);
|
|
1311
|
+
assert.deepEqual(mqeData.videoTransmit[1].streams, [
|
|
1312
|
+
{
|
|
1313
|
+
common: {
|
|
1314
|
+
codec: 'H264',
|
|
1315
|
+
csi: [],
|
|
1316
|
+
duplicateSsci: 0,
|
|
1317
|
+
requestedBitrate: 0,
|
|
1318
|
+
requestedFrames: 0,
|
|
1319
|
+
rtpPackets: 0,
|
|
1320
|
+
ssci: 0,
|
|
1321
|
+
transmittedBitrate: 0.13333333333333333,
|
|
1322
|
+
transmittedFrameRate: 0,
|
|
1323
|
+
},
|
|
1324
|
+
h264CodecProfile: 'BP',
|
|
1325
|
+
isAvatar: false,
|
|
1326
|
+
isHardwareEncoded: false,
|
|
1327
|
+
localConfigurationChanges: 2,
|
|
1328
|
+
maxFrameQp: 0,
|
|
1329
|
+
maxNoiseLevel: 0,
|
|
1330
|
+
minRegionQp: 0,
|
|
1331
|
+
remoteConfigurationChanges: 0,
|
|
1332
|
+
requestedFrameSize: 0,
|
|
1333
|
+
requestedKeyFrames: 0,
|
|
1334
|
+
transmittedFrameSize: 0,
|
|
1335
|
+
transmittedHeight: 0,
|
|
1336
|
+
transmittedKeyFrames: 0,
|
|
1337
|
+
transmittedKeyFramesClient: 0,
|
|
1338
|
+
transmittedKeyFramesConfigurationChange: 0,
|
|
1339
|
+
transmittedKeyFramesFeedback: 0,
|
|
1340
|
+
transmittedKeyFramesLocalDrop: 0,
|
|
1341
|
+
transmittedKeyFramesOtherLayer: 0,
|
|
1342
|
+
transmittedKeyFramesPeriodic: 0,
|
|
1343
|
+
transmittedKeyFramesSceneChange: 0,
|
|
1344
|
+
transmittedKeyFramesStartup: 0,
|
|
1345
|
+
transmittedKeyFramesUnknown: 0,
|
|
1346
|
+
transmittedWidth: 0,
|
|
1347
|
+
},
|
|
1348
|
+
]);
|
|
1349
|
+
assert.deepEqual(mqeData.videoReceive[0].streams, [
|
|
1350
|
+
{
|
|
1351
|
+
common: {
|
|
1352
|
+
codec: 'H264',
|
|
1353
|
+
concealedFrames: 0,
|
|
1354
|
+
csi: [],
|
|
1355
|
+
maxConcealRunLength: 0,
|
|
1356
|
+
optimalBitrate: 0,
|
|
1357
|
+
optimalFrameRate: 0,
|
|
1358
|
+
receivedBitrate: 0.13333333333333333,
|
|
1359
|
+
receivedFrameRate: 0,
|
|
1360
|
+
renderedFrameRate: 0,
|
|
1361
|
+
requestedBitrate: 0,
|
|
1362
|
+
requestedFrameRate: 0,
|
|
1363
|
+
rtpEndToEndLost: 0,
|
|
1364
|
+
rtpJitter: 0,
|
|
1365
|
+
rtpPackets: 0,
|
|
1366
|
+
ssci: 0,
|
|
1367
|
+
framesDropped: 0,
|
|
1368
|
+
},
|
|
1369
|
+
h264CodecProfile: 'BP',
|
|
1370
|
+
isActiveSpeaker: true,
|
|
1371
|
+
optimalFrameSize: 0,
|
|
1372
|
+
receivedFrameSize: 3600,
|
|
1373
|
+
receivedHeight: 720,
|
|
1374
|
+
receivedKeyFrames: 0,
|
|
1375
|
+
receivedKeyFramesForRequest: 0,
|
|
1376
|
+
receivedKeyFramesSourceChange: 0,
|
|
1377
|
+
receivedKeyFramesUnknown: 0,
|
|
1378
|
+
receivedWidth: 1280,
|
|
1379
|
+
requestedFrameSize: 0,
|
|
1380
|
+
requestedKeyFrames: 0,
|
|
1381
|
+
},
|
|
1382
|
+
]);
|
|
1383
|
+
assert.deepEqual(mqeData.videoReceive[1].streams, [
|
|
1384
|
+
{
|
|
1385
|
+
common: {
|
|
1386
|
+
codec: 'H264',
|
|
1387
|
+
concealedFrames: 0,
|
|
1388
|
+
csi: [],
|
|
1389
|
+
maxConcealRunLength: 0,
|
|
1390
|
+
optimalBitrate: 0,
|
|
1391
|
+
optimalFrameRate: 0,
|
|
1392
|
+
receivedBitrate: 0.13333333333333333,
|
|
1393
|
+
receivedFrameRate: 0,
|
|
1394
|
+
renderedFrameRate: 0,
|
|
1395
|
+
requestedBitrate: 0,
|
|
1396
|
+
requestedFrameRate: 0,
|
|
1397
|
+
rtpEndToEndLost: 0,
|
|
1398
|
+
rtpJitter: 0,
|
|
1399
|
+
rtpPackets: 0,
|
|
1400
|
+
ssci: 0,
|
|
1401
|
+
framesDropped: 0,
|
|
1402
|
+
},
|
|
1403
|
+
h264CodecProfile: 'BP',
|
|
1404
|
+
isActiveSpeaker: true,
|
|
1405
|
+
optimalFrameSize: 0,
|
|
1406
|
+
receivedFrameSize: 3600,
|
|
1407
|
+
receivedHeight: 720,
|
|
1408
|
+
receivedKeyFrames: 0,
|
|
1409
|
+
receivedKeyFramesForRequest: 0,
|
|
1410
|
+
receivedKeyFramesSourceChange: 0,
|
|
1411
|
+
receivedKeyFramesUnknown: 0,
|
|
1412
|
+
receivedWidth: 1280,
|
|
1413
|
+
requestedFrameSize: 0,
|
|
1414
|
+
requestedKeyFrames: 0,
|
|
1415
|
+
},
|
|
1416
|
+
]);
|
|
1417
|
+
});
|
|
1418
|
+
|
|
1419
|
+
it('has three streams for video receivers when three exist', async () => {
|
|
1420
|
+
pc.getTransceiverStats = sinon.stub().resolves({
|
|
1421
|
+
audio: {
|
|
1422
|
+
senders: [fakeStats.audio.senders[0]],
|
|
1423
|
+
receivers: [fakeStats.audio.receivers[0]],
|
|
1424
|
+
},
|
|
1425
|
+
video: {
|
|
1426
|
+
senders: [fakeStats.video.senders[0]],
|
|
1427
|
+
receivers: [
|
|
1428
|
+
fakeStats.video.receivers[0],
|
|
1429
|
+
fakeStats.video.receivers[0],
|
|
1430
|
+
fakeStats.video.receivers[0],
|
|
1431
|
+
],
|
|
1432
|
+
},
|
|
1433
|
+
screenShareAudio: {
|
|
1434
|
+
senders: [fakeStats.audio.senders[0]],
|
|
1435
|
+
receivers: [fakeStats.audio.receivers[0]],
|
|
1436
|
+
},
|
|
1437
|
+
screenShareVideo: {
|
|
1438
|
+
senders: [fakeStats.video.senders[0]],
|
|
1439
|
+
receivers: [fakeStats.video.receivers[0]],
|
|
1440
|
+
},
|
|
1441
|
+
});
|
|
1442
|
+
|
|
1443
|
+
await startStatsAnalyzer({expected: {receiveVideo: true}});
|
|
1444
|
+
|
|
1445
|
+
await progressTime();
|
|
1446
|
+
|
|
1447
|
+
assert.deepEqual(mqeData.videoReceive[0].streams, [
|
|
1448
|
+
{
|
|
1449
|
+
common: {
|
|
1450
|
+
codec: 'H264',
|
|
1451
|
+
concealedFrames: 0,
|
|
1452
|
+
csi: [],
|
|
1453
|
+
maxConcealRunLength: 0,
|
|
1454
|
+
optimalBitrate: 0,
|
|
1455
|
+
optimalFrameRate: 0,
|
|
1456
|
+
receivedBitrate: 0.13333333333333333,
|
|
1457
|
+
receivedFrameRate: 0,
|
|
1458
|
+
renderedFrameRate: 0,
|
|
1459
|
+
requestedBitrate: 0,
|
|
1460
|
+
requestedFrameRate: 0,
|
|
1461
|
+
rtpEndToEndLost: 0,
|
|
1462
|
+
rtpJitter: 0,
|
|
1463
|
+
rtpPackets: 0,
|
|
1464
|
+
ssci: 0,
|
|
1465
|
+
framesDropped: 0,
|
|
1466
|
+
},
|
|
1467
|
+
h264CodecProfile: 'BP',
|
|
1468
|
+
isActiveSpeaker: true,
|
|
1469
|
+
optimalFrameSize: 0,
|
|
1470
|
+
receivedFrameSize: 3600,
|
|
1471
|
+
receivedHeight: 720,
|
|
1472
|
+
receivedKeyFrames: 0,
|
|
1473
|
+
receivedKeyFramesForRequest: 0,
|
|
1474
|
+
receivedKeyFramesSourceChange: 0,
|
|
1475
|
+
receivedKeyFramesUnknown: 0,
|
|
1476
|
+
receivedWidth: 1280,
|
|
1477
|
+
requestedFrameSize: 0,
|
|
1478
|
+
requestedKeyFrames: 0,
|
|
1479
|
+
},
|
|
1480
|
+
{
|
|
1481
|
+
common: {
|
|
1482
|
+
codec: 'H264',
|
|
1483
|
+
concealedFrames: 0,
|
|
1484
|
+
csi: [],
|
|
1485
|
+
maxConcealRunLength: 0,
|
|
1486
|
+
optimalBitrate: 0,
|
|
1487
|
+
optimalFrameRate: 0,
|
|
1488
|
+
receivedBitrate: 0.13333333333333333,
|
|
1489
|
+
receivedFrameRate: 0,
|
|
1490
|
+
renderedFrameRate: 0,
|
|
1491
|
+
requestedBitrate: 0,
|
|
1492
|
+
requestedFrameRate: 0,
|
|
1493
|
+
rtpEndToEndLost: 0,
|
|
1494
|
+
rtpJitter: 0,
|
|
1495
|
+
rtpPackets: 0,
|
|
1496
|
+
ssci: 0,
|
|
1497
|
+
framesDropped: 0,
|
|
1498
|
+
},
|
|
1499
|
+
h264CodecProfile: 'BP',
|
|
1500
|
+
isActiveSpeaker: true,
|
|
1501
|
+
optimalFrameSize: 0,
|
|
1502
|
+
receivedFrameSize: 3600,
|
|
1503
|
+
receivedHeight: 720,
|
|
1504
|
+
receivedKeyFrames: 0,
|
|
1505
|
+
receivedKeyFramesForRequest: 0,
|
|
1506
|
+
receivedKeyFramesSourceChange: 0,
|
|
1507
|
+
receivedKeyFramesUnknown: 0,
|
|
1508
|
+
receivedWidth: 1280,
|
|
1509
|
+
requestedFrameSize: 0,
|
|
1510
|
+
requestedKeyFrames: 0,
|
|
1511
|
+
},
|
|
1512
|
+
{
|
|
1513
|
+
common: {
|
|
1514
|
+
codec: 'H264',
|
|
1515
|
+
concealedFrames: 0,
|
|
1516
|
+
csi: [],
|
|
1517
|
+
maxConcealRunLength: 0,
|
|
1518
|
+
optimalBitrate: 0,
|
|
1519
|
+
optimalFrameRate: 0,
|
|
1520
|
+
receivedBitrate: 0.13333333333333333,
|
|
1521
|
+
receivedFrameRate: 0,
|
|
1522
|
+
renderedFrameRate: 0,
|
|
1523
|
+
requestedBitrate: 0,
|
|
1524
|
+
requestedFrameRate: 0,
|
|
1525
|
+
rtpEndToEndLost: 0,
|
|
1526
|
+
rtpJitter: 0,
|
|
1527
|
+
rtpPackets: 0,
|
|
1528
|
+
ssci: 0,
|
|
1529
|
+
framesDropped: 0,
|
|
1530
|
+
},
|
|
1531
|
+
h264CodecProfile: 'BP',
|
|
1532
|
+
isActiveSpeaker: true,
|
|
1533
|
+
optimalFrameSize: 0,
|
|
1534
|
+
receivedFrameSize: 3600,
|
|
1535
|
+
receivedHeight: 720,
|
|
1536
|
+
receivedKeyFrames: 0,
|
|
1537
|
+
receivedKeyFramesForRequest: 0,
|
|
1538
|
+
receivedKeyFramesSourceChange: 0,
|
|
1539
|
+
receivedKeyFramesUnknown: 0,
|
|
1540
|
+
receivedWidth: 1280,
|
|
1541
|
+
requestedFrameSize: 0,
|
|
1542
|
+
requestedKeyFrames: 0,
|
|
1543
|
+
},
|
|
1544
|
+
]);
|
|
1545
|
+
});
|
|
306
1546
|
});
|
|
307
1547
|
});
|
|
308
1548
|
});
|