Start · Sprachen · JavaScript · Referenz · RTCOutboundRtpStreamStats.totalEncodedBytesTarget

RTCOutboundRtpStreamStats.totalEncodedBytesTarget

Eigenschaft

Kumulierte Summe der Zielgrößen in Bytes, die der Encoder für jeden bisher enkodierten Frame eines ausgehenden RTP-Streams angestrebt hat.

seit JavaScript WebRTC Statistics API; derzeit nur in Chromium-Bro Kategorie: webapi

Signatur

RTCOutboundRtpStreamStats.totalEncodedBytesTarget

Beschreibung

Die schreibgeschützte Eigenschaft totalEncodedBytesTarget des Wörterbuchs RTCOutboundRtpStreamStats ist ein Zähler, der nur wächst. Jedes Mal, wenn der Encoder einen Frame erfolgreich enkodiert hat, wird die Zielgröße dieses Frames in Bytes addiert. Die Zielgröße ist die Größe, die der Encoder laut seiner Ratensteuerung für den Frame anpeilt. Wie groß der Frame am Ende tatsächlich wird, spielt für diesen Wert keine Rolle.

Der Wert zeigt also, wie viele Daten der Encoder liefern sollte. Setzt du ihn ins Verhältnis zu framesEncoded, erhältst du die durchschnittliche Zielgröße pro Frame. Vergleichst du ihn mit den tatsächlich gesendeten Nutzdaten (bytesSent - headerBytesSent), siehst du, ob der Encoder sein Ziel regelmäßig über- oder unterschreitet. Das hilft bei der Fehlersuche in der Bandbreitenschätzung, bei Qualitätseinbrüchen oder bei zu hoher Datenrate.

Du liest die Eigenschaft aus einem RTCStatsReport, den RTCPeerConnection.getStats() oder RTCRtpSender.getStats() liefert. Dort filterst du nach Einträgen mit type === "outbound-rtp". Da es sich um einen kumulierten Zähler handelt, brauchst du für Aussagen über einen Zeitraum zwei Momentaufnahmen und ihre Differenz.

Rückgabewert

Typ
number | undefined
Beschreibung
Nicht negative Ganzzahl (in der WebIDL unsigned long long): Summe der Zielgrößen aller bisher enkodierten Frames in Bytes. Gibt der Browser die Metrik nicht an, fehlt die Eigenschaft und der Wert ist undefined. Bei Audio-Streams ist sie in der Regel nicht vorhanden.

Beispiele

Durchschnittliche Zielgröße pro Frame ermitteln

// pc ist eine bestehende RTCPeerConnection, die Video sendet
const logTargetFrameSize = async (pc) => {
  const report = await pc.getStats();
  report.forEach((stats) => {
    if (stats.type !== 'outbound-rtp' || stats.kind !== 'video') return;
    const { totalEncodedBytesTarget, framesEncoded } = stats;
    if (totalEncodedBytesTarget === undefined || !framesEncoded) {
      console.log('Metrik nicht verfügbar');
      return;
    }
    const avg = totalEncodedBytesTarget / framesEncoded;
    console.log(`SSRC ${stats.ssrc}: Ø Zielgröße ${avg.toFixed(0)} Bytes/Frame`);
  });
};

logTargetFrameSize(pc);
SSRC 1234567890: Ø Zielgröße 4210 Bytes/Frame

Ziel-Bitrate des Encoders über ein Intervall berechnen

// Differenz zweier Momentaufnahmen -> angestrebte Nutzdaten-Bitrate
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));

const getVideoOutbound = async (sender) => {
  const report = await sender.getStats();
  return [...report.values()].find((s) => s.type === 'outbound-rtp');
};

const measureTargetBitrate = async (sender, intervalMs = 2000) => {
  const a = await getVideoOutbound(sender);
  await sleep(intervalMs);
  const b = await getVideoOutbound(sender);
  if (a?.totalEncodedBytesTarget === undefined) return null;
  const bytes = b.totalEncodedBytesTarget - a.totalEncodedBytesTarget;
  const seconds = (b.timestamp - a.timestamp) / 1000;
  return Math.round((bytes * 8) / seconds / 1000); // kbit/s
};

const [videoSender] = pc.getSenders().filter((s) => s.track?.kind === 'video');
console.log(`Ziel: ${await measureTargetBitrate(videoSender)} kbit/s`);
Ziel: 1480 kbit/s

Soll und Ist der Encoder-Ausgabe vergleichen

// Überschreitet der Encoder dauerhaft sein Ziel?
const compareTargetVsActual = async (pc) => {
  const report = await pc.getStats();
  for (const s of report.values()) {
    if (s.type !== 'outbound-rtp' || s.totalEncodedBytesTarget === undefined) continue;
    // Nutzdaten ohne RTP-Header (Retransmissions sind hier enthalten)
    const payload = s.bytesSent - (s.headerBytesSent ?? 0);
    const ratio = payload / s.totalEncodedBytesTarget;
    console.log(`Ist/Soll-Verhältnis: ${ratio.toFixed(2)}`);
    if (ratio > 1.2) console.warn('Encoder liegt deutlich über dem Ziel');
  }
};

compareTargetVsActual(pc);
Ist/Soll-Verhältnis: 1.03

// Wichtig · Fallstricke

  • Kompatibilität: Die Metrik steht in der W3C-Spezifikation „Identifiers for WebRTC's Statistics API“, wird aber derzeit nur von Chromium-Browsern (Chrome, Edge, Opera) gemeldet. In Firefox und Safari fehlt sie meist. Prüfe deshalb immer auf undefined.
  • Kumulierter Zähler: Der Wert zählt seit Beginn des Streams hoch. Für aktuelle Raten brauchst du zwei Momentaufnahmen und die Differenz ihrer timestamp-Werte in Millisekunden.
  • Soll statt Ist: Der Wert sagt nichts über tatsächlich gesendete Daten aus. Für die echte Datenmenge nimmst du bytesSent bzw. headerBytesSent. Diese Zähler enthalten allerdings auch Retransmissions und Padding. Ein Vergleich mit dem Zielwert ist deshalb nur ein Näherungswert.
  • Simulcast/SVC: Bei Simulcast gibt es pro Schicht (rid) einen eigenen outbound-rtp-Eintrag mit eigenem Zähler. Für eine Gesamtbetrachtung musst du die Werte selbst addieren.
  • Pausierte oder deaktivierte Encodings (active: false) erhöhen den Zähler nicht.