Skip to content

Docker

Run the recorder in a container on any laptop — Windows, macOS or Linux — without installing Python, portaudio or any build toolchain.

The image contains the recorder (the device side): bark-monitor, bark-monitor-lite and bark-monitor-cloud-record. The hosted cloud server is a separate thing and is not part of this image.

The catch with containers is the microphone: docker cannot hand a mic to a container on Windows or macOS. The image solves this the same way the snap does on Linux — the recorder records through PulseAudio, and PulseAudio can travel over the network. Inside the container ALSA (what pyaudio talks to) is routed to a PulseAudio server, and the container connects to a PulseAudio server running on your laptop (PULSE_SERVER).

recorder → pyaudio → ALSA → pulse plugin → PULSE_SERVER=tcp:host.docker.internal:4713 → PulseAudio on the laptop → microphone

Build the image

From the repository root:

docker build --build-arg BARK_MONITOR_VERSION=$(git describe --tags 2>/dev/null || echo 0.0.0) -t bark-monitor .

The version normally comes from git, which a docker build cannot see, so it is passed as a build argument instead.

Give the container your microphone

You need a PulseAudio server on the laptop listening on TCP port 4713.

macOS

  1. Install and start PulseAudio:

    bash brew install pulseaudio pulseaudio --daemon --exit-idle-time=-1 \ --load="module-native-protocol-tcp auth-anonymous=1"

  2. The first time a recording is made, macOS must let the pulseaudio daemon use the microphone. If nothing is captured, open System Settings → Privacy & Security → Microphone and make sure pulseaudio is enabled.

auth-anonymous=1 lets any client that can reach port 4713 use your audio. Fine on a laptop behind a firewall at home; on a shared network tighten it with auth-ip-acl=127.0.0.1;192.168.65.0/24 (the range Docker Desktop uses to reach the host).

Windows

  1. Install PulseAudio for Windows (or choco install pulseaudio) and run pulseaudio.exe from the installation folder.
  2. Load the TCP module so the container can reach it:

    bat pactl.exe load-module module-native-protocol-tcp auth-anonymous=1

  3. Allow pulseaudio.exe through the Windows firewall when prompted, and make sure the microphone is enabled for desktop apps in Settings → Privacy & security → Microphone.

Linux

You can use the same TCP setup (start pulseaudio with --load="module-native-protocol-tcp auth-anonymous=1", or load the module in paprefs), but mounting the desktop's existing socket is simpler and works with PipeWire too:

-e PULSE_SERVER=unix:/run/pulse/native \
-v "${XDG_RUNTIME_DIR}/pulse/native:/run/pulse/native:ro"

Run the recorder

The shipped docker/compose.yaml runs the cloud recorder as a service — the Windows/macOS counterpart of the snap daemon on Linux:

docker compose -f docker/compose.yaml up -d

On first start the container has no pairing yet, so the recorder starts the pairing wizard on port 8753 and prints its URL in the logs:

docker compose -f docker/compose.yaml logs

Open that URL in the laptop browser, paste the pairing code from the dashboard, and recording starts — restart: unless-stopped brings it back after reboots and Docker Desktop restarts. Nothing to write by hand: the config file is created on first run and everything (config, device id, recordings) lives in the mounted ./config folder.

The one-shot way

Prepare a folder with your config.json (see the configuration file) and an empty folder for the recordings, then:

docker run --rm -it \
    -v "$(pwd)/config:/config" \
    -v "$(pwd)/outputs:/outputs" \
    bark-monitor

The default command is bark-monitor --config-file /config/config.json — set output_folder in your config.json to /outputs so the recordings survive the container. The same container runs any recorder entry point by naming it after the image:

Command What it runs
(default) bark-monitor — telegram bot + recorder
bark-monitor-lite --config-file /config/config.json the TFLite recorder, for weaker machines
bark-monitor-cloud-record --config-file /config/parameters.json record to the hosted cloud, controlled through the cloud bot (creates the config on first run)
bark-monitor-cloud-pair ... pair the device with a cloud (interactive, needs -it)

For the always-on cloud recorder, use the shipped docker/compose.yaml — see the always-on way above.

Test the microphone

Before pointing the real recorder at it, check that audio actually reaches the container — this records 5 seconds from the same path the recorder uses and writes them to outputs/test.wav:

docker run --rm -it \
    -v "$(pwd)/outputs:/outputs" \
    bark-monitor arecord -d 5 -f S16_LE -r 16000 /outputs/test.wav

Play outputs/test.wav on the laptop. If it is silent:

  • parecord /outputs/test.wav inside the container talks to PulseAudio directly, skipping the ALSA layer — if that works but arecord does not, the ALSA-to-PulseAudio routing (/etc/asound.conf in the image) is the problem.
  • pactl list short fails: the container cannot reach the PulseAudio server — check that the daemon is running on the laptop and that port 4713 is not firewalled.
  • The host PulseAudio is reachable but no sound: check the macOS/Windows microphone permissions above.

Troubleshooting

  • ALSA lib pulse.c: ... Connection refused — the container cannot reach the PulseAudio server. On Linux with the TCP setup, add --add-host=host.docker.internal:host-gateway (or use the socket mount, which avoids networking entirely).
  • OSError: [Errno -9985] Device unavailable from pyaudio — audio reached PulseAudio but there is no input source; check the mic permissions on the host and that the right input device is selected.
  • Recordings owned by a wrong user on Linux — the image runs as uid 1000; run with --user $(id -u):$(id -g) if that does not match you.