Start · Sprachen · JavaScript · Referenz · MediaKeySession: message

MediaKeySession: message

Ereignis

Wird ausgelöst, wenn das Inhaltsentschlüsselungsmodul (CDM) eine Nachricht erzeugt, etwa eine Lizenzanfrage, die an den Lizenzserver weitergeleitet werden muss.

seit JavaScript Baseline: alle modernen Browser (Encrypted Media E Kategorie: webapi

Signatur

mediaKeySession.addEventListener("message", handler)

Beschreibung

Das message-Ereignis gehört zu den Encrypted Media Extensions (EME). Es wird an einer MediaKeySession ausgelöst, sobald das Inhaltsentschlüsselungsmodul (Content Decryption Module, CDM) Daten an die Anwendung übergeben möchte, meistens nach generateRequest(). Das Ereignisobjekt ist ein MediaKeyMessageEvent mit den Eigenschaften messageType und message (ein ArrayBuffer).

Die Anwendung sieht in die Nachricht nicht hinein. Sie schickt sie unverändert an den Lizenzserver, zum Beispiel per fetch(), und übergibt die Antwort des Servers über session.update(response) wieder an das CDM. Erst danach kann das Video entschlüsselt und abgespielt werden.

Den Listener registriert man mit session.addEventListener("message", handler) oder über die Eigenschaft session.onmessage = handler. Wichtig: Der Listener muss vor dem Aufruf von generateRequest() registriert werden, sonst geht die erste Lizenzanfrage verloren.

Mögliche Werte von messageType: "license-request", "license-renewal", "license-release" und "individualization-request".

Rückgabewert

Typ
void
Beschreibung
addEventListener hat keinen Rückgabewert. Die Daten stehen im übergebenen MediaKeyMessageEvent.

Beispiele

Lizenzanfrage an einen Lizenzserver weiterleiten (ClearKey)

const video = document.querySelector('video');
const LICENSE_URL = 'https://license.example.com/clearkey';

video.addEventListener('encrypted', async (event) => {
  if (!video.mediaKeys) {
    const access = await navigator.requestMediaKeySystemAccess('org.w3.clearkey', [{
      initDataTypes: ['cenc'],
      videoCapabilities: [{ contentType: 'video/mp4; codecs="avc1.42E01E"' }]
    }]);
    const mediaKeys = await access.createMediaKeys();
    await video.setMediaKeys(mediaKeys);
  }

  const session = video.mediaKeys.createSession();

  // Listener VOR generateRequest() registrieren
  session.addEventListener('message', async (msgEvent) => {
    console.log('Nachrichtentyp:', msgEvent.messageType);
    const response = await fetch(LICENSE_URL, {
      method: 'POST',
      body: msgEvent.message
    });
    const license = await response.arrayBuffer();
    await session.update(license);
    console.log('Lizenz übergeben');
  });

  await session.generateRequest(event.initDataType, event.initData);
});
Nachrichtentyp: license-request Lizenz übergeben

Nach messageType unterscheiden mit der onmessage-Eigenschaft

const handleMessage = async (session, event) => {
  switch (event.messageType) {
    case 'license-request':
    case 'license-renewal': {
      const res = await fetch('/drm/license', { method: 'POST', body: event.message });
      if (!res.ok) throw new Error(`Lizenzserver: HTTP ${res.status}`);
      await session.update(await res.arrayBuffer());
      break;
    }
    case 'license-release':
      // Bestätigung der Freigabe an den Server senden
      await fetch('/drm/release', { method: 'POST', body: event.message });
      break;
    default:
      console.warn('Unbekannter Nachrichtentyp:', event.messageType);
  }
};

const setupSession = (mediaKeys) => {
  const session = mediaKeys.createSession();
  session.onmessage = (event) => {
    handleMessage(session, event).catch(console.error);
  };
  return session;
};

Listener beim Schließen der Session entfernen

const attachLicenseHandler = (session) => {
  const onMessage = async (event) => {
    const res = await fetch('/drm/license', { method: 'POST', body: event.message });
    await session.update(await res.arrayBuffer());
  };

  session.addEventListener('message', onMessage);

  // Wenn die Session geschlossen wird, Listener aufräumen
  session.closed.then(() => {
    session.removeEventListener('message', onMessage);
    console.log('Session geschlossen, Listener entfernt');
  });
};
Session geschlossen, Listener entfernt

// Wichtig · Fallstricke

  • Reihenfolge: Registriere den message-Listener immer vor generateRequest() bzw. load(). Sonst wird die erste Nachricht nicht verarbeitet.
  • Nachricht nicht verändern: event.message ist ein Binärpuffer, dessen Format vom Schlüsselsystem abhängt (Widevine, PlayReady, FairPlay, ClearKey). Leite ihn unverändert weiter. Manche Lizenzserver, etwa bei PlayReady oder FairPlay, erwarten eigene Header oder eine eigene Hülle (z. B. XML oder Base64). Das steht in der Dokumentation des Anbieters.
  • Sicherer Kontext: EME steht nur über HTTPS zur Verfügung. In iframes muss die Permissions-Policy encrypted-media erlaubt sein.
  • Fehlerbehandlung: Wenn fetch() oder update() fehlschlägt, entsteht ein nicht abgefangenes Promise. Fange Fehler ab und zeige den Nutzern eine verständliche Meldung.
  • Browserunterstützung: Alle modernen Browser unterstützen das Ereignis. Welche Schlüsselsysteme verfügbar sind, unterscheidet sich aber: Chrome und Firefox bieten Widevine, Edge bietet PlayReady und Widevine, Safari bietet FairPlay. ClearKey ist nur zum Testen gedacht und bietet keinen echten Schutz.
  • Verlängerungen: "license-renewal"-Nachrichten können während der Wiedergabe jederzeit erneut eintreffen. Der Listener sollte deshalb für die ganze Lebensdauer der Session aktiv bleiben.