Signatur
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 neueMediaKeySession. Mögliche Typen sind"temporary"(Standard) und"persistent-license".setServerCertificate(certificate): Übergibt ein Serverzertifikat, mit dem Lizenznachrichten verschlüsselt werden. Rückgabewert ist einPromise<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
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));
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);
});
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);
}
};
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"
};
// Wichtig · Fallstricke
- Nur in sicheren Kontexten: EME steht nur unter HTTPS bzw.
localhostzur Verfügung. In iframes muss außerdem die Permissions Policyencrypted-mediaerlaubt 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äfixWebKitMediaKeys).org.w3.clearkeyist 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 mitQuotaExceededErrorfehl. Zum Lösen der Bindung ruft mansetMediaKeys(null)auf. createSession("persistent-license")wirftNotSupportedError, wenn der Sitzungstyp in der Konfiguration vonrequestMediaKeySystemAccess()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()mitNotSupportedErrorab. Dafür sollte es immer einen Fallback geben.