Start · Sprachen · JavaScript · Referenz · MediaEncryptedEvent

MediaEncryptedEvent

Schnittstelle

Ereignisobjekt des <code>encrypted</code>-Events, das ein <code>HTMLMediaElement</code> auslöst, wenn es in den Mediendaten Initialisierungsdaten für eine Verschlüsselung findet.

seit JavaScript Baseline: alle modernen Browser (seit 2019); Teil Kategorie: webapi

Signatur

interface MediaEncryptedEvent extends Event

Beschreibung

MediaEncryptedEvent gehört zur Encrypted Media Extensions API (EME). Ein <video>- oder <audio>-Element löst das Ereignis encrypted aus, sobald der Browser in den Mediendaten Initialisierungsdaten für die Verschlüsselung findet, etwa eine pssh-Box in einem MP4-Container oder eine ContentEncKeyID in WebM. Das Ereignisobjekt enthält genau diese Daten. Deine Anwendung braucht sie, um beim Lizenzserver einen Schlüssel anzufordern.

Das Objekt hat zwei schreibgeschützte Eigenschaften:

  • initDataType: Ein String, der das Format der Daten angibt, z. B. "cenc", "keyids" oder "webm".
  • initData: Ein ArrayBuffer mit den Initialisierungsdaten oder null.

Der übliche Ablauf sieht so aus: Mit navigator.requestMediaKeySystemAccess() Zugriff auf ein Schlüsselsystem (Widevine, PlayReady, FairPlay oder Clear Key) anfordern und daraus MediaKeys erzeugen. Diese mit video.setMediaKeys() an das Element binden. Im encrypted-Handler eine MediaKeySession erstellen und session.generateRequest(event.initDataType, event.initData) aufrufen. Die Lizenzanfrage kommt dann über das message-Event der Sitzung. Die Antwort des Lizenzservers wird mit session.update() übergeben.

Einen eigenen Konstruktor new MediaEncryptedEvent(type, init) gibt es auch. Er dient vor allem für Tests oder dazu, Ereignisse nachzubilden. In echten Abspielern erzeugt der Browser die Ereignisse selbst.

Parameter

Name Typ Default Beschreibung
$type Pflicht string Nur für den Konstruktor: der Name des Ereignisses, normalerweise "encrypted".
$init { initDataType?: string, initData?: ArrayBuffer | null, bubbles?: boolean, cancelable?: boolean, composed?: boolean } { initDataType: "", initData: null } Nur für den Konstruktor: optionales Objekt mit dem Format (initDataType) und den Initialisierungsdaten (initData) sowie den üblichen EventInit-Feldern.

Rückgabewert

Typ
MediaEncryptedEvent
Beschreibung
Das Ereignisobjekt mit den schreibgeschützten Eigenschaften initDataType (string) und initData (ArrayBuffer | null).

Beispiele

encrypted-Event abfangen und Initialisierungsdaten lesen

const video = document.querySelector('video');

video.addEventListener('encrypted', (event) => {
  // event ist ein MediaEncryptedEvent
  console.log('Format:', event.initDataType);
  console.log('Bytes:', event.initData?.byteLength ?? 0);
});
Format: cenc Bytes: 52

Vollständiger Clear-Key-Ablauf mit Lizenzanfrage

const video = document.querySelector('video');

const config = [{
  initDataTypes: ['cenc', 'keyids'],
  videoCapabilities: [{ contentType: 'video/mp4; codecs="avc1.42E01E"' }]
}];

const setupEme = async () => {
  const access = await navigator.requestMediaKeySystemAccess('org.w3.clearkey', config);
  const mediaKeys = await access.createMediaKeys();
  await video.setMediaKeys(mediaKeys);

  video.addEventListener('encrypted', async ({ initDataType, initData }) => {
    const session = mediaKeys.createSession();

    session.addEventListener('message', async (msg) => {
      // Lizenzanfrage an den eigenen Server schicken
      const res = await fetch('/license', {
        method: 'POST',
        body: msg.message
      });
      await session.update(await res.arrayBuffer());
    });

    await session.generateRequest(initDataType, initData);
  });
};

setupEme().catch((err) => console.error('EME-Fehler:', err));

Handler per on-Property registrieren und entfernen

const video = document.querySelector('video');

video.onencrypted = (event) => {
  console.log(`Verschlüsselung erkannt (${event.initDataType})`);
  video.onencrypted = null; // nur einmal reagieren
};
Verschlüsselung erkannt (cenc)

Event manuell erzeugen (z. B. für Tests)

const keyIds = new TextEncoder().encode(JSON.stringify({ kids: ['LwVHf8JLtPrv2GUXFW2v_A'] }));

const event = new MediaEncryptedEvent('encrypted', {
  initDataType: 'keyids',
  initData: keyIds.buffer
});

console.log(event.type, event.initDataType, event.initData.byteLength);
encrypted keyids 37

// Wichtig · Fallstricke

  • Nur in sicheren Kontexten: EME und damit requestMediaKeySystemAccess() funktionieren nur über HTTPS (oder localhost). Über reines HTTP ist die API in modernen Browsern nicht verfügbar.
  • Mehrfaches Auslösen: Das Event kann für dieselben Daten mehrmals kommen, z. B. einmal pro Spur oder bei jedem Init-Segment. Merke dir schon verarbeitete initData, damit du keine doppelten Sitzungen und Lizenzanfragen erzeugst.
  • Reihenfolge: Wenn noch keine MediaKeys gesetzt sind, während encrypted ausgelöst wird, musst du setMediaKeys() im Handler nachholen. Sonst bleibt die Wiedergabe hängen (waitingforkey).
  • initData kann null sein, etwa wenn die Daten aus Sicherheitsgründen zurückgehalten werden (Cross-Origin-Medien ohne CORS). Prüfe den Wert, bevor du ihn verwendest.
  • Unterstützte Formate: Welche Werte von initDataType und welche Schlüsselsysteme unterstützt werden, hängt vom Browser ab. Safari nutzt FairPlay, meist mit initDataType "sinf" oder "skd". Chrome und Firefox nutzen Widevine, Edge zusätzlich PlayReady. Clear Key ist nicht in allen Browsern vollständig umgesetzt.
  • Datenschutz: CDMs können eindeutige Geräte-Kennungen erzeugen. Browser zeigen dafür teils Berechtigungsabfragen an, besonders in privaten Fenstern kann EME eingeschränkt sein.