Skip to content

Commit b7db99f

Browse files
feat: rework detector to only check bytesReceived
1 parent 38746a3 commit b7db99f

File tree

1 file changed

+32
-75
lines changed

1 file changed

+32
-75
lines changed

src/detectors/MissingStreamDataDetector.ts

Lines changed: 32 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import {
2+
CommonParsedInboundStreamStats,
23
IssueDetectorResult,
4+
IssuePayload,
35
IssueReason,
46
IssueType,
5-
ParsedInboundAudioStreamStats,
6-
ParsedInboundVideoStreamStats,
7-
WebRTCStatsParsed,
7+
WebRTCStatsParsed
88
} from '../types';
99
import BaseIssueDetector from './BaseIssueDetector';
1010

@@ -18,7 +18,7 @@ export class MissingStreamDataDetector extends BaseIssueDetector {
1818

1919
constructor(params: MissingStreamDetectorParams = {}) {
2020
super();
21-
this.#timeoutMs = params.timeoutMs ?? 10_000;
21+
this.#timeoutMs = params.timeoutMs ?? 5_000;
2222
}
2323

2424
performDetection(data: WebRTCStatsParsed): IssueDetectorResult {
@@ -29,108 +29,65 @@ export class MissingStreamDataDetector extends BaseIssueDetector {
2929
}
3030

3131
private processData(data: WebRTCStatsParsed): IssueDetectorResult {
32-
const { connection: { id: connectionId } } = data;
33-
const previousStats = this.getLastProcessedStats(connectionId);
3432
const issues: IssueDetectorResult = [];
3533

36-
if (!previousStats) {
37-
return issues;
38-
}
39-
4034
const { video: { inbound: newVideoInbound } } = data;
41-
const { video: { inbound: prevVideoInbound } } = previousStats;
4235
const { audio: { inbound: newAudioInbound } } = data;
43-
const { audio: { inbound: prevAudioInbound } } = previousStats;
44-
45-
const mapVideoStatsByTrackId = (items: ParsedInboundVideoStreamStats[]) => new Map<string, ParsedInboundVideoStreamStats>(
46-
items.map((item) => [item.track.trackIdentifier, item] as const),
47-
);
48-
const mapAudioStatsByTrackId = (items: ParsedInboundAudioStreamStats[]) => new Map<string, ParsedInboundAudioStreamStats>(
49-
items.map((item) => [item.track.trackIdentifier, item] as const),
50-
);
51-
52-
const newVideoInboundByTrackId = mapVideoStatsByTrackId(newVideoInbound);
53-
const prevVideoInboundByTrackId = mapVideoStatsByTrackId(prevVideoInbound);
54-
const newAudioInboundByTrackId = mapAudioStatsByTrackId(newAudioInbound);
55-
const prevAudioInboundByTrackId = mapAudioStatsByTrackId(prevAudioInbound);
56-
const unvisitedTrackIds = new Set(this.#lastMarkedAt.keys());
57-
58-
Array.from(newVideoInboundByTrackId.entries()).forEach(([trackId, newInboundItem]) => {
59-
unvisitedTrackIds.delete(trackId);
6036

61-
const prevInboundItem = prevVideoInboundByTrackId.get(trackId);
62-
if (!prevInboundItem) {
63-
return;
64-
}
65-
66-
const deltaFramesReceived = newInboundItem.framesReceived - prevInboundItem.framesReceived;
67-
68-
if (deltaFramesReceived === 0 && !newInboundItem.track.detached && !newInboundItem.track.ended) {
69-
const hasIssue = this.markIssue(trackId);
37+
issues.push(...this.detectMissingData(
38+
newAudioInbound as unknown as CommonParsedInboundStreamStats[],
39+
IssueType.Stream,
40+
IssueReason.MissingAudioStreamData,
41+
));
42+
issues.push(...this.detectMissingData(
43+
newVideoInbound,
44+
IssueType.Stream,
45+
IssueReason.MissingVideoStreamData,
46+
));
7047

71-
if (!hasIssue) {
72-
return;
73-
}
74-
75-
const statsSample = {
76-
framesReceived: newInboundItem.framesReceived,
77-
framesDropped: newInboundItem.framesDropped,
78-
trackDetached: newInboundItem.track.detached,
79-
trackEnded: newInboundItem.track.ended,
80-
};
48+
const unvisitedTrackIds = new Set(this.#lastMarkedAt.keys());
8149

82-
issues.push({
83-
type: IssueType.Stream,
84-
reason: IssueReason.MissingVideoStreamData,
85-
statsSample,
86-
});
87-
} else {
50+
unvisitedTrackIds.forEach((trackId) => {
51+
const lastMarkedAt = this.#lastMarkedAt.get(trackId);
52+
if (lastMarkedAt && Date.now() - lastMarkedAt > this.#timeoutMs) {
8853
this.removeMarkIssue(trackId);
8954
}
9055
});
9156

92-
Array.from(newAudioInboundByTrackId.entries()).forEach(([trackId, newInboundItem]) => {
93-
unvisitedTrackIds.delete(trackId);
57+
return issues;
58+
}
9459

95-
const prevInboundItem = prevAudioInboundByTrackId.get(trackId);
96-
if (!prevInboundItem) {
97-
return;
98-
}
60+
private detectMissingData(commonStreamStats: CommonParsedInboundStreamStats[], type: IssueType, reason: IssueReason): IssueDetectorResult {
61+
const issues: IssuePayload[] = [];
9962

100-
const deltaFramesReceived = newInboundItem.bytesReceived - prevInboundItem.bytesReceived;
63+
commonStreamStats.forEach((inboundItem) => {
64+
const trackId = inboundItem.track.trackIdentifier
10165

102-
if (deltaFramesReceived === 0 && !newInboundItem.track.detached && !newInboundItem.track.ended) {
66+
if (inboundItem.bytesReceived === 0 && !inboundItem.track.detached && !inboundItem.track.ended) {
10367
const hasIssue = this.markIssue(trackId);
10468

10569
if (!hasIssue) {
10670
return;
10771
}
10872

10973
const statsSample = {
110-
bytesReceived: newInboundItem.bytesReceived,
111-
packetsDiscarded: newInboundItem.packetsDiscarded,
112-
trackDetached: newInboundItem.track.detached,
113-
trackEnded: newInboundItem.track.ended,
74+
bytesReceived: inboundItem.bytesReceived,
75+
trackDetached: inboundItem.track.detached,
76+
trackEnded: inboundItem.track.ended,
11477
};
11578

11679
issues.push({
117-
type: IssueType.Stream,
118-
reason: IssueReason.MissingAudioStreamData,
80+
type,
81+
reason,
11982
statsSample,
83+
trackIdentifier: trackId,
12084
});
12185
} else {
12286
this.removeMarkIssue(trackId);
12387
}
12488
});
12589

126-
unvisitedTrackIds.forEach((trackId) => {
127-
const lastMarkedAt = this.#lastMarkedAt.get(trackId);
128-
if (lastMarkedAt && Date.now() - lastMarkedAt > this.#timeoutMs) {
129-
this.removeMarkIssue(trackId);
130-
}
131-
});
132-
133-
return issues;
90+
return issues
13491
}
13592

13693
private markIssue(trackId: string): boolean {

0 commit comments

Comments
 (0)