Start · Sprachen · JavaScript · Referenz · RTCPeerConnection.addIceCandidate()

RTCPeerConnection.addIceCandidate()

Methode

Übergibt einen über den Signalisierungskanal empfangenen ICE-Kandidaten der Gegenseite an die <code>RTCPeerConnection</code>, damit ICE diesen Verbindungsweg prüfen kann.

seit JavaScript Baseline: alle modernen Browser (Promise-Variante Kategorie: webapi

Signatur

RTCPeerConnection.prototype.addIceCandidate(candidate)

Beschreibung

Bei WebRTC suchen beide Seiten mit ICE (Interactive Connectivity Establishment) nach möglichen Netzwerkpfaden: lokale Adressen, per STUN ermittelte öffentliche Adressen und TURN-Relays. Die eigene Seite meldet gefundene Kandidaten über das Ereignis icecandidate. Diese schickst du über deinen eigenen Signalisierungskanal (z. B. WebSocket) an die Gegenseite, und dort übergibt addIceCandidate() sie an die eigene RTCPeerConnection.

Das nennt man Trickle ICE: Kandidaten werden einzeln verschickt, sobald sie gefunden werden, statt zu warten, bis die Sammlung abgeschlossen ist. Dadurch kommt die Verbindung deutlich schneller zustande. Jeder hinzugefügte Kandidat wird Teil der Remote-Beschreibung, und der ICE-Agent führt damit Konnektivitätsprüfungen durch.

Die Methode gibt ein Promise zurück. Es wird erfüllt, sobald der Kandidat übernommen wurde, und abgelehnt, wenn er ungültig ist oder noch keine Remote-Beschreibung gesetzt ist. Ruf sie deshalb erst nach setRemoteDescription() auf, oder halte früh eintreffende Kandidaten so lange in einer Warteschlange zurück.

Wenn du null, undefined oder einen Kandidaten mit leerem candidate-String übergibst, signalisierst du das Ende der Kandidaten (End-of-Candidates) für die jeweilige Medien-Sektion bzw. Generation.

Parameter

Name Typ Default Beschreibung
$candidate RTCIceCandidateInit | RTCIceCandidate | null undefined (entspricht End-of-Candidates) Der Kandidat der Gegenseite, typischerweise das Objekt aus event.candidate.toJSON(). Wichtige Felder: candidate (SDP-Attributzeile als String), sdpMid (ID der Medien-Sektion), sdpMLineIndex (Index der m-Zeile) und usernameFragment. Mindestens eines der Felder sdpMid oder sdpMLineIndex muss gesetzt sein, sonst wird ein TypeError ausgelöst. null, ein fehlender Wert oder ein leerer candidate-String bedeutet End-of-Candidates.
$successCallback / failureCallback Function Veraltet. Alte Callback-Syntax als zweites und drittes Argument. Nutze stattdessen das zurückgegebene Promise.

Rückgabewert

Typ
Promise<undefined>
Beschreibung
Ein Promise, das erfüllt wird, sobald der Kandidat vom ICE-Agenten übernommen wurde. Es wird mit TypeError, InvalidStateError oder OperationError abgelehnt, wenn der Kandidat fehlerhaft ist oder der Zeitpunkt nicht passt.

Beispiele

Kandidaten über WebSocket austauschen

const pc = new RTCPeerConnection({
  iceServers: [{ urls: 'stun:stun.l.google.com:19302' }]
});
const ws = new WebSocket('wss://signal.example.com');

// Eigene Kandidaten an die Gegenseite schicken
pc.addEventListener('icecandidate', ({ candidate }) => {
  ws.send(JSON.stringify({ type: 'candidate', candidate: candidate ? candidate.toJSON() : null }));
});

// Kandidaten der Gegenseite hinzufügen
ws.addEventListener('message', async (event) => {
  const msg = JSON.parse(event.data);
  if (msg.type === 'candidate') {
    try {
      await pc.addIceCandidate(msg.candidate); // null = End-of-Candidates
      console.log('Remote-Kandidat hinzugefügt');
    } catch (err) {
      console.error('Kandidat abgelehnt:', err.name, err.message);
    }
  }
});
Remote-Kandidat hinzugefügt

Früh eintreffende Kandidaten zwischenspeichern

const pc = new RTCPeerConnection();
const pendingCandidates = [];

const handleCandidate = async (candidate) => {
  // Ohne Remote-Beschreibung würde addIceCandidate() fehlschlagen
  if (!pc.remoteDescription) {
    pendingCandidates.push(candidate);
    return;
  }
  await pc.addIceCandidate(candidate);
};

const handleOffer = async (offer) => {
  await pc.setRemoteDescription(offer);
  // Zwischengespeicherte Kandidaten nachreichen
  for (const c of pendingCandidates.splice(0)) {
    await pc.addIceCandidate(c);
  }
  const answer = await pc.createAnswer();
  await pc.setLocalDescription(answer);
  return pc.localDescription;
};

Kandidat manuell aus SDP-Zeile erzeugen

const addRemote = async (pc, line, mid) => {
  const candidate = new RTCIceCandidate({
    candidate: line,
    sdpMid: mid,
    sdpMLineIndex: 0
  });
  await pc.addIceCandidate(candidate);
  console.log(`Hinzugefügt: ${candidate.type} ${candidate.protocol} ${candidate.address}`);
};

// Beispielaufruf (nach setRemoteDescription):
// await addRemote(pc, 'candidate:842163049 1 udp 1677729535 203.0.113.5 50000 typ srflx raddr 0.0.0.0 rport 0 generation 0', '0');
Hinzugefügt: srflx udp 203.0.113.5

// Wichtig · Fallstricke

  • Reihenfolge: Wird die Methode aufgerufen, bevor setRemoteDescription() gesetzt ist, lehnt sie mit InvalidStateError ab. Kandidaten, die zu früh eintreffen, musst du puffern. Das ist der häufigste Fehler in WebRTC-Anwendungen.
  • Vollständiges Objekt senden: Übertrage candidate.toJSON() oder alle Felder (candidate, sdpMid, sdpMLineIndex, usernameFragment). Fehlen sowohl sdpMid als auch sdpMLineIndex, wird ein TypeError ausgelöst.
  • End-of-Candidates: Ältere Browser (vor allem ältere Safari- und Chrome-Versionen) haben null oder einen leeren String als Argument abgelehnt. Umschließe den Aufruf deshalb mit try/catch.
  • ICE-Neustart: Nach restartIce() gehören Kandidaten mit altem usernameFragment zu einer veralteten Generation und führen zu einem OperationError.
  • Veraltete Callback-Syntax: Die Callback-Variante gilt als veraltet. Verwende das Promise mit async/await.
  • Datenschutz und Sicherheit: Kandidaten enthalten IP-Adressen. Moderne Browser verbergen lokale Adressen per mDNS (*.local). Sichere den Signalisierungskanal ab (WSS, Authentifizierung), damit Dritte keine Kandidaten einschleusen können.
  • Kompatibilität: Wird in Chrome, Edge, Firefox und Safari (ab 11) unterstützt. Für Node.js brauchst du Bibliotheken wie wrtc oder node-datachannel.