Dockerfile and Runtime Architecture Specification
1. System Purpose
The image implements a PulseAudio streaming sidecar with two websocket services:
- Speaker relay: reads encoded audio from a FIFO and broadcasts to websocket clients.
- Microphone relay: receives websocket payloads and writes to a FIFO consumed by PulseAudio module-pipe-source.
- Supervisor manages lifecycle of PulseAudio and relay processes.
2. Build Specification
2.1 Base Image and Reproducibility
- Base image: ubuntu:24.04.
- This is pinned by tag, but not by 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 strategy now uses lockfiles and npm ci:
- /composer/node/websocket-relay.speaker: npm ci --omit=dev
- /composer/node/websocket-relay.microphone: npm ci --omit=dev
Required lockfiles are present in both relay directories.
2.7 Runtime Filesystem Preparation
Dockerfile prepares these paths:
- /var/run/dbus
- /var/log/desktop
- /var/run/desktop
- /var/run/local
- /var/log/local
- /var/lib/dbus/machine-id
- /etc/pulse/abcdesktopcookie
- /container
Current mode setup uses 666 for directories and selected files.
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.sh captures PulseAudio source speaker.monitor.
- ffmpeg outputs MPEG-TS/MP2 stream redirected into /container/speaker.
- websocket-relay.speaker reads /container/speaker.
- websocket server on 29788 broadcasts chunks to all connected clients.
Control behavior:
- On first client, relay requests Supervisor startProcess("ffmpeg.speaker").
- On last client disconnect, relay requests stopProcess("ffmpeg").
4.2 Microphone Data Path
- websocket-relay.microphone listens on 29789.
- On first client, it opens a write stream to /container/microphone.
- Incoming websocket messages are written to /container/microphone.
- PulseAudio module-pipe-source (configured in PulseAudio config) consumes FIFO data as 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 audio as MP2 inside MPEG-TS.
- Stream to /container/speaker FIFO.
Important runtime inputs:
- PULSE_SERVER (default /tmp/.pulse.sock)
- POD_IP optional (for CONTAINER_IP_ADDR)
- WEBRELAY_INTERNAL_TCP_PORT metadata variable
FFmpeg main characteristics:
- sample rate 44100
- mono channel
- bitrate 128k
- mpegts output
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