Skip to content

Lifecycle

The player’s phase machine tracks what the player is doing at any point. player.phase() returns one of 13 stable string values.

Phase diagram

PhaseTransition
idlesetup() called
setupPlugin use() runs, then transitions to ready
readyload() or current() called, transitions to loading
loadingMedia loads, transitions to starting
startingFirst frame decoded, transitions to playing
playingCan recover from buffering or seeking
playingBranches to paused, ended, or stopped
pausedNext play() call transitions back to starting
endedNext play() call transitions back to starting
stoppedNext play() call transitions back to starting
startingdispose() called, transitions to disposing
disposingTeardown completes, transitions to disposed
disposedTerminal state, instance can be garbage collected

All 13 phases

PhaseWhen
idleBefore setup() is called
setupsetup() is running, plugins are initializing
readyAll plugins resolved, player can accept transport commands
loadingload() or current() is in progress
startingMedia is loaded, play() dispatched, waiting for first frame
playingPlayback is active
pausedPlayback is paused
bufferingBuffer underrun, player is stalled, waiting for data
seekingA seek operation is in progress
endedCurrent item played to the end
stoppedstop() was called, position reset to 0
disposingdispose() is in progress, teardown running
disposedPlayer is fully torn down, instance can be garbage collected

Listening to phase changes

TypeScript
player.on('phase', ({ from, to }) => {
console.log(`Phase transition: ${from}${to}`);
});

Current phase at any point:

TypeScript
player.phase(); // 'playing' | 'paused' | etc.

Setup stages

The setup pipeline fires events at each stage. Each stage can fail independently:

EventPayloadFires when
beforeSetupvoidImmediately before setup begins (last chance to add plugins)
setupStart{ container: HTMLElement }Setup begins
configResolved{ config }Config normalized
pluginsRegisteringvoidPlugin use() running
pluginsRegisteredvoidAll plugins’ use() resolved
streamsReadyvoidHLS/native stream adapters registered
authReadyvoidAuth pipeline wired
playlistResolving{ url: string }Fetching a URL-based playlist
playlistReady{ length: number }Playlist loaded (or URL load complete)
mediaReadyvoidMedia backend ready
readyvoidFull setup complete, all plugins resolved

Each stage has a paired *Error event for observability:

TypeScript
player.on('pluginsRegisteredError', (err) => {
console.error('Plugin registration failed:', err.code, err.message);
});

URL-based playlist loading

If setup({ playlist: 'https://...' }) receives a URL string instead of an array, the setup pipeline fetches and parses it as a JSON array of playlist items. The fetch uses the player’s auth pipeline. Events:

  • playlistResolving: fetch started, { url }
  • playlistReady: fetch succeeded, { length }
  • playlistError: fetch or parse failed, { url, error, code }, player still reaches ready with an empty queue

The fetch never throws, all errors are emitted and the player completes setup regardless.

play/pause lifecycle events

Each transport action emits a sequence of before + post events:

ActionEvent sequence
playbeforePlayplayplaying (+ firstFrame on first play)
pausebeforePausepause
stopbeforeStopstop
nextbeforeNextnextcurrent
previousbeforePreviouspreviouscurrent
loadbeforeLoadcurrentloadingstartingplaying
seekbeforeSeekseekseeked

A prevented action emits *Prevented instead of the post-action event:

TypeScript
player.on('playPrevented', ({ reason }) => {
// reason: 'listener-prevented' | 'delay-rejected' | 'delay-timeout'
});

Dispatch context

player.dispatching() returns the stack of events currently being processed:

TypeScript
player.on('beforePlay', () => {
player.dispatching(); // ['beforePlay']
});

Useful for debugging circular event chains and for plugins that need to know they are operating inside an event handler.