The Hurd currently does not have an audio framework or audio device drivers. One option would be to port ALSA to the Hurd, but ALSA is suboptimal for a number of reasons:

  • poor device enumeration. If you unplug a sound card and plug it in again, you could get a different card number. The same problem can happen when you reboot.
  • With ALSA you cannot use two sound cards as one virtual sound card with synced time clocks.
  • ALSA makes it difficult to use a low latency application like Ardour alongside a higher latency application, like a desktop environment's sound notifications.
  • ALSA encourages applications to control hardware directly using a push model, meaning that the application tries to decide when to play sound. The pull model is much better, in that the audio subsystem tells hardware when to play sound based on requests from applications.
  • ALSA has backwards support for OSS, which is an even worse API, which partially makes ALSA such a poor design.

Pulseaudio and pipewire, which are built to support ALSA, have similar problems. Our Hurd developer/audio-expert Damien Zammit believes that the Hurd sound subsystem should use the JACK daemon/API. He is an audiophile, who wrote and maintains some JACK plugins, and he also wrote native JACK support for Qubes OS. Damien spoke to Paul Davis, who is the reason there is professional audio on Linux, and the author of Ardour DAW and JACK. Paul suggested we write a new JACK backend directly with low level driver code, and hack on the driver code until it is working. Then we could see how to define an API to move the driver level code into a hurd translator. One potential issue is that JACK uses lots of POSIX shmem that the hurd lacks, though a patch exists in Debian or in the tg tree.

We would have to create a hurd-jack backend for the jackd daemon. If clients do not support the JACK API, then they can connect to the Hurd's running pipewire daemon that would forward all sound requests to the jackd daemon. We would have a hurd translator sitting on /dev/snd and use RPCs to create a hurdish API that implements all of the things that jackd needs. We would not use ALSA's API anywhere, but ALSA-only applications should be able to play sounds through pipewire.

A sound card driver would expose a set of RPCs that jackd would need. We could implement that part ourselves, which would be the easy part. The difficult part is making the driver, so that jackd opens /dev/snd and calls the RPCs to control it. Audio will not flow through /dev/snd. Rather, a callback is registered with a pointer to some buffer. We would NOT move the audio data via Mach messages, because that would be too slow. Instead jackd would mmap the device buffer directly or use shared memory to a small ring-buffer. The audio driver would mmap the device buffer directly, and we would share that with the caller.

The audio driver would start and stop the sound card. We just need to fill its buffer somehow. The audio driver would know when to do this. It would schedule a writer and a reader probably based on timers. The arrival of the audio IRQ tells you when the hw pointer is at the end of the cycle, but you don't just copy the buffer when this happens (like alsa does). You use the timestamps of arrival of the audio IRQs to calibrate a delay locked loop. At any time you want in between the audio irq, you can ask the question: where is the buffer pointer now?

We would use some kind of timer interrupt to schedule the transfer when you want, depending on the requested latency. This all happens in the audio driver, but it is controlled by jackd, and the audio driver will call the callback provided by the user application.

The audio driver basically writes and reads zeroes until you fill it with some audio data, and if the callback blocks for too long and cannot deliver the audio in time for the next cycle, the audio drops the frame and you get silence, unless the audio driver is in the same process as jackd. Somehow jackd gets access to a mmap-ed buffer. jackd handles all the routing between different audio applications by creating a process graph.

rumpsound has an audio driver, but it's based on SunOS and does not have many cards. If rumpsound, does not give the Hurd many device drivers for sound cards, then we may be able to use ALSA's well organized low-level functions that implement all the features of sound cards. We will need to implement a pcm streaming driver that calls into ALSA low-level functions (it could be GPLv2). It's difficult to break out, so maybe we will just start with pci. Damien got a sound card in qemu with -soundhw ac97, and linux/sound/pci/intel8x0.c should support that. The tricky bit will be sending audio data from the driver to another proccess without mach_msg (). We could possibly use a ring buffer.

irc logs

https://logs.guix.gnu.org/hurd/2023-10-06.log

https://logs.guix.gnu.org/hurd/2023-10-07.log

https://logs.guix.gnu.org/hurd/2023-10-08.log