Start · Sprachen · JavaScript · Referenz · RTCRtpReceiver.transform

RTCRtpReceiver.transform

Eigenschaft

Setzt oder liefert ein <code>RTCRtpScriptTransform</code>, mit dem empfangene, noch codierte Audio-/Video-Frames in einem Worker verarbeitet werden, bevor der Decoder sie erhält.

seit JavaScript Firefox 117+, Safari 15.4+; Chromium bisher nur üb Kategorie: webapi

Signatur

RTCRtpReceiver.transform

Beschreibung

Die Eigenschaft transform eines RTCRtpReceiver gehört zur WebRTC Encoded Transform-API. Weist du ihr ein RTCRtpScriptTransform zu, fügt der Browser einen Verarbeitungsschritt in die Empfangspipeline ein: Jedes eingehende, noch codierte Frame (RTCEncodedVideoFrame bzw. RTCEncodedAudioFrame) wird an einen Worker übergeben. Dort kannst du es über einen TransformStream verändern und dann an den Decoder weiterreichen.

Typische Anwendungen sind Ende-zu-Ende-Verschlüsselung (z. B. SFrame oder eigene AES-GCM-Schemata bei Konferenzen über SFU-Server), das Auslesen oder Entfernen eingebetteter Metadaten und das Messen von Frame-Größen oder Zeitstempeln. Auf der Sendeseite gibt es dazu das Gegenstück RTCRtpSender.transform.

Im Worker löst das Zuweisen das Ereignis rtctransform aus. Dessen Eigenschaft event.transformer (RTCRtpScriptTransformer) stellt einen readable- und einen writable-Stream bereit, außerdem die beim Erzeugen übergebenen options. Setzt du transform auf null, wird die Transformation wieder aus der Pipeline entfernt.

Parameter

Name Typ Default Beschreibung
$value RTCRtpScriptTransform | null null Beim Setzen: ein mit new RTCRtpScriptTransform(worker, options, transfer) erzeugtes Objekt oder null, um die Transformation zu entfernen.

Rückgabewert

Typ
RTCRtpScriptTransform | null
Beschreibung
Das aktuell zugewiesene RTCRtpScriptTransform oder null, wenn keine Transformation aktiv ist.

Beispiele

Transformation beim Empfang eines Tracks setzen (Haupt-Thread)

const worker = new Worker('receiver-worker.js');
const pc = new RTCPeerConnection();

pc.addEventListener('track', (event) => {
  // Optionen landen im Worker unter transformer.options
  event.receiver.transform = new RTCRtpScriptTransform(worker, {
    operation: 'decrypt',
    kind: event.track.kind
  });
  document.querySelector('video').srcObject = event.streams[0];
});

Frames im Worker entschlüsseln (receiver-worker.js)

// receiver-worker.js
const KEY_BYTE = 0x5a; // Demo-XOR – in der Praxis AES-GCM über crypto.subtle

const decrypt = (encodedFrame, controller) => {
  const view = new Uint8Array(encodedFrame.data);
  const out = new Uint8Array(view.length);
  for (let i = 0; i < view.length; i++) out[i] = view[i] ^ KEY_BYTE;
  encodedFrame.data = out.buffer;
  controller.enqueue(encodedFrame);
};

self.addEventListener('rtctransform', (event) => {
  const { readable, writable, options } = event.transformer;
  console.log('Transform aktiv:', options.operation, options.kind);
  readable
    .pipeThrough(new TransformStream({ transform: decrypt }))
    .pipeTo(writable);
});
Transform aktiv: decrypt video

Funktionsprüfung und Entfernen der Transformation

const supportsEncodedTransform = 'RTCRtpScriptTransform' in window &&
  'transform' in RTCRtpReceiver.prototype;

const toggleDecryption = (receiver, worker, enabled) => {
  if (!supportsEncodedTransform) {
    console.warn('WebRTC Encoded Transform wird nicht unterstützt');
    return;
  }
  receiver.transform = enabled
    ? new RTCRtpScriptTransform(worker, { operation: 'decrypt' })
    : null;
  console.log('Aktiv:', receiver.transform !== null);
};
Aktiv: true (bzw. false nach dem Abschalten)

// Wichtig · Fallstricke

  • Browser-Unterstützung: Standardkonform in Firefox (ab 117) und Safari (ab 15.4). Chromium-Browser haben lange nur das nicht standardisierte receiver.createEncodedStreams() angeboten, das die Option encodedInsertableStreams: true im RTCPeerConnection-Konstruktor voraussetzt. Prüfe die Unterstützung deshalb vorher und sieh bei Bedarf einen Fallback vor.
  • Die Transformation läuft immer in einem Worker. Das Ereignis rtctransform wird dort ausgelöst, nicht im Haupt-Thread.
  • Rufe controller.enqueue() für jedes Frame auf. Frames, die du verwirfst oder die sich nicht entschlüsseln lassen, fehlen danach im Bild (Artefakte, eingefrorenes Video) oder im Ton. Kommt ein Keyframe nicht an, fordere auf der Sendeseite mit generateKeyFrame() ein neues an.
  • Bei Video bleiben je nach Codec einige Header-Bytes unverschlüsselt, zum Beispiel bei VP8 die ersten 1–10 Bytes. Werden sie verändert, können Zwischenstationen (SFU) und Paketierung scheitern.
  • Ein RTCRtpScriptTransform kann nur einem einzigen Sender oder Empfänger zugewiesen werden. Jeder weitere Versuch löst einen Fehler aus.
  • Sicherheit: Die Beispiel-XOR-Verschlüsselung schützt nicht. Für echte Ende-zu-Ende-Verschlüsselung nimm crypto.subtle (AES-GCM) und einen sicheren Schlüsselaustausch.