Signatur
Beschreibung
Die Eigenschaft selectedCandidatePairId ist ein String im RTCTransportStats-Wörterbuch, also in einem Statistik-Eintrag mit type === "transport". Sie verweist auf die id eines anderen Eintrags im selben RTCStatsReport, nämlich auf das RTCIceCandidatePairStats-Objekt (type === "candidate-pair"), über das der Transport gerade Daten sendet und empfängt.
So findet man zuverlässig heraus, welche Verbindung tatsächlich genutzt wird: Über das Kandidatenpaar gelangt man per localCandidateId und remoteCandidateId zu den lokalen und entfernten Kandidaten und sieht deren Typ (host, srflx, relay). Damit lässt sich etwa erkennen, ob der Datenverkehr über einen TURN-Server läuft, und man kann Werte wie currentRoundTripTime oder availableOutgoingBitrate auslesen.
Solange ICE noch kein Paar ausgewählt hat (z. B. direkt nach dem Verbindungsaufbau oder bei Fehlschlag), fehlt die Eigenschaft oder ist undefined. Nach einem ICE-Restart oder einem Netzwerkwechsel kann sich der Wert ändern. Deshalb sollte man ihn bei jeder Abfrage von getStats() neu auswerten statt ihn zwischenzuspeichern.
Rückgabewert
id des ausgewählten RTCIceCandidatePairStats-Eintrags im selben Bericht oder undefined, wenn noch kein Paar ausgewählt wurde.Beispiele
Ausgewähltes Kandidatenpaar ermitteln
// pc ist eine bereits verbundene RTCPeerConnection
const getSelectedPair = async (pc) => {
const report = await pc.getStats();
for (const stats of report.values()) {
if (stats.type === 'transport' && stats.selectedCandidatePairId) {
return report.get(stats.selectedCandidatePairId);
}
}
return null;
};
const pair = await getSelectedPair(pc);
console.log(pair?.state, pair?.currentRoundTripTime);
Prüfen, ob die Verbindung über TURN läuft
const isRelayed = async (pc) => {
const report = await pc.getStats();
const transport = [...report.values()].find((s) => s.type === 'transport');
if (!transport?.selectedCandidatePairId) return false;
const pair = report.get(transport.selectedCandidatePairId);
const local = report.get(pair.localCandidateId);
const remote = report.get(pair.remoteCandidateId);
return local.candidateType === 'relay' || remote.candidateType === 'relay';
};
console.log('Über TURN:', await isRelayed(pc));
Verbindungsqualität regelmäßig überwachen
const monitor = (pc, intervalMs = 2000) => {
const timer = setInterval(async () => {
const report = await pc.getStats();
report.forEach((s) => {
if (s.type !== 'transport' || !s.selectedCandidatePairId) return;
const pair = report.get(s.selectedCandidatePairId);
const rtt = ((pair.currentRoundTripTime ?? 0) * 1000).toFixed(0);
const kbps = ((pair.availableOutgoingBitrate ?? 0) / 1000).toFixed(0);
console.log(`Paar ${pair.id}: RTT ${rtt} ms, ${kbps} kbit/s`);
});
}, intervalMs);
return () => clearInterval(timer);
};
const stopMonitor = monitor(pc);
// später: stopMonitor();
// Wichtig · Fallstricke
- Firefox liefert (Stand 2024) keine
transport-Statistiken. Dort findet man das aktive Paar übercandidate-pair-Einträge mitselected === true(nicht standardisiert) bzw.nominated === trueundstate === "succeeded". Für browserübergreifenden Code braucht man einen Fallback. - Die Eigenschaft kann fehlen, solange ICE noch nicht verbunden ist. Vor dem Zugriff mit
?.oder einer Prüfung absichern. - Die ID ist nur innerhalb desselben
RTCStatsReportgültig. IDs aus früheren Berichten sollte man nicht wiederverwenden, da sich das Paar nach einem ICE-Restart oder Netzwerkwechsel ändern kann. - Bei BUNDLE (Standardfall) gibt es meist nur einen Transport. Ohne BUNDLE oder bei getrenntem RTCP können mehrere
transport-Einträge mit unterschiedlichen Paaren vorhanden sein. - Datenschutz: Kandidaten-Statistiken können lokale bzw. öffentliche IP-Adressen enthalten. Nicht ungefiltert an Analysedienste senden.