title: Sound Container — PulseAudio Streaming | abcdesktop.io description: Developer reference for the abcdesktop.io sound container: PulseAudio setup, speaker/microphone streaming via WebSocket, and FFmpeg pipeline. keywords: sound, PulseAudio, audio, WebSocket, FFmpeg, speaker, microphone, abcdesktop, contribute, user pod tags: - contribute - sound - PulseAudio - user pod
Dockerfile and Runtime Architecture Specification
Scope
This specification documents the container architecture, build behavior, runtime process topology, and media relay contracts for this repository.
Primary configuration artifacts:
Dockerfiledocker-entrypoint.shetc/supervisord.confetc/supervisor/conf.d/pulseaudio.confetc/supervisor/conf.d/ffmpeg.speaker.confetc/supervisor/conf.d/websocket-relay.speaker.confetc/supervisor/conf.d/websocket-relay.microphone.confcomposer/ffmpeg.speaker.sh
Primary sound artifacts:
composer/node/websocket-relay.microphone/websocket-relay.jscomposer/node/websocket-relay.speaker/websocket-relay.js
1. System Purpose
The image implements a PulseAudio streaming sidecar with two WebSocket relay services:
- Speaker relay: reads encoded audio from a FIFO and broadcasts the stream to connected WebSocket clients.
- Microphone relay: receives WebSocket payloads from the browser and writes them to a FIFO consumed by a PulseAudio
module-pipe-source. - Supervisor manages the lifecycle of the PulseAudio daemon and both relay processes.
2. Build Specification
2.1 Base Image and Reproducibility
- Base image:
ubuntu:24.04. - The image is pinned by tag but not by digest. For fully reproducible builds, pin to a specific image digest.
2.2 Identity Model
Configured variables: - PULSEUID=102 - PULSEGID=104 - PULSELOGNAME=pulse - PULSEUSER=pulse - PULSEGROUP=pulse
Provisioning:
- Creates group pulse with GID 104.
- Creates user pulse with UID 102.
- User supplementary groups are set via --groups 104.
- Runtime user is pulse.
2.3 OS Package Layer
Debconf noninteractive mode is configured and these packages are installed:
- ca-certificates
- pulseaudio
- pulseaudio-utils
- supervisor
- libnss-extrausers
- ffmpeg
- gnupg
- curl
2.4 Node.js Layer
- NODE_MAJOR=20.
- NodeSource repository is configured.
- nodejs package is installed.
- npm is globally upgraded.
2.5 Source and Config Copy
Build copies: 1. etc -> /etc 2. composer -> /composer 3. etc/nsswitch.conf -> /etc/nsswitch.conf
2.6 Node Dependency Installation
Dependency installation uses lockfiles and npm ci for reproducible builds:
/composer/node/websocket-relay.speaker:npm ci --omit=dev/composer/node/websocket-relay.microphone:npm ci --omit=dev
Required lockfiles must be present in both relay directories.
2.7 Runtime Filesystem Preparation
The Dockerfile creates these paths at build time:
/var/run/dbus/var/log/desktop/var/run/desktop/var/run/local/var/log/local/var/lib/dbus/machine-id/etc/pulse/abcdesktopcookie/container
Directory permissions are set to mode 666 for directories and selected files that require broad write access across process users.
2.8 Entrypoint and Port Contract
- ENV PULSE_SERVER=/tmp/.pulse.sock
- CMD /docker-entrypoint.sh
- USER pulse
- EXPOSE 29788 29789
3. Runtime Topology and Control Plane
3.1 Entrypoint Behavior
At startup, docker-entrypoint.sh:
- Sets ABCDESKTOP_LOG_DIR and ABCDESKTOP_RUN_DIR defaults.
- Logs id, environment, home listing, and /etc/pulse listing.
- Resolves CONTAINER_IP_ADDR from POD_IP or hostname -i.
- Rewrites /etc/pulse/abcdesktopcookie from PULSEAUDIO_COOKIE if provided.
- Exports WEBRELAY_INTERNAL_TCP_PORT=29780.
- Creates FIFO /container/speaker.
- Starts supervisord in foreground with /etc/supervisord.conf.
3.2 Supervisor Programs
From include pattern /etc/supervisor/conf.d/*.conf:
- pulseaudio
- command: /composer/pulseaudio.sh
- autostart: true
- websocket-relay.speaker
- command: node /composer/node/websocket-relay.speaker/websocket-relay.js /container/speaker 29788
- autostart: true
- websocket-relay.microphone
- command: node /composer/node/websocket-relay.microphone/websocket-relay.js /container/microphone 29789
- autostart: true
- ffmpeg.speaker
- command: /composer/ffmpeg.speaker.sh
- autostart: false
4. Dataflow Specification
4.1 Speaker Data Path
ffmpeg.speaker.shcaptures audio from thespeaker.monitorPulseAudio source.ffmpegencodes the audio as an MPEG-TS/MP2 stream and redirects the output to/container/speaker.websocket-relay.speakerreads from/container/speaker.- The WebSocket server on port
29788broadcasts audio chunks to all connected clients.
Control behavior:
- On the first client connection, the relay requests Supervisor to start the
ffmpeg.speakerprocess. - When the last client disconnects, the relay requests Supervisor to stop the
ffmpegprocess.
4.2 Microphone Data Path
websocket-relay.microphonelistens on port29789.- On the first client connection, it opens a write stream to
/container/microphone. - Incoming WebSocket messages are written to
/container/microphone. - The PulseAudio
module-pipe-source(configured in the PulseAudio configuration) consumes the FIFO data as a virtual microphone source.
5. Script-Level Specification
5.1 composer/pulseaudio.sh
- Executes pulseaudio with module-native-protocol-tcp.
- listen address uses CONTAINER_IP_ADDR.
- auth-cookie uses /etc/pulse/abcdesktopcookie.
5.2 composer/ffmpeg.speaker.sh
Purpose:
- Read audio from
speaker.monitor. - Encode the audio as MP2 inside an MPEG-TS container.
- Stream the encoded output to the
/container/speakerFIFO.
Important runtime inputs:
PULSE_SERVER(default:/tmp/.pulse.sock)POD_IP(optional, used to deriveCONTAINER_IP_ADDR)WEBRELAY_INTERNAL_TCP_PORTmetadata variable
FFmpeg stream characteristics:
- Sample rate: 44100 Hz
- Channels: mono
- Bitrate: 128 kbps
- Container format: MPEG-TS
5.3 Speaker Relay Node Service
File: composer/node/websocket-relay.speaker/websocket-relay.js
Behavior:
- Creates websocket server on configured host:port.
- Opens read stream from FIFO.
- Broadcasts FIFO chunks to connected clients.
- Starts ffmpeg.speaker on first client.
- Requests stop of process named ffmpeg when count returns to zero.
5.4 Microphone Relay Node Service
File: composer/node/websocket-relay.microphone/websocket-relay.js
Behavior:
- Creates websocket server on configured host:port.
- On first connection opens write stream to FIFO.
- Writes websocket payloads to FIFO.
- Closes FIFO stream when last client disconnects.
- Includes documentation note for PulseAudio module-pipe-source contract.
6. Interface Contracts
6.1 Runtime Environment Variables
Used variables:
- PULSEAUDIO_COOKIE
- POD_IP
- ABCDESKTOP_LOG_DIR
- ABCDESKTOP_RUN_DIR
- CONTAINER_IP_ADDR
- WEBRELAY_INTERNAL_TCP_PORT
- PULSE_SERVER
6.2 Network Interface
- 29788/tcp: speaker websocket relay
- 29789/tcp: microphone websocket relay
6.3 Filesystem and IPC Interface
- /container/speaker: FIFO producer/consumer path for speaker stream
- /container/microphone: FIFO ingestion path for microphone stream
- /var/run/desktop/supervisor.sock: Supervisor RPC socket