Signatur
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
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);
});
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);
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));
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);
}
// Wichtig · Fallstricke
- Kumulative Zähler: Werte wie
bytesSent,packetsLostoderframesDecodedzählen seit Beginn der Verbindung weiter. Raten erhält man nur aus der Differenz zweier Messungen. Dertimestampist in Millisekunden angegeben. - Browser-Unterschiede: Nicht jeder Browser liefert jedes Feld. Beispiele sind
framesPerSecond,selectedCandidatePairIdund 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.