Start · Sprachen · JavaScript · Referenz · RTCInboundRtpStreamStats.totalInterFrameDelay

RTCInboundRtpStreamStats.totalInterFrameDelay

Eigenschaft

Gibt die aufsummierte Zeit in Sekunden zwischen aufeinanderfolgend gerenderten Video-Frames eines eingehenden RTP-Streams an.

seit JavaScript WebRTC Statistics (W3C); unterstützt in Chromium-B Kategorie: webapi

Signatur

RTCInboundRtpStreamStats.totalInterFrameDelay

Beschreibung

<p>Die Eigenschaft <code>totalInterFrameDelay</code> des Wörterbuchs <code>RTCInboundRtpStreamStats</code> enthält die Summe aller Abstände (<em>Inter-Frame-Delays</em>) in Sekunden zwischen zwei nacheinander gerenderten Frames. Der Wert wird jeweils direkt nach dem Rendern eines Frames erhöht. Er existiert nur für Video-Streams (<code>kind === "video"</code>). Bei Audio-Streams fehlt er.</p> <p>Weil der Wert kumuliert ist, sagt er allein wenig aus. Nützlich wird er erst im Zusammenspiel mit anderen Werten: Teilt man den Zuwachs von <code>totalInterFrameDelay</code> zwischen zwei <code>getStats()</code>-Abfragen durch den Zuwachs von <code>framesRendered</code>, erhält man den <strong>mittleren Frame-Abstand</strong> in diesem Zeitraum. Der Kehrwert davon ist die tatsächlich wahrgenommene Bildrate.</p> <p>Zusammen mit <code>totalSquaredInterFrameDelay</code> lässt sich die <strong>Varianz</strong> der Frame-Abstände berechnen. Die Formel lautet <code>(totalSquaredInterFrameDelay - totalInterFrameDelay² / n) / n</code>, wobei <code>n</code> die Anzahl der Frames ist. Eine hohe Varianz zeigt ruckelnde Wiedergabe (<em>Jank</em>) an, auch wenn die mittlere Bildrate in Ordnung aussieht. Das ist ein wichtiger Messwert für die Dienstgüte (QoS) in Videokonferenz-Anwendungen.</p>

Rückgabewert

Typ
number | undefined
Beschreibung
Nicht-negative Gleitkommazahl: die aufsummierte Zeit zwischen gerenderten Frames in <strong>Sekunden</strong>. Bei Audio-Streams oder fehlender Unterstützung ist der Wert <code>undefined</code>.

Beispiele

Wert für eingehende Video-Streams auslesen

// pc ist eine bestehende RTCPeerConnection mit empfangenem Video
const logInterFrameDelay = async (pc) => {
  const stats = await pc.getStats();
  stats.forEach((report) => {
    if (report.type === 'inbound-rtp' && report.kind === 'video') {
      console.log(`SSRC ${report.ssrc}: totalInterFrameDelay = ${report.totalInterFrameDelay?.toFixed(3)} s`);
    }
  });
};

await logInterFrameDelay(pc);
SSRC 3735928559: totalInterFrameDelay = 42.137 s

Mittleren Frame-Abstand und effektive Bildrate messen

// Unterschied zwischen zwei Abfragen im Abstand von 1 Sekunde
const getInboundVideo = async (pc) => {
  const stats = await pc.getStats();
  return [...stats.values()].find(
    (r) => r.type === 'inbound-rtp' && r.kind === 'video'
  );
};

const measureSmoothness = async (pc) => {
  const a = await getInboundVideo(pc);
  await new Promise((resolve) => setTimeout(resolve, 1000));
  const b = await getInboundVideo(pc);
  if (!a || !b || b.totalInterFrameDelay === undefined) return null;

  const frames = b.framesRendered - a.framesRendered;
  const delay = b.totalInterFrameDelay - a.totalInterFrameDelay;
  if (frames <= 0) return null;

  const avgDelayMs = (delay / frames) * 1000;
  return { avgDelayMs: avgDelayMs.toFixed(1), fps: (1000 / avgDelayMs).toFixed(1) };
};

console.log(await measureSmoothness(pc));
{ avgDelayMs: '33.4', fps: '29.9' }

Varianz und Standardabweichung der Frame-Abstände (Ruckel-Erkennung)

const jitterOfFrames = (report) => {
  const n = report.framesRendered ?? report.framesDecoded;
  const sum = report.totalInterFrameDelay;
  const sumSq = report.totalSquaredInterFrameDelay;
  if (!n || sum === undefined || sumSq === undefined) return null;

  const variance = (sumSq - (sum * sum) / n) / n;
  const stdDevMs = Math.sqrt(Math.max(variance, 0)) * 1000;
  return stdDevMs;
};

const stats = await pc.getStats();
for (const report of stats.values()) {
  if (report.type === 'inbound-rtp' && report.kind === 'video') {
    const sd = jitterOfFrames(report);
    console.log(sd > 15 ? `Ruckelig: σ = ${sd.toFixed(1)} ms` : `Flüssig: σ = ${sd?.toFixed(1)} ms`);
  }
}
Flüssig: σ = 4.8 ms

// Wichtig · Fallstricke

<ul> <li><strong>Einheit Sekunden:</strong> Der Wert ist in Sekunden angegeben, nicht in Millisekunden. Für Anzeigen muss man ihn meist mit 1000 multiplizieren.</li> <li><strong>Nur Video:</strong> Bei <code>kind === "audio"</code> gibt es die Eigenschaft nicht. Prüfe deshalb immer auf <code>undefined</code>.</li> <li><strong>Kumulierter Wert:</strong> Er wächst über die ganze Lebensdauer des Streams. Aussagekräftige Werte für einen bestimmten Zeitraum bekommt man nur, wenn man die Differenz zwischen zwei <code>getStats()</code>-Aufrufen bildet. Bei einem neuen Stream mit neuer SSRC oder einer neuen Verbindung beginnt der Wert wieder bei 0.</li> <li><strong>Frame-Zähler:</strong> Frühere Versionen der Spezifikation und einige Implementierungen erfassten den Wert beim <em>Dekodieren</em> statt beim Rendern. Bei der Mittelwert- und Varianzberechnung wurde dann <code>framesDecoded</code> statt <code>framesRendered</code> verwendet. Plane für ältere Browser einen Rückgriff ein (siehe Beispiel 3).</li> <li><strong>Kompatibilität:</strong> Chromium-Browser, Firefox und Safari unterstützen die Eigenschaft in aktuellen Versionen. Ältere Browser liefern sie teils nicht. Frage Statistiken nicht zu oft ab (Richtwert: höchstens etwa einmal pro Sekunde), denn <code>getStats()</code> ist verhältnismäßig aufwendig.</li> </ul>