Contributed by ray on from the secure-audio-system dept.
We just committed the code of an audio server and a general sound access library usable in audio ports. Here is how and why this happened.
Certain audio applications do not work properly because they support none of the encodings or the sample frequencies of your audio(4) device. For instance, if you have a fixed rate ac97(4) codec supporting only 48kHz sample frequency and you try to use mpg321 or ogg123, you notice that they play too fast. With envy(4) devices the situation is even worse, since the device supports only 10/12-channel and 32-bit encoding, roughly no audio application is usable with it.
To make my hardware usable I first thought that the easiest would be to add the missing conversion code in the kernel, so the device can appear as a soundblaster-like card and any application can use it.
However this is not satisfying: the user must be able to tell which of the 10-channels must be mapped to the stereo device, and the conversion code is not simple because there are lots of possible configurations.Thanks to Alexandre and Jacob for all their hard work!
Furthermore such audio conversions are CPU intensive, and I dislike having CPU intensive code in kernel. The reason is that while a process is running in kernel mode, it cannot be preempted, which means that an audio application may hog the CPU and delay the execution of any time sensitive application. For instance that would penalize real-time MIDI applications, and I use a lot of MIDI. So I convinced myself that putting conversion code in kernel was not the way to go.
At the same time, I wrote a small utility to play and record audio in full-duplex doing any format conversion, resampling, mixing and demultiplexing on the fly with any number of audio streams. Initially it was for my own use, but finally we committed it as aucat(1) few months ago.
At this stage, It was possible to do primitive multitracking with aucat(1), or to use simple pipes like the following:I realized that if we can make apps use directly aucat(1) rather than setting up pipes by hand, most of the conversion problems would be solved, and since aucat(1) supports any number of streams, as a side effect, this would allow multiple applications to share the same audio device. Roughly that's what an audio server does.
ogg123 -o - mymusic.ogg |aucat -i -
All ingredients required for an audio server were there, except the communication layer. So i wrote a small add-on to aucat(1) to make it listen on an unix socket and dynamically attach streams to its mixer demultiplexer.
To expose it to applications we added a simple "sound I/O" library, libsndio. If the aucat(1) server isn't running, it just uses the usual audio(4) device, so everything should just work. We locally updated few ports to use the new API and we observed it's pretty easy to use. The API is simple, there's only one way to do one thing, there are virtually no knobs, so less chances to make a mistake.
So, what's next? First, we'll continue updating ports to use libsndio rather than the kernel API. The aucat(1) conversion code is somewhat primitive and should be optimized for both quality and speed. I'd like to keep this stuff minimalistic, so I plan to work on improving quality and robustness rather than adding new features.
Editor's note: Jacob also posted this note to the ports@ list. It includes a diff to make aucat(1) the new default sound server for SDL. Jacob already reports improvements compared to the older audio(4) backend. As always, testing by porters and users is needed.
(Comments are closed)