Skip to content

Commit d6b7dcf

Browse files
authored
feat: Improve FrozenVideo and VideoDecoderCPU detectors (#32)
1 parent 4c7a59f commit d6b7dcf

18 files changed

+297
-338
lines changed

.eslintrc

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
"no-underscore-dangle": "off",
1616
"max-len": ["error", { "code": 120 }],
1717
"import/extensions": "off",
18-
"import/no-cycle": "off"
18+
"import/no-cycle": "off",
19+
"no-continue": "off",
20+
"import/prefer-default-export": "off"
1921
}
2022
}

README.md

Lines changed: 7 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -51,14 +51,13 @@ By default, WebRTCIssueDetector can be created with minimum of mandatory constru
5151
```typescript
5252
import WebRTCIssueDetector, {
5353
QualityLimitationsIssueDetector,
54-
FramesDroppedIssueDetector,
55-
FramesEncodedSentIssueDetector,
5654
InboundNetworkIssueDetector,
5755
OutboundNetworkIssueDetector,
5856
NetworkMediaSyncIssueDetector,
5957
AvailableOutgoingBitrateIssueDetector,
6058
UnknownVideoDecoderImplementationDetector,
6159
FrozenVideoTrackDetector,
60+
VideoDecoderIssueDetector,
6261
} from 'webrtc-issue-detector';
6362

6463
const widWithDefaultConstructorArgs = new WebRTCIssueDetector();
@@ -68,14 +67,13 @@ const widWithDefaultConstructorArgs = new WebRTCIssueDetector();
6867
const widWithCustomConstructorArgs = new WebRTCIssueDetector({
6968
detectors: [ // you are free to change the detectors list according to your needs
7069
new QualityLimitationsIssueDetector(),
71-
new FramesDroppedIssueDetector(),
72-
new FramesEncodedSentIssueDetector(),
7370
new InboundNetworkIssueDetector(),
7471
new OutboundNetworkIssueDetector(),
7572
new NetworkMediaSyncIssueDetector(),
7673
new AvailableOutgoingBitrateIssueDetector(),
7774
new UnknownVideoDecoderImplementationDetector(),
7875
new FrozenVideoTrackDetector(),
76+
new VideoDecoderIssueDetector(),
7977
],
8078
getStatsInterval: 10_000, // set custom stats parsing interval
8179
onIssues: (payload: IssueDetectorResult) => {
@@ -106,34 +104,18 @@ const exampleIssue = {
106104
}
107105
```
108106

109-
### FramesDroppedIssueDetector
107+
### VideoDecoderIssueDetector
110108
Detects issues with decoder.
111109
```js
112110
const exampleIssue = {
113111
type: 'cpu',
114112
reason: 'decoder-cpu-throttling',
115113
statsSample: {
116-
deltaFramesDropped: 100,
117-
deltaFramesReceived: 1000,
118-
deltaFramesDecoded: 900,
119-
framesDroppedPct: 10,
114+
affectedStreamsPercent: 67,
115+
throtthedStreams: [
116+
{ ssrc: 123, allDecodeTimePerFrame: [1.2, 1.6, 1.9, 2.4, 2.9], volatility: 1.7 },
117+
]
120118
},
121-
ssrc: 1234,
122-
}
123-
```
124-
125-
### FramesEncodedSentIssueDetector
126-
Detects issues with outbound network throughput.
127-
```js
128-
const exampleIssue = {
129-
type: 'network',
130-
reason: 'outbound-network-throughput',
131-
statsSample: {
132-
deltaFramesSent: 900,
133-
deltaFramesEncoded: 1000,
134-
missedFramesPct: 10,
135-
},
136-
ssrc: 1234,
137119
}
138120
```
139121

