Start · Sprachen · JavaScript · Referenz · RTCIceCandidatePairStats.availableOutgoingBitrate

RTCIceCandidatePairStats.availableOutgoingBitrate

Eigenschaft

Liefert die von der Staukontrolle geschätzte verfügbare ausgehende Bandbreite (in Bit pro Sekunde) der Verbindung, die ein ICE-Kandidatenpaar darstellt.

seit JavaScript WebRTC Statistics (W3C); Chromium-Browser und Safa Kategorie: webapi

Signatur

RTCIceCandidatePairStats.availableOutgoingBitrate

Beschreibung

Die Eigenschaft availableOutgoingBitrate eines RTCIceCandidatePairStats-Objekts gibt an, wie viel ausgehende Kapazität die Netzwerkverbindung eines Kandidatenpaars gerade hat. Der Wert ist eine Zahl in Bit pro Sekunde. Der Browser berechnet ihn mit seiner Staukontrolle (z. B. GCC oder Transport-CC) und fasst dabei alle ausgehenden RTP-Streams zusammen, die über dieses Kandidatenpaar laufen.

Header von IP, UDP oder TCP sind in der Messung nicht enthalten. Sie entspricht damit etwa dem Wert TIAS (Transport Independent Application Specific Maximum) aus RFC 3890. In der Praxis zeigt sie, welche Bitrate Audio, Video und Datenkanäle gemeinsam nutzen können, bevor Pakete verloren gehen oder sich die Verzögerung erhöht.

Typische Einsatzfälle sind adaptive Bitraten-Steuerung (z. B. Auflösung oder maxBitrate eines RTCRtpSender anpassen), Anzeigen zur Verbindungsqualität in Videokonferenz-Apps und Telemetrie zur Fehlersuche bei schlechten Anrufen. Den Wert bekommst du über RTCPeerConnection.getStats(), indem du im zurückgegebenen RTCStatsReport den Eintrag mit type === "candidate-pair" suchst, der gerade genutzt wird.

Rückgabewert

Typ
number | undefined
Beschreibung
Geschätzte verfügbare ausgehende Bitrate in Bit pro Sekunde (ohne IP- und Transport-Header). Der Wert ist undefined, wenn der Browser keine senderseitige Schätzung berechnet oder das Paar nicht das aktive bzw. nominierte Paar ist.

Beispiele

Verfügbare Upload-Bandbreite des aktiven Kandidatenpaars auslesen

// pc ist eine bereits verbundene RTCPeerConnection
const getOutgoingBitrate = async (pc) => {
  const report = await pc.getStats();
  let selectedPairId;

  // Das aktive Paar über die Transport-Statistik finden
  report.forEach((stat) => {
    if (stat.type === 'transport' && stat.selectedCandidatePairId) {
      selectedPairId = stat.selectedCandidatePairId;
    }
  });

  // Rückfall: nominiertes Paar im Zustand "succeeded"
  const pair = selectedPairId
    ? report.get(selectedPairId)
    : [...report.values()].find(
        (s) => s.type === 'candidate-pair' && s.nominated && s.state === 'succeeded'
      );

  return pair?.availableOutgoingBitrate;
};

const bitrate = await getOutgoingBitrate(pc);
if (bitrate !== undefined) {
  console.log(`Verfügbar: ${(bitrate / 1_000_000).toFixed(2)} Mbit/s`);
} else {
  console.log('Keine Bandbreitenschätzung verfügbar');
}
Verfügbar: 2.47 Mbit/s

Video-Bitrate dynamisch an die verfügbare Bandbreite anpassen

const adaptVideoBitrate = async (pc) => {
  const report = await pc.getStats();
  const pair = [...report.values()].find(
    (s) => s.type === 'candidate-pair' && s.nominated && s.state === 'succeeded'
  );
  const available = pair?.availableOutgoingBitrate;
  if (!available) return;

  const sender = pc.getSenders().find((s) => s.track?.kind === 'video');
  if (!sender) return;

  const params = sender.getParameters();
  if (!params.encodings?.length) return;

  // 80 % der Kapazität für Video, Rest als Puffer für Audio/Daten
  const target = Math.floor(available * 0.8);
  params.encodings[0].maxBitrate = target;
  await sender.setParameters(params);
  console.log(`maxBitrate gesetzt auf ${Math.round(target / 1000)} kbit/s`);
};

// Alle 2 Sekunden neu bewerten
const timer = setInterval(() => adaptVideoBitrate(pc), 2000);
pc.addEventListener('connectionstatechange', () => {
  if (pc.connectionState === 'closed') clearInterval(timer);
});
maxBitrate gesetzt auf 1976 kbit/s

Qualitätsanzeige für eine Videokonferenz

const qualityLabel = (bps) => {
  if (bps === undefined) return 'unbekannt';
  if (bps >= 2_500_000) return 'sehr gut (HD)';
  if (bps >= 1_000_000) return 'gut';
  if (bps >= 300_000) return 'eingeschränkt';
  return 'schlecht';
};

const updateIndicator = async (pc, element) => {
  const report = await pc.getStats();
  const pair = [...report.values()].find(
    (s) => s.type === 'candidate-pair' && s.nominated && s.state === 'succeeded'
  );
  element.textContent = `Verbindung: ${qualityLabel(pair?.availableOutgoingBitrate)}`;
};

setInterval(() => updateIndicator(pc, document.querySelector('#quality')), 1000);
Verbindung: gut

// Wichtig · Fallstricke

  • Einheit: Der Wert ist in Bit pro Sekunde angegeben, nicht in Byte. Für kbit/s teilst du durch 1000, für Mbit/s durch 1 000 000.
  • Nur für das aktive Paar sinnvoll: Bei nicht genutzten oder fehlgeschlagenen Kandidatenpaaren fehlt die Eigenschaft meist (undefined). Nimm daher möglichst das Paar aus RTCTransportStats.selectedCandidatePairId.
  • Es ist eine Schätzung: Der Wert stammt aus der Staukontrolle und schwankt, besonders kurz nach dem Verbindungsaufbau. Er steigt oft erst dann, wenn tatsächlich Daten gesendet werden. Glätte ihn für Regelungen, z. B. mit einem gleitenden Mittelwert.
  • Kein Overhead enthalten: IP-, UDP- und TCP-Header werden nicht mitgezählt. Die tatsächlich über die Leitung übertragene Datenmenge ist also etwas größer.
  • Browser-Kompatibilität: Chrome, Edge und Safari unterstützen die Eigenschaft. Firefox liefert sie bislang nicht. Prüfe daher immer auf undefined und sieh eine Ersatzlösung vor, z. B. eine eigene Berechnung aus bytesSent über die Zeit.
  • Rufe getStats() nicht zu oft auf (Intervalle unter etwa 500 ms), denn jeder Aufruf erzeugt einen vollständigen Bericht und kostet Rechenzeit.