Signatur
Beschreibung
Die Eigenschaft writable eines RTCRtpScriptTransformer gibt einen WritableStream zurück. Er ist das Ziel für kodierte Medienframes (RTCEncodedVideoFrame oder RTCEncodedAudioFrame), nachdem Ihr Code im Worker sie verarbeitet hat. Beim Sender gehen die geschriebenen Frames an den Paketierer und dann ins Netz, beim Empfänger an den Decoder.
Der RTCRtpScriptTransformer existiert nur im Worker-Kontext. Er steht im Ereignis rtctransform als event.transformer bereit, sobald im Hauptthread ein RTCRtpScriptTransform einem RTCRtpSender.transform oder RTCRtpReceiver.transform zugewiesen wurde. Üblicherweise verbindet man readable über einen TransformStream mit writable: readable.pipeThrough(transform).pipeTo(writable).
Typische Einsatzfälle sind Ende-zu-Ende-Verschlüsselung (z. B. SFrame-ähnliche Verfahren), das Anhängen von Metadaten an Frames oder das gezielte Verwerfen von Frames. Ein Frame, der nicht in writable geschrieben wird, gilt als verworfen.
Rückgabewert
WritableStream, der kodierte Frames annimmt und sie an die WebRTC-Pipeline (Paketierer bzw. Decoder) weiterreicht. Pro Transformer immer dieselbe Instanz.Beispiele
Einfaches Durchreichen (Worker)
// worker.js
addEventListener('rtctransform', (event) => {
const { readable, writable } = event.transformer;
// Frames unverändert weiterleiten
readable.pipeTo(writable).catch((err) => console.error('Pipe-Fehler:', err));
});
XOR-"Verschlüsselung" mit TransformStream
// Hauptthread
const worker = new Worker('worker.js');
const pc = new RTCPeerConnection();
const stream = await navigator.mediaDevices.getUserMedia({ video: true });
const sender = pc.addTrack(stream.getVideoTracks()[0], stream);
sender.transform = new RTCRtpScriptTransform(worker, { key: 0x5a });
// worker.js
addEventListener('rtctransform', (event) => {
const { readable, writable, options } = event.transformer;
const xor = new TransformStream({
transform(frame, controller) {
const data = new Uint8Array(frame.data);
for (let i = 0; i < data.length; i++) data[i] ^= options.key;
frame.data = data.buffer;
controller.enqueue(frame); // landet in writable
}
});
readable.pipeThrough(xor).pipeTo(writable);
});
Direkt mit einem Writer schreiben und Frames verwerfen
// worker.js
addEventListener('rtctransform', async (event) => {
const reader = event.transformer.readable.getReader();
const writer = event.transformer.writable.getWriter();
let count = 0;
while (true) {
const { value: frame, done } = await reader.read();
if (done) break;
count++;
// Nur Audio-Frames mit Inhalt weitergeben
if (frame.data.byteLength > 0) {
await writer.write(frame);
}
}
console.log(`Verarbeitet: ${count} Frames`);
});
// Wichtig · Fallstricke
- Nur im Worker:
RTCRtpScriptTransformerkann man nicht selbst erzeugen. Man erhält ihn ausschließlich über das Ereignisrtctransformim dedizierten Worker. - Sperre: Nach
getWriter()oderpipeTo()ist der Stream gesperrt. Ein zweiter Writer oder eine zweite Pipe löst einenTypeErroraus. - Frames nicht klonen und liegen lassen: Schreiben Sie nur Frames aus dem zugehörigen
readable. Fremde oder schon geschriebene Frames können abgewiesen werden. - Verworfene Frames: Bei Video können fehlende Frames Artefakte erzeugen, bis ein Keyframe kommt. Beim Sender hilft dann
generateKeyFrame(), beim EmpfängersendKeyFrameRequest(). - Kompatibilität: Firefox und Safari unterstützen die Script-Transform-API seit Längerem. Chrome hatte lange nur die ältere, nicht standardisierte Variante
createEncodedStreams()(Insertable Streams) und bietetRTCRtpScriptTransformerst seit neueren Versionen an. Prüfen Sie die Unterstützung per Feature-Erkennung:'RTCRtpScriptTransform' in window. - Sicherheit: Eine XOR-Transformation ist keine echte Verschlüsselung. Für E2EE verwenden Sie
crypto.subtle(z. B. AES-GCM) und lassen Header-Bytes unverschlüsselt, die der Paketierer benötigt.