Skip to content

Container sound: ALSA or Pulseaudio

Martin Viereck edited this page May 12, 2022 · 14 revisions

ALSA or Pulseaudio sound in docker container

This page describes three possible ways how to set up sound for docker containers without x11docker. Most common is the easy ALSA setup. A bit more advanced, but with better integration in most desktop environments is a setup with Pulseaudio.

Pulseaudio 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.

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 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.
Clone this wiki locally