Start · Sprachen · JavaScript · Referenz · RTCPeerConnection: signalingstatechange

RTCPeerConnection: signalingstatechange

Ereignis

Wird an eine <code>RTCPeerConnection</code> gesendet, sobald sich ihr Signalisierungsstatus (<code>signalingState</code>) im Offer/Answer-Austausch ändert.

seit JavaScript Baseline: alle modernen Browser (seit 2020) Kategorie: webapi

Signatur

peerConnection.addEventListener("signalingstatechange", handler)

Beschreibung

Das Ereignis signalingstatechange wird an einer RTCPeerConnection ausgelöst, wenn sich der Wert der Eigenschaft signalingState ändert. Das passiert während der SDP-Aushandlung (Offer/Answer), typischerweise als Folge von setLocalDescription(), setRemoteDescription() oder beim Schließen der Verbindung mit close().

Mögliche Werte von signalingState:

  • "stable" – kein Austausch läuft gerade; Ausgangs- und Endzustand einer erfolgreichen Aushandlung.
  • "have-local-offer" – ein lokales Angebot wurde gesetzt, es wird auf die Antwort gewartet.
  • "have-remote-offer" – ein entferntes Angebot wurde gesetzt, eine lokale Antwort steht aus.
  • "have-local-pranswer" / "have-remote-pranswer" – eine vorläufige Antwort (Provisional Answer) wurde gesetzt.
  • "closed" – die Verbindung wurde geschlossen.

Das Ereignis ist ein einfaches Event ohne zusätzliche Eigenschaften; den neuen Zustand liest man über pc.signalingState aus. Es eignet sich zum Debuggen der Signalisierung, zur Umsetzung von „Perfect Negotiation“ (Kollisionserkennung) und zur Steuerung der Oberfläche. Alternativ zu addEventListener() kann die Eigenschaft onsignalingstatechange verwendet werden.

Parameter

Name Typ Default Beschreibung
$type Pflicht string Der Ereignisname "signalingstatechange".
$handler Pflicht (event: Event) => void Callback, der bei jeder Änderung von signalingState aufgerufen wird. Das übergebene Event enthält keine Statusdaten; event.target.signalingState liefert den neuen Wert.
$options boolean | AddEventListenerOptions false Optionale Listener-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-Objekt.

Beispiele

Statuswechsel während der Aushandlung protokollieren

const pc = new RTCPeerConnection();

pc.addEventListener("signalingstatechange", () => {
  console.log("Signalisierungsstatus:", pc.signalingState);
});

const start = async () => {
  pc.addTransceiver("audio");
  const offer = await pc.createOffer();
  await pc.setLocalDescription(offer);
};

start();
Signalisierungsstatus: have-local-offer

Handler über die on-Property setzen und entfernen

const pc = new RTCPeerConnection();

pc.onsignalingstatechange = () => {
  if (pc.signalingState === "stable") {
    console.log("Aushandlung abgeschlossen");
  } else if (pc.signalingState === "closed") {
    console.log("Verbindung geschlossen");
    pc.onsignalingstatechange = null; // Handler entfernen
  }
};

pc.close(); // Hinweis: close() löst in aktuellen Browsern kein Ereignis aus
console.log(pc.signalingState);
closed

Perfect Negotiation: Angebots-Kollision erkennen und Listener per AbortController entfernen

const pc = new RTCPeerConnection();
const controller = new AbortController();
let makingOffer = false;

pc.addEventListener("signalingstatechange", () => {
  document.body.dataset.signaling = pc.signalingState;
}, { signal: controller.signal });

pc.addEventListener("negotiationneeded", async () => {
  try {
    makingOffer = true;
    await pc.setLocalDescription(); // implizites Offer
    // sendToPeer({ description: pc.localDescription });
  } finally {
    makingOffer = false;
  }
});

// Beim Eintreffen eines entfernten Angebots:
const isCollision = (description) =>
  description.type === "offer" &&
  (makingOffer || pc.signalingState !== "stable");

// Später: alle Listener mit diesem Signal entfernen
// controller.abort();

// Wichtig · Fallstricke

  • Kein Status im Ereignis: Das Objekt ist ein schlichtes Event. Den Zustand immer über pc.signalingState lesen – bei schnell aufeinanderfolgenden Wechseln kann er schon weitergesprungen sein.
  • close(): Laut aktueller Spezifikation löst ein lokales pc.close() kein signalingstatechange aus, obwohl signalingState auf "closed" wechselt. Aufräumlogik gehört deshalb direkt neben den close()-Aufruf.
  • Nicht mit anderen Zuständen verwechseln: signalingState betrifft nur den SDP-Austausch. Ob Medien tatsächlich fließen, zeigen connectionstatechange und iceconnectionstatechange.
  • Rollback: setLocalDescription({ type: "rollback" }) setzt den Zustand auf "stable" zurück und löst das Ereignis ebenfalls aus.
  • Kompatibilität: In Chrome, Firefox, Safari und Edge unterstützt. Vorläufige Antworten (pranswer) werden in der Praxis selten verwendet und sind nicht in jedem Browser gleich gut getestet.