Signatur
Beschreibung
Die Eigenschaft readable eines RTCRtpScriptTransformer gibt einen ReadableStream zurück, der die kodierten Medienframes eines RTCRtpSender oder RTCRtpReceiver liefert. Die Frames sind Instanzen von RTCEncodedVideoFrame oder RTCEncodedAudioFrame.
Der Transformer existiert nur in einem Dedicated Worker. Er wird dort über das Ereignis rtctransform als event.transformer bereitgestellt, sobald im Hauptthread ein RTCRtpScriptTransform an sender.transform bzw. receiver.transform gebunden wird. Im Worker liest man die Frames aus readable, verändert sie (z. B. Ende-zu-Ende-Verschlüsselung, Metadaten einfügen, Analyse) und schreibt sie in transformer.writable zurück.
Üblicherweise leitet man readable mit pipeThrough() durch einen TransformStream und dann mit pipeTo() weiter an writable. Wer mehr Kontrolle braucht, kann auch direkt einen Reader verwenden (getReader()) oder mit for await...of über den Stream iterieren.
Rückgabewert
Beispiele
Hauptthread: Transform an einen Sender binden
// main.js
const worker = new Worker('worker.js');
const pc = new RTCPeerConnection();
const stream = await navigator.mediaDevices.getUserMedia({ video: true });
const [track] = stream.getVideoTracks();
const sender = pc.addTrack(track, stream);
// Löst im Worker das Ereignis 'rtctransform' aus
sender.transform = new RTCRtpScriptTransform(worker, { role: 'sender' });
Worker: Frames per pipeThrough verändern (einfache XOR-„Verschlüsselung“)
// worker.js
const key = 0x5a;
addEventListener('rtctransform', (event) => {
const transformer = 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] ^= key;
frame.data = data.buffer;
controller.enqueue(frame);
}
});
transformer.readable
.pipeThrough(xor)
.pipeTo(transformer.writable)
.catch((err) => console.error('Pipeline abgebrochen:', err));
});
Worker: Frames mit for await...of zählen und durchreichen
// worker.js
addEventListener('rtctransform', async ({ transformer }) => {
const writer = transformer.writable.getWriter();
let count = 0;
for await (const frame of transformer.readable) {
count++;
if (frame.type === 'key') {
console.log(`Keyframe #${count}, ${frame.data.byteLength} Bytes`);
}
await writer.write(frame);
}
});
// Wichtig · Fallstricke
- Nur im Worker:
RTCRtpScriptTransformergibt es ausschließlich im Kontext eines Dedicated Workers. Im Hauptthread kommt man nicht anreadable. - Kompatibilität: Firefox und Safari unterstützen diese standardisierte API. Ältere Chrome-Versionen boten stattdessen die nicht standardisierte Variante
RTCRtpSender.createEncodedStreams()an (dafür mussteencodedInsertableStreams: truein derRTCPeerConnectiongesetzt sein). Die Feature-Erkennung gelingt mit'RTCRtpScriptTransform' in window. - Frames immer weiterreichen: Frames, die nicht in
writablegeschrieben werden, gehen verloren – das Video friert ein oder der Ton bricht ab. Bei Video-Frames sollte man auf keinen Fall die Header-Bytes des Codecs verändern, wenn der Empfänger die Transformation nicht rückgängig macht. - Sperre: Ein Stream kann immer nur einen Leser haben. Nach
pipeThrough()odergetReader()istreadable.lockedauftruegesetzt, und ein zweiter Zugriff wirft einenTypeError. - Performance: Die Transformation läuft für jeden Frame. Aufwendige Verarbeitung erhöht die Latenz. Wer Schlüssel verwendet, sollte die Web Crypto API nutzen und sie nicht in Schleifen neu erzeugen.