Signatur
Beschreibung
Die Eigenschaft state eines RTCIceCandidatePairStats-Objekts gibt an, in welchem Zustand sich die Verbindungsprüfung für dieses Paar aus lokalem und entferntem ICE-Kandidaten gerade befindet. ICE (Interactive Connectivity Establishment) legt für jede Komponente eine Checkliste von Kandidatenpaaren an und testet sie nacheinander mit STUN-Anfragen. state zeigt, wie weit dieser Test beim jeweiligen Paar gekommen ist.
Mögliche Werte (Aufzählung RTCStatsIceCandidatePairState):
"frozen": Das Paar wird erst geprüft, wenn ein anderes Paar mit derselben Foundation erfolgreich getestet wurde."waiting": Die Prüfung ist bereit, hat aber noch nicht begonnen."in-progress": Eine Prüfung läuft gerade; es wird auf eine Antwort gewartet."succeeded": Die Prüfung war erfolgreich – über dieses Paar ist eine Verbindung möglich."failed": Die Prüfung ist fehlgeschlagen oder hat nicht rechtzeitig geantwortet.
Die Statistik erhältst du über RTCPeerConnection.getStats(): Im zurückgegebenen RTCStatsReport sind alle Einträge mit type === "candidate-pair" Objekte vom Typ RTCIceCandidatePairStats. Das ist nützlich für die Fehlersuche bei Verbindungsproblemen (NAT, Firewalls, TURN-Konfiguration) oder um festzustellen, welches Paar tatsächlich genutzt wird.
Wichtig: "succeeded" bedeutet nur, dass das Paar funktioniert – nicht, dass es für die Übertragung ausgewählt ist. Das aktive Paar erkennst du über RTCTransportStats.selectedCandidatePairId bzw. zusätzlich über nominated.
Rückgabewert
getStats()-Aufrufs.Beispiele
Zustände aller Kandidatenpaare auflisten
const logPairStates = async (pc) => {
const report = await pc.getStats();
report.forEach((stats) => {
if (stats.type === "candidate-pair") {
console.log(`${stats.id}: ${stats.state} (nominiert: ${stats.nominated})`);
}
});
};
// z. B. nach Aufbau der Verbindung
const pc = new RTCPeerConnection({ iceServers: [{ urls: "stun:stun.l.google.com:19302" }] });
// ... Signalisierung, Offer/Answer ...
await logPairStates(pc);
Aktiv genutztes Kandidatenpaar ermitteln
const getSelectedPair = async (pc) => {
const report = await pc.getStats();
let pairId;
report.forEach((s) => {
if (s.type === "transport" && s.selectedCandidatePairId) {
pairId = s.selectedCandidatePairId;
}
});
const pair = pairId ? report.get(pairId) : undefined;
if (!pair) return null;
const local = report.get(pair.localCandidateId);
const remote = report.get(pair.remoteCandidateId);
return {
state: pair.state,
local: `${local?.candidateType} ${local?.address}:${local?.port}`,
remote: `${remote?.candidateType} ${remote?.address}:${remote?.port}`
};
};
console.log(await getSelectedPair(pc));
Diagnose: Sind alle Paare fehlgeschlagen?
pc.addEventListener("iceconnectionstatechange", async () => {
if (pc.iceConnectionState !== "failed") return;
const report = await pc.getStats();
const pairs = [...report.values()].filter((s) => s.type === "candidate-pair");
const counts = pairs.reduce((acc, p) => {
acc[p.state] = (acc[p.state] ?? 0) + 1;
return acc;
}, {});
console.warn("ICE fehlgeschlagen, Paar-Zustände:", counts);
if (!pairs.some((p) => p.state === "succeeded")) {
console.warn("Kein funktionierendes Paar – TURN-Server prüfen!");
}
});
// Wichtig · Fallstricke
- Schnappschuss statt Live-Wert: Der Wert ändert sich nicht von selbst. Für eine Überwachung musst du
getStats()erneut aufrufen, z. B. per Intervall oder beiiceconnectionstatechange. - „succeeded“ ≠ ausgewählt: Mehrere Paare können erfolgreich sein. Das tatsächlich genutzte Paar findest du über
RTCTransportStats.selectedCandidatePairId. Die ältere, nicht standardisierte Eigenschaftselectedgibt es nur in Firefox. - Entfernter Wert: Ältere Spezifikationsentwürfe kannten zusätzlich
"cancelled"; der Wert ist entfallen und sollte in neuem Code nicht mehr erwartet werden. - Browser-Unterschiede: Welche Paare im Bericht auftauchen und wie schnell sie von
"frozen"/"waiting"wechseln, hängt vom Browser ab. Bei ICE-Neustarts können alte Paare verschwinden oder neu angelegt werden. - Datenschutz: Die zugehörigen Kandidaten-Statistiken enthalten IP-Adressen. Sende Statistiken nicht ungefiltert an Analysedienste. Bei mDNS-Kandidaten sind lokale Adressen außerdem als
.local-Hostnamen verschleiert.