Signatur
Beschreibung
Mit RTCPeerConnection.getStats() bekommst du einen RTCStatsReport. Das ist eine Map-ähnliche Sammlung vieler Statistik-Objekte unterschiedlicher Art, etwa "inbound-rtp", "outbound-rtp", "local-candidate", "transport" oder "candidate-pair". Jedes dieser Objekte hat die Eigenschaft type. Daran erkennst du, zu welchem Wörterbuch das Objekt gehört.
Bei RTCIceCandidatePairStats ist type immer "candidate-pair". Ein solches Objekt beschreibt ein Paar aus einem lokalen und einem entfernten ICE-Kandidaten. Es enthält unter anderem den Zustand (state), die aktuelle Umlaufzeit (currentRoundTripTime), die übertragenen Bytes und die geschätzte verfügbare Bandbreite (availableOutgoingBitrate).
Meist dient type als Filterkriterium: Du durchläufst den Bericht, suchst alle Einträge mit type === "candidate-pair" und wertest dann zum Beispiel das gerade genutzte Paar aus. Das ist das Paar mit nominated === true und state === "succeeded" oder das Paar, auf das RTCTransportStats.selectedCandidatePairId verweist. So lässt sich die Verbindungsqualität überwachen und der tatsächlich verwendete Netzwerkpfad bestimmen, etwa direkt (host/srflx) oder über einen TURN-Server (relay).
Rückgabewert
"candidate-pair" (ein Wert der Aufzählung RTCStatsType).Beispiele
Alle Kandidatenpaare aus dem Statistikbericht filtern
const pc = new RTCPeerConnection();
// ... Signalisierung und Verbindungsaufbau ...
const logCandidatePairs = async () => {
const report = await pc.getStats();
report.forEach((stats) => {
if (stats.type === 'candidate-pair') {
console.log(stats.id, stats.state, stats.nominated);
}
});
};
logCandidatePairs();
Aktives Paar über den Transport ermitteln und RTT ausgeben
const getActivePair = async (pc) => {
const report = await pc.getStats();
let pair = null;
for (const stats of report.values()) {
if (stats.type === 'transport' && stats.selectedCandidatePairId) {
pair = report.get(stats.selectedCandidatePairId);
}
}
// Fallback, z. B. für Firefox: nominiertes, erfolgreiches Paar
if (!pair) {
pair = [...report.values()].find(
(s) => s.type === 'candidate-pair' && s.nominated && s.state === 'succeeded'
);
}
return pair;
};
const pair = await getActivePair(pc);
if (pair) {
console.log(pair.type);
console.log(`RTT: ${(pair.currentRoundTripTime * 1000).toFixed(0)} ms`);
}
Verbindungsweg (direkt oder TURN-Relay) erkennen
const detectRoute = async (pc) => {
const report = await pc.getStats();
const pair = [...report.values()].find(
(s) => s.type === 'candidate-pair' && s.nominated && s.state === 'succeeded'
);
if (!pair) return 'keine aktive Verbindung';
const local = report.get(pair.localCandidateId);
const remote = report.get(pair.remoteCandidateId);
return `${local.candidateType} -> ${remote.candidateType}`;
};
setInterval(async () => console.log(await detectRoute(pc)), 5000);
// Wichtig · Fallstricke
- Nur lesbar:
typeist immer"candidate-pair"und kann nicht geändert werden. Die Eigenschaft ist vonRTCStatsgeerbt, genau wieidundtimestamp. - Bindestrich-Schreibweise: In früheren Entwürfen und manchen alten Codebeispielen steht
"candidatepair"ohne Bindestrich. Aktuelle Browser verwenden"candidate-pair". Vergleiche daher genau mit diesem Wert. - Mehrere Paare: Ein Bericht enthält oft viele Kandidatenpaare, auch fehlgeschlagene oder eingefrorene. Wähle das aktive Paar über
selectedCandidatePairIdam Transport-Eintrag oder übernominatedundstate === "succeeded"aus. - Browser-Unterschiede: Welche weiteren Felder vorhanden sind, zum Beispiel
availableOutgoingBitrateodercurrentRoundTripTime, ist je nach Browser unterschiedlich. Firefox hat ältere Nicht-Standard-Felder wieselectedverwendet. Prüfe daher immer, ob ein Feld vorhanden ist, bevor du es nutzt. - Leistung:
getStats()ist asynchron und nicht kostenlos. Frage die Statistik in vernünftigen Abständen ab (etwa alle 1–5 Sekunden), nicht in jedem Animationsframe.