Skip to content

Commit

Permalink
refactor: LD-6968 do changes after code review
Browse files Browse the repository at this point in the history
  • Loading branch information
vlad-livedigital committed Jul 31, 2024
1 parent bfe5221 commit cecbcb1
Showing 1 changed file with 66 additions and 33 deletions.
99 changes: 66 additions & 33 deletions src/detectors/DeadVideoTrackDetector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,22 @@ import {
} from '../types';
import BaseIssueDetector from './BaseIssueDetector';

interface DeadVideoTrackDetectorParams {
timeoutMs?: number;
framesDroppedThreshold?: number;
}

class DeadVideoTrackDetector extends BaseIssueDetector {
#lastMarkedAt: number | undefined;
readonly #lastMarkedAt = new Map<string, number>();

readonly #timeoutMs: number;

#timeoutMs: number;
readonly #framesDroppedThreshold: number;

constructor(params: { timeoutMs?: number } = {}) {
constructor(params: DeadVideoTrackDetectorParams = {}) {
super();
this.#timeoutMs = params.timeoutMs ?? 10_000;
this.#framesDroppedThreshold = params.framesDroppedThreshold ?? 0.5;
}

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

const newInboundByTrackId = mapByTrackId(newInbound);
const prevInboundByTrackId = mapByTrackId(prevInbound);
const unvisitedTrackIds = new Set(this.#lastMarkedAt.keys());

Array.from(newInboundByTrackId.entries()).forEach(([trackId, newInboundItem]) => {
unvisitedTrackIds.delete(trackId);

const prevInboundItem = prevInboundByTrackId.get(trackId);
if (!prevInboundItem) {
return;
}

if (
newInboundItem.packetsReceived > prevInboundItem.packetsReceived
) {
if (newInboundItem.framesDecoded > prevInboundItem.framesDecoded) {
this.removeMarkIssue();
} else {
const hasIssue = this.markIssue();

if (hasIssue) {
const statsSample = {
packetsReceived: newInboundItem.packetsReceived,
framesDecoded: newInboundItem.framesDecoded,
deltaFramesDecoded: newInboundItem.framesDecoded - prevInboundItem.framesDecoded,
deltaPacketsReceived: newInboundItem.packetsReceived - prevInboundItem.packetsReceived,
};

issues.push({
statsSample,
type: IssueType.Stream,
reason: IssueReason.DeadVideoTrack,
iceCandidate: trackId,
});
}
}
const deltaFramesReceived = newInboundItem.framesReceived - prevInboundItem.framesReceived;
const deltaFramesDropped = newInboundItem.framesDropped - prevInboundItem.framesDropped;
const deltaFramesDecoded = newInboundItem.framesDecoded - prevInboundItem.framesDecoded;
const ratioFramesDropped = deltaFramesDropped / deltaFramesReceived;

if (deltaFramesReceived === 0) {
return;
}

if (ratioFramesDropped >= this.#framesDroppedThreshold) {
return;
}

// It seems that track is alive and we can remove mark if it was marked
if (deltaFramesDecoded > 0) {
this.removeMarkIssue(trackId);
return;
}

const hasIssue = this.markIssue(trackId);

if (!hasIssue) {
return;
}

const statsSample = {
framesReceived: newInboundItem.framesReceived,
framesDropped: newInboundItem.framesDropped,
framesDecoded: newInboundItem.framesDecoded,
deltaFramesReceived,
deltaFramesDropped,
deltaFramesDecoded,
};

issues.push({
statsSample,
type: IssueType.Stream,
reason: IssueReason.DeadVideoTrack,
iceCandidate: trackId,
});
});

// just clear unvisited tracks from memory
unvisitedTrackIds.forEach((trackId) => {
this.removeMarkIssue(trackId);
});

return issues;
}

private markIssue(): boolean {
private markIssue(trackId: string): boolean {
const now = Date.now();

if (!this.#lastMarkedAt) {
this.#lastMarkedAt = now;
const lastMarkedAt = this.#lastMarkedAt.get(trackId);

if (!lastMarkedAt) {
this.#lastMarkedAt.set(trackId, now);
return false;
}

if (now - this.#lastMarkedAt < this.#timeoutMs) {
if (now - lastMarkedAt < this.#timeoutMs) {
return false;
}

return true;
}

private removeMarkIssue(): void {
this.#lastMarkedAt = undefined;
private removeMarkIssue(trackId: string): void {
this.#lastMarkedAt.delete(trackId);
}
}

Expand Down

0 comments on commit cecbcb1

Please sign in to comment.