Skip to content

AudioElementBackend

The default audio backend. Uses a native <audio> element for transport and optionally creates a MediaElementAudioSourceNode when a plugin requests the Web Audio graph.

Kind: 'audio-element'

Activation

This backend is active by default. No configuration is required.

To explicitly select it:

TypeScript
player.setup({ backend: 'audio-element' });

Or switch to it at runtime:

TypeScript
await player.backend('audio-element');

HLS support

When the audio URL ends with .m3u8 and the browser does not support native HLS:

  1. The backend imports hls.js (a transitive production dependency via nomercy-player-core)
  2. Creates an Hls instance and calls loadSource() + attachMedia()
  3. All subsequent segment fetches are handled by hls.js

On Safari and iOS, native HLS is used directly and hls.js is skipped.

Web Audio graph (lazy)

The backend creates MediaElementAudioSourceNode only when the first plugin calls outputNode(ctx) or analyserSource(ctx). Until then, the <audio> element routes directly to the system output.

This means AudioGraphPlugin and EqualizerPlugin work with this backend, at a slight cost: once the MediaElementAudioSourceNode is created, it cannot be removed for the lifetime of the backend instance.

Crossfade implementation

Crossfade is driven by a requestAnimationFrame loop at ~50 fps. A secondary <audio> element is allocated via loadSecondary(), pre-rolled via primeSecondary(), and then both elements are gain-ramped in opposite directions over durationMs.

  • Primary ramps from current volume to 0
  • Secondary ramps from 0 to current volume
  • At completion, the secondary becomes the primary element and the old primary is discarded

Accuracy: ±20 ms (one RAF frame). Use WebAudioBackend for sub-millisecond accuracy.

Secondary gain API

TypeScript
const backend = player.backend();

// Read secondary gain (0–1):
const gain = backend.secondaryGain();

// Write secondary gain directly (0–1):
backend.secondaryGain(0.5);

secondaryGain() returns 0 when no secondary element is allocated.

Output routing

TypeScript
const backend = player.backend();

// List available output devices:
const devices = await navigator.mediaDevices.enumerateDevices();
const outputs = devices.filter((device) => device.kind === 'audiooutput');

// Route to a specific device:
await backend.setSinkId(outputs[0].deviceId);

// Read current sink:
const sinkId = backend.getSinkId();

setSinkId is available in Chrome and Chromium-based browsers. Safari does not support it.

See also