Skip to content

Commit e37c2ff

Browse files
authored
fix: ignore dtx streams (#35)
1 parent 2bc109d commit e37c2ff

File tree

4 files changed

+65
-0
lines changed

4 files changed

+65
-0
lines changed

src/detectors/FrozenVideoTrackDetector.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { isDtxLikeBehavior } from '../helpers/streams';
12
import {
23
IssueDetectorResult,
34
IssueReason,
@@ -71,6 +72,12 @@ class FrozenVideoTrackDetector extends BaseIssueDetector {
7172
return undefined;
7273
}
7374

75+
const isDtx = isDtxLikeBehavior(videoStream.ssrc, allLastProcessedStats);
76+
if (isDtx) {
77+
// DTX-like behavior detected, ignoring freezes check
78+
return undefined;
79+
}
80+
7481
const deltaFreezeCount = videoStream.freezeCount - (prevStat.freezeCount ?? 0);
7582
const deltaFreezesTimeMs = (videoStream.totalFreezesDuration - (prevStat.totalFreezesDuration ?? 0)) * 1000;
7683
const avgFreezeDurationMs = deltaFreezeCount > 0 ? deltaFreezesTimeMs / deltaFreezeCount : 0;

src/detectors/VideoDecoderIssueDetector.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { calculateVolatility } from '../helpers/calc';
2+
import { isDtxLikeBehavior } from '../helpers/streams';
23
import {
34
IssueDetectorResult,
45
IssueReason,
@@ -84,6 +85,12 @@ class VideoDecoderIssueDetector extends BaseIssueDetector {
8485
return undefined;
8586
}
8687

88+
const isDtx = isDtxLikeBehavior(incomeVideoStream.ssrc, allProcessedStats);
89+
if (isDtx) {
90+
// DTX-like behavior detected, ignoring FPS volatility check
91+
return undefined;
92+
}
93+
8794
const volatility = calculateVolatility(allFps);
8895

8996
if (volatility > this.#volatilityThreshold) {

src/helpers/calc.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
export const calculateMean = (values: number[]) => values.reduce((acc, val) => acc + val, 0) / values.length;
22

3+
export const calculateVariance = (mean: number, values: number[]) => values
4+
.reduce((sum, val) => sum + (val - mean) ** 2, 0) / values.length;
5+
6+
export const calculateStandardDeviation = (values: number[]) => {
7+
const mean = calculateMean(values);
8+
const variance = calculateVariance(mean, values);
9+
return Math.sqrt(variance);
10+
};
11+
312
export const calculateVolatility = (values: number[]) => {
413
if (values.length === 0) {
514
throw new Error('Cannot calculate volatility for empty array');

src/helpers/streams.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import { WebRTCStatsParsedWithNetworkScores } from '../types';
2+
import { calculateStandardDeviation } from './calc';
3+
4+
export const isDtxLikeBehavior = (
5+
ssrc: number,
6+
allProcessedStats: WebRTCStatsParsedWithNetworkScores[],
7+
stdDevThreshold = 30,
8+
): boolean => {
9+
const frameIntervals: number[] = [];
10+
for (let i = 1; i < allProcessedStats.length - 1; i += 1) {
11+
const videoStreamStats = allProcessedStats[i]?.video?.inbound.find(
12+
(stream) => stream.ssrc === ssrc,
13+
);
14+
15+
if (!videoStreamStats) {
16+
continue;
17+
}
18+
19+
const previousVideoStreamStats = allProcessedStats[i - 1]?.video?.inbound?.find(
20+
(stream) => stream.ssrc === ssrc,
21+
);
22+
23+
if (!videoStreamStats || !previousVideoStreamStats) {
24+
continue;
25+
}
26+
27+
const deltaTime = videoStreamStats.timestamp - previousVideoStreamStats.timestamp;
28+
const deltaFrames = videoStreamStats.framesDecoded - previousVideoStreamStats.framesDecoded;
29+
30+
if (deltaFrames > 0) {
31+
const frameInterval = deltaTime / deltaFrames; // Average time per frame
32+
frameIntervals.push(frameInterval);
33+
}
34+
}
35+
36+
if (frameIntervals.length <= 1) {
37+
return false;
38+
}
39+
40+
const stdDev = calculateStandardDeviation(frameIntervals);
41+
return stdDev > stdDevThreshold;
42+
};

0 commit comments

Comments
 (0)