Audio Backend
The audio backend is the music player’s media backend adapter, the IAudioBackend port. It is the layer between NMMusicPlayer and the browser’s audio APIs, and it is swappable the same way every other adapter is, through the player config rather than a fork. The video player has the same role in its Video Backend.
Two implementations are built in, and you can inject your own via backendFactory.
The choice affects crossfade accuracy, iOS compatibility, and how much Web Audio overhead you pay.
AudioElementBackend (default)
Kind: 'audio-element'
Uses a native <audio> element for transport.
Crossfade is driven by a requestAnimationFrame loop at approximately 50 fps, not sample-accurate.
Expect ±20 ms seams at track boundaries during a crossfade.
Web Audio graph access is available lazily: a MediaElementAudioSourceNode is created the first time a plugin requests outputNode() or analyserSource().
You pay zero Web Audio overhead if no plugin requests the graph.
Choose this when:
- Running on iOS where
AudioContextcreation requires a user gesture - You need the safest possible compatibility
- Crossfade timing accuracy of ±20 ms is acceptable
- You do not need sample-accurate crossfades but still want EQ via
AudioGraphPlugin
WebAudioBackend
Kind: 'webaudio'
Routes audio through a full AudioContext graph.
Crossfade uses linearRampToValueAtTime for sample-accurate gain ramps.
Volume changes are smoothed via GainNode.gain.setTargetAtTime with a 10 ms time constant to eliminate clicks.
HLS streams fall back to MediaElementAudioSourceNode even in webaudio mode, because hls.js requires a <audio> element.
Non-HLS playback (MP3, AAC, FLAC, OGG) also uses MediaElementAudioSourceNode — the backend always routes through the <audio> element so hls.js and non-HLS sources are handled identically.
Choose this when:
- You need sample-accurate crossfades
- You are building a custom audio processing chain
AudioGraphPluginandEqualizerPluginare in use
Capability comparison
| Capability | audio-element | webaudio |
|---|---|---|
| Default | Yes | No |
| Crossfade accuracy | ~50 fps (RAF) | Sample-accurate |
| EQ / effect chain | Via lazy MediaElementSourceNode | Full AudioContext graph |
| HLS support | hls.js or native | hls.js or native (MediaElementSource) |
| iOS compatibility | Full | Requires user gesture |
setSinkId (output routing) | Yes | Yes |
captureStream() | Yes | Yes |
Switching at runtime
// Switch from audio-element to webaudio:
await player.backend('webaudio');
// Read the active backend:
const backend = player.backend();
console.log(backend.kind); // 'webaudio'
Switching disposes the current backend, constructs the new one, and re-wires all events. The player enters a paused state after the switch.
Custom backend
Inject a fully custom backend via backendFactory in the player config:
player.setup({
backendFactory: (kind, config) => new MyNativeAudioBackend(kind, config),
});
See also
- AudioElementBackend, implementation details
- WebAudioBackend, implementation details
- IAudioBackend, full interface reference
- Configuration,
backendandbackendFactoryoptions