src/WebRTCIssueDetector.ts

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
IssueDetector,
88
IssuePayload,
99
Logger,
10+
NetworkScores,
1011
StatsReportItem,
1112
WebRTCIssueDetectorConstructorParams,
1213
WebRTCStatsParsed,
@@ -16,14 +17,13 @@ import PeriodicWebRTCStatsReporter from './parser/PeriodicWebRTCStatsReporter';
1617
import DefaultNetworkScoresCalculator from './NetworkScoresCalculator';
1718
import {
1819
AvailableOutgoingBitrateIssueDetector,
19-
FramesDroppedIssueDetector,
20-
FramesEncodedSentIssueDetector,
2120
InboundNetworkIssueDetector,
2221
NetworkMediaSyncIssueDetector,
2322
OutboundNetworkIssueDetector,
2423
QualityLimitationsIssueDetector,
2524
UnknownVideoDecoderImplementationDetector,
2625
FrozenVideoTrackDetector,
26+
VideoDecoderIssueDetector,
2727
} from './detectors';
2828
import { CompositeRTCStatsParser, RTCStatsParser } from './parser';
2929
import createLogger from './utils/logger';
@@ -60,14 +60,13 @@ class WebRTCIssueDetector {
6060

6161
this.detectors = params.detectors ?? [
6262
new QualityLimitationsIssueDetector(),
63-
new FramesDroppedIssueDetector(),
64-
new FramesEncodedSentIssueDetector(),
6563
new InboundNetworkIssueDetector(),
6664
new OutboundNetworkIssueDetector(),
6765
new NetworkMediaSyncIssueDetector(),
6866
new AvailableOutgoingBitrateIssueDetector(),
6967
new UnknownVideoDecoderImplementationDetector(),
7068
new FrozenVideoTrackDetector(),
69+
new VideoDecoderIssueDetector(),
7170
new MissingStreamDataDetector(),
7271
];
7372

@@ -90,11 +89,8 @@ class WebRTCIssueDetector {
9089
}
9190

9291
this.statsReporter.on(PeriodicWebRTCStatsReporter.STATS_REPORT_READY_EVENT, (report: StatsReportItem) => {
93-
this.detectIssues({
94-
data: report.stats,
95-
});
96-
97-
this.calculateNetworkScores(report.stats);
92+
const networkScores = this.calculateNetworkScores(report.stats);
93+
this.detectIssues({ data: report.stats }, networkScores);
9894
});
9995

10096
this.statsReporter.on(PeriodicWebRTCStatsReporter.STATS_REPORTS_PARSED, (data: {
@@ -163,16 +159,19 @@ class WebRTCIssueDetector {
163159
this.eventEmitter.emit(EventType.Issue, issues);
164160
}
165161

166-
private detectIssues({ data }: DetectIssuesPayload): void {
167-
const issues = this.detectors.reduce<IssuePayload[]>((acc, detector) => [...acc, ...detector.detect(data)], []);
162+
private detectIssues({ data }: DetectIssuesPayload, networkScores: NetworkScores): void {
163+
const issues = this.detectors
164+
.reduce<IssuePayload[]>((acc, detector) => [...acc, ...detector.detect(data, networkScores)], []);
165+
168166
if (issues.length > 0) {
169167
this.emitIssues(issues);
170168
}
171169
}
172170

173-
private calculateNetworkScores(data: WebRTCStatsParsed): void {
171+
private calculateNetworkScores(data: WebRTCStatsParsed): NetworkScores {
174172
const networkScores = this.networkScoresCalculator.calculate(data);
175173
this.eventEmitter.emit(EventType.NetworkScoresUpdated, networkScores);
174+
return networkScores;
176175
}
177176

178177
private wrapRTCPeerConnection(): void {

src/detectors/BaseIssueDetector.ts

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1-
import { IssueDetector, IssueDetectorResult, WebRTCStatsParsed } from '../types';
1+
import {
2+
IssueDetector,
3+
IssueDetectorResult,
4+
NetworkScores,
5+
WebRTCStatsParsed,
6+
WebRTCStatsParsedWithNetworkScores,
7+
} from '../types';
28
import { scheduleTask } from '../utils/tasks';
39
import { CLEANUP_PREV_STATS_TTL_MS, MAX_PARSED_STATS_STORAGE_SIZE } from '../utils/constants';
410

@@ -13,7 +19,7 @@ export interface BaseIssueDetectorParams {
1319
}
1420

1521
abstract class BaseIssueDetector implements IssueDetector {
16-
readonly #parsedStatsStorage: Map<string, WebRTCStatsParsed[]> = new Map();
22+
readonly #parsedStatsStorage: Map<string, WebRTCStatsParsedWithNetworkScores[]> = new Map();
1723

1824
readonly #statsCleanupDelayMs: number;
1925

@@ -24,11 +30,19 @@ abstract class BaseIssueDetector implements IssueDetector {
2430
this.#maxParsedStatsStorageSize = params.maxParsedStatsStorageSize ?? MAX_PARSED_STATS_STORAGE_SIZE;
2531
}
2632

27-
abstract performDetection(data: WebRTCStatsParsed): IssueDetectorResult;
33+
abstract performDetection(data: WebRTCStatsParsedWithNetworkScores): IssueDetectorResult;
2834

29-
detect(data: WebRTCStatsParsed): IssueDetectorResult {
30-
const result = this.performDetection(data);
35+
detect(data: WebRTCStatsParsed, networkScores?: NetworkScores): IssueDetectorResult {
36+
const parsedStatsWithNetworkScores = {
37+
...data,
38+
networkScores: {
39+
...networkScores,
40+
statsSamples: networkScores?.statsSamples || {},
41+
},
42+
};
43+
const result = this.performDetection(parsedStatsWithNetworkScores);
3144

45+
this.setLastProcessedStats(data.connection.id, parsedStatsWithNetworkScores);
3246
this.performPrevStatsCleanup({
3347
connectionId: data.connection.id,
3448
});
@@ -56,7 +70,7 @@ abstract class BaseIssueDetector implements IssueDetector {
5670
});
5771
}
5872

59-
protected setLastProcessedStats(connectionId: string, parsedStats: WebRTCStatsParsed): void {
73+
protected setLastProcessedStats(connectionId: string, parsedStats: WebRTCStatsParsedWithNetworkScores): void {
6074
if (!connectionId || parsedStats.connection.id !== connectionId) {
6175
return;
6276
}
@@ -71,16 +85,16 @@ abstract class BaseIssueDetector implements IssueDetector {
7185
this.#parsedStatsStorage.set(connectionId, connectionStats);
7286
}
7387

74-
protected getLastProcessedStats(connectionId: string): WebRTCStatsParsed | undefined {
88+
protected getLastProcessedStats(connectionId: string): WebRTCStatsParsedWithNetworkScores | undefined {
7589
const connectionStats = this.#parsedStatsStorage.get(connectionId);
7690
return connectionStats?.[connectionStats.length - 1];
7791
}
7892

79-
protected getAllLastProcessedStats(connectionId: string): WebRTCStatsParsed[] {
93+
protected getAllLastProcessedStats(connectionId: string): WebRTCStatsParsedWithNetworkScores[] {
8094
return this.#parsedStatsStorage.get(connectionId) ?? [];
8195
}
8296

83-
private deleteLastProcessedStats(connectionId: string): void {
97+
protected deleteLastProcessedStats(connectionId: string): void {
8498
this.#parsedStatsStorage.delete(connectionId);
8599
}
86100
}

src/detectors/FramesDroppedIssueDetector.ts

Lines changed: 0 additions & 80 deletions
This file was deleted.

src/detectors/FramesEncodedSentIssueDetector.ts

Lines changed: 0 additions & 83 deletions
This file was deleted.

0 commit comments

Comments
 (0)