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.

The Player class is the main entry point for WebRTS live stream playback. It wraps an HTMLVideoElement and orchestrates three key subsystems: a Source transport layer that fetches and demuxes the media, a MediaPlayback engine that feeds data into the browser’s Media Source Extensions (MSE) pipeline, and an optional MediaKeysEngine for DRM-protected streams. Player extends EventEmitter and implements both IPlaying (exposing buffer and rate metrics to the Source) and ICMCD (Common Media Client Data telemetry). Override the on* event methods to hook into lifecycle events without needing to add manual listeners.
import { Player, PlayerError } from '@ceeblue/wrts-client';

Constructor

new Player(
  video: HTMLVideoElement,
  SourceClass?: { new(playing: IPlaying, params: Connect.Params): Source }
)
Constructs a new Player instance. This does not start playback — call start() to begin streaming.
video
HTMLVideoElement
required
The video element on which the stream will be rendered.
SourceClass
{ new(playing: IPlaying, params: Connect.Params): Source }
Optional custom Source implementation to use for transport. When omitted, Player.start() resolves the class from the endpoint protocol via Source.getClass(), or falls back to HTTPAdaptiveSource. If the endpoint starts with ws:// or wss://, WSSource is used automatically when it is registered.
// Default: protocol-resolved source
const player = new Player(videoElement);

// Custom source implementation
const player = new Player(videoElement, MyCustomSource);

Methods

start()

start(params: Connect.Params, idleTimeout?: number): void
Begins playback of the stream described by params. Internally creates a MediaSource, attaches it to the video element, then instantiates the resolved Source and MediaPlayback. If a MediaKeysEngine from a previous session is still cleaning up, the call is automatically deferred until the teardown completes.
params
Connect.Params
required
Connection parameters including endPoint, optional streamName, mediaExt, contentProtection, and query overrides. The protocol prefix of endPoint (e.g., https, wss) determines which registered Source class is instantiated.
idleTimeout
number
Idle timeout in milliseconds. Defaults to approximately 14 000 ms (chosen to be safely above the maximum GOP duration of ~10 s). The timer resets on connection and data events; if it fires, playback stops with a 'Start timeout', 'Connection timeout', or 'Data timeout' PlayerError.
player.start({
  endPoint: 'https://live.example.com',
  streamName: 'my-stream'
});

stop()

stop(error?: PlayerError): void
Ends playback, tears down the Source, MediaPlayback, and MSE pipeline, and resets all internal state. Calls onStop when complete.
error
PlayerError
When provided, the stop is treated as an improper termination and the error is forwarded to onStop. Omit for a graceful, user-initiated stop.

goLive()

goLive(reason?: string): void
Seeks the playback head as close as possible to the live edge. Internally sets video.currentTime to endTime - bufferLimitMiddle / 1000, clamped to be no earlier than startTime.
reason
string
Optional human-readable label appended to the internal log entry, useful for distinguishing automatic ('restoring', 'repairing') from manual seeks.

adjustPlaybackRate()

adjustPlaybackRate(minRate?: number, maxRate?: number): void
Adjusts video.playbackRate linearly based on the current bufferState to keep the buffer within the configured thresholds. Call this from onBufferChange (the default implementation already does so).
minRate
number
Minimum playback rate as a percentage. Defaults to 84 (0.84×). Values above 92 are clamped to 92 to ensure the decrease is meaningful.
maxRate
number
Maximum playback rate as a percentage. Defaults to 116 (1.16×). Values below 108 are clamped to 108 to ensure the increase is meaningful. Set to 100 or less to disable speed-up entirely.
On iOS / Safari, playbackRate changes can produce audible glitches during live streaming. Override onBufferChange and detect ManagedMediaSource to skip rate adaptation on those platforms.

computeStats()

computeStats(): PlayerStats
Returns a snapshot of the current player statistics as a PlayerStats object (from @ceeblue/web-utils). Includes protocol, buffer amount, latency, playback rate, per-track byte rates, frames per second, stall count, and more.

Events (Overridable Methods)

Override any of these methods on a Player instance to react to lifecycle and media events. Each method has a default implementation that logs to the internal logger.

onStart()

onStart(): void
Fired when streaming begins — that is, when the MediaSource opens and the Source and MediaPlayback are fully initialized. After this event started returns true and track properties become assignable.

onStop()

onStop(error?: PlayerError): void
Fired when playback stops. error is populated for improper stops (timeout, decode failure, network error, etc.); it is undefined for clean stops triggered by calling stop() without an argument.

onMetadata()

onMetadata(metadata: Metadata): Media.Tracks | void
Fired when stream metadata (track list, content protection info, etc.) is received from the source. Return a Media.Tracks object to specify the initial audio and video tracks to use; returning nothing (or undefined) selects the middle-quality rendition by default. Setting player.videoTrack or player.audioTrack inside this handler disables MBR for that track.
// Start with the highest-quality video; MBR can still adjust it later
player.onMetadata = (metadata) => ({ video: metadata.videoTracks[0].id });

// Pin the video track and disable MBR
player.onMetadata = (metadata) => {
  player.videoTrack = metadata.videoTracks[0].id;
};

onTrackChange()

onTrackChange(audioTrack: number, videoTrack: number, dataTrack: Set<number>): void
Fired whenever the active track selection changes — either from an MBR algorithm decision or a manual assignment.
audioTrack
number
Active audio track ID, or -1 if disabled.
videoTrack
number
Active video track ID, or -1 if disabled.
dataTrack
Set<number>
Set of active data track IDs.

onBufferState()

onBufferState(oldState: BufferState): void
Fired when bufferState transitions between NONE, LOW, OK, and HIGH. oldState is the previous value; read this.bufferState for the new one.

onBufferChange()

onBufferChange(): void
Fired when bufferAmount changes by at least 50 ms (the BUFFER_CHANGE_STEP constant). The default implementation calls adjustPlaybackRate(). Override to implement custom rate adaptation logic.

onStall()

onStall(): void
Fired when the browser stalls waiting for media data (the video element emits waiting and the buffer is below bufferLimitLow).

onAudioSkipping()

onAudioSkipping(holeMs: number): void
Fired when a gap in the audio timeline is detected and skipped.
holeMs
number
Duration of the skipped audio hole in milliseconds.

onVideoSkipping()

onVideoSkipping(holeMs: number): void
Fired when video frames are skipped to maintain synchronization.
holeMs
number
Duration of the skipped video region in milliseconds.

onFinalizeRequest()

onFinalizeRequest(url: URL, headers: Headers): void
Fired just before every HTTP request is dispatched, allowing you to inspect or mutate the URL and headers (e.g., to add authentication tokens).
url
URL
A mutable clone of the request URL.
headers
Headers
The mutable request headers object.

onData()

onData(track: number, time: number, duration: number, data: Uint8Array): void
Fired when a timed data sample (subtitle, metadata, etc.) is received from the stream.

onAudioAppended()

onAudioAppended(data: Uint8Array): void
Fired each time an audio buffer is appended to the MSE SourceBuffer. Useful for low-level debugging of the MSE ingestion pipeline.

onVideoAppended()

onVideoAppended(data: Uint8Array): void
Fired each time a video buffer is appended to the MSE SourceBuffer.

onMediaKeys()

onMediaKeys(mediaKeysEngine?: MediaKeysEngine): void
Fired when the DRM MediaKeysEngine state changes. Receives the engine instance when it becomes ready, or undefined when it is released (after stop()).

Properties

Playback State

running
boolean
Read-only. true between a call to start() and stop(). Guards track assignment and pause operations.
started
boolean
Read-only. true after onStart fires (i.e., after the Source is fully initialized). Track properties are only valid when started is true.
paused
boolean
Read/write. Pauses or resumes the underlying video element. Throws if running is false.
reliable
boolean
Read/write. Controls frame-skipping mode. false (default) enables frame skipping for low-latency live streaming. true disables skipping and enforces reliable delivery. Throws on write if the player has not started (i.e., _source is not yet initialised).

Track Selection

audioTrack
number | undefined
Read/write. Index of the active audio track. Setting a value disables MBR for audio; set to undefined to re-enable automatic selection. Throws on write if not started.
videoTrack
number | undefined
Read/write. Index of the active video track. Setting a value disables MBR for video; set to undefined to re-enable automatic selection. Throws on write if not started.
dataTrack
Set<number> | undefined
Read/write. Set of active data track IDs. Accepts a single number, an Array<number>, a Set<number>, or undefined (which selects all available data tracks). Throws on write if not started.
trackSelectable
boolean | undefined
Read-only. true if the active Source implementation supports manual track selection. Returns undefined when the player is not running.
metadata
Metadata
Read-only. The most recently received stream Metadata object, containing track lists, content-protection details, and live-time information.

Buffer Metrics

bufferAmount
number
Read-only. Current buffer depth in milliseconds, computed as (endTime - currentTime) * 1000.
bufferLimitLow
number
Read/write. Low-buffer threshold in milliseconds. Default 150 ms. When bufferAmount falls below this value, bufferState transitions to LOW.
bufferLimitHigh
number
Read/write. High-buffer threshold in milliseconds. Default 550 ms. When bufferAmount exceeds this value, bufferState transitions to HIGH.
bufferLimitMiddle
number
Read-only. Computed midpoint between bufferLimitLow and bufferLimitHigh, used as the target buffer depth for live-edge seeks (goLive) and post-stall recovery.
bufferState
BufferState
Read-only. Current BufferState value: NONE, LOW, OK, or HIGH.
buffering
boolean
Read-only. true while the player is accumulating data before playback can resume (initial start, or recovering from a stall). Becomes false when bufferAmount reaches bufferLimitMiddle.

Timing

startTime
number
Read-only. Playback start time in seconds (the oldest buffered position in the MSE timeline).
endTime
number
Read-only. Playback end time in seconds (the most recently appended media position).
currentTime
number
Read-only. Current playback position in seconds (mirrors video.currentTime).
latency
number | undefined
Read-only. Estimated live latency in milliseconds, calculated as metadata.liveTime - currentTime * 1000. Returns undefined when the player has not yet started or currentTime is zero.

Playback Rate

playbackRate
number
Read-only. Current video.playbackRate. Controlled by adjustPlaybackRate().
playbackSpeed
number
Read-only. Effective playback speed measured from elapsed currentTime changes. 1.0 represents real-time.

Byte Rates

recvByteRate
number
Read-only. Total incoming byte rate (audio + video + data overhead) in bytes per second.
audioByteRate
number
Read-only. Audio payload byte rate in bytes per second.
videoByteRate
number
Read-only. Video payload byte rate in bytes per second.
dataByteRate
number
Read-only. Data/metadata payload byte rate in bytes per second.
audioPerSecond
number
Read-only. Audio frames decoded per second.
videoPerSecond
number
Read-only. Video frames decoded per second.

Resolution & Tracks Combinability

maximumResolution
Media.Resolution | undefined
Read/write. Upper-bound resolution for the MBR algorithm. Defaults to Media.screenResolution() (updated on window.resize). Set to undefined for no cap.
tracksCombinable
boolean | undefined
Read/write. When true (default), audio and video tracks are fetched in a single combined request to reduce connection overhead. Set to false to force separate requests. Returns undefined when not running. Throws on write if not started.

Debug & DRM

passthroughCMAF
boolean | undefined
Read-only. Debug flag. true when params.mediaExt was set to 'cmaf', which bypasses the internal demuxer and passes CMAF segments directly to MSE.
signal
AbortSignal
Read-only. An AbortSignal that fires when stop() is called. Sources and other async operations tied to this signal are automatically cancelled on stop.

CMCD Properties

cmcd
CMCD
Read/write. Common Media Client Data payload mode (CMCD.NONE, CMCD.SHORT, or CMCD.FULL). Proxied to the active Source. Throws on write if not started.
cmcdMode
CMCDMode
Read/write. Delivery mode for CMCD data: CMCDMode.HEADER (default) or CMCDMode.QUERY. Throws on write if not started.
cmcdSid
string
Read/write. CMCD session identifier string. Throws on write if not started.

PlayerError Type

PlayerError is a discriminated union. Match on error.type and then error.name to handle each case: PlayerError also covers errors forwarded from sub-systems:
  • SourceError — transport / parsing errors. See Source.
  • MediaPlaybackError — MSE SourceBuffer errors (e.g., 'Exceeds buffer size').
  • MediaKeysEngineError — DRM initialisation / key-request errors.
player.onStop = (error) => {
  if (!error) return; // clean stop
  switch (error.type) {
    case 'PlayerError':
      if (error.name === 'Video play error') {
        // Prompt user for interaction
      }
      break;
    case 'SourceError':
      if (error.name === 'Resource unavailable') {
        // Stream not found — show offline message
      }
      break;
  }
};

Full Usage Example

import { Player, PlayerError, BufferState } from '@ceeblue/wrts-client';

const video = document.getElementById('video') as HTMLVideoElement;
const player = new Player(video);

// ── Lifecycle events ────────────────────────────────────────────────────────

player.onStart = () => {
  console.log('Playback started');
  updateUI('live');
};

player.onStop = (error?: PlayerError) => {
  if (error) {
    console.error('Playback stopped with error:', error);
    showErrorBanner(error.name);
  } else {
    console.log('Playback stopped cleanly');
    updateUI('stopped');
  }
};

// ── Metadata / initial track selection ─────────────────────────────────────

player.onMetadata = (metadata) => {
  console.log('Tracks available:', metadata.videoTracks.length, 'video renditions');
  // Start at the highest quality; MBR will adjust based on bandwidth
  return { video: metadata.videoTracks[0].id };
};

// ── Track changes ───────────────────────────────────────────────────────────

player.onTrackChange = (audioTrack, videoTrack, dataTrack) => {
  console.log(`Active tracks — audio: ${audioTrack}, video: ${videoTrack}`);
};

// ── Buffer monitoring ───────────────────────────────────────────────────────

player.onBufferState = (oldState) => {
  console.log(`Buffer state: ${oldState}${player.bufferState}`);
};

// ── Start playback ──────────────────────────────────────────────────────────

player.start({
  endPoint: 'https://live.example.com',
  streamName: 'my-stream'
});

// ── Manual track selection after start ─────────────────────────────────────

// Switch to a specific video rendition (disables MBR)
setTimeout(() => {
  if (player.started) {
    player.videoTrack = player.metadata.videoTracks[1].id;
  }
}, 5000);

// ── Stop cleanly ────────────────────────────────────────────────────────────

document.getElementById('stop-btn')?.addEventListener('click', () => {
  player.stop();
});

Build docs developers (and LLMs) love