Start · Sprachen · JavaScript · Referenz · RTCRtpScriptTransformer.generateKeyFrame()

RTCRtpScriptTransformer.generateKeyFrame()

Methode

Fordert den Video-Encoder eines sendeseitigen WebRTC-Transformers auf, so bald wie möglich ein Schlüsselbild (Key Frame) zu erzeugen.

seit JavaScript Firefox 117+, Safari 15.4+; in Chromium-Browsern n Kategorie: webapi

Signatur

RTCRtpScriptTransformer.prototype.generateKeyFrame(rid)

Beschreibung

Die Methode generateKeyFrame() steht im Worker-Kontext eines RTCRtpScriptTransformer zur Verfügung. Sie veranlasst den Video-Encoder des zugehörigen RTCRtpSender, ein Schlüsselbild (auch I-Frame oder Intra-Frame) zu erzeugen. Ein Schlüsselbild enthält alle Informationen, die zum Dekodieren des Bildes nötig sind, und hängt nicht von vorherigen Frames ab.

Gebraucht wird die Methode vor allem bei Ende-zu-Ende-Verschlüsselung (E2EE) mit Encoded Transforms: Nach einem Schlüsselwechsel sollte der erste mit dem neuen Schlüssel verschlüsselte Frame ein Schlüsselbild sein. So kann der Empfänger ab diesem Frame dekodieren, ohne auf alte, mit dem vorherigen Schlüssel verschlüsselte Delta-Frames angewiesen zu sein. Weitere Einsatzfälle sind das Zurücksetzen des Bildstroms nach Paketverlust oder wenn neue Teilnehmende einer Konferenz beitreten.

Die Methode funktioniert nur auf der Senderseite und nur bei Video. Wird Simulcast verwendet, lässt sich über den optionalen Parameter rid gezielt ein einzelner Encoding-Layer ansprechen; ohne rid erzeugen alle Encoder ein Schlüsselbild. Auf der Empfängerseite verwendest du stattdessen sendKeyFrameRequest(), um beim Gegenüber ein Schlüsselbild anzufordern.

Parameter

Name Typ Default Beschreibung
$rid string Optionale RTP-Stream-ID (Restriction Identifier) eines Simulcast-Encodings, z. B. "h" oder "low". Muss der RID-Syntax entsprechen (alphanumerisch). Fehlt der Wert, wird für alle Encodings des Senders ein Schlüsselbild angefordert.

Rückgabewert

Typ
Promise<undefined>
Beschreibung
Ein Promise, das erfüllt wird, sobald das angeforderte Schlüsselbild erzeugt wurde bzw. in den Stream des Transformers eingereiht wird. Wird abgelehnt mit InvalidStateError (kein Video-Encoder aktiv oder Transformer ist empfangsseitig), NotFoundError (kein passender Encoder, z. B. weil der Sender inaktiv oder der Track beendet ist, oder unbekannte rid) bzw. TypeError (ungültige rid-Syntax).

Beispiele

Hauptthread: Sender-Transform mit Worker einrichten

// main.js
const worker = new Worker('e2ee-worker.js');
const stream = await navigator.mediaDevices.getUserMedia({ video: true });
const pc = new RTCPeerConnection();

const [track] = stream.getVideoTracks();
const sender = pc.addTrack(track, stream);

// Transform an den Sender hängen; die Optionen landen im Worker als transformer.options
sender.transform = new RTCRtpScriptTransform(worker, { side: 'send' });

// Später: Schlüsselwechsel auslösen
const rotateKey = () => worker.postMessage({ type: 'rotateKey', key: crypto.getRandomValues(new Uint8Array(16)) });
setInterval(rotateKey, 60_000);

Worker: nach Schlüsselwechsel ein Schlüsselbild erzwingen

// e2ee-worker.js
let currentKey = null;
let transformer = null;

self.onrtctransform = (event) => {
  transformer = event.transformer;
  if (transformer.options.side !== 'send') return;

  const xor = new TransformStream({
    transform(frame, controller) {
      if (currentKey) {
        const data = new Uint8Array(frame.data);
        // Demo-"Verschlüsselung" ab Byte 10 (Header bleibt lesbar)
        for (let i = 10; i < data.length; i++) data[i] ^= currentKey[i % currentKey.length];
        frame.data = data.buffer;
      }
      controller.enqueue(frame);
    }
  });

  transformer.readable.pipeThrough(xor).pipeTo(transformer.writable);
};

self.onmessage = async ({ data }) => {
  if (data.type !== 'rotateKey' || !transformer) return;
  currentKey = data.key;
  try {
    await transformer.generateKeyFrame();
    console.log('Schlüsselbild mit neuem Schlüssel angefordert');
  } catch (err) {
    console.error(`${err.name}: ${err.message}`);
  }
};
Schlüsselbild mit neuem Schlüssel angefordert

Simulcast: nur für einen Layer ein Schlüsselbild anfordern

// Im Worker, transformer stammt aus dem rtctransform-Event
const requestKeyFrame = async (transformer, rid) => {
  try {
    await transformer.generateKeyFrame(rid);
    console.log(`Schlüsselbild für Layer "${rid}" erzeugt`);
  } catch (err) {
    if (err.name === 'NotFoundError') {
      console.warn(`Kein aktiver Encoder für rid "${rid}"`);
    } else {
      throw err;
    }
  }
};

await requestKeyFrame(transformer, 'h');
Schlüsselbild für Layer "h" erzeugt

// Wichtig · Fallstricke

  • Nur im Worker: RTCRtpScriptTransformer-Instanzen gibt es ausschließlich im rtctransform-Event eines Dedicated Workers. Im Hauptthread lässt sich die Methode nicht aufrufen. Du steuerst sie per postMessage() an.
  • Nur sendeseitig und nur Video: Hängt der Transformer an einem RTCRtpReceiver oder an einem Audio-Track, wird das Promise mit InvalidStateError abgelehnt. Auf der Empfängerseite nutzt du sendKeyFrameRequest().
  • Timing: Das Promise sagt nichts über die Zustellung beim Empfänger aus. Setze bei E2EE den neuen Schlüssel spätestens dann ein, wenn der Key Frame durch den Transform-Stream läuft. Sonst kann der Empfänger für kurze Zeit nicht dekodieren.
  • Performance: Schlüsselbilder sind deutlich größer als Delta-Frames. Häufige Aufrufe erhöhen die Bitrate und können zu Qualitätseinbrüchen oder Stau führen. Rufe die Methode also nur gezielt auf, etwa bei einem Schlüsselwechsel.
  • Kompatibilität: Firefox und Safari unterstützen RTCRtpScriptTransform. Chromium-basierte Browser nutzen bislang meist die ältere, nicht standardisierte API createEncodedStreams() ohne diese Methode. Prüfe daher vorher mit 'RTCRtpScriptTransform' in window, ob die API verfügbar ist.