Signatur
Beschreibung
RTCStatsReport ist ein schreibgeschütztes, Map-ähnliches Objekt. Die Schlüssel sind Statistik-IDs (Strings), die Werte sind Statistik-Wörterbücher wie RTCInboundRtpStreamStats, RTCOutboundRtpStreamStats, RTCIceCandidatePairStats oder RTCTransportStats. Die Methode values() liefert einen Iterator, der diese Statistik-Objekte einzeln in Einfügereihenfolge zurückgibt.
Das ist praktisch, wenn die IDs egal sind und man nur alle Statistiken durchlaufen will, etwa um nach dem Feld type zu filtern ("inbound-rtp", "candidate-pair" usw.) und daraus Bitrate, Paketverlust, Jitter oder Round-Trip-Zeit zu berechnen.
Einen Bericht bekommt man asynchron über RTCPeerConnection.getStats(), RTCRtpSender.getStats() oder RTCRtpReceiver.getStats(). Der Iterator selbst ist ebenfalls iterierbar. Er funktioniert also mit for...of, mit dem Spread-Operator und mit Array.from().
Rückgabewert
id, type und timestamp.Beispiele
Alle Statistik-Typen eines Berichts auflisten
const pc = new RTCPeerConnection();
pc.createDataChannel('chat');
await pc.setLocalDescription(await pc.createOffer());
const report = await pc.getStats();
for (const stats of report.values()) {
console.log(`${stats.type} (${stats.id})`);
}
Paketverlust und Jitter eingehender Streams auswerten
const logInboundQuality = async (pc) => {
const report = await pc.getStats();
const inbound = [...report.values()].filter((s) => s.type === 'inbound-rtp');
for (const s of inbound) {
const total = s.packetsReceived + s.packetsLost;
const lossPct = total > 0 ? (s.packetsLost / total) * 100 : 0;
console.log(`${s.kind}: Verlust ${lossPct.toFixed(2)} %, Jitter ${(s.jitter * 1000).toFixed(1)} ms`);
}
};
// alle 2 Sekunden ausführen
setInterval(() => logInboundQuality(pc), 2000);
Round-Trip-Zeit des aktiven Kandidatenpaars ermitteln
const getRtt = async (pc) => {
const report = await pc.getStats();
const pair = Array.from(report.values()).find(
(s) => s.type === 'candidate-pair' && s.nominated && s.state === 'succeeded'
);
return pair?.currentRoundTripTime ?? null; // in Sekunden
};
const rtt = await getRtt(pc);
console.log(rtt !== null ? `RTT: ${(rtt * 1000).toFixed(0)} ms` : 'Keine aktive Verbindung');
Ausgehende Bitrate aus zwei Messungen berechnen
const bytesSent = async (sender) => {
const report = await sender.getStats();
let sum = 0;
for (const s of report.values()) {
if (s.type === 'outbound-rtp') sum += s.bytesSent;
}
return sum;
};
const [sender] = pc.getSenders();
const before = await bytesSent(sender);
await new Promise((r) => setTimeout(r, 1000));
const after = await bytesSent(sender);
console.log(`Bitrate: ${((after - before) * 8 / 1000).toFixed(0)} kbit/s`);
// Wichtig · Fallstricke
- Einmal-Iterator: Ein Iterator ist nach einem vollständigen Durchlauf verbraucht. Für einen weiteren Durchlauf
report.values()erneut aufrufen oder das Ergebnis vorher mit[...report.values()]in ein Array kopieren. - Momentaufnahme: Ein
RTCStatsReportwird nicht automatisch aktualisiert. Für frische Werte mussgetStats()erneut aufgerufen werden. Raten wie die Bitrate ergeben sich erst aus der Differenz zweier Berichte, geteilt durch die Differenz ihrertimestamp-Werte. - Browser-Unterschiede: Welche Statistik-Typen und Felder vorhanden sind, unterscheidet sich zwischen Chrome, Firefox und Safari. Einige Felder wie
trackIdentifieroder die veraltetentrack-/stream-Statistiken fehlen je nach Browser. Felder deshalb immer defensiv abfragen, z. B. mit?.und??. - Kein Array: Der Iterator hat keine Methoden wie
filterodermap. Man wandelt ihn vorher mitArray.from()oder Spread um. In neueren Engines gibt es dafür auch Iterator-Hilfsmethoden wiereport.values().filter(...), die aber noch nicht überall verfügbar sind. - Datenschutz: ICE-Kandidaten-Statistiken können IP-Adressen enthalten. Beim Senden an Analyse-Server auf Datenschutz achten.