Skip to main content
Euca’s audio system (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:
That 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:
On a server that registers an 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/play returns {"error":"AudioEngine not initialized","ok":false}. Playback is a client-side concern — register an AudioEngine on a host with real audio hardware to enable it. /audio/list returns {"count":0,"sources":[]} on a bare headless host for the same reason.
  • A missing path is 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.
  • position is what makes a source spatial. Include it and you get an AudioSource::spatial(clip, max_distance) with quadratic distance attenuation relative to an AudioListener; omit it and you get a global source. max_distance defaults to 50.0, volume to 1.0, loop to false.
  • /audio/stop flips the source’s playing flag; 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/Ui buses with per-bus volume, ReverbZones, AudioOcclusion line-of-sight muffling, and a concurrency cap live in euca-audio and 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 returns AudioEngine not initialized.

Audio endpoints

Play, stop, and list endpoints, with request and response schemas.