Start · Sprachen · JavaScript · Referenz · MediaKeys

MediaKeys

Schnittstelle

Repräsentiert einen Satz von Schlüsseln eines Key-Systems (CDM), mit denen ein zugeordnetes <code>HTMLMediaElement</code> verschlüsselte Medien bei der Wiedergabe entschlüsselt.

seit JavaScript Baseline: alle modernen Browser (EME, seit ca. 201 Kategorie: webapi

Signatur

interface MediaKeys

Beschreibung

MediaKeys ist Teil der Encrypted Media Extensions (EME) und steht für eine Instanz des Content Decryption Module (CDM) eines bestimmten Key-Systems, z. B. com.widevine.alpha, com.microsoft.playready, com.apple.fps oder das einfache org.w3.clearkey. Die Schnittstelle hat keinen öffentlichen Konstruktor. Eine Instanz bekommt man über MediaKeySystemAccess.createMediaKeys(), nachdem navigator.requestMediaKeySystemAccess() erfolgreich war.

Die Instanz wird mit HTMLMediaElement.setMediaKeys() an ein <video>- oder <audio>-Element gebunden. Über createSession() erzeugt man dann MediaKeySession-Objekte. Diese tauschen Lizenzanfragen und -antworten mit dem Lizenzserver aus (message-Ereignis und update()).

Die Schnittstelle bietet zwei Methoden:

  • createSession(sessionType?): Erzeugt eine neue MediaKeySession. Mögliche Typen sind "temporary" (Standard) und "persistent-license".
  • setServerCertificate(certificate): Übergibt ein Serverzertifikat, mit dem Lizenznachrichten verschlüsselt werden. Rückgabewert ist ein Promise<boolean>.
  • getStatusForPolicy(policy) (neuer, nicht überall verfügbar): Prüft, ob ein Schlüssel mit einer bestimmten HDCP-Richtlinie nutzbar wäre.

Man braucht MediaKeys, wenn man DRM-geschützte Inhalte (meist MSE-basiertes DASH/HLS) ohne fertige Player-Bibliothek abspielen will. In der Praxis übernehmen Bibliotheken wie Shaka Player, dash.js oder hls.js diese Abläufe. Für eigene Implementierungen und zum Debuggen muss man die Schnittstelle trotzdem kennen.

Parameter

Name Typ Default Beschreibung
$sessionType "temporary" | "persistent-license" "temporary" Parameter von createSession(): der Typ der zu erzeugenden Sitzung. "persistent-license" funktioniert nur, wenn das Key-System es unterstützt und die Konfiguration persistentState: "required" enthielt.
$certificate Pflicht BufferSource Parameter von setServerCertificate(): das Serverzertifikat des Lizenzservers als ArrayBuffer bzw. TypedArray.
$policy { minHdcpVersion?: string } {} Parameter von getStatusForPolicy(): die zu prüfende Richtlinie, z. B. { minHdcpVersion: "2.2" }.

Rückgabewert

Typ
MediaKeys
Beschreibung
Wird von MediaKeySystemAccess.createMediaKeys() als Promise<MediaKeys> geliefert. createSession() gibt eine MediaKeySession zurück, setServerCertificate() ein Promise<boolean> und getStatusForPolicy() ein Promise<MediaKeyStatus>.

Beispiele

MediaKeys erzeugen und an ein Video binden

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

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

const setupDrm = async () => {
  const access = await navigator.requestMediaKeySystemAccess('com.widevine.alpha', config);
  const mediaKeys = await access.createMediaKeys();
  await video.setMediaKeys(mediaKeys);
  console.log('Key-System:', access.keySystem);
  return mediaKeys;
};

setupDrm().catch(err => console.error('DRM nicht verfügbar:', err.name));
Key-System: com.widevine.alpha

Sitzung erzeugen und Lizenz vom Server holen

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

video.addEventListener('encrypted', async (event) => {
  const mediaKeys = video.mediaKeys;
  const session = mediaKeys.createSession('temporary');

  session.addEventListener('message', async (msgEvent) => {
    // Lizenzanfrage an den eigenen Lizenzserver senden
    const response = await fetch('https://license.example.com/widevine', {
      method: 'POST',
      body: msgEvent.message
    });
    const license = await response.arrayBuffer();
    await session.update(license);
    console.log('Lizenz eingespielt');
  });

  await session.generateRequest(event.initDataType, event.initData);
});
Lizenz eingespielt

Serverzertifikat setzen (z. B. Widevine-Privacy-Mode)

const applyCertificate = async (mediaKeys) => {
  const res = await fetch('https://license.example.com/cert.bin');
  const cert = new Uint8Array(await res.arrayBuffer());
  try {
    const ok = await mediaKeys.setServerCertificate(cert);
    console.log('Zertifikat akzeptiert:', ok);
  } catch (err) {
    // NotSupportedError, falls das Key-System keine Zertifikate kennt (z. B. ClearKey)
    console.warn('Zertifikat nicht unterstützt:', err.name);
  }
};
Zertifikat akzeptiert: true

HDCP-Anforderung prüfen

const checkHdcp = async (mediaKeys) => {
  if (typeof mediaKeys.getStatusForPolicy !== 'function') {
    console.log('getStatusForPolicy wird nicht unterstützt');
    return;
  }
  const status = await mediaKeys.getStatusForPolicy({ minHdcpVersion: '2.2' });
  console.log('HDCP 2.2:', status); // "usable" oder z. B. "output-restricted"
};
HDCP 2.2: usable

// Wichtig · Fallstricke

  • Nur in sicheren Kontexten: EME steht nur unter HTTPS bzw. localhost zur Verfügung. In iframes muss außerdem die Permissions Policy encrypted-media erlaubt sein (<iframe allow="encrypted-media">).
  • Key-Systeme unterscheiden sich je nach Browser: Chrome, Firefox und Edge unterstützen Widevine, Edge außerdem PlayReady. Safari nutzt FairPlay (com.apple.fps, teils noch über das ältere Präfix WebKitMediaKeys). org.w3.clearkey ist das einzige Key-System, das die Spezifikation vorschreibt. Es bietet keinen echten Kopierschutz.
  • Ein MediaKeys-Objekt kann immer nur an ein Medienelement gebunden sein. setMediaKeys() auf einem zweiten Element schlägt mit QuotaExceededError fehl. Zum Lösen der Bindung ruft man setMediaKeys(null) auf.
  • createSession("persistent-license") wirft NotSupportedError, wenn der Sitzungstyp in der Konfiguration von requestMediaKeySystemAccess() nicht angefordert wurde.
  • Nicht mehr benötigte Sitzungen sollte man mit session.close() schließen. CDMs erlauben oft nur wenige gleichzeitige Sitzungen.
  • Browser ohne CDM, etwa Chromium-Builds ohne Widevine oder manche Linux-Distributionen, lehnen requestMediaKeySystemAccess() mit NotSupportedError ab. Dafür sollte es immer einen Fallback geben.