Signatur
Beschreibung
Die Methode getMetadata() eines RTCEncodedAudioFrame liefert ein einfaches Objekt (RTCEncodedAudioFrameMetadata) mit Informationen zum RTP-Kontext des Frames. Dazu gehören die Synchronisationsquelle (synchronizationSource, SSRC), die beitragenden Quellen (contributingSources, CSRCs), der RTP-payloadType, die sequenceNumber und – in neueren Implementierungen – der mimeType des Codecs (z. B. "audio/opus") und der rtpTimestamp.
Einsatz findet die Methode in WebRTC Encoded Transforms (früher „Insertable Streams“). Dort bekommt man in einem Worker über das Ereignis rtctransform einen lesbaren und einen schreibbaren Stream mit codierten Frames. Mit getMetadata() kann man pro Frame entscheiden, wie er verarbeitet wird, z. B. für Ende-zu-Ende-Verschlüsselung Schlüssel pro SSRC auswählen, Frames nach Codec filtern oder Diagnosedaten protokollieren.
Das zurückgegebene Objekt ist eine Momentaufnahme: Änderungen daran wirken sich nicht auf den Frame aus. Die eigentlichen Nutzdaten stehen weiterhin in frame.data (ein ArrayBuffer).
Rückgabewert
synchronizationSource (number), contributingSources (Array<number>), payloadType (number), sequenceNumber (number) sowie je nach Browser mimeType (string) und rtpTimestamp (number).Beispiele
Metadaten im Worker protokollieren (RTCRtpScriptTransform)
// worker.js
self.addEventListener('rtctransform', (event) => {
const { readable, writable } = event.transformer;
const transform = new TransformStream({
transform(frame, controller) {
const meta = frame.getMetadata();
console.log(
`SSRC=${meta.synchronizationSource} PT=${meta.payloadType} ` +
`Seq=${meta.sequenceNumber} Codec=${meta.mimeType ?? 'unbekannt'}`
);
controller.enqueue(frame); // Frame unverändert weiterreichen
}
});
readable.pipeThrough(transform).pipeTo(writable);
});
Transform auf der Hauptseite an einen Receiver hängen
// main.js
const worker = new Worker('worker.js');
const pc = new RTCPeerConnection();
pc.addEventListener('track', (event) => {
if (event.track.kind === 'audio') {
event.receiver.transform = new RTCRtpScriptTransform(worker, { side: 'receive' });
}
});
Schlüssel pro Sender (SSRC) für E2E-Verschlüsselung wählen
// worker.js – vereinfachte XOR-"Verschlüsselung" nur zur Demonstration
const keys = new Map([[1234567890, 0x5a]]);
const decrypt = new TransformStream({
transform(frame, controller) {
const { synchronizationSource, contributingSources } = frame.getMetadata();
const key = keys.get(synchronizationSource);
if (key === undefined) return; // unbekannter Sender: Frame verwerfen
const bytes = new Uint8Array(frame.data);
for (let i = 0; i < bytes.length; i++) bytes[i] ^= key;
frame.data = bytes.buffer;
if (contributingSources.length) {
console.log('Gemischter Stream, CSRCs:', contributingSources);
}
controller.enqueue(frame);
}
});
self.onrtctransform = ({ transformer }) =>
transformer.readable.pipeThrough(decrypt).pipeTo(transformer.writable);
// Wichtig · Fallstricke
- Kompatibilität: Firefox und Safari unterstützen den standardisierten Weg über
RTCRtpScriptTransform. Chrome unterstützt dies erst in neueren Versionen (ab ca. 141) und bot vorher nur die proprietäre APIRTCRtpSender.createEncodedStreams()bzw.RTCRtpReceiver.createEncodedStreams()(setztencodedInsertableStreams: truein derRTCPeerConnection-Konfiguration voraus). Vor dem Einsatz ist Feature-Detection nötig. - Felder wie
mimeType,rtpTimestampodersequenceNumbergibt es nicht in allen Browsern – immer mit??oderinabsichern. - Beim Senden können einige Werte (z. B.
sequenceNumber) fehlen, da der RTP-Header erst nach der Transformation erzeugt wird. - Das Metadaten-Objekt ist eine Kopie; zum Ändern gibt es in neueren Spezifikationen
setMetadata()bzw. den Konstruktornew RTCEncodedAudioFrame(frame, { metadata })– noch nicht überall verfügbar. - Transformationen laufen pro Frame (alle ~20 ms bei Opus) – aufwendige Logik oder
console.login jedem Frame kann die Latenz erhöhen.