Start · Sprachen · JavaScript · Referenz · MediaKeySession

MediaKeySession

Schnittstelle

Repräsentiert eine Sitzung für den Austausch von Lizenz-Nachrichten zwischen Anwendung und Content Decryption Module (CDM) der Encrypted Media Extensions.

seit JavaScript Baseline: alle modernen Browser (EME, W3C Recommen Kategorie: webapi

Signatur

interface MediaKeySession extends EventTarget

Beschreibung

MediaKeySession gehört zur Encrypted Media Extensions API (EME). Mit einer Sitzung spricht deine Webanwendung mit dem Content Decryption Module (CDM) des Browsers, etwa Widevine, PlayReady, FairPlay oder Clear Key. Die Sitzung erzeugt Lizenzanfragen, nimmt die Antworten des Lizenzservers entgegen und verwaltet die Schlüssel, mit denen verschlüsselte Medien entschlüsselt werden.

Du erzeugst eine Sitzung nicht mit einem Konstruktor, sondern über MediaKeys.prototype.createSession(sessionType). Danach läuft es meist so ab:

  • generateRequest(initDataType, initData) mit den Initialisierungsdaten aus dem encrypted-Event des Media-Elements aufrufen.
  • Auf das message-Event warten. Es liefert die Lizenzanfrage als ArrayBuffer.
  • Die Anfrage an den Lizenzserver schicken und die Antwort mit update(response) an die Sitzung übergeben.
  • Mit keystatuseschange bzw. keyStatuses den Zustand der Schlüssel überwachen. Am Ende die Sitzung mit close() beenden.

Eigenschaften: sessionId (string, schreibgeschützt), expiration (Ablaufzeit in ms seit der Epoche oder NaN), closed (Promise, das beim Schließen der Sitzung erfüllt wird), keyStatuses (MediaKeyStatusMap), sowie die Handler onmessage und onkeystatuseschange.

Methoden: generateRequest(), load(sessionId) (lädt eine persistente Sitzung), update(response), close() und remove() (löscht gespeicherte Lizenzdaten). Alle Methoden geben ein Promise zurück.

Parameter

Name Typ Default Beschreibung
$sessionType "temporary" | "persistent-license" "temporary" Wird an MediaKeys.createSession() übergeben und legt fest, ob die Lizenz nur im Speicher liegt oder dauerhaft gespeichert wird. "persistent-license" muss vorher in der MediaKeySystemConfiguration über sessionTypes angefordert worden sein.
$initDataType Pflicht "cenc" | "keyids" | "webm" | string Parameter von generateRequest(): Format der Initialisierungsdaten, meist event.initDataType aus dem encrypted-Event.
$initData Pflicht ArrayBuffer | ArrayBufferView Parameter von generateRequest(): die Initialisierungsdaten, z. B. die PSSH-Box bei CENC.
$response Pflicht ArrayBuffer | ArrayBufferView Parameter von update(): die Antwort des Lizenzservers bzw. bei Clear Key ein JSON-Web-Key-Set.

Rückgabewert

Typ
MediaKeySession
Beschreibung
Die Instanz liefert MediaKeys.createSession(). Ihre Methoden geben jeweils ein Promise zurück: generateRequest(), update(), close() und remove() ein Promise<void>, load() ein Promise<boolean>.

Beispiele

Sitzung erzeugen und Lizenz anfordern (Widevine)

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

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

const access = await navigator.requestMediaKeySystemAccess('com.widevine.alpha', config);
const mediaKeys = await access.createMediaKeys();
await video.setMediaKeys(mediaKeys);

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

  session.addEventListener('message', async (msgEvent) => {
    // Lizenzanfrage an den Server schicken
    const res = await fetch('https://license.example.com/widevine', {
      method: 'POST',
      body: msgEvent.message
    });
    const license = await res.arrayBuffer();
    await session.update(license);
    console.log('Lizenz übernommen für Sitzung', session.sessionId);
  });

  await session.generateRequest(event.initDataType, event.initData);
});
Lizenz übernommen für Sitzung 3F2A…

Clear Key: Schlüssel direkt als JSON Web Key übergeben

const toBase64Url = (bytes) =>
  btoa(String.fromCharCode(...bytes))
    .replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');

const keyId = new Uint8Array([0x10,0x20,0x30,0x40,0x50,0x60,0x70,0x80,0x90,0xa0,0xb0,0xc0,0xd0,0xe0,0xf0,0x00]);
const key   = new Uint8Array([0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10]);

const access = await navigator.requestMediaKeySystemAccess('org.w3.clearkey', [{
  initDataTypes: ['keyids'],
  videoCapabilities: [{ contentType: 'video/webm; codecs="vp9"' }]
}]);
const mediaKeys = await access.createMediaKeys();
const session = mediaKeys.createSession('temporary');

session.onmessage = async () => {
  const jwks = { keys: [{ kty: 'oct', kid: toBase64Url(keyId), k: toBase64Url(key) }] };
  await session.update(new TextEncoder().encode(JSON.stringify(jwks)));
};

const initData = new TextEncoder().encode(JSON.stringify({ kids: [toBase64Url(keyId)] }));
await session.generateRequest('keyids', initData);

Schlüsselstatus überwachen und Sitzung aufräumen

const watchSession = (session) => {
  session.addEventListener('keystatuseschange', () => {
    for (const [keyId, status] of session.keyStatuses) {
      console.log('Schlüssel', new Uint8Array(keyId)[0], '→', status);
      if (status === 'expired') session.close();
    }
  });

  session.closed.then((reason) => {
    // reason ab neueren Spezifikationen, z. B. "closed-by-application"
    console.log('Sitzung geschlossen:', reason ?? 'unbekannt');
  });
};

// Beim Verlassen der Seite alle Sitzungen schließen
const sessions = new Set();
window.addEventListener('pagehide', () => {
  sessions.forEach((s) => s.close());
});
Schlüssel 16 → usable Sitzung geschlossen: closed-by-application

Persistente Sitzung laden und Lizenz entfernen

const restoreAndRemove = async (mediaKeys, storedId) => {
  const session = mediaKeys.createSession('persistent-license');
  const found = await session.load(storedId);
  if (!found) {
    console.log('Keine gespeicherte Sitzung gefunden');
    return;
  }
  // Lizenzdaten löschen; CDM sendet ggf. eine "license-release"-Nachricht
  session.onmessage = async (e) => {
    const res = await fetch('/license/release', { method: 'POST', body: e.message });
    await session.update(await res.arrayBuffer());
  };
  await session.remove();
  console.log('Lizenz entfernt');
};
Lizenz entfernt