Start · Sprachen · JavaScript · Referenz · MediaKeyStatusMap.forEach()

MediaKeyStatusMap.forEach()

Methode

Ruft eine Rückruffunktion einmal für jedes Paar aus Schlüssel-ID und Schlüsselstatus in einer <code>MediaKeyStatusMap</code> auf.

seit JavaScript Encrypted Media Extensions (EME); Baseline: alle m Kategorie: webapi

Signatur

MediaKeyStatusMap.prototype.forEach(callbackFn, thisArg)

Beschreibung

Die Methode forEach() der Schnittstelle MediaKeyStatusMap geht alle Einträge der Statusliste einer MediaKeySession durch. Für jeden Eintrag wird die übergebene Funktion mit dem Status (Wert), der Schlüssel-ID (Schlüssel) und der Map selbst aufgerufen, ähnlich wie bei Map.prototype.forEach().

Man erreicht die Map über MediaKeySession.keyStatuses. Typischerweise wird sie im Handler des Ereignisses keystatuseschange ausgewertet. Dort prüft man etwa, ob Lizenzschlüssel abgelaufen ("expired") sind, ob die Ausgabe eingeschränkt ist ("output-restricted", z. B. wegen fehlendem HDCP) oder ob alle Schlüssel nutzbar ("usable") sind.

Die Schlüssel-IDs sind Binärdaten (ArrayBuffer bzw. BufferSource) und keine Zeichenketten. Für Protokolle oder Vergleiche muss man sie daher selbst umwandeln, z. B. in einen Hex-String.

Parameter

Name Typ Default Beschreibung
$callbackFn Pflicht (value: MediaKeyStatus, key: ArrayBuffer, map: MediaKeyStatusMap) => void Wird für jeden Eintrag aufgerufen. value ist der Status als String ("usable", "expired", "released", "output-restricted", "output-downscaled", "usable-in-future", "status-pending", "internal-error"), key ist die Schlüssel-ID und map die durchlaufene MediaKeyStatusMap.
$thisArg any undefined Wert, der beim Aufruf von callbackFn als this gesetzt wird. Bei Pfeilfunktionen wirkungslos.

Rückgabewert

Typ
undefined
Beschreibung
Kein Rückgabewert. Um Ergebnisse zu sammeln, schreibt man sie in eine äußere Variable oder nutzt entries() bzw. den Iterator.

Beispiele

Schlüsselstatus bei keystatuseschange protokollieren

// Schlüssel-ID (ArrayBuffer) in Hex-String umwandeln
const toHex = (buf) =>
  [...new Uint8Array(buf)].map((b) => b.toString(16).padStart(2, '0')).join('');

const watchSession = (session) => {
  session.addEventListener('keystatuseschange', () => {
    session.keyStatuses.forEach((status, keyId) => {
      console.log(`Schlüssel ${toHex(keyId)}: ${status}`);
    });
  });
};
Schlüssel 9eb4050de44b4802932e27d75083e266: usable

Auf abgelaufene oder eingeschränkte Schlüssel reagieren

const checkKeys = async (session, video) => {
  let problem = null;

  session.keyStatuses.forEach((status) => {
    if (status === 'expired') problem = 'Lizenz abgelaufen';
    if (status === 'output-restricted') problem ??= 'Ausgabe eingeschränkt (z. B. HDCP)';
    if (status === 'internal-error') problem ??= 'Interner CDM-Fehler';
  });

  if (problem) {
    video.pause();
    console.warn('Wiedergabe gestoppt:', problem);
    if (problem === 'Lizenz abgelaufen') await session.close();
  }
};
Wiedergabe gestoppt: Lizenz abgelaufen

Status zählen mit thisArg

const counter = { usable: 0, other: 0 };

function count(status) {
  status === 'usable' ? this.usable++ : this.other++;
}

// session ist eine bestehende MediaKeySession
session.keyStatuses.forEach(count, counter);
console.log(counter);
{ usable: 2, other: 0 }

// Wichtig · Fallstricke

  • Reihenfolge der Argumente: Zuerst kommt der Status (Wert), danach die Schlüssel-ID. Das ist dieselbe Reihenfolge wie bei Map.prototype.forEach() und wird oft verwechselt.
  • Binäre Schlüssel: keyId ist ein ArrayBuffer. Ein Vergleich mit === vergleicht nur Referenzen und nicht den Inhalt. Wandle die IDs deshalb vorher um, zum Beispiel in einen Hex-String.
  • Vor der ersten Lizenzantwort (session.update()) ist die Map normalerweise leer. Werte sie am besten erst im Ereignis keystatuseschange aus.
  • Die Map ist eine Momentaufnahme. Ändern sich Status später, wird wieder keystatuseschange ausgelöst.
  • EME ist nur in sicheren Kontexten (HTTPS) verfügbar. Welche Statuswerte tatsächlich vorkommen (z. B. \"usable-in-future\"), hängt vom CDM ab (Widevine, FairPlay, PlayReady). Ältere Browser liefern teilweise nicht alle Werte.
  • break geht in forEach() nicht. Wer früh abbrechen will, nutzt for...of über session.keyStatuses.