Audio streaming software for ZuidWest FM and Radio Rucphen. Stream audio from a Raspberry Pi to multiple SRT destinations simultaneously. Built for broadcast environments with real-time monitoring and web-based configuration.
- Multi-output streaming - Send to multiple SRT servers with different codecs simultaneously
- Real-time VU meters - Peak hold (1.5 s) with peak/RMS toggle, clip detection, updated via WebSocket
- Silence detection - Alerts via webhook, email, file log, or Zabbix when audio drops below threshold
- Web interface - Configure outputs, select audio input, monitor levels
- Auto-recovery - Automatic reconnection with configurable retry limits per output
- Multiple codecs - MP3, MP2, Ogg Vorbis, or uncompressed WAV per output
- Update notifications - Alerts when new versions are available
- Single binary - Web interface embedded, minimal runtime dependencies
| Platform | Status | Audio Capture |
|---|---|---|
| Linux (Raspberry Pi) | Primary | arecord (ALSA) |
| macOS | Development only | FFmpeg (AVFoundation) |
| Windows | Experimental | FFmpeg (DirectShow) |
Linux on Raspberry Pi is the primary target. macOS works for development. Windows is experimental.
- Raspberry Pi 4 or 5
- HiFiBerry Digi+ I/O or HiFiBerry DAC+ ADC
- Raspberry Pi OS Trixie Lite (64-bit)
ffmpeg(for encoding)alsa-utils(for audio capture viaarecord)
- Install Raspberry Pi OS Trixie Lite (64-bit)
- Configure HiFiBerry following the official guide
- Run the installer as root:
sudo su
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/oszuidwest/zwfm-encoder/main/deploy/install.sh)"The web interface will be available at http://<raspberry-pi-ip>:8080
Default credentials: admin / encoder
Run the same installer script to update to the latest version:
sudo su
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/oszuidwest/zwfm-encoder/main/deploy/install.sh)"The installer detects existing installations and asks whether to:
- Update only - Downloads the latest binary while preserving your configuration
- Fresh install - Overwrites configuration (existing config is backed up)
The web interface shows a notification when updates are available.
Connect the digital output of your audio processor to the HiFiBerry input.
Requirements:
- 48 kHz sample rate
- 16-bit depth
- Stereo (2 channels)
- S/PDIF format preferred (AES/EBU compatibility not guaranteed)
| Codec | Encoder | Bitrate | Notes |
|---|---|---|---|
| MP3 | libmp3lame | 320 kbit/s | — |
| MP2 | libtwolame | 384 kbit/s | Uses psymodel 4 |
| Ogg | libvorbis | ~500 kbit/s (Q10) | — |
| WAV | pcm_s16le | Uncompressed | — |
Monitors audio levels and sends alerts when silence is detected or recovered. Uses hysteresis to prevent alert flapping:
| Setting | Default | Range | Description |
|---|---|---|---|
| Threshold | -40 dB | -60 to 0 | Audio level below which silence is detected |
| Duration | 15 s | 1 to 300 | Seconds of silence before alerting |
| Recovery | 5 s | 1 to 60 | Seconds of audio before recovery |
Alerting options (can use multiple simultaneously):
- Webhook - POST request to a URL on silence start and recovery
- Email - Microsoft Graph API notification to configured recipients on silence start and recovery
- File Log - Append JSON Lines to a local file for each silence event
- Zabbix - Send trapper items to a Zabbix server on silence start and recovery
Configure via the web interface under Settings → Alerts.
Email notifications use Microsoft Graph API with app-only authentication.
- Create an App Registration → copy Client ID and Tenant ID
- Add API permissions:
Mail.Send(required),Application.Read.All(optional, for secret expiry warnings) - Grant admin consent
- Create a client secret → copy the value immediately (won't be shown again)
- Create a shared mailbox as the sender (no license required)
The encoder warns when the secret expires within 30 days.
- Import
zabbix/template.xmlin Zabbix (Data collection → Templates → Import) - Link the template to your encoder host
- Configure in the encoder: server, port (default 10051), host name (must match Zabbix exactly), and item key
The template creates triggers for SILENCE (Disaster), RECOVERY (Info), and TEST (Info) events.
Configuration is stored in /etc/encoder/config.json on production systems. For development, use the -config flag to specify a custom path, or place config.json next to the binary.
{
"system": { "port": 8080, "username": "admin", "password": "encoder" },
"web": { "station_name": "ZuidWest FM" }
}The installer creates a minimal config file. All other settings are configured through the web interface.
The encoder logs all stream, silence, and recording events to a JSON Lines file for monitoring and debugging. Events are accessible via the web interface and REST API.
See docs/events.md for the complete event reference.
flowchart LR
A[Audio Input]
subgraph Capture["Capture"]
B[arecord]
end
subgraph Processing["Audio Processing"]
D[Distributor]
subgraph Metering["Metering"]
M[RMS/Peak<br>Calculator]
PH[Peak Hold<br>1.5s Decay]
CD[Clip<br>Detect]
end
subgraph Silence["Silence Detection"]
SD[Detector<br>Hysteresis]
SDM[Dump Manager<br>Ring Buffer]
end
end
subgraph Outputs["Streaming Outputs"]
OM[Output Manager<br>Retry + Backoff]
F1[FFmpeg MP3]
F2[FFmpeg MP2]
F3[FFmpeg OGG]
S1[SRT 1]
S2[SRT 2]
S3[SRT 3]
end
subgraph Recording["Recording"]
RM[Recording Manager]
R1[Hourly]
R2[On-Demand]
ST[(Storage)]
end
subgraph Alerts["Alerting"]
SN[Silence Notifier]
N1[Webhook]
N2[Email]
N3[Log]
N4[Zabbix]
end
subgraph UI["Web UI"]
WS[WebSocket<br>10fps]
end
%% Main audio flow
A ==>|S/PDIF| B ==>|PCM| D
%% Metering branch
D ==>|PCM| M -->|dB| PH
M -->|samples| CD
PH -->|dB JSON| WS
CD -->|clip JSON| WS
%% Silence detection branch
D -->|dB| SD
D ==>|PCM| SDM
SD -->|events| SDM
SD -->|state JSON| WS
%% Alerting
SD -->|event| SN
SDM -->|MP3| SN
SN -->|HTTP| N1
SN -->|Graph API| N2
SN -->|file| N3
SN -->|trapper| N4
%% Streaming
D ==>|PCM| OM
OM ==>|PCM| F1 -->|SRT| S1
OM ==>|PCM| F2 -->|SRT| S2
OM ==>|PCM| F3 -->|SRT| S3
%% Recording
D ==>|PCM| RM
RM ==>|PCM| R1 -->|MP3| ST
RM ==>|PCM| R2 -->|MP3| ST
- Capture:
arecord(Linux) or FFmpeg (macOS/Windows) captures 48kHz 16-bit stereo PCM - Distributor: Processes PCM in ~100ms chunks, fans out to all consumers
- Metering: Calculates RMS/peak levels in Go (no FFmpeg filters), holds peaks for 1.5s, detects clipping at ±32760
- Silence Detection: Hysteresis-based detection with configurable threshold/duration/recovery. Buffers 15s audio context before/after silence events
- Alerting: Silence triggers webhook, email (MS Graph), log (JSON Lines), and/or Zabbix. Recovery includes MP3 dump attachment
- Streaming: Per-output FFmpeg processes with automatic retry and exponential backoff
- Recording: Hourly rotation or on-demand, with optional S3 upload
Optional hardening:
echo "dtoverlay=disable-wifi" >> /boot/firmware/config.txt # Disable WiFi
apt remove bolt bluez ntfs-3g telnet # Remove unused packages- Liquidsoap Server - Companion server software for receiving SRT streams
MIT License - See LICENSE.md