Skip to content

Container sound: ALSA or Pulseaudio

Martin Viereck edited this page Dec 15, 2025 · 18 revisions

Sound in docker container: PipeWire, Pulseaudio, Jack and ALSA

This page describes some possible ways how to set up sound for docker containers without x11docker.

Quite common is the easy ALSA setup. A bit more advanced, but with better integration in most desktop environments are setup with PipeWire or Pulseaudio.

Pulseaudio is a sound server that has been standard on Linux desktops for several years. It can be provided with shared unix sockets or with a TCP connection. Both ways need Pulseaudio server on host and Pulseaudio client library (Debian: libpulse0) in image. x11docker supports both ways with --pulseaudio=socket or --pulseaudio=tcp.

PipeWire is the successor of Pulseaudio. It becomes the standard sound system on Linux desktops. The setup here is done with two shared sockets. x11docker provides it with option --pipewire.

JACK is a professional sound server system for Linux.

ALSA

For ALSA sound just share sound devices with --device /dev/snd. You would not need the more advanced Pulseaudio setup, but will have trouble if more than one application tries to access the sound hardware. x11docker provides this setup with option --alsa.

  • If you have an unprivileged user in container, add him to group audio with --group-add=audio.
  • If you can't hear sound, you might need to set environment variable --env ALSA_CARD=Generic or another card name that shows up in aplay -l.
  • To check ALSA sound in container, install alsa-utils in image and run speaker-test:
    docker run --rm --device /dev/snd ALSAIMAGE speaker-test
    
  • Applications that only support Pulseaudio can be fooled with apulse. Example: apulse firefox sets up a fake Pulseaudio environment, but forwards the sound signals to ALSA.

Pulseaudio

Pulseaudio with shared socket

Create pulseaudio socket:

pactl load-module module-native-protocol-unix socket=/tmp/pulseaudio.socket

Create /tmp/pulseaudio.client.conf for pulseaudio clients:

default-server = unix:/tmp/pulseaudio.socket
# Prevent a server running in the container
autospawn = no
daemon-binary = /bin/true
# Prevent the use of shared memory
enable-shm = false

Share socket and config file with docker and set environment variables PULSE_SERVER and PULSE_COOKIE. Container user must be same as on host:

docker run --rm \
    --env PULSE_SERVER=unix:/tmp/pulseaudio.socket \
    --env PULSE_COOKIE=/tmp/pulseaudio.cookie \
    --volume /tmp/pulseaudio.socket:/tmp/pulseaudio.socket \
    --volume /tmp/pulseaudio.client.conf:/etc/pulse/client.conf \
    --user $(id -u):$(id -g) \
    imagename

The cookie will be created by pulseaudio itself.

Pulseaudio over TCP

Get IP address from host:

# either an arbitrary IPv4 address from host
Hostip="$(ip -4 -o a | awk '{print $4}' | cut -d/ -f1 | grep -v 127.0.0.1 | head -n1)"

# or especially IP from docker daemon
Hostip="$(ip -4 -o a| grep docker0 | awk '{print $4}' | cut -d/ -f1)"

Run docker image. You need a free TCP port, here 34567 is used. (TCP port number must be in range of cat /proc/sys/net/ipv4/ip_local_port_range and must not be in use. Check with ss -nlp | grep 34567.)

docker run --rm \
    --name pulsecontainer \
    --env PULSE_SERVER=tcp:$Hostip:34567 \
    imagename

After docker run [...] get IP of container with:

Containerip="$(docker inspect --format '{{ .NetworkSettings.IPAddress }}' pulsecontainer)"

Load pulseaudio TCP module authenticated with container IP:

pactl load-module module-native-protocol-tcp  port=34567 auth-ip-acl=$Containerip

Be aware that the TCP module is loaded after container is up and running. It takes a moment until pulseaudio server is available for container applications. If TCP connection fails, check for possible iptables and ufw settings that might prohibit the connection.

Pulseaudio as system wide daemon

If pulseaudio runs as a system wide daemon on host, LC_ALL=C pactl info shows Server String: /var/run/pulse/native and User Name: pulse. Note that such a setup is discouraged.

  • By default pulseaudio runs under an unprivileged user.
  • If pulseaudio runs as a system wide daemon, the TCP setup works.
  • To share the system socket /var/run/pulse/native, the container user must be added to group pulse-access with --group-add pulse-access. PULSE_COOKIE is not needed in that case.

PipeWire

A container gets access to PipeWire sharing the PipeWire unix socket from host. Usually it is $XDG_RUNTIME_DIR/pipewire-0.

  • The pipewire socket must either be in XDG_RUNTIME_DIR of container, or its localization can be indicated with environment variable PIPEWIRE_RUNTIME_DIR.
  • For ALSA client support the container needs the PipeWire ALSA module.
  • For Pulseaudio client support host and container need the PipeWire Pulseaudio module.
    • The pulseaudio socket location on host can be achieved from pactl --info.
    • The Pulseaudio socket created by PipeWire has to be shared. Usually it it $XDG_RUNTIME_DIR/pulse/native.
    • The environment variable PULSE_SERVER must point to the pulseaudio socket in container.
  • For package names of modules compare wiki: Dependencies in image.

Example:

docker run --rm \
  -v $XDG_RUNTIME_DIR/pipewire-0:/tmp/pipewire-0 \
  -e PIPEWIRE_RUNTIME_DIR=/tmp \
  -v $XDG_RUNTIME_DIR/pulse/native:/tmp/pulse.socket \
  -e PULSE_SERVER=/tmp/pulse.socket
  ...

Instead of sharing the host Pipewire socket it is possible to create a restricted socket in /tmp with pw-container. It is a bit difficult to catch the output of pw-container. This solution writes the output to a file and than reads from it:

echo "#! /bin/bash
# helper script to get socket path. Reading output of pw-container directly somehow not possible.
echo \$PIPEWIRE_REMOTE >/tmp/PIPEWIRE_REMOTE
while :; do
  sleep 1000
done
" >/tmp/pw_script

bash /tmp/pw_script &
PIPEWIRE_REMOTE="$(cat /tmp/PIPEWIRE_REMOTE)"

Use it like:

docker run --rm \
  -v $PIPEWIRE_REMOTE:$PIPEWIRE_REMOTE \
  -e PIPEWIRE_REMOTE=$PIPEWIRE_REMOTE
  ...

JACK

JACK clients in container with PipeWire on host

This should work with a PipeWire JACK module on host and in image. Compare chapter PipeWire.

JACK setup for docker and x11docker containers with JACK server on host

Look at this contribution of @domichel: Howto get JACK audio working with a docker container #544

Clone this wiki locally