Signatur
Beschreibung
Das Ereignis encrypted gehört zu den Encrypted Media Extensions (EME). Es wird an einem <video>- oder <audio>-Element ausgelöst, sobald der Browser beim Parsen des Medienstroms (z. B. einer pssh-Box in MP4/CENC oder in WebM-Headern) Initialisierungsdaten für eine Verschlüsselung findet. Das Ereignis ist vom Typ MediaEncryptedEvent, es bubbelt nicht und lässt sich nicht abbrechen.
Genutzt wird es als Startpunkt für den DRM-Ablauf: Im Handler wählt man über navigator.requestMediaKeySystemAccess() ein Schlüsselsystem aus (z. B. Widevine, PlayReady, FairPlay oder Clear Key), erzeugt MediaKeys, hängt sie mit setMediaKeys() an das Element und öffnet eine MediaKeySession. Mit event.initDataType und event.initData ruft man dann session.generateRequest() auf. Die Lizenzanfrage bekommt man über das Ereignis message der Session.
Das Ereignis wird entweder über addEventListener("encrypted", handler) oder über die Eigenschaft onencrypted registriert. Es kann mehrfach ausgelöst werden, etwa einmal pro Track oder bei Schlüsselwechseln. Deshalb sollte man doppelte Initialisierungsdaten abfangen.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $type Pflicht | string | Der Ereignisname "encrypted". |
|
| $handler Pflicht | (event: MediaEncryptedEvent) => void | Callback, der ein MediaEncryptedEvent bekommt. Wichtige Eigenschaften sind initDataType (string, z. B. "cenc", "webm" oder "keyids") und initData (ArrayBuffer | null). |
|
| $options | boolean | AddEventListenerOptions | false | Die üblichen Listener-Optionen, z. B. { once: true } oder { signal }. |
Rückgabewert
addEventListener gibt nichts zurück. Die Daten stehen im MediaEncryptedEvent.Beispiele
Initialisierungsdaten per addEventListener protokollieren
const video = document.querySelector('video');
video.addEventListener('encrypted', (event) => {
console.log('Typ der Init-Daten:', event.initDataType);
console.log('Größe:', event.initData?.byteLength, 'Bytes');
});
Vollständiger Clear-Key-Ablauf mit onencrypted
const video = document.querySelector('video');
// Schlüssel-ID und Schlüssel als Base64url (nur für Demo/Tests)
const KEYS = { 'nrQFDeRLSAKTLifXUIPiZg': 'FmY0xnWCPCNaSpRG-tUuTQ' };
const config = [{
initDataTypes: ['cenc', 'keyids'],
videoCapabilities: [{ contentType: 'video/mp4; codecs="avc1.42E01E"' }]
}];
video.onencrypted = async (event) => {
if (!video.mediaKeys) {
const access = await navigator.requestMediaKeySystemAccess('org.w3.clearkey', config);
const mediaKeys = await access.createMediaKeys();
await video.setMediaKeys(mediaKeys);
}
const session = video.mediaKeys.createSession();
session.addEventListener('message', async (msgEvent) => {
const request = JSON.parse(new TextDecoder().decode(msgEvent.message));
const license = {
keys: request.kids.map((kid) => ({ kty: 'oct', kid, k: KEYS[kid] })),
type: 'temporary'
};
await session.update(new TextEncoder().encode(JSON.stringify(license)));
console.log('Lizenz gesetzt');
});
await session.generateRequest(event.initDataType, event.initData);
};
Doppelte Init-Daten ignorieren und Listener wieder entfernen
const video = document.querySelector('video');
const seen = new Set();
const toHex = (buf) => [...new Uint8Array(buf)]
.map((b) => b.toString(16).padStart(2, '0')).join('');
const onEncrypted = (event) => {
const key = `${event.initDataType}:${toHex(event.initData)}`;
if (seen.has(key)) return; // gleiche Daten schon verarbeitet
seen.add(key);
console.log('Neue Init-Daten, Sitzungen offen:', seen.size);
};
video.addEventListener('encrypted', onEncrypted);
// Beim Wechsel der Quelle aufräumen
const resetPlayer = () => {
video.removeEventListener('encrypted', onEncrypted);
seen.clear();
};
// Wichtig · Fallstricke
- Nur in sicherem Kontext: EME (
requestMediaKeySystemAccess) funktioniert nur über HTTPS. In iframes, die nicht vom gleichen Ursprung stammen, braucht man zusätzlich die Berechtigungsrichtlinieencrypted-media, z. B.<iframe allow=\"encrypted-media\">. - Welche Schlüsselsysteme es gibt, hängt vom Browser ab: Chrome, Edge und Firefox bringen Widevine mit, Edge auch PlayReady, Safari FairPlay (
com.apple.fps).org.w3.clearkeyist nicht wirklich geschützt und nur für Tests gedacht. - Safari: Ältere Safari-Versionen haben nur das Präfix-API (
webkitneedkey,WebKitMediaKeys). Das standardisierteencryptedgibt es ab Safari 12.1. initDatakannnullsein, und das Ereignis kann mehrfach auftreten (mehrere Tracks, Schlüsselrotation). Duplikate sollte man erkennen, sonst entstehen unnötige Sitzungen und Lizenzanfragen.- Bei Media Source Extensions (MSE) kommt das Ereignis erst, wenn das Init-Segment an den
SourceBufferangehängt wurde. - Übergeben Sie Lizenzschlüssel nie im Klartext im Client-Code (außer bei Clear-Key-Tests). Die Lizenz muss vom Lizenzserver mit Authentifizierung kommen.