ALSA For Linux Game Sound
This week I started working on the audio subsystem for Rival Fortress.
I’m not using FMOD, OpenAL, or any other middleware to output game sound. As with the rest of the engine, I’m trying to build most things from the ground up.
The sound APIs I’m using are: DirectSound on Windows, CoreAudio on Mac and ASLA on Linux.
Starting out with ALSA
My main development platform is Linux, so I started with ALSA.
The official documentation is lacking, considering ALSA has been around for more than ten years, but fortunately the examples provided are good enough to show you how to string together the half-a-billion function calls required to set-up audio playback.
There is a lot of trial and error involved if you are looking for the ‘just-right’ playback settings.
Even though ALSA has been part of the kernel for a long time, I decided not to link with libasound
directly, as I’ve read many reports of version incompatibility between distributions. I’m dlopen
-ing at runtime and loading in just the required function pointers.
If anything fails during initialization at runtime, the subsystem is disabled and no audio is reproduced. For most games the audio subsystem is optional, the game should be able to run even without it.
The ALSA API
The ALSA API is pretty chatty: a full playback-only initialization sequence requires almost thirty(!) function calls, all of which must be guarded against failure. Take a look at the example pcm playback to see what I’m talking about.
To keep latency low, I decided to use blocking playback with very small buffers. This requires a separate thread for audio playback, complicating the plumbing between the game and the audio subsystem, but in my current implementation I’m able to achieve very low latency levels.