Signatur
Beschreibung
Die schreibgeschützte Eigenschaft selectedCandidatePairChanges eines RTCTransportStats-Objekts (Statistik-Typ "transport") enthält eine ganze Zahl. Sie zählt, wie oft der ICE-Agent das aktive Kandidatenpaar gewechselt hat, also die Kombination aus lokalem und entferntem Kandidaten, über die Medien und Daten tatsächlich fließen.
Ein Wechsel kommt z. B. vor, wenn während der ICE-Aushandlung ein besseres Paar gefunden wird (etwa eine direkte Host- oder srflx-Verbindung statt eines TURN-Relays), wenn ein ICE-Neustart ausgelöst wird oder wenn sich das Netzwerk ändert, zum Beispiel beim Wechsel von WLAN zu Mobilfunk. Die Initialauswahl wird dabei als erster Wechsel gezählt. Nach dem Verbindungsaufbau ist der Wert deshalb typischerweise 1.
Die Eigenschaft eignet sich vor allem für Monitoring und Fehlerdiagnose. Wenn der Zähler während einer laufenden Sitzung ständig steigt, spricht das für instabile Netzwerkpfade, Paketverluste oder Probleme mit NAT/Firewall. Solche Wechsel führen oft zu kurzen Aussetzern in Audio und Video. Den Wert liest du über RTCPeerConnection.getStats() aus. Das aktuell gewählte Paar findest du über selectedCandidatePairId.
Rückgabewert
unsigned long): wie oft das ausgewählte Kandidatenpaar dieses Transports insgesamt gewechselt hat.Beispiele
Anzahl der Paarwechsel auslesen
const pc = new RTCPeerConnection();
// ... Verbindung wie üblich aufbauen (Offer/Answer, ICE) ...
const logPairChanges = async () => {
const report = await pc.getStats();
report.forEach((stats) => {
if (stats.type === 'transport') {
console.log(`Transport ${stats.id}: ${stats.selectedCandidatePairChanges ?? 'n/a'} Wechsel`);
}
});
};
await logPairChanges();
Instabile Verbindung per Polling erkennen
const watchCandidateSwitches = (pc, intervalMs = 5000) => {
let lastCount = null;
const timer = setInterval(async () => {
const report = await pc.getStats();
for (const stats of report.values()) {
if (stats.type !== 'transport' || stats.selectedCandidatePairChanges === undefined) continue;
const count = stats.selectedCandidatePairChanges;
if (lastCount !== null && count > lastCount) {
console.warn(`Kandidatenpaar gewechselt (${count - lastCount}x in ${intervalMs / 1000}s)`);
}
lastCount = count;
}
}, intervalMs);
// Aufräumen, sobald die Verbindung geschlossen wird
pc.addEventListener('connectionstatechange', () => {
if (pc.connectionState === 'closed') clearInterval(timer);
});
return () => clearInterval(timer);
};
const stopWatching = watchCandidateSwitches(pc);
Wechselzähler zusammen mit dem aktiven Paar anzeigen
const describeTransport = async (pc) => {
const report = await pc.getStats();
for (const t of report.values()) {
if (t.type !== 'transport') continue;
const pair = report.get(t.selectedCandidatePairId);
const local = pair && report.get(pair.localCandidateId);
const remote = pair && report.get(pair.remoteCandidateId);
console.log({
wechsel: t.selectedCandidatePairChanges,
lokal: local?.candidateType,
entfernt: remote?.candidateType,
rttMs: pair ? Math.round(pair.currentRoundTripTime * 1000) : null
});
}
};
await describeTransport(pc);
// Wichtig · Fallstricke
- Browser-Kompatibilität: Chromium-Browser und Safari unterstützen die Eigenschaft, Firefox liefert sie derzeit nicht. Prüfe daher immer auf
undefined, z. B. mit??. - Der Wert ist ein kumulativer Zähler. Für Aussagen über Instabilität brauchst du die Differenz zwischen zwei Messungen, nicht den absoluten Wert.
- Die erste Auswahl eines Paars zählt bereits als Wechsel. Ein Wert von
1ist also normal und kein Hinweis auf ein Problem. - Bei
bundlePolicy: "max-bundle"gibt es meist nur einen Transport. Ohne Bundling kann es mehrere"transport"-Einträge mit eigenen Zählern geben. getStats()ist asynchron und nicht kostenlos. Frage die Statistik nicht in sehr kurzen Abständen ab, typisch sind 1–10 Sekunden.