Skip to content

Events

All events emitted by NMMusicPlayer<T>. Subscribe with player.on(event, handler). MusicEventMap extends BaseEventMap from the player core. Music-specific events are listed first; inherited core events follow.

Music-specific events

current

TypeScript
'current': { item: MusicPlaylistItem | undefined; index: number }

Fires when the current track changes. item is undefined when the queue is exhausted or cleared. index is -1 in that case.

TypeScript
player.on('current', ({ item, index }) => {
if (item) {
document.title = item.name;
updateAlbumArt(item.cover);
}
});

trackEndingSoon

TypeScript
'trackEndingSoon': { remaining: number; currentTrack: MusicPlaylistItem }

Fires when the current track has trackEndingSoonThreshold seconds remaining (default: 10). remaining is the actual seconds left at the time of emission. AutoAdvancePlugin listens to this event for preload and crossfade cues.

crossfadeStart

TypeScript
'crossfadeStart': { from: MusicPlaylistItem | null; to: MusicPlaylistItem; duration: number }

Fires when a crossfade begins. from is null when there is no current track. duration is the total fade duration in milliseconds (converted from the duration seconds value in CrossfadeOptions before emission).

crossfadeComplete

TypeScript
'crossfadeComplete': { track: MusicPlaylistItem }

Fires when the crossfade completes and the incoming track is now the primary.

repeat

TypeScript
'repeat': { state: RepeatState }

Fires when repeatState() changes.

shuffle

TypeScript
'shuffle': { state: ShuffleState }

Fires when shuffleState() changes.

backend:changed

TypeScript
'backend:changed': { kind: AudioBackendKind }

Fires when backend(kind) completes a backend swap. kind is 'audio-element' or 'webaudio'. Declared in MusicEventMap, fully typed, no cast required.

TypeScript
player.on('backend:changed', ({ kind }) => {
console.log('Switched to', kind);
});

Transport events (inherited)

EventPayloadWhen
playActionOptionsPlayback starts
pauseActionOptionsPlayback pauses
playingundefinedMedia rendering after buffering resolves
endedundefinedCurrent track finishes naturally

Time events (inherited)

EventPayloadWhen
time{ time: number }Position updates (from the backend timeupdate)
duration{ duration: number }Duration becomes known
progress{ time: number; duration: number; percentage: number }Throttled position update (default every 5 s). Use for server-side watch-position saves instead of time to avoid per-frame callback noise. Configure the interval with progressIntervalMs in setup(); set to 0 to disable.

Use time to drive a real-time seekbar. Use progress to save resume positions server-side. Duration fires once after loadedmetadata.

Queue events (inherited)

EventPayloadWhen
queueT[]Queue replaced
queue:append{ items: T[]; from: number }Items appended. from is the index of the first appended item.
queue:prepend{ items: T[] }Items prepended
queue:remove{ id: string | number; index: number; item: T }Item removed. index is the position that was vacated.
queue:move{ from: number; to: number }Item moved
queue:clear{ previousLength: number }Queue cleared. previousLength is the count before clearing.
queue:exhaustedundefinedQueue played through with no repeat active
backlogReadonlyArray<T>Backlog changes

Volume events (inherited from BaseEventMap)

mute and volume are inherited from BaseEventMap and are not re-declared in MusicEventMap.

EventPayloadWhen
volume{ level: number }Volume changes. level is on the 0–100 scale.
mute{ muted: boolean }Mute state changes

Phase events (inherited)

TypeScript
'phase': { from: PlayerPhase; to: PlayerPhase }

Fires on every player phase transition. Useful for orchestrating UI state (loading spinners, disabled controls).

PlayerPhase values: 'idle' | 'setup' | 'ready' | 'loading' | 'starting' | 'playing' | 'paused' | 'buffering' | 'seeking' | 'ended' | 'stopped' | 'disposing' | 'disposed'

Setup and lifecycle events (inherited)

EventPayloadWhen
readyundefinedSetup complete, all plugins resolved
firstFrameundefinedFirst audio frame decoded after load
disposeundefinedPlayer teardown begins

Error events (inherited)

EventPayloadWhen
errorPlayerErrorEventRecoverable error
fatalPlayerErrorEventNon-recoverable, playback stopped
warningPlayerErrorEventNon-fatal degradation
TypeScript
interface PlayerErrorEvent {
error: PlayerError; // .code (e.g. 'plugin:lyrics/fetch-failed'), .message, .severity, .suggestion?, .context?
severity: 'fatal' | 'error' | 'warning' | 'info';
scope: ErrorScope;
timestamp: number;
// plus cancellable-event controls: markHandled() / preventDefault() / stopImmediatePropagation() / ...
}
// Access the code/message via event.error.code / event.error.message

Auth events (inherited)

EventPayloadWhen
auth:refreshed{ tokenAcquiredAt: number }Token refresh succeeded. tokenAcquiredAt is a Date.now() timestamp.
auth:failed{ error: PlayerErrorEvent['error'] }Token refresh failed

Subscribing and unsubscribing

TypeScript
const handler = ({ item }: { item: MusicPlaylistItem | undefined }) => {
if (item) updateNowPlaying(item);
};

player.on('current', handler); // subscribe
player.off('current', handler); // unsubscribe
player.once('ready', () => {}); // one-shot

From inside a plugin, always use this.on(...) rather than player.on(...), as the plugin base class auto-disposes all its listeners when the plugin is removed.

EQ events (EqualizerPlugin)

EqualizerPlugin emits events namespaced as plugin:equalizer:<event>. Subscribe via the string form on player.on():

TypeScript
player.on('plugin:equalizer:band:changed', ({ band }) => {
updateSlider(band.frequency, band.gain);
});

player.on('plugin:equalizer:change', ({ bands, selectedPreset }) => {
renderFullEqState(bands, selectedPreset);
});

These are EqualizerPlugin events, not MusicEventMap events.

Plugin events

Plugin events are namespaced under plugin:<id>:<event>. Examples:

EventPayload
plugin:lyrics:line{ text: string }
plugin:lyrics:lineEnter{ text: string }
plugin:lyrics:lineExit{ text: string }
plugin:lyrics:loaded{ count: number }
TypeScript
player.on('plugin:lyrics:line', ({ text }) => {
updateLyricsDisplay(text);
});

See also