Start · Sprachen · JavaScript · Referenz · RTCInboundRtpStreamStats.totalFreezesDuration

RTCInboundRtpStreamStats.totalFreezesDuration

Eigenschaft

Gibt an, wie lange das empfangene Video dieses eingehenden RTP-Streams insgesamt eingefroren war, in Sekunden (<code>number</code>, nur bei Video-Streams).

seit JavaScript WebRTC Statistics (Level 1); unterstützt in Chromi Kategorie: webapi

Signatur

RTCInboundRtpStreamStats.totalFreezesDuration

Beschreibung

Die Eigenschaft totalFreezesDuration des Wörterbuchs RTCInboundRtpStreamStats (Statistik-Typ "inbound-rtp") summiert die Dauer aller Video-Einfrierer (Freezes) seit Beginn des Streams, in Sekunden. Die MDN-Kurzbeschreibung nennt hier RTCRemoteInboundRtpStreamStats. Das ist ein Fehler: Die Eigenschaft gehört zu RTCInboundRtpStreamStats, also zu den Statistiken des lokal empfangenen Streams.

Als Einfrieren gilt laut Spezifikation, wenn der Abstand zwischen zwei gerenderten Bildern größer ist als max(3 × durchschnittliche Bilddauer, durchschnittliche Bilddauer + 150 ms). Die durchschnittliche Bilddauer wird dabei über die letzten 30 gerenderten Bilder ermittelt. Jedes solche Ereignis erhöht freezeCount um eins und addiert seine Dauer zu totalFreezesDuration.

Die Eigenschaft ist eine wichtige Kennzahl für die wahrgenommene Videoqualität, z. B. für Qualitäts-Dashboards, adaptive Steuerung oder Telemetrie in Videokonferenz-Anwendungen. Weil der Wert kumulativ ist, bildet man für Auswertungen über die Zeit meist die Differenz zwischen zwei getStats()-Aufrufen. Zusammen mit freezeCount lässt sich außerdem die durchschnittliche Dauer eines Einfrierers berechnen.

Rückgabewert

Typ
number | undefined
Beschreibung
Gesamtdauer aller erkannten Video-Einfrierer in Sekunden (Gleitkommazahl, steigt nur an). Bei Audio-Streams oder in Browsern ohne Unterstützung ist der Wert undefined.

Beispiele

Einfrier-Dauer aller eingehenden Video-Streams auslesen

// pc ist eine bestehende RTCPeerConnection mit empfangenem Video
const logFreezes = async (pc) => {
  const stats = await pc.getStats();
  stats.forEach((report) => {
    if (report.type === 'inbound-rtp' && report.kind === 'video') {
      console.log(
        `SSRC ${report.ssrc}: ${report.freezeCount ?? 0} Einfrierer, ` +
        `gesamt ${(report.totalFreezesDuration ?? 0).toFixed(2)} s`
      );
    }
  });
};

await logFreezes(pc);
SSRC 1234567890: 3 Einfrierer, gesamt 1.48 s

Einfrier-Anteil pro Intervall überwachen (Differenzbildung)

const monitorFreezes = (pc, intervalMs = 5000) => {
  let last = new Map(); // id -> { t, freeze }

  return setInterval(async () => {
    const stats = await pc.getStats();
    for (const r of stats.values()) {
      if (r.type !== 'inbound-rtp' || r.kind !== 'video') continue;
      const freeze = r.totalFreezesDuration ?? 0;
      const prev = last.get(r.id);
      if (prev) {
        const dt = (r.timestamp - prev.t) / 1000; // Sekunden
        const ratio = (freeze - prev.freeze) / dt;
        if (ratio > 0.05) {
          console.warn(`Video ${(ratio * 100).toFixed(1)} % der Zeit eingefroren`);
        }
      }
      last.set(r.id, { t: r.timestamp, freeze });
    }
  }, intervalMs);
};

const timer = monitorFreezes(pc);
// später: clearInterval(timer);
Video 12.4 % der Zeit eingefroren

Durchschnittliche Dauer eines Einfrierers berechnen

const averageFreeze = async (pc) => {
  const stats = await pc.getStats();
  const video = [...stats.values()].find(
    (r) => r.type === 'inbound-rtp' && r.kind === 'video'
  );
  if (!video || video.totalFreezesDuration === undefined) {
    return null; // nicht unterstützt oder kein Video
  }
  return video.freezeCount > 0
    ? video.totalFreezesDuration / video.freezeCount
    : 0;
};

console.log(`Ø Einfrierer: ${await averageFreeze(pc)} s`);
Ø Einfrierer: 0.4933 s

// Wichtig · Fallstricke

  • Nur Video: Bei Einträgen mit kind === "audio" fehlt die Eigenschaft. Filtere deshalb immer nach type und kind.
  • Kumulativ: Der Wert wird seit Beginn des Streams aufaddiert. Für Aussagen über den aktuellen Zeitraum musst du Differenzen bilden und dafür timestamp des Berichts verwenden, nicht Date.now().
  • Einfrieren ist keine Pause: Kommen länger als 5 Sekunden keine Bilder an (z. B. weil der Sender das Video abgeschaltet hat), zählt das als Pause. Pausen werden in pauseCount und totalPausesDuration erfasst, nicht hier.
  • Browser-Kompatibilität: Chromium-basierte Browser (Chrome, Edge) unterstützen die Eigenschaft. Firefox und Safari liefern sie teilweise nicht. Prüfe deshalb auf undefined und nutze ?? 0 als Absicherung.
  • Fehler in der MDN-Beschreibung: Die Eigenschaft gehört nicht zu RTCRemoteInboundRtpStreamStats ("remote-inbound-rtp"), sondern zu RTCInboundRtpStreamStats ("inbound-rtp").