Start · Sprachen · JavaScript · Referenz · RTCIceCandidatePair

RTCIceCandidatePair

Schnittstelle

Beschreibt ein Paar aus lokalem und entferntem ICE-Kandidaten, das zusammen einen möglichen oder aktiven Verbindungsweg zwischen zwei WebRTC-Endpunkten bildet.

seit JavaScript WebRTC 1.0 – Chromium 72+, Safari 14.1+; Firefox b Kategorie: webapi

Signatur

dictionary RTCIceCandidatePair { RTCIceCandidate local; RTCIceCandidate remote; }

Beschreibung

RTCIceCandidatePair ist ein einfaches Dictionary mit genau zwei Einträgen: local und remote, beide vom Typ RTCIceCandidate. Ein solches Paar beschreibt einen konkreten Netzwerkweg: Die Medien fließen von der Adresse und dem Port des lokalen Kandidaten zur Adresse und zum Port des entfernten Kandidaten.

Während des ICE-Verfahrens (Interactive Connectivity Establishment) bildet der Browser aus allen gesammelten lokalen und entfernten Kandidaten viele Paare und prüft sie per STUN auf Erreichbarkeit. Am Ende wird ein Paar ausgewählt, über das die Daten tatsächlich laufen. Dieses ausgewählte Paar bekommen Sie über RTCIceTransport.getSelectedCandidatePair(). Ändert es sich, etwa bei einem Netzwechsel oder einem ICE-Restart, wird am RTCIceTransport das Ereignis selectedcandidatepairchange ausgelöst.

In der Praxis brauchen Sie das Dictionary vor allem für Diagnose und Überwachung: Läuft die Verbindung direkt (host), über NAT-Traversal (srflx/prflx) oder über einen TURN-Server (relay)? Wird UDP oder TCP verwendet? Solche Angaben helfen bei der Fehlersuche, bei Qualitätsmetriken und bei der Kostenkontrolle für TURN-Server.

Verwechseln Sie das Dictionary nicht mit RTCIceCandidatePairStats: Diese Statistik-Einträge vom Typ "candidate-pair" stammen aus RTCPeerConnection.getStats() und enthalten Messwerte wie RTT oder übertragene Bytes, aber nur IDs der Kandidaten statt der RTCIceCandidate-Objekte selbst.

Parameter

Name Typ Default Beschreibung
$local Pflicht RTCIceCandidate Der lokale ICE-Kandidat des Paares, also Adresse, Port, Protokoll und Typ (host, srflx, prflx, relay) auf der eigenen Seite.
$remote Pflicht RTCIceCandidate Der entfernte ICE-Kandidat des Paares, also der Endpunkt der Gegenstelle, zu dem die Daten gesendet werden.

Rückgabewert

Typ
RTCIceCandidatePair | null
Beschreibung
RTCIceTransport.getSelectedCandidatePair() liefert ein Objekt mit den Eigenschaften local und remote. Solange noch kein Paar ausgewählt wurde, ist der Rückgabewert null.

Beispiele

Ausgewähltes Kandidatenpaar nach dem Verbindungsaufbau auslesen

const pc = new RTCPeerConnection({ iceServers: [{ urls: 'stun:stun.l.google.com:19302' }] });

pc.addEventListener('connectionstatechange', () => {
  if (pc.connectionState !== 'connected') return;

  const sender = pc.getSenders()[0];
  const iceTransport = sender?.transport?.iceTransport;
  if (!iceTransport?.getSelectedCandidatePair) {
    console.warn('getSelectedCandidatePair() wird nicht unterstützt');
    return;
  }

  const pair = iceTransport.getSelectedCandidatePair();
  if (!pair) return;

  const { local, remote } = pair;
  console.log(`Lokal:   ${local.type} ${local.protocol} ${local.address}:${local.port}`);
  console.log(`Entfernt: ${remote.type} ${remote.protocol} ${remote.address}:${remote.port}`);
});
Lokal: srflx udp 203.0.113.17:54321 Entfernt: host udp 192.168.1.20:61234

Auf Wechsel des Kandidatenpaares reagieren (z. B. WLAN → Mobilfunk)

const watchCandidatePair = (pc) => {
  const iceTransport = pc.getSenders()[0]?.transport?.iceTransport;
  if (!iceTransport) return;

  const onChange = () => {
    const pair = iceTransport.getSelectedCandidatePair();
    if (!pair) return;
    const viaTurn = pair.local.type === 'relay' || pair.remote.type === 'relay';
    console.log(viaTurn ? 'Verbindung läuft über TURN-Relay' : 'Direkte Verbindung (P2P)');
  };

  // Variante 1: addEventListener
  iceTransport.addEventListener('selectedcandidatepairchange', onChange);
  // Variante 2: on-Property
  // iceTransport.onselectedcandidatepairchange = onChange;

  // Aufräumen, wenn nicht mehr benötigt
  return () => iceTransport.removeEventListener('selectedcandidatepairchange', onChange);
};
Direkte Verbindung (P2P)

Browserübergreifender Fallback über getStats()

const getActivePair = async (pc) => {
  const stats = await pc.getStats();
  let pairStats;

  stats.forEach((report) => {
    // Chrome/Safari: über den transport-Eintrag; Firefox: selected-Flag
    if (report.type === 'transport' && report.selectedCandidatePairId) {
      pairStats = stats.get(report.selectedCandidatePairId);
    }
    if (!pairStats && report.type === 'candidate-pair' && report.selected) {
      pairStats = report;
    }
  });

  if (!pairStats) return null;
  const local = stats.get(pairStats.localCandidateId);
  const remote = stats.get(pairStats.remoteCandidateId);
  return {
    local: `${local.candidateType} ${local.address}:${local.port}`,
    remote: `${remote.candidateType} ${remote.address}:${remote.port}`,
    rttMs: (pairStats.currentRoundTripTime ?? 0) * 1000
  };
};

// Nutzung: console.log(await getActivePair(pc));
{ local: 'host 192.168.1.10:50000', remote: 'host 192.168.1.20:61234', rttMs: 4 }

// Wichtig · Fallstricke

  • Browser-Kompatibilität: RTCIceTransport.getSelectedCandidatePair() und das Ereignis selectedcandidatepairchange gibt es in Chromium-Browsern und Safari. Firefox stellt RTCDtlsTransport.iceTransport bislang nicht (vollständig) bereit. Für browserübergreifenden Code sollten Sie deshalb auf getStats() mit den Einträgen "candidate-pair" zurückgreifen.
  • Zeitpunkt: Vor dem Verbindungsaufbau ist sender.transport oft noch null und getSelectedCandidatePair() liefert null. Fragen Sie das Paar erst ab, wenn der Verbindungszustand connected erreicht ist, oder hören Sie auf das Wechsel-Ereignis.
  • Datenschutz: address kann wegen mDNS-Verschleierung als xxxx.local erscheinen oder leer sein. Echte IP-Adressen sind personenbezogene Daten und sollten nicht ungefragt an Analyse-Server geschickt werden.
  • Kein Konstruktor: Es handelt sich um ein Dictionary und nicht um eine Klasse. new RTCIceCandidatePair() gibt es nicht. Wenn Sie ein solches Objekt selbst anlegen, übernimmt der Browser es nicht als aktiven Pfad.