Start · Sprachen · JavaScript · Referenz · RTCInboundRtpStreamStats.totalSquaredInterFrameDelay

RTCInboundRtpStreamStats.totalSquaredInterFrameDelay

Eigenschaft

Summe der Quadrate aller Zwischenbildverzögerungen (in Sekunden) zwischen aufeinanderfolgend dargestellten Videoframes eines eingehenden RTP-Streams.

seit JavaScript WebRTC Statistics API; Chromium-basierte Browser u Kategorie: webapi

Signatur

RTCInboundRtpStreamStats.totalSquaredInterFrameDelay

Beschreibung

Die schreibgeschützte Eigenschaft totalSquaredInterFrameDelay des Wörterbuchs RTCInboundRtpStreamStats ist ein aufsummierter Wert: Nach jedem dargestellten Frame misst der Browser die Zeit seit dem vorherigen dargestellten Frame (die Zwischenbildverzögerung), quadriert sie und addiert sie zu diesem Zähler. Der Wert wird in Sekunden² angegeben und gilt nur für Video-Streams (kind === "video").

Für sich allein ist der Wert wenig aussagekräftig. Zusammen mit totalInterFrameDelay (Summe der einfachen Verzögerungen) und framesRendered lässt sich jedoch die Varianz bzw. Standardabweichung der Zwischenbildverzögerung berechnen – ein gutes Maß für ruckelndes Video (Frame-Jitter), auch wenn die mittlere Bildrate unauffällig ist:

  • Varianz = (totalSquaredInterFrameDelay - totalInterFrameDelay² / n) / n, wobei n die Anzahl der Frames ist (laut Spezifikation framesRendered).

Man erhält den Wert über RTCPeerConnection.getStats() bzw. RTCRtpReceiver.getStats(), indem man im zurückgegebenen RTCStatsReport nach Einträgen mit type === "inbound-rtp" filtert. Da der Zähler seit Beginn des Streams kumuliert, bildet man für Live-Überwachung meist Differenzen zwischen zwei Messzeitpunkten.

Rückgabewert

Typ
number | undefined
Beschreibung
Eine Gleitkommazahl (double) mit der Summe der quadrierten Zwischenbildverzögerungen in Sekunden². undefined bei Audio-Streams oder wenn der Browser die Eigenschaft nicht unterstützt.

Beispiele

Wert aus dem Statistikbericht auslesen

// pc ist eine bestehende RTCPeerConnection mit eingehendem Video
const logSquaredDelay = async (pc) => {
  const report = await pc.getStats();
  report.forEach((stats) => {
    if (stats.type === 'inbound-rtp' && stats.kind === 'video') {
      console.log('Summe quadrierter Verzögerungen:',
        stats.totalSquaredInterFrameDelay?.toFixed(4), 's²');
    }
  });
};

logSquaredDelay(pc);
Summe quadrierter Verzögerungen: 3.4127 s²

Standardabweichung der Zwischenbildverzögerung (Frame-Jitter)

const getFrameJitter = async (receiver) => {
  const report = await receiver.getStats();
  for (const stats of report.values()) {
    if (stats.type !== 'inbound-rtp' || stats.kind !== 'video') continue;

    const { totalInterFrameDelay: sum, totalSquaredInterFrameDelay: sumSq } = stats;
    const n = stats.framesRendered ?? stats.framesDecoded;
    if (sum === undefined || sumSq === undefined || !n) return null;

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

const [videoReceiver] = pc.getReceivers().filter((r) => r.track.kind === 'video');
console.log(await getFrameJitter(videoReceiver));
{ meanMs: 33.4, stdDevMs: 6.2 }

Ruckeln im laufenden Betrieb über Intervall-Differenzen erkennen

let prev = null;

const monitor = async (pc) => {
  const report = await pc.getStats();
  const cur = [...report.values()].find(
    (s) => s.type === 'inbound-rtp' && s.kind === 'video'
  );
  if (!cur || cur.totalSquaredInterFrameDelay === undefined) return;

  if (prev) {
    const n = cur.framesRendered - prev.framesRendered;
    const sum = cur.totalInterFrameDelay - prev.totalInterFrameDelay;
    const sumSq = cur.totalSquaredInterFrameDelay - prev.totalSquaredInterFrameDelay;
    if (n > 0) {
      const stdDevMs = Math.sqrt(Math.max(0, (sumSq - sum * sum / n) / n)) * 1000;
      if (stdDevMs > 20) console.warn(`Video ruckelt: σ = ${stdDevMs.toFixed(1)} ms`);
    }
  }
  prev = cur;
};

const timer = setInterval(() => monitor(pc), 2000);
// Später: clearInterval(timer);
Video ruckelt: σ = 27.8 ms

// Wichtig · Fallstricke

  • Nur Video: Für Audio-Streams (kind === "audio") ist die Eigenschaft nicht vorhanden.
  • Einheit: Der Wert ist in Sekunden² angegeben, nicht in Millisekunden. Erst nach dem Wurzelziehen der Varianz und Multiplikation mit 1000 erhält man Millisekunden.
  • Kumulativ: Der Zähler wächst über die gesamte Lebensdauer des Streams. Für aktuelle Werte immer Differenzen zwischen zwei getStats()-Aufrufen bilden, sonst glätten alte Daten neue Probleme weg.
  • Nenner: Die Spezifikation nennt framesRendered; in älteren Implementierungen bzw. Spezifikationsständen wurde framesDecoded verwendet. Streng genommen gibt es eine Verzögerung weniger als Frames – bei großen Frame-Zahlen ist der Unterschied vernachlässigbar.
  • Rundungsfehler: Durch Gleitkomma-Ungenauigkeit kann die berechnete Varianz minimal negativ werden – vor Math.sqrt() mit Math.max(0, …) absichern.
  • Kompatibilität: In Chromium-basierten Browsern verfügbar, in Firefox und Safari je nach Version eingeschränkt oder fehlend. Immer per Prüfung auf undefined absichern.