After building a base Gentoo system using OpenRC, everything
functioned as expected except audio output. Players like mpv or
ffplay reported no errors, but no sound was produced. This wasn't
due to ALSA itself failing aplay -l showed hardware
devices, and /proc/asound/cards was populated. The
issue was absence of a sound server managing the userland routing...
On more guided distributions, something like
pipewire-pulse is pulled automatically by metapackages
or profile defaults. Gentoo requires explicit configuration. I chose
PipeWire without running the PulseAudio daemon, but kept
compatibility via libpulse.
The audio stack behavior depends heavily on USE flags. Here's the relevant setup:
# /etc/portage/make.conf USE="-qt5 -kde -telemetry X pulseaudio"
The global pulseaudio USE flag is needed for packages
like SDL2, libcanberra, or anything that links against libpulse.
However, I did not want the PulseAudio daemon to be built or
installed.
To achieve that:
# /etc/portage/package.use/pulseaudio media-sound/pulseaudio -daemon
This disables the init/startup part of PulseAudio while keeping the client library. Simultaneously, I needed PipeWire to act as the actual sound server:
# /etc/portage/package.use/pipewire media-video/pipewire sound-server
Executed the following:
emerge --ask media-video/pipewire emerge --ask media-video/wireplumber emerge --ask sys-auth/rtkit
wireplumber is necessary as the session manager.
Without it, PipeWire's services start but remain inert, no nodes are
created, and no audio routing occurs. rtkit provides
real-time priority handling, which is required by PipeWire to set
thread priorities via SCHED_RR. On OpenRC, this is not
automatically available unless rtkit is present and its service
started.
Also added the user to the pipewire group:
usermod -aG pipewire rian
Although not always necessary, some setups especially with custom PAM or seatd handling benefit from explicit group permissions.
PipeWire's default configuration is located in
/usr/share/pipewire. To allow for user-specific
overrides:
mkdir -p ~/.config/pipewire/ cp /usr/share/pipewire/pipewire.conf ~/.config/pipewire/
System-wide:
cp /usr/share/pipewire/pipewire.conf /etc/pipewire/
If using pipewire-pulse, it binds to
$XDG_RUNTIME_DIR/pipewire-0 and creates a
Pulse-compatible socket at
$XDG_RUNTIME_DIR/pulse/native. That's how programs
linked against libpulse are transparently routed to PipeWire without
reconfiguration.
You can confirm this by:
pactl info
Which should report:
Server Name: PulseAudio (on PipeWire X.Y.Z)
PipeWire does not provide native OpenRC scripts. I created a local
init file in /etc/init.d/pipewire, wrapping pipewire
and pipewire-pulse, then added it to default:
rc-update add pipewire default
Alternatively, one can manage it via per-user autostart if running a desktop session, especially under X or Wayland.
With this configuration, PipeWire serves as the active sound server, replacing the PulseAudio daemon entirely. libpulse is still available for compatibility, but no extra daemon is launched. The system remains minimal, controlled, and fully functional in audio without systemd or extraneous layers.