euca-audio) wraps Kira for mixing: /audio/play loads a clip
and spawns an AudioSource entity (global or spatial), /audio/list reports active sources, and
/audio/stop silences one. The route logic — loading, spawning the source entity, tracking its state — is
headless, but actual playback needs an AudioEngine bound to an OS audio device, which a bare
headless host doesn’t register. So this page shows the goal, the real error you’ll see
without a device, and what a host with audio enables.
Play and stop a spatial sound
Point/audio/play at a clip; add a position [x,y,z] to make it spatial, with max_distance for the
falloff radius:
AudioEngine not initialized is the real response from a bare headless host — the handler looks up
an Arc<Mutex<AudioEngine>> resource and bails before loading the clip, because no audio engine is
registered. (On a host that registers one but has no working audio hardware, AudioEngine::new() fails
earlier, at construction.) The malformed request is still validated first — a missing path short-circuits:
AudioEngine on a machine with an audio device, the same play call loads
the clip, spawns the source entity, and returns its id, clip handle, and spatial flag — e.g.
{"ok":true,"entity_id":7,"clip":0,"spatial":true}. That source then appears in /audio/list, and
/audio/stop silences it by entity id:
Behavior and gotchas
The things you only find out by running it:- The headless host has no audio device, so
/audio/playreturns{"error":"AudioEngine not initialized","ok":false}. Playback is a client-side concern — register anAudioEngineon a host with real audio hardware to enable it./audio/listreturns{"count":0,"sources":[]}on a bare headless host for the same reason. - A missing
pathis rejected before the engine check with{"error":"Missing 'path' to audio file","ok":false}, so a malformed call won’t even reach the (missing) engine. positionis what makes a source spatial. Include it and you get anAudioSource::spatial(clip, max_distance)with quadratic distance attenuation relative to anAudioListener; omit it and you get a global source.max_distancedefaults to50.0,volumeto1.0,looptofalse./audio/stopflips the source’splayingflag; it doesn’t despawn the entity. Stopping an unknown entity returns{"ok":false,"message":"Entity 7 not found"}.- Buses, reverb, and occlusion exist beyond these routes.
Master/Music/Sfx/Voice/Uibuses with per-bus volume,ReverbZones,AudioOcclusionline-of-sight muffling, and a concurrency cap live ineuca-audioand apply once an engine is registered. - The engine is fork-safe. It’s shared as
Arc<Mutex<AudioEngine>>, so a forked world reuses the same engine rather than cloning a device handle.
Endpoints
To enable these end to end, register an
AudioEngine on a host with an audio device — see
Hosting & deployment for the host-side resource pattern.
Status
- Shipped — clip loading, global and spatial playback, distance attenuation, bus routing with per-bus volume, sound concurrency, fading, reverb zones, and occlusion.
- Requires — a host with an OS audio device and a registered
AudioEngine; the reference headless server returnsAudioEngine not initialized.
Audio endpoints
Play, stop, and list endpoints, with request and response schemas.