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.

WebRTS plays DRM-protected streams via the W3C Encrypted Media Extensions (EME) API, which is supported by all modern browsers. When the stream metadata signals that content protection is required, the player automatically negotiates the best key system available in the current browser, fetches a license from your server, and unlocks the decryption keys — all without any additional code beyond providing the license URL.

Supported Key Systems

Widevine

com.widevine.alphaChrome, Firefox, Edge, Opera, Android

PlayReady

com.microsoft.playreadyEdge, Xbox, Windows Store, Samsung Tizen, LG webOS

FairPlay

com.apple.fps.1_0Safari (macOS, iOS, iPadOS)
Where multiple key systems are supported by a browser, Widevine is preferred over PlayReady. On Chrome and Firefox, Widevine is always available and recommended.

Configuring DRM

Pass a contentProtection map to player.start(). The key is the key system string; the value is either a license URL string (for Widevine and PlayReady) or an object with license and certificate URLs (required for FairPlay).
player.start({
  endPoint: 'https://<hostname>/wrts/out+<stream-id>/index.json',
  contentProtection: {
    'com.widevine.alpha': 'https://widevine.example.com/license',
    'com.microsoft.playready': 'https://playready.example.com/license',
    'com.apple.fps.1_0': {
      license: 'https://fairplay.example.com/license',
      certificate: 'https://fairplay.example.com/certificate'
    }
  }
});
At runtime the player negotiates the most-preferred key system supported by the current browser. You can safely list all three key systems; the player picks the right one automatically.

FairPlay specifics

FairPlay requires both a license URL (where license challenges are POSTed) and a certificate URL (used to fetch the Application Certificate from Apple). Both fields are mandatory for FairPlay to work on Safari.

Reacting to DRM State Changes

The onMediaKeys event fires whenever the MediaKeysEngine becomes ready or is released. Use it to show or hide DRM status indicators in your UI.
player.onMediaKeys = (mediaKeysEngine) => {
  if (mediaKeysEngine) {
    console.log('DRM active, key system:', mediaKeysEngine.keySystem);
  } else {
    console.log('DRM released');
  }
};

Standalone MediaKeysEngine

The MediaKeysEngine class can be used independently of Player — for example, to drive EME from a custom player implementation or to pre-negotiate keys.
import { MediaKeysEngine } from '@ceeblue/wrts-client';

const mediaKeysEngine = new MediaKeysEngine(videoElement);

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

// metadata is optional; omit it to let the engine negotiate purely from contentProtection config
mediaKeysEngine.start(params, metadata);

// Later, when finished
await mediaKeysEngine.stop();
The MediaKeysEngine must be fully released (i.e., stop() must resolve) before starting a new playback session on the same video element. Starting a new session while the engine is still attached causes the player to stop and emit a 'Playback error' with the message: MediaKeys engine must be released before starting a new playback.

PlayReady on Edge — Known Limitations

For browser playback, prefer Widevine wherever available. PlayReady is fully supported but the Edge/Chromium implementation has constraints that require specific workarounds.
The default Player raises <video>.playbackRate above 1.0 to stay close to the live edge. With PlayReady on Edge this produces audio artifacts and visible video lag. Override onBufferChange to clamp the rate to ≤ 1.0:
player.onBufferChange = () => {
  // Disable rate increase; allow rate decrease [0.84, 0.92] to protect against stalls
  player.adjustPlaybackRate(84, 100);
};
This keeps the player’s stall-protection behaviour (slowing down when the buffer runs low) while preventing the audio artifacts caused by speeding up.
PlayReady’s decoder path needs more headroom under bandwidth jitter. Configure the buffer thresholds to roughly min=400ms / max=2000ms instead of the WebRTS low-latency defaults:
player.bufferLimitLow  = 400;   // ms (default: 150)
player.bufferLimitHigh = 2000;  // ms (default: 550)
Apply both fixes together for the best experience with PlayReady:
// Larger buffers for PlayReady decoder headroom
player.bufferLimitLow  = 400;
player.bufferLimitHigh = 2000;

// Prevent playback rate increases that cause artifacts
player.onBufferChange = () => {
  player.adjustPlaybackRate(84, 100);
};

player.start({
  endPoint: 'https://<hostname>/wrts/out+<stream-id>/index.json',
  contentProtection: {
    'com.widevine.alpha':      'https://widevine.example.com/license',
    'com.microsoft.playready': 'https://playready.example.com/license',
    'com.apple.fps.1_0': {
      license:     'https://fairplay.example.com/license',
      certificate: 'https://fairplay.example.com/certificate'
    }
  }
});

Build docs developers (and LLMs) love