Start · Sprachen · JavaScript · Referenz · RTCSctpTransport

RTCSctpTransport

Schnittstelle

Beschreibt den SCTP-Transport einer <code>RTCPeerConnection</code>, über den alle <code>RTCDataChannel</code>s laufen, mit Zustand, maximaler Nachrichtengröße und Kanalanzahl.

seit JavaScript Baseline 2023: Chrome 76+, Edge 79+, Firefox 64+, Kategorie: webapi

Signatur

interface RTCSctpTransport extends EventTarget

Beschreibung

RTCSctpTransport steht für die SCTP-Verbindung (Stream Control Transmission Protocol), die WebRTC für Datenkanäle nutzt. Alle RTCDataChannel-Objekte einer RTCPeerConnection teilen sich eine SCTP-Verbindung. Diese läuft ihrerseits verschlüsselt über einen RTCDtlsTransport.

Du kannst das Objekt nicht selbst erzeugen, es hat keinen Konstruktor. Du erreichst es über RTCPeerConnection.sctp. Die Eigenschaft ist null, bis SCTP ausgehandelt wurde. Dafür muss mindestens ein Datenkanal angelegt sein und die Remote-Beschreibung mit einem m=application-Abschnitt gesetzt worden sein.

Die Schnittstelle bietet diese schreibgeschützten Eigenschaften:

  • state: Zustand der Verbindung, also "connecting", "connected" oder "closed".
  • maxMessageSize: größte Nachricht in Bytes, die RTCDataChannel.send() annimmt. Der Wert wird mit der Gegenseite ausgehandelt und kann Infinity sein.
  • maxChannels: Höchstzahl gleichzeitig offener Datenkanäle. Vor dem Zustand "connected" ist der Wert null.
  • transport: der zugrunde liegende RTCDtlsTransport.

Ändert sich state, wird das Ereignis statechange ausgelöst. Du kannst es mit addEventListener("statechange", …) oder über die Eigenschaft onstatechange abfangen.

Wofür du das in der Praxis brauchst:

  • große Dateien anhand von maxMessageSize in passende Teile zerlegen,
  • die Verbindungsqualität überwachen, über transport.iceTransport,
  • Diagnose, wenn Datenkanäle nicht aufgehen.

Rückgabewert

Typ
RTCSctpTransport | null
Beschreibung
Du erhältst das Objekt über RTCPeerConnection.sctp. Vor der SCTP-Aushandlung ist der Wert null.

Beispiele

SCTP-Transport lokal aushandeln und auslesen

// Zwei Peers im selben Tab (Loopback), um SCTP ohne Signalisierungsserver zu testen
const pc1 = new RTCPeerConnection();
const pc2 = new RTCPeerConnection();

pc1.onicecandidate = (e) => e.candidate && pc2.addIceCandidate(e.candidate);
pc2.onicecandidate = (e) => e.candidate && pc1.addIceCandidate(e.candidate);

// Ohne Datenkanal wird kein SCTP ausgehandelt
const channel = pc1.createDataChannel('chat');
console.log('Vor Aushandlung:', pc1.sctp);

const offer = await pc1.createOffer();
await pc1.setLocalDescription(offer);
await pc2.setRemoteDescription(offer);
const answer = await pc2.createAnswer();
await pc2.setLocalDescription(answer);
await pc1.setRemoteDescription(answer);

const sctp = pc1.sctp;
console.log('Zustand:', sctp.state);
console.log('Max. Nachrichtengröße:', sctp.maxMessageSize);
console.log('DTLS-Zustand:', sctp.transport.state);
Vor Aushandlung: null Zustand: connecting Max. Nachrichtengröße: 262144 DTLS-Zustand: new

Auf Zustandsänderungen reagieren (addEventListener und onstatechange)

const watchSctp = (pc) => {
  const sctp = pc.sctp;
  if (!sctp) return;

  const onChange = () => {
    console.log('SCTP-Zustand:', sctp.state);
    if (sctp.state === 'connected') {
      console.log('Max. Kanäle:', sctp.maxChannels);
    }
    if (sctp.state === 'closed') {
      // Listener wieder entfernen, wenn die Verbindung beendet ist
      sctp.removeEventListener('statechange', onChange);
    }
  };

  sctp.addEventListener('statechange', onChange);
  // Alternative mit der Eigenschaft:
  // sctp.onstatechange = onChange;
};

// Aufruf nach setRemoteDescription():
// watchSctp(pc1);
SCTP-Zustand: connected Max. Kanäle: 65535

Datei passend zu maxMessageSize aufteilen

const sendFile = async (pc, channel, file) => {
  // Konservativer Standardwert, falls noch nichts ausgehandelt wurde
  const max = pc.sctp?.maxMessageSize ?? 16 * 1024;
  // Nicht zu große Teile wählen, damit der Kanal nicht blockiert
  const chunkSize = Math.min(max, 64 * 1024);
  const buffer = await file.arrayBuffer();

  channel.bufferedAmountLowThreshold = chunkSize * 4;
  for (let offset = 0; offset < buffer.byteLength; offset += chunkSize) {
    if (channel.bufferedAmount > chunkSize * 16) {
      await new Promise((r) =>
        channel.addEventListener('bufferedamountlow', r, { once: true })
      );
    }
    channel.send(buffer.slice(offset, offset + chunkSize));
  }
  console.log(`Gesendet: ${buffer.byteLength} Bytes in Teilen zu ${chunkSize} Bytes`);
};
Gesendet: 1048576 Bytes in Teilen zu 65536 Bytes

// Wichtig · Fallstricke

  • pc.sctp ist oft null: SCTP gibt es erst, nachdem vor dem Angebot mindestens ein Datenkanal angelegt und die Remote-Beschreibung gesetzt wurde. Prüfe deshalb immer mit pc.sctp?.…. Eine reine Audio- oder Video-Verbindung hat keinen SCTP-Transport.
  • maxMessageSize ist nicht einheitlich: Je nach Browser und Gegenseite liegt der Wert z. B. bei 64 KiB, 256 KiB oder 1 GiB. Größere Nachrichten lassen send() mit einem TypeError scheitern. Zerlege Daten daher immer in Teile.
  • maxChannels ist erst im Zustand "connected" gesetzt, vorher ist der Wert null.
  • Browser-Unterstützung: Chrome/Edge ab 76, Firefox ab 64, Safari erst ab 15.4. In älteren Safari-Versionen fehlt RTCPeerConnection.sctp ganz. Prüfe das per Feature-Erkennung: 'sctp' in RTCPeerConnection.prototype.
  • Du kannst das Objekt nicht selbst mit new erzeugen. Der Browser verwaltet es, und nach pc.close() wechselt es in den Zustand "closed".