Go service that takes an internet radio stream (MP3), decodes/resamples it via FFmpeg, and sends it as AES67-style RTP multicast (L24/48000/2) with Web UI, REST API, MQTT control, ICY metadata, and SAP/SDP announcement.
# Dependencies
sudo apt-get install -y ffmpeg # Debian/Ubuntu / Raspberry Pi OS
brew install ffmpeg # macOS
# Build
cd go-radio-streamer
CGO_ENABLED=0 go build -o radio-streamer ./cmd
# Run
./radio-streamerServer URL: http://localhost:8080
Raspberry Pi guide: RASPBERRY_PI_SETUP.md
curl -sS http://localhost:8080/api/stations
curl -sS -X POST http://localhost:8080/api/play -H 'Content-Type: application/json' -d '{"station":1}'
curl -sS -X POST http://localhost:8080/api/stop
curl -sS http://localhost:8080/api/status
curl -sS http://localhost:8080/api/stream.sdp- Control:
gostreamer/play,gostreamer/stop - Status:
gostreamer/current,gostreamer/heartbeat
MIT (LICENSE)
Go-Service, der einen Internet-Radiostream (MP3) per FFmpeg dekodiert/resampelt und als AES67-ähnlichen RTP-Multicast (L24/48000/2) mit Web-UI, REST-API, MQTT-Steuerung, ICY-Metadaten und SAP/SDP-Announcement sendet.
- Go (aktuell mit Go
1.26.xgebaut) - FFmpeg in
PATH - MQTT optional (ohne
mqtt.confläuft HTTP/Web trotzdem)
# Debian/Ubuntu / Raspberry Pi OS
sudo apt-get update
sudo apt-get install -y ffmpeg
# macOS
brew install ffmpegcd go-radio-streamer
CGO_ENABLED=0 go build -o radio-streamer ./cmd
./radio-streamerServer läuft dann auf http://localhost:8080.
Vollständige Anleitung mit Pi 5 Optimierungen: RASPBERRY_PI_SETUP.md
docker run -d --name radio-streamer --network host \
-v $(pwd)/stations.txt:/app/stations.txt \
-v $(pwd)/streamer.conf:/app/streamer.conf \
silly82/go-radio-streamer:latestDie App liest drei Dateien aus dem Projekt-Root.
1. SRF-1 https://stream.srg-ssr.ch/m/rsrp1/mp3_128
2. SRF-2 https://stream.srg-ssr.ch/m/rsrp2/mp3_128
Hinweise:
- Erstes Token muss
<nummer>.sein - Zweites Token ist Stationsname (ein Token)
- Rest ist URL
broker=tcp://192.168.188.62:1883
user=your_user
pass=your_password
# Multicast address for RTP streaming and SAP announcements
multicast_address=239.69.250.171:5004
# PTP reference clock (optional)
# ptp_ref_clock=IEEE1588-2008:AA-BB-CC-DD-EE-FF-00-00:0
# Network optimisations (Pi 5)
bind_interface=eth0
ttl=1
udp_buffer_size=4194304Fehlende Optionen nutzen Defaults:
multicast_address:239.69.250.171:5004bind_interface: leer (default route)ttl: 32udp_buffer_size: 1048576 (1 MiB)ptp_ref_clock: leer (verwendetlocalmac)
- RTP Multicast auf konfigurierbarer Adresse (Default
239.69.250.171:5004) - Audioformat:
L24/48000/2(Payload Type97) - Stabiler Senderwechsel über
POST /api/play(kontrollierter Stop/Start) - Stabilitätsorientiertes Tuning (
ptime=40, Prebuffer, Silence bei Underrun)
- Interface-Binding – Multicast zwingend über bestimmtes Interface (
bind_interface) - Konfigurierbarer TTL – für Subnet-Only oder geroutete Netze
- Konfigurierbare Socket-Buffer – Pi 5 Gigabit Ethernet: bis 4 MiB Sendbuffer
- Multicast Loopback deaktiviert – kein selbst-Empfang
SO_REUSEPORT– schnelle Neustarts
- HTML Station Selection UI
- Play/Stop Controls
- Status Display (Artist/Track from ICY metadata)
- Auto-Refresh alle 5 Sekunden
GET /api/stationsPOST /api/playPOST /api/stopGET /api/statusGET /api/stream.sdp
- Broker Connection (optional, ohne läuft HTTP/Web trotzdem)
- Topic Subscription (
gostreamer/play,gostreamer/stop) - Status Publishing (
gostreamer/current,gostreamer/heartbeat)
- SDP Announcement via SAP auf
239.255.255.255:9875 - Intervall: 30 Sekunden
- SAP Delete-Announcement beim Stop
Aufrufen:
http://localhost:8080/
Funktionen:
- Start/Stop
- Senderwechsel ohne separaten Stop (Backend macht atomaren Switch)
- Anzeige von aktiver Station +
artist/track
curl -sS http://localhost:8080/api/stationscurl -sS -X POST http://localhost:8080/api/play \
-H 'Content-Type: application/json' \
-d '{"station":1}'curl -sS -X POST http://localhost:8080/api/stopcurl -sS http://localhost:8080/api/statusBeispielantwort:
{
"running": true,
"station": "SRF-1",
"artist": "...",
"track": "...",
"meta_updated": 1774982390
}curl -sS http://localhost:8080/api/stream.sdpQuery-Parameter:
ip(Default ausmulticast_address)port(Default ausmulticast_address)pt(Default97)ptime(Default40)ptp(Default: konfigurierteptp_ref_clockoderlocalmac)originip(Default: auto-detected local IP)
gostreamer/play(Payload: z. B.1)gostreamer/stop(Payload optional)
gostreamer/current(JSON)gostreamer/heartbeat(JSON, alle 30s)
Beispiele:
# subscribe
mosquitto_sub -h 192.168.188.62 -u your_user -P your_password -t 'gostreamer/#'
# play station 1
mosquitto_pub -h 192.168.188.62 -u your_user -P your_password -t 'gostreamer/play' -m '1'
# stop
mosquitto_pub -h 192.168.188.62 -u your_user -P your_password -t 'gostreamer/stop' -m ''- FFmpeg-Output:
pcm_s24be(s24beraw) - RTP-Clock: 48 kHz
- Grösserer UDP-Write-Buffer für glatteres Senden (konfigurierbar)
- Fokus auf Kontinuität statt ultra-niedriger Latenz
sync.RWMutexfür thread-sicheren Metadaten-Zugriff- Alte go-mp3-Codepfade entfernt (nur FFmpeg-basiert)
Der SDP enthält standardmässig a=ts-refclk:localmac=…. Wenn dein
AES67-Hardware-Receiver PTP erzwingt, einfach ptp_ref_clock in der
streamer.conf auf die Clock-ID des
PTP-Grandmasters setzen (z.B. Powersoft Nota/Mezzo in ArmoníaPlus zum GM
bestimmen → Clock-ID ins Config → SDP annonciert die PTP-ID → Receiver
akzeptiert). Der Pi braucht kein eigenes Hardware-PTP.
Detailierte Anleitung: RASPBERRY_PI_SETUP.md.
ps aux | grep radio-streamer
curl -sS http://localhost:8080/api/status- RTP-Verkehr prüfen:
tcpdump -ni eth0 udp and port 5004- SDP prüfen:
curl -sS http://localhost:8080/api/stream.sdp- Empfänger muss
L24/48000/2, PT97erwarten.
udp_buffer_sizeerhöhen (auf Pi 5:4194304)bind_interface=eth0setzen (WLAN meiden)- Defaults sind stabilitätsorientiert (
ptime=40, Prebuffer, Silence bei Underrun) - Receiver-Jitterbuffer erhöhen
- Host-/Netzlast und Paketverlust prüfen
- Hardware-Receiver erwartet PTP Grandmaster im Netz
- Lösung: Empfänger zum PTP-GM machen, Clock-ID in
streamer.confsetzen (sieheRASPBERRY_PI_SETUP.md) - Software-Receiver (ffplay, VLC) ignorieren das → für Tests erstmal nutzen
ffmpeg -version
sudo apt install -y ffmpeg- Server startet trotzdem (HTTP/Web-only)
- MQTT wird aktiviert, sobald gültige
mqtt.confvorhanden ist
cd go-radio-streamer
go test -v ./...
CGO_ENABLED=0 go build -o radio-streamer ./cmdAktuelle Testabdeckung: 13 Tests (config 6, streamer 5, aes67 3)
Dieses Projekt steht unter der MIT-Lizenz. Details siehe LICENSE.
go-radio-streamer/
├── RASPBERRY_PI_SETUP.md # Pi Setup Guide (Pi 4 + Pi 5)
├── cmd/main.go # Entry point
├── internal/
│ ├── api/handlers.go # REST API endpoints
│ ├── config/config.go # Config parsing (stations, MQTT, streamer)
│ ├── mqtt/mqtt.go # MQTT client
│ ├── streamer/
│ │ ├── metadata.go # ICY metadata parser
│ │ ├── streamer.go # Core: FFmpeg → RTP multicast
│ │ └── streamer_test.go
│ └── web/ # Web UI (static HTML)
├── pkg/aes67/
│ ├── sap.go # SAP announcements
│ ├── sdp.go # SDP builder
│ └── sdp_test.go
├── stations.txt # Station list (example)
├── streamer.conf # Streamer config (multicast, network, PTP)
├── mqtt.conf # MQTT credentials (example)
├── go.mod
└── README.md
Stand: Juli 2026 · go-radio-streamer v2.0