Signatur
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
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);
}
}
});
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');
// Wichtig · Fallstricke
- Reihenfolge: Wird die Methode aufgerufen, bevor
setRemoteDescription()gesetzt ist, lehnt sie mitInvalidStateErrorab. 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 sowohlsdpMidals auchsdpMLineIndex, wird einTypeErrorausgelöst. - End-of-Candidates: Ältere Browser (vor allem ältere Safari- und Chrome-Versionen) haben
nulloder einen leeren String als Argument abgelehnt. Umschließe den Aufruf deshalb mittry/catch. - ICE-Neustart: Nach
restartIce()gehören Kandidaten mit altemusernameFragmentzu einer veralteten Generation und führen zu einemOperationError. - Veraltete Callback-Syntax: Die Callback-Variante gilt als veraltet. Verwende das
Promisemitasync/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
wrtcodernode-datachannel.