Signatur
Beschreibung
Die schreibgeschützte Eigenschaft totalRoundTripTime eines RTCIceCandidatePairStats-Objekts gibt als number in Sekunden an, wie viel Zeit insgesamt zwischen dem Senden von STUN-Verbindungsprüfungen (Binding Requests) und dem Eintreffen der Antworten vergangen ist. Gezählt werden alle Anfragen, die seit Aufbau der Verbindung auf diesem ICE-Kandidatenpaar beantwortet wurden.
Allein ist der Wert wenig aussagekräftig, weil er mit jeder Antwort größer wird. Nützlich wird er zusammen mit responsesReceived: Teilt man totalRoundTripTime durch responsesReceived, erhält man die durchschnittliche Round-Trip-Zeit seit Verbindungsbeginn. Die Differenz zweier Messungen in zeitlichem Abstand, geteilt durch die Differenz der Antwortzähler, ergibt den Durchschnitt für genau dieses Intervall. So lassen sich Latenz-Dashboards und Qualitätsanzeigen bauen.
Den Wert liest du über RTCPeerConnection.getStats() aus. Dabei filterst du die Einträge mit type === "candidate-pair". Meistens interessiert dich nur das gerade aktive Paar. Das erkennst du an nominated === true und state === "succeeded" oder über selectedCandidatePairId im transport-Eintrag.
Rückgabewert
undefined, solange noch keine Antwort gemessen wurde oder wenn der Browser die Eigenschaft nicht unterstützt.Beispiele
Durchschnittliche RTT des aktiven Kandidatenpaars
// pc ist eine bereits verbundene RTCPeerConnection
const getAverageRtt = async (pc) => {
const stats = await pc.getStats();
let transport;
stats.forEach((report) => {
if (report.type === 'transport') transport = report;
});
const pair = transport && stats.get(transport.selectedCandidatePairId);
if (!pair || !pair.responsesReceived) return null;
// Mittelwert in Millisekunden
return (pair.totalRoundTripTime / pair.responsesReceived) * 1000;
};
const avg = await getAverageRtt(pc);
console.log(`Ø RTT: ${avg?.toFixed(1)} ms`);
RTT pro Messintervall für eine Live-Anzeige
let last = null;
const sampleRtt = async (pc) => {
const stats = await pc.getStats();
for (const report of stats.values()) {
if (report.type !== 'candidate-pair' || !report.nominated || report.state !== 'succeeded') continue;
if (last) {
const dTime = report.totalRoundTripTime - last.totalRoundTripTime;
const dResp = report.responsesReceived - last.responsesReceived;
if (dResp > 0) {
console.log(`RTT (letzte 2 s): ${((dTime / dResp) * 1000).toFixed(1)} ms`);
}
}
last = { totalRoundTripTime: report.totalRoundTripTime, responsesReceived: report.responsesReceived };
}
};
const timer = setInterval(() => sampleRtt(pc), 2000);
// Beim Auflegen: clearInterval(timer);
Vergleich mit currentRoundTripTime
const stats = await pc.getStats();
stats.forEach((r) => {
if (r.type === 'candidate-pair' && r.nominated) {
console.log({
aktuell: r.currentRoundTripTime, // letzte Messung
gesamt: r.totalRoundTripTime, // Summe aller Messungen
antworten: r.responsesReceived
});
}
});
// Wichtig · Fallstricke
- Einheit Sekunden: Der Wert ist nicht in Millisekunden angegeben. Für die Anzeige musst du ihn mit 1000 multiplizieren.
- Werte werden aufsummiert: Als Latenzwert taugt
totalRoundTripTimenur geteilt durchresponsesReceived. Wenn du den Wert direkt anzeigst, wächst er einfach immer weiter. - Nur STUN-Prüfungen zählen: Gemessen wird die RTT der ICE-Verbindungsprüfungen und Keep-Alives, nicht die von Mediendaten. Für die RTT der Medien sind
roundTripTimeundtotalRoundTripTimeinRTCRemoteInboundRtpStreamStatszuständig. - Division durch null vermeiden: Kurz nach dem Verbindungsaufbau kann
responsesReceivednoch 0 sein undtotalRoundTripTimefehlen. - Browser-Kompatibilität: Aktuelle Versionen von Chromium-Browsern, Firefox und Safari unterstützen die Eigenschaft. Ältere Versionen liefern teils nur das veraltete Format von
getStats()mit Callback. Prüfe deshalb im Code, ob der Wert vorhanden ist. - Mehrere Kandidatenpaare können gleichzeitig existieren. Filtere deshalb immer auf das ausgewählte Paar, sonst mischst du Messwerte verschiedener Netzwege.