diff --git a/docker/Dockerfile.gnuradio-audio b/docker/Dockerfile.gnuradio-audio new file mode 100644 index 0000000..9c35558 --- /dev/null +++ b/docker/Dockerfile.gnuradio-audio @@ -0,0 +1,35 @@ +FROM librespace/gnuradio:latest + +# PulseAudio client + ALSA-PulseAudio plugin for audio output +# GNU Radio uses ALSA backend, so we bridge ALSA → PulseAudio +RUN apt-get update && apt-get install -y --no-install-recommends \ + pulseaudio-utils \ + libpulse0 \ + libasound2-plugins \ + alsa-utils \ + && rm -rf /var/lib/apt/lists/* + +# Configure ALSA to use PulseAudio as default output +# This makes any ALSA app (including GNU Radio) output to PulseAudio +RUN echo 'pcm.!default { type pulse }' > /etc/asound.conf && \ + echo 'ctl.!default { type pulse }' >> /etc/asound.conf + +# Create non-root user for PulseAudio (matches typical host UID) +ARG USER_ID=1000 +ARG GROUP_ID=1000 +RUN groupadd -g ${GROUP_ID} gnuradio || true \ + && useradd -m -u ${USER_ID} -g ${GROUP_ID} gnuradio || true + +WORKDIR /flowgraphs + +# PulseAudio socket location +ENV PULSE_SERVER=unix:/run/pulse/native + +# XML-RPC port for runtime control +ENV XMLRPC_PORT=8090 +EXPOSE 8090 + +USER gnuradio + +# Default: run a flowgraph passed as argument +ENTRYPOINT ["python3"] diff --git a/docker/docker-compose.fm-receiver.yml b/docker/docker-compose.fm-receiver.yml new file mode 100644 index 0000000..4af5a76 --- /dev/null +++ b/docker/docker-compose.fm-receiver.yml @@ -0,0 +1,32 @@ +services: + fm-receiver: + build: + context: . + dockerfile: Dockerfile.gnuradio-audio + + # Root required for USB device access (RTL-SDR) + user: root + privileged: true + + volumes: + # PulseAudio socket for audio output (ALSA → PulseAudio bridge) + - /run/user/${HOST_UID:-1000}/pulse/native:/run/pulse/native + # Flowgraph source files + - ../examples:/flowgraphs:ro + - ../src:/src:ro + # Entrypoint script + - ./entrypoint-fm.sh:/entrypoint-fm.sh:ro + + environment: + - PULSE_SERVER=unix:/run/pulse/native + - FREQ_MHZ=${FREQ_MHZ:-101.1} + - GAIN=${GAIN:-10} + + # XML-RPC port for tuning control from host + ports: + - "8090:8090" + + entrypoint: ["/bin/bash", "/entrypoint-fm.sh"] + + stdin_open: true + tty: true diff --git a/docker/entrypoint-fm.sh b/docker/entrypoint-fm.sh new file mode 100644 index 0000000..f265ab6 --- /dev/null +++ b/docker/entrypoint-fm.sh @@ -0,0 +1,22 @@ +#!/bin/bash +# Entrypoint for containerized FM receiver +set -e + +FREQ_MHZ=${FREQ_MHZ:-101.1} +GAIN=${GAIN:-10} + +python3 -c " +import sys, subprocess, os +sys.path.insert(0, '/flowgraphs') +sys.path.insert(0, '/src') +from fm_scanner import build_fm_receiver + +freq = float(os.environ.get('FREQ_MHZ', '101.1')) +gain = int(os.environ.get('GAIN', '10')) + +print(f'Building FM receiver for {freq} MHz (gain {gain} dB)...') +py_path = build_fm_receiver(freq, gain=gain) +print(f'Launching {py_path.name} — Ctrl+C to stop') +print(f'XML-RPC control at http://localhost:8090') +subprocess.run([sys.executable, str(py_path)]) +" diff --git a/docker/run-fm-receiver.sh b/docker/run-fm-receiver.sh new file mode 100755 index 0000000..6586867 --- /dev/null +++ b/docker/run-fm-receiver.sh @@ -0,0 +1,24 @@ +#!/bin/bash +# Run containerized FM receiver with audio output to host +# +# Usage: ./run-fm-receiver.sh [FREQ_MHZ] [GAIN] +# FREQ_MHZ: FM frequency (default: 101.1) +# GAIN: RF gain in dB (default: 10) +# +# Once running, use XML-RPC from host to retune: +# python -c "import xmlrpc.client; p=xmlrpc.client.ServerProxy('http://localhost:8090'); p.set_freq(107.2e6)" + +set -e + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +export HOST_UID=$(id -u) +export FREQ_MHZ=${1:-101.1} +export GAIN=${2:-10} + +echo "Starting FM receiver at $FREQ_MHZ MHz (gain: $GAIN dB)" +echo "XML-RPC control available at http://localhost:8090" +echo "Press Ctrl+C to stop" +echo + +docker compose -f "$SCRIPT_DIR/docker-compose.fm-receiver.yml" up --build