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 forOSS
, which is an even worse API, which partially makesALSA
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