Skip to content

Commit cecbcb1

Browse files
refactor: LD-6968 do changes after code review
1 parent bfe5221 commit cecbcb1

File tree

1 file changed

+66
-33
lines changed

1 file changed

+66
-33
lines changed

src/detectors/DeadVideoTrackDetector.ts

Lines changed: 66 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,22 @@ import {
77
} from '../types';
88
import BaseIssueDetector from './BaseIssueDetector';
99

10+
interface DeadVideoTrackDetectorParams {
11+
timeoutMs?: number;
12+
framesDroppedThreshold?: number;
13+
}
14+
1015
class DeadVideoTrackDetector extends BaseIssueDetector {
11-
#lastMarkedAt: number | undefined;
16+
readonly #lastMarkedAt = new Map<string, number>();
17+
18+
readonly #timeoutMs: number;
1219

13-
#timeoutMs: number;
20+
readonly #framesDroppedThreshold: number;
1421

15-
constructor(params: { timeoutMs?: number } = {}) {
22+
constructor(params: DeadVideoTrackDetectorParams = {}) {
1623
super();
1724
this.#timeoutMs = params.timeoutMs ?? 10_000;
25+
this.#framesDroppedThreshold = params.framesDroppedThreshold ?? 0.5;
1826
}
1927

2028
performDetection(data: WebRTCStatsParsed): IssueDetectorResult {
@@ -42,60 +50,85 @@ class DeadVideoTrackDetector extends BaseIssueDetector {
4250

4351
const newInboundByTrackId = mapByTrackId(newInbound);
4452
const prevInboundByTrackId = mapByTrackId(prevInbound);
53+
const unvisitedTrackIds = new Set(this.#lastMarkedAt.keys());
4554

4655
Array.from(newInboundByTrackId.entries()).forEach(([trackId, newInboundItem]) => {
56+
unvisitedTrackIds.delete(trackId);
57+
4758
const prevInboundItem = prevInboundByTrackId.get(trackId);
4859
if (!prevInboundItem) {
4960
return;
5061
}
5162

52-
if (
53-
newInboundItem.packetsReceived > prevInboundItem.packetsReceived
54-
) {
55-
if (newInboundItem.framesDecoded > prevInboundItem.framesDecoded) {
56-
this.removeMarkIssue();
57-
} else {
58-
const hasIssue = this.markIssue();
59-
60-
if (hasIssue) {
61-
const statsSample = {
62-
packetsReceived: newInboundItem.packetsReceived,
63-
framesDecoded: newInboundItem.framesDecoded,
64-
deltaFramesDecoded: newInboundItem.framesDecoded - prevInboundItem.framesDecoded,
65-
deltaPacketsReceived: newInboundItem.packetsReceived - prevInboundItem.packetsReceived,
66-
};
67-
68-
issues.push({
69-
statsSample,
70-
type: IssueType.Stream,
71-
reason: IssueReason.DeadVideoTrack,
72-
iceCandidate: trackId,
73-
});
74-
}
75-
}
63+
const deltaFramesReceived = newInboundItem.framesReceived - prevInboundItem.framesReceived;
64+
const deltaFramesDropped = newInboundItem.framesDropped - prevInboundItem.framesDropped;
65+
const deltaFramesDecoded = newInboundItem.framesDecoded - prevInboundItem.framesDecoded;
66+
const ratioFramesDropped = deltaFramesDropped / deltaFramesReceived;
67+
68+
if (deltaFramesReceived === 0) {
69+
return;
70+
}
71+
72+
if (ratioFramesDropped >= this.#framesDroppedThreshold) {
73+
return;
74+
}
75+
76+
// It seems that track is alive and we can remove mark if it was marked
77+
if (deltaFramesDecoded > 0) {
78+
this.removeMarkIssue(trackId);
79+
return;
80+
}
81+
82+
const hasIssue = this.markIssue(trackId);
83+
84+
if (!hasIssue) {
85+
return;
7686
}
87+
88+
const statsSample = {
89+
framesReceived: newInboundItem.framesReceived,
90+
framesDropped: newInboundItem.framesDropped,
91+
framesDecoded: newInboundItem.framesDecoded,
92+
deltaFramesReceived,
93+
deltaFramesDropped,
94+
deltaFramesDecoded,
95+
};
96+
97+
issues.push({
98+
statsSample,
99+
type: IssueType.Stream,
100+
reason: IssueReason.DeadVideoTrack,
101+
iceCandidate: trackId,
102+
});
103+
});
104+
105+
// just clear unvisited tracks from memory
106+
unvisitedTrackIds.forEach((trackId) => {
107+
this.removeMarkIssue(trackId);
77108
});
78109

79110
return issues;
80111
}
81112

82-
private markIssue(): boolean {
113+
private markIssue(trackId: string): boolean {
83114
const now = Date.now();
84115

85-
if (!this.#lastMarkedAt) {
86-
this.#lastMarkedAt = now;
116+
const lastMarkedAt = this.#lastMarkedAt.get(trackId);
117+
118+
if (!lastMarkedAt) {
119+
this.#lastMarkedAt.set(trackId, now);
87120
return false;
88121
}
89122

90-
if (now - this.#lastMarkedAt < this.#timeoutMs) {
123+
if (now - lastMarkedAt < this.#timeoutMs) {
91124
return false;
92125
}
93126

94127
return true;
95128
}
96129

97-
private removeMarkIssue(): void {
98-
this.#lastMarkedAt = undefined;
130+
private removeMarkIssue(trackId: string): void {
131+
this.#lastMarkedAt.delete(trackId);
99132
}
100133
}
101134

0 commit comments

Comments
 (0)