Enable audio on GNU Hurd with a rump kernel server and PulseAudio.
This project provides a translator to be run at /dev/audio
which is partially
compatible with the Solaris audio device. It is not a complete implementation,
but it supports enough of the functionality for a PulseAudio sink. This allows
any application that plays sounds through PulseAudio to output audio on a GNU
Hurd system.
This project itself depends on Hurd libraries and the rump client library, and it is a dependency of the PulseAudio build. The order should go as follows:
- Build and install everything needed for a Hurd development environment
- Build and install the rump kernel's
buildrump.sh
andpci-userspace
- Build and install this
- Build and install PulseAudio with the Solaris module enabled
The first two steps can be done with the standard upstream build processes.
The Makefile
here is very basic. It supports many of the usual variables for
configuring the build. Just running make && sudo make install
should be
enough to handle most needs. It will install the translator at /hurd/audio
and its ioctl
definitions at /usr/include/sys/audio.h
by default.
PulseAudio versions older than 11.0 require a minor edit to compile, since the Solaris module was only expected to be built with Solaris system headers.
sed -i -e 's,<sys/conf.h>,<sys/poll.h>,' src/modules/module-solaris.c
After this edit, it should be able to be built and installed using the normal
upstream procedure. Ensure the configure
command does not use the option
--disable-solaris
so it can detect <sys/audio.h>
. Alternatively, append
the --enable-solaris
option to the configure
command to require it.
With the translator and PulseAudio's Solaris module installed, the following component configurations should result in an audible Hurd system.
The rump kernel described here expects to drive an AC97 sound card. For use
with QEMU, include the -soundhw ac97
option to emulate such a device.
The translator acts as a rump client that accesses /dev/audio
in the rump
server's VFS. The following command starts a server with enough modules to
support this and drive AC97 sound cards.
rump_server -s -v \
-lrumpvfs \
-lrumpdev \
-lrumpdev_audio \
-lrumpdev_audio_ac97 \
-lrumpdev_pci \
-lrumpdev_pci_auich \
unix:///run/rump.sock
Note the socket it creates at /run/rump.sock
must be writable for the UID of
the translator process, which should be 0
(root
) if it was started from a
translator record on the file system.
The translator command only has a single option, the URL of the rump server's
socket. It is equivalent to using the RUMP_SERVER
environment variable, but
the command-line option has higher precedence. Assuming the translator was
installed as /hurd/audio
, the following command will start it for the above
server and write the translator record to run it automatically on future boots.
settrans -acfgp /dev/audio /hurd/audio --url=unix:///run/rump.sock
Make sure /dev/audio
is writable for whatever users should have permission to
play sounds. At this point *.au
files should be playable (or recordable) by
direct writes (or reads) to this device.
To account for the translator's incomplete compatibility with Solaris, a few
settings in PulseAudio's configuration should be defined to avoid unsupported
ioctl
calls, etc. If using default.pa
, make the following modifications.
- Avoid suspending, so don't load
module-suspend-on-idle
- Since
module-detect
isn't needed, replace it withmodule-solaris
- Set
record=no
onmodule-solaris
to avoid using streams - Set
channel_map=mono channels=1 format=ulaw rate=8000
onmodule-solaris
to pick some known-supported playback parameters
Any applications that use PulseAudio should now be able to play sounds without
modifying them. A user's PulseAudio server should start automatically when it
is needed, e.g. by running paplay
on a sound file.
The translator provides a device node supporting four important operations:
- Writing data, i.e. playing audio out of speakers
- Reading data, i.e. recording audio from a microphone
- The
AUDIO_GETINFO
ioctl, for retrieving device information - The
AUDIO_SETINFO
ioctl, for changing device information
The installed header <sys/audio.h>
is a modified version of NetBSD's header
<sys/audioio.h>
to be more compatible with Solaris. However, the changes
required to build on Hurd make it incompatible with both NetBSD and Solaris.
The Solaris device node uses the old POSIX streams interface which is not implemented here, but PulseAudio's usage of the device is limited enough for it to bypass the streams ioctls with the aforementioned configuration changes.
The audio ioctl character is A
on both Solaris and NetBSD, but this value is
invalid on Hurd, so the installed audio.h
uses s
instead. Also, Hurd's
ioctl definitions for structured parameters are normally defined by pairs of
the member data type and the count of consecutive members of that type. The
struct audio_info
members are too many to fit into that encoding scheme, so
the ioctl definitions in audio.h
pretend all members are 64-bit integers,
with enough of them to match the same structure size.
The Solaris data structure has an output_muted
member used by PulseAudio, but
NetBSD does not define it. It was appended to the structure in audio.h
as a
64-bit integer (to keep things evenly divisble) for source compatibility, but
the value is never actually used by the translator.
As a final note: This is just a silly toy program. If anyone really wants to have PulseAudio use a rump server, it would be better to write a new PulseAudio module that directly connects to it for platform independence and less IPC.