Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/CeeblueTV/wrts-client/llms.txt

Use this file to discover all available pages before exploring further.

MediaKeysEngine manages the complete W3C Encrypted Media Extensions (EME) lifecycle for an HTMLVideoElement. It handles key system selection (Widevine, PlayReady, FairPlay, and Clear Key), certificate acquisition, license request/response, key session creation, and key status monitoring. The engine supports multiple robustness configurations per key system and negotiates them in order until the browser accepts one. While MediaKeysEngine is integrated in Player and activated automatically when content protection is present, it can also be used standalone when you need explicit control over DRM capabilities without relying on stream metadata.
import { MediaKeysEngine, MediaKeysEngineError } from '@ceeblue/wrts-client';

Constructor

video
HTMLVideoElement
required
The video element to attach MediaKeys to. The constructor throws if video.mediaKeys is already set on the element, since only one MediaKeysEngine may own a video element at a time.
const mediaKeysEngine = new MediaKeysEngine(videoElement);

Static Properties

MediaKeysEngine.MEDIA_KEYS_TIMEOUT
number
Maximum time in milliseconds to wait for MediaKeys negotiation to complete. Defaults to 8000 ms. If key system access is not granted within this window, the setup promise rejects.
MediaKeysEngine.STOP_TIMEOUT
number
Maximum time in milliseconds to wait for all key sessions to close and MediaKeys to detach from the video element during stop(). Defaults to 5000 ms.

Instance Properties

keySystem
string | undefined
The name of the key system that was successfully negotiated, e.g. 'com.widevine.alpha', 'com.microsoft.playready', or 'com.apple.fps'. Returns undefined if the engine has not started or has not yet successfully set up a key system.
started
boolean
true after start() has been called and before stop() resolves.

Methods

start(params, metadata?)
method
Begins the DRM negotiation lifecycle by attaching an encrypted event listener to the video element. When the first encrypted event fires, the engine calls navigator.requestMediaKeySystemAccess() with the provided key system configurations, creates MediaKeys, optionally loads a server certificate, and attaches the keys to the video element.
start(params: Connect.Params, metadata?: Metadata): boolean
Returns booleanfalse if the engine is already started, currently stopping, contentProtection is missing, or MediaKeys are already set on the element. Fires onError with details in those cases.
stop(error?)
method
Releases all key sessions, removes event listeners, and calls video.setMediaKeys(null) to detach the engine from the video element. Must be awaited before starting a new DRM session on the same video element.
stop(error?: MediaKeysEngineError): Promise<unknown>
Returns Promise<unknown> — resolves when cleanup is complete, or rejects if detaching fails. Subject to MediaKeysEngine.STOP_TIMEOUT.

Events

onMediaKeys()
event
Fired when MediaKeys have been successfully created and attached to the video element via video.setMediaKeys(). At this point mediaKeysEngine.keySystem is populated and the player is ready to decrypt.
mediaKeysEngine.onMediaKeys = () => {
  console.log('MediaKeys ready, key system:', mediaKeysEngine.keySystem);
};
onError(error)
event
Fired when any step of the EME lifecycle fails. The default implementation logs the error at the error level.
mediaKeysEngine.onError = (error: MediaKeysEngineError) => {
  console.error('DRM error:', error.name, (error as any).detail);
};
See MediaKeysEngineError below for all variants.
onKeyStatusChanged(keyId, status)
event
Fired whenever the status of a decryption key changes inside any active session. The default implementation logs the change at the info level.
mediaKeysEngine.onKeyStatusChanged = (keyId: string, status: MediaKeyStatus) => {
  console.log(`Key ${keyId}${status}`);
  // status: 'usable' | 'expired' | 'released' | 'output-restricted'
  //         | 'output-downscaled' | 'usable-in-future' | 'status-pending' | 'internal-error'
};

MediaKeysEngineError Type

All errors fired through onError conform to the MediaKeysEngineError discriminated union:
A general EME lifecycle error, including missing contentProtection in params, failed generateRequest, failed license fetch, failed setMediaKeys, or a concurrent-start guard failure.
{
  type: 'MediaKeysEngineError';
  name: 'MediaKeys issue';
  detail: string;
}
Emitted on WebKit-based browsers (older Safari) when the legacy WebKitMediaKeys API fails to instantiate.
{
  type: 'MediaKeysEngineError';
  name: 'Unable to create WebKitMediaKeys';
  detail: string;
}
Emitted on WebKit-based browsers when WebKitMediaKeys.createSession() fails.
{
  type: 'MediaKeysEngineError';
  name: 'Unable to create session with WebKitMediaKeys';
}

Standalone Usage Example

The following example shows MediaKeysEngine used independently of Player, driving Widevine DRM with explicit capability declarations:
import { MediaKeysEngine } from '@ceeblue/wrts-client';
import { Connect } from '@ceeblue/web-utils';

const videoElement = document.querySelector('video')!;
const mediaKeysEngine = new MediaKeysEngine(videoElement);

mediaKeysEngine.onMediaKeys = () => {
  console.log('MediaKeys ready on', mediaKeysEngine.keySystem);
};

mediaKeysEngine.onError = error => {
  console.error('MediaKeysEngine error:', error);
};

mediaKeysEngine.onKeyStatusChanged = (keyId, status) => {
  if (status === 'expired') {
    console.warn('Key expired:', keyId);
  }
};

mediaKeysEngine.start({
  endPoint: 'https://example.com/stream',
  contentProtection: {
    'com.widevine.alpha': {
      license: 'https://widevine.example.com/getLicense',
      configurations: Connect.createMediaKeySystemConfigurations({
        audioContentTypes: ['audio/mp4; codecs="mp4a.40.2"'],
        videoContentTypes: ['video/mp4; codecs="avc1.640028"']
      })
    }
  }
});

// When done with the stream:
await mediaKeysEngine.stop();
Player automatically creates and manages a MediaKeysEngine instance when contentProtection is present in the params passed to player.start() and the stream metadata reports DRM-protected tracks. In that scenario you do not need to instantiate MediaKeysEngine directly.
MediaKeysEngine is strictly single-use per video element per session. You must await mediaKeysEngine.stop() and verify the engine has fully cleaned up before calling start() again or constructing a new instance for the same element. Starting a new Player session with DRM on a video element that still has mediaKeys set will throw an error.

Build docs developers (and LLMs) love