Start · Sprachen · JavaScript · Referenz · RTCPeerConnection.getStats()

RTCPeerConnection.getStats()

Methode

Liefert ein Promise, das mit einem <code>RTCStatsReport</code> mit Statistiken zur gesamten Verbindung oder zu einem bestimmten <code>MediaStreamTrack</code> aufgelöst wird.

seit JavaScript Baseline: alle modernen Browser (seit 2020) Kategorie: webapi

Signatur

RTCPeerConnection.prototype.getStats(selector)

Beschreibung

getStats() fragt aktuelle Messwerte einer WebRTC-Verbindung ab. Dazu gehören übertragene und empfangene Bytes und Pakete, Paketverluste, Jitter, Round-Trip-Time, verwendete Codecs, die Auflösung und Bildrate von Videos sowie Angaben zu ICE-Kandidaten und zum ausgewählten Kandidatenpaar.

Das Ergebnis ist ein RTCStatsReport, ein Map-ähnliches Objekt. Jeder Eintrag ist ein Statistik-Wörterbuch mit einer eindeutigen id, einem timestamp und einem type, z. B. "inbound-rtp", "outbound-rtp", "remote-inbound-rtp", "candidate-pair", "local-candidate", "codec" oder "transport". Die Einträge verweisen über IDs wie transportId oder codecId aufeinander.

Typische Einsatzfälle sind Anzeigen zur Verbindungsqualität, adaptive Bitraten-Logik, Fehlersuche bei ICE- und TURN-Problemen und das Sammeln von Telemetrie. Weil die meisten Zähler kumulativ sind, ruft man getStats() meist regelmäßig auf und berechnet Raten wie kbit/s aus der Differenz zweier Messungen und ihrer Zeitstempel.

Übergibt man einen MediaStreamTrack, werden nur die Statistiken zurückgegeben, die zu diesem Track gehören. Alternativ gibt es RTCRtpSender.getStats() und RTCRtpReceiver.getStats(), die denselben Zweck oft klarer erfüllen.

Parameter

Name Typ Default Beschreibung
$selector MediaStreamTrack | null null Optional. Ein Track, auf den der Bericht beschränkt wird. Bei null oder ohne Angabe gibt es Statistiken zur gesamten Verbindung. Gehört der Track zu keinem oder zu mehreren Sendern bzw. Empfängern, wird das Promise mit einem InvalidAccessError abgelehnt.

Rückgabewert

Typ
Promise<RTCStatsReport>
Beschreibung
Ein Promise, das mit einem RTCStatsReport aufgelöst wird. Das ist ein Map-ähnliches Objekt mit forEach(), get(), entries() usw., dessen Werte Statistik-Objekte mit den Feldern id, type und timestamp sowie typabhängigen Feldern sind.

Beispiele

Alle Statistik-Typen einer Verbindung auflisten

const pc = new RTCPeerConnection();
// ... Verbindung aufbauen (Angebot, Antwort, ICE) ...

const report = await pc.getStats();
report.forEach((stat) => {
  console.log(stat.type, stat.id);
});
codec COT01_111_minptime=10;useinbandfec=1 candidate-pair CPabc123_def456 local-candidate Iabc123 outbound-rtp OT01A1234567 transport T01 ...

Eingehende Video-Bitrate jede Sekunde berechnen

let last = null;

const messeBitrate = async (pc) => {
  const report = await pc.getStats();
  for (const stat of report.values()) {
    if (stat.type !== 'inbound-rtp' || stat.kind !== 'video') continue;
    if (last) {
      const bytes = stat.bytesReceived - last.bytesReceived;
      const ms = stat.timestamp - last.timestamp;
      const kbps = Math.round((bytes * 8) / ms); // bit/ms = kbit/s
      console.log(`Video: ${kbps} kbit/s, ${stat.framesPerSecond ?? '?'} fps, ` +
        `${stat.frameWidth}x${stat.frameHeight}, verloren: ${stat.packetsLost}`);
    }
    last = stat;
  }
};

const timer = setInterval(() => messeBitrate(pc), 1000);
// Beim Beenden: clearInterval(timer);
Video: 1487 kbit/s, 30 fps, 1280x720, verloren: 3

Round-Trip-Time und genutzten Verbindungsweg (direkt oder TURN) ermitteln

const verbindungsInfo = async (pc) => {
  const report = await pc.getStats();
  let pair = null;
  for (const stat of report.values()) {
    if (stat.type === 'transport' && stat.selectedCandidatePairId) {
      pair = report.get(stat.selectedCandidatePairId);
    }
  }
  // Fallback für ältere Browser ohne selectedCandidatePairId
  if (!pair) {
    pair = [...report.values()].find(
      (s) => s.type === 'candidate-pair' && s.state === 'succeeded' && s.nominated
    );
  }
  if (!pair) return null;
  const local = report.get(pair.localCandidateId);
  return {
    rttMs: (pair.currentRoundTripTime ?? 0) * 1000,
    typ: local?.candidateType, // 'host' | 'srflx' | 'prflx' | 'relay'
    protokoll: local?.protocol
  };
};

console.log(await verbindungsInfo(pc));
{ rttMs: 42, typ: 'srflx', protokoll: 'udp' }

Statistiken auf einen Track beschränken

const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
const [audioTrack] = stream.getAudioTracks();
pc.addTrack(audioTrack, stream);

try {
  const report = await pc.getStats(audioTrack);
  const out = [...report.values()].find((s) => s.type === 'outbound-rtp');
  console.log('Gesendete Audio-Pakete:', out?.packetsSent);
} catch (err) {
  // InvalidAccessError, wenn der Track keinem Sender eindeutig zugeordnet ist
  console.error(err.name, err.message);
}
Gesendete Audio-Pakete: 2513

// Wichtig · Fallstricke

  • Kumulative Zähler: Werte wie bytesSent, packetsLost oder framesDecoded zählen seit Beginn der Verbindung weiter. Raten erhält man nur aus der Differenz zweier Messungen. Der timestamp ist in Millisekunden angegeben.
  • Browser-Unterschiede: Nicht jeder Browser liefert jedes Feld. Beispiele sind framesPerSecond, selectedCandidatePairId und die Felder von "media-source". Fehlende Werte sollte man immer abfangen, etwa mit ?. oder ??.
  • Veraltete Form: Die alte, callback-basierte Signatur getStats(successCallback, errorCallback) und die Typen "track" und "stream" sind veraltet und wurden weitgehend entfernt. Verwenden Sie nur die Promise-Variante.
  • Performance: Jeder Aufruf erzeugt einen vollständigen Bericht. Ein Abstand von etwa einer Sekunde reicht in der Regel. Sehr häufige Abfragen, etwa pro Animationsframe, belasten die CPU unnötig.
  • Datenschutz: Die Kandidaten-Statistiken können lokale bzw. öffentliche IP-Adressen enthalten. Telemetrie sollte man vor dem Hochladen anonymisieren.
  • Nach pc.close() können noch Statistiken abgefragt werden, die Werte ändern sich dann aber nicht mehr.