Start · Sprachen · JavaScript · Referenz · RTCIceTransport: gatheringstatechange

RTCIceTransport: gatheringstatechange

Ereignis

Wird an ein <code>RTCIceTransport</code> gesendet, wenn sich dessen <code>gatheringState</code> ändert, also der Zustand der ICE-Kandidatensammlung.

seit JavaScript Chrome/Edge 75+, Safari 14.1+; Firefox nur eingesc Kategorie: webapi

Signatur

iceTransport.addEventListener("gatheringstatechange", handler)

Beschreibung

Das Event gatheringstatechange wird an einem RTCIceTransport ausgelöst, sobald sich seine Eigenschaft gatheringState ändert. Diese Eigenschaft zeigt an, wie weit das Sammeln der lokalen ICE-Kandidaten für genau diesen einen Transport ist. Mögliche Werte:

  • "new": Das Sammeln hat noch nicht begonnen.
  • "gathering": Es werden gerade Kandidaten gesammelt (Host, STUN/srflx, TURN/relay).
  • "complete": Das Sammeln ist abgeschlossen. Bis zu einem ICE-Restart kommen keine weiteren Kandidaten hinzu.

Einen Handler registrierst du mit addEventListener("gatheringstatechange", handler) oder über die Eigenschaft ongatheringstatechange. Das Event ist ein einfaches Event ohne zusätzliche Daten. Den neuen Zustand liest du im Handler aus event.target.gatheringState. Das Event lässt sich nicht abbrechen und steigt im DOM nicht auf (es „bubbelt“ nicht).

An den RTCIceTransport kommst du über RTCRtpSender.transport.iceTransport, RTCRtpReceiver.transport.iceTransport oder RTCSctpTransport.transport.iceTransport. Das Event ist sinnvoll, wenn du die Kandidatensammlung pro Transport genau beobachten willst, etwa ohne BUNDLE oder zur Fehlersuche. In den meisten Anwendungen reicht das zusammengefasste Event icegatheringstatechange an RTCPeerConnection, das den Zustand über alle Transporte hinweg meldet.

Parameter

Name Typ Default Beschreibung
$type Pflicht string Der Event-Name: "gatheringstatechange".
$handler Pflicht (event: Event) => void Callback, der bei jeder Zustandsänderung aufgerufen wird. Den aktuellen Wert liefert event.target.gatheringState.
$options boolean | AddEventListenerOptions false Optionen wie once oder signal (zum Entfernen per AbortController).

Rückgabewert

Typ
void
Beschreibung
addEventListener gibt nichts zurück. Der Handler erhält ein Event, dessen target der betroffene RTCIceTransport ist.

Beispiele

Kandidatensammlung eines Senders beobachten

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

const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
const sender = pc.addTrack(stream.getAudioTracks()[0], stream);

// transport ist erst nach setLocalDescription gesetzt
await pc.setLocalDescription(await pc.createOffer());

const iceTransport = sender.transport?.iceTransport;
if (iceTransport) {
  console.log('Start:', iceTransport.gatheringState);
  iceTransport.addEventListener('gatheringstatechange', (event) => {
    console.log('ICE-Gathering:', event.target.gatheringState);
  });
}
Start: gathering ICE-Gathering: complete

on-Property nutzen und Handler wieder entfernen

const pc = new RTCPeerConnection();
const channel = pc.createDataChannel('chat');
await pc.setLocalDescription(await pc.createOffer());

const iceTransport = pc.sctp?.transport.iceTransport;

// Variante 1: on-Property
iceTransport.ongatheringstatechange = () => {
  console.log('Zustand:', iceTransport.gatheringState);
};

// Variante 2: benannter Listener, später wieder entfernen
const onGathering = () => {
  if (iceTransport.gatheringState === 'complete') {
    console.log('Fertig gesammelt');
    iceTransport.removeEventListener('gatheringstatechange', onGathering);
    iceTransport.ongatheringstatechange = null;
  }
};
iceTransport.addEventListener('gatheringstatechange', onGathering);
Zustand: complete Fertig gesammelt

Auf vollständige Sammlung warten (mit Timeout und Fallback)

const waitForGatheringComplete = (pc, sender, timeoutMs = 5000) =>
  new Promise((resolve) => {
    // Fallback auf RTCPeerConnection, wenn RTCIceTransport fehlt
    const target = sender?.transport?.iceTransport ?? pc;
    const stateOf = () => target === pc ? pc.iceGatheringState : target.gatheringState;
    const eventName = target === pc ? 'icegatheringstatechange' : 'gatheringstatechange';

    if (stateOf() === 'complete') return resolve('complete');

    const controller = new AbortController();
    const timer = setTimeout(() => { controller.abort(); resolve('timeout'); }, timeoutMs);

    target.addEventListener(eventName, () => {
      if (stateOf() === 'complete') {
        clearTimeout(timer);
        controller.abort();
        resolve('complete');
      }
    }, { signal: controller.signal });
  });

const pc = new RTCPeerConnection({ iceServers: [{ urls: 'stun:stun.l.google.com:19302' }] });
const stream = await navigator.mediaDevices.getUserMedia({ video: true });
const sender = pc.addTrack(stream.getVideoTracks()[0], stream);
await pc.setLocalDescription(await pc.createOffer());

console.log(await waitForGatheringComplete(pc, sender));
// Jetzt enthält pc.localDescription.sdp alle Kandidaten (non-trickle ICE)
complete

// Wichtig · Fallstricke

  • Transport erst später verfügbar: sender.transport ist null, bis setLocalDescription() bzw. setRemoteDescription() gelaufen ist. Registrierst du den Listener zu spät, hast du den Wechsel zu "gathering" eventuell schon verpasst. Prüfe deshalb zuerst den aktuellen gatheringState.
  • BUNDLE: Mit dem üblichen bundlePolicy: "max-bundle" teilen sich alle Sender und Empfänger denselben RTCIceTransport. Bei mehreren Listenern wird das Event dann für jeden von ihnen ausgelöst.
  • Nicht verwechseln: icegatheringstatechange an RTCPeerConnection fasst den Zustand aller Transporte zusammen und wird von allen Browsern unterstützt. gatheringstatechange gilt nur für einen einzelnen Transport.
  • ICE-Restart: Nach pc.restartIce() kann der Zustand wieder von "complete" auf "gathering" wechseln. Ein Handler mit once: true bekommt das nicht mit.
  • Browser-Kompatibilität: RTCIceTransport und dieses Event gibt es in Chromium-Browsern und Safari. Firefox unterstützt sie nur eingeschränkt bzw. erst in neueren Versionen. Prüfe daher vorher mit sender.transport?.iceTransport und greif sonst auf RTCPeerConnection zurück.
  • Das Event enthält keine Kandidaten. Die einzelnen Kandidaten liefert das Event icecandidate an RTCPeerConnection.