- Dependency Updates & Cleanup
- Frontend Security Enhancements (Nginx/Entrypoint) - Docker Networking & Binding - Code Bug Fix
This commit is contained in:
@@ -1,171 +1,706 @@
|
||||
# audioserver — Docker Compose stack
|
||||
# audioserver
|
||||
|
||||
Runs on the **Audio Server (Pi 5)**.
|
||||
Combines Snapserver, Mopidy, and the audiocontrol web frontend in one stack.
|
||||
`audioserver` is a Docker Compose based home audio stack for a Raspberry Pi
|
||||
audio server. It combines Mopidy, Snapserver, Icecast, a React control UI,
|
||||
Bandcamp/Spotify credential helpers, and optional native iOS/Android clients.
|
||||
|
||||
```
|
||||
internet / LAN
|
||||
│
|
||||
▼
|
||||
┌───────────────────────────────────────┐ Docker network
|
||||
│ frontend (Nginx :80) │
|
||||
│ /api/hifiberry/ ──────────────────────────→ BeoCreate Pi :5005
|
||||
│ /api/mopidy/rpc → mopidy:6680 │
|
||||
│ /ws/mopidy → mopidy:6680 │
|
||||
│ /ws/snapcast → snapserver:1705 │
|
||||
├───────────────────────────────────────┤
|
||||
│ mopidy (:6680, :6600 MPD) │──→ /audio/mopidy.fifo ─┐
|
||||
├───────────────────────────────────────┤ │
|
||||
│ snapserver (:1704, :1705, :1780) │←── /audio/mopidy.fifo ─┘
|
||||
│ │←── /audio/turntable.fifo ← host service
|
||||
└───────────────────────────────────────┘
|
||||
The intended deployment target is an always-on Linux host on the same LAN as
|
||||
Snapcast clients and a HiFiBerry BeoCreate DSP device.
|
||||
|
||||
## What This Stack Provides
|
||||
|
||||
- **Mopidy music server** for local files, Spotify, YouTube, Beets, Iris, MPD,
|
||||
and HTTP JSON-RPC control.
|
||||
- **Snapserver multi-room audio** with streams for Mopidy, turntable input, and
|
||||
several TCP sources.
|
||||
- **Icecast FLAC stream** for browser and mobile playback outside Snapcast.
|
||||
- **audiocontrol web UI** served by Nginx for Mopidy, Snapcast, and BeoCreate
|
||||
DSP control.
|
||||
- **Nginx API proxy** so the browser talks to one origin instead of many backend
|
||||
services.
|
||||
- **Turntable capture helper** that records from a HiFiBerry ALSA device on the
|
||||
host and writes PCM into Snapserver.
|
||||
- **Now-playing helper service** for Snapcast metadata and audio recognition.
|
||||
- **GrooveAudio mobile apps** for iOS and Android streaming/control.
|
||||
|
||||
## Architecture
|
||||
|
||||
```text
|
||||
LAN / browser / mobile app
|
||||
|
|
||||
v
|
||||
frontend container, Nginx :${FRONTEND_PORT:-8180}
|
||||
|-- React audiocontrol UI
|
||||
|-- /api/mopidy/* -> mopidy:6680
|
||||
|-- /ws/mopidy -> mopidy:6680
|
||||
|-- /api/snapcast/rpc -> snapserver:1780/jsonrpc
|
||||
|-- /ws/snapcast -> snapserver:1780/jsonrpc
|
||||
|-- /api/hifiberry/* -> BeoCreate DSP REST API
|
||||
|-- /api/bandcamp/* -> bandcamp-api:8091
|
||||
|-- /api/spotify/* -> bandcamp-api:8091
|
||||
|-- /api/now-playing/* -> host now-playing service :8090
|
||||
|-- /stream.flac -> icecast:8000/stream.flac
|
||||
|
||||
mopidy container
|
||||
|-- writes 48 kHz / 16-bit / stereo PCM to /audio/mopidy.fifo
|
||||
|-- mirrors PCM to /audio/cava.fifo and /audio/stream.fifo
|
||||
|
||||
stream-relay container
|
||||
|-- reads /audio/stream.fifo
|
||||
|-- encodes FLAC with ffmpeg
|
||||
|-- publishes to icecast:8000/stream.flac
|
||||
|
||||
snapserver container
|
||||
|-- reads /audio/mopidy.fifo
|
||||
|-- reads /audio/turntable.fifo
|
||||
|-- connects to configured TCP audio sources
|
||||
|-- serves Snapcast clients on port 1704
|
||||
|
||||
host turntable-capture systemd service
|
||||
|-- records from HiFiBerry ALSA capture device
|
||||
|-- writes raw PCM to /audio/turntable.fifo
|
||||
```
|
||||
|
||||
---
|
||||
## Repository Layout
|
||||
|
||||
```text
|
||||
.
|
||||
|-- docker-compose.yml # Main service stack
|
||||
|-- .env.example # Environment template
|
||||
|-- frontend/ # Nginx image and proxy template
|
||||
|-- audiocontrol/ # React/Vite control UI
|
||||
|-- mopidy/ # Mopidy image and config
|
||||
|-- snapserver/ # Snapserver image and config
|
||||
|-- icecast/ # Icecast image and config template
|
||||
|-- stream-relay/ # FIFO-to-Icecast FLAC relay
|
||||
|-- bandcamp-api/ # Credential helper microservice
|
||||
|-- scripts/ # Host helper scripts and systemd units
|
||||
|-- GrooveAudio (Android)/ # Native Android client
|
||||
|-- GrooveAudio (iOS)/ # Native iOS client
|
||||
|-- MOBILE_APP_INSTRUCTIONS.md # Extra mobile/networking notes
|
||||
`-- IMPLEMENTATION_SUMMARY.md # Historical implementation notes
|
||||
```
|
||||
|
||||
## Prerequisites
|
||||
|
||||
```bash
|
||||
sudo apt install docker.io docker-compose-plugin
|
||||
sudo usermod -aG docker $USER # logout & back in
|
||||
```
|
||||
### Host
|
||||
|
||||
---
|
||||
- Linux host, preferably Raspberry Pi OS or Debian/Ubuntu.
|
||||
- Docker Engine and Docker Compose plugin.
|
||||
- `git`, `curl`, `alsa-utils`, and `systemd` for host helper services.
|
||||
- A reachable BeoCreate/HiFiBerry DSP API if you want DSP control from the UI.
|
||||
- A capture-capable ALSA device if you want turntable input.
|
||||
|
||||
## One-time setup
|
||||
|
||||
### 1. Clone / copy this directory to the Pi 5
|
||||
Install the common packages on Debian/Raspberry Pi OS:
|
||||
|
||||
```bash
|
||||
scp -r audioserver/ pi@audioserver.local:/opt/audiocontrol/stack
|
||||
cd /opt/audiocontrol/stack
|
||||
sudo apt update
|
||||
sudo apt install -y docker.io docker-compose-plugin git curl alsa-utils
|
||||
sudo usermod -aG docker "$USER"
|
||||
```
|
||||
|
||||
### 2. Copy the React source
|
||||
Log out and back in after adding your user to the `docker` group.
|
||||
|
||||
The `audiocontrol/` directory (from `audiocontrol.tar.gz`) must sit next to `docker-compose.yml`:
|
||||
### Optional Host Packages
|
||||
|
||||
The now-playing helper can use Flask, NumPy, CAVA, and SongRec:
|
||||
|
||||
```bash
|
||||
tar -xzf audiocontrol.tar.gz -C /opt/audiocontrol/stack/
|
||||
sudo apt install -y python3 python3-pip cava
|
||||
pip3 install -r scripts/requirements.txt
|
||||
```
|
||||
|
||||
### 3. Configure
|
||||
SongRec CLI is optional and must be installed separately if you want acoustic
|
||||
recognition through `snapcast-now-playing.py`.
|
||||
|
||||
### Development Tools
|
||||
|
||||
Only needed when developing outside Docker:
|
||||
|
||||
- Node.js 20+ for `audiocontrol`.
|
||||
- Android Studio for the Android client.
|
||||
- Xcode for the iOS client.
|
||||
|
||||
## First-Time Setup
|
||||
|
||||
### 1. Clone The Repository
|
||||
|
||||
Choose a stable location. The systemd units in `scripts/` expect a fixed path,
|
||||
so avoid temporary directories.
|
||||
|
||||
```bash
|
||||
git clone <repo-url> /home/admin/appdata/audioserver
|
||||
cd /home/admin/appdata/audioserver
|
||||
```
|
||||
|
||||
Any path is fine, but if you use a different one, update the `WorkingDirectory`,
|
||||
`ExecStart`, and `EnvironmentFile` paths in the systemd service files before
|
||||
installing them.
|
||||
|
||||
### 2. Create Your Environment File
|
||||
|
||||
```bash
|
||||
cp .env.example .env
|
||||
nano .env # set BEOCREATE_HOST, TZ, HIFIBERRY_CARD, etc.
|
||||
nano .env
|
||||
```
|
||||
|
||||
### 4. Create audio FIFOs
|
||||
At minimum, review these values:
|
||||
|
||||
```dotenv
|
||||
BEOCREATE_HOST=beocreate.local
|
||||
BEOCREATE_PORT=13141
|
||||
AUDIO_PIPES_DIR=/opt/audiocontrol/pipes
|
||||
MUSIC_DIR=/opt/audiocontrol/music
|
||||
FRONTEND_PORT=8180
|
||||
SNAPSERVER_HOST=192.168.178.100
|
||||
HIFIBERRY_CARD=sndrpihifiberry
|
||||
ICECAST_LISTENER_PASSWORD=groove_listen
|
||||
```
|
||||
|
||||
Set `AUDIOCONTROL_PASSWORD` if the web UI should require HTTP Basic Auth:
|
||||
|
||||
```dotenv
|
||||
AUDIOCONTROL_USERNAME=admin
|
||||
AUDIOCONTROL_PASSWORD=change-me
|
||||
```
|
||||
|
||||
Leave `AUDIOCONTROL_PASSWORD` empty to disable Basic Auth.
|
||||
|
||||
### 3. Create Host Directories
|
||||
|
||||
Create the default music and FIFO directories:
|
||||
|
||||
```bash
|
||||
sudo mkdir -p /opt/audiocontrol/music
|
||||
sudo bash scripts/init-pipes.sh
|
||||
```
|
||||
|
||||
### 5. Install the turntable capture service
|
||||
If you use a non-default FIFO path, pass it to the script and keep `.env`
|
||||
aligned:
|
||||
|
||||
```bash
|
||||
sudo cp scripts/turntable-capture.sh /opt/audiocontrol/scripts/
|
||||
sudo chmod +x /opt/audiocontrol/scripts/turntable-capture.sh
|
||||
sudo cp scripts/turntable-capture.service /etc/systemd/system/
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable --now turntable-capture
|
||||
sudo bash scripts/init-pipes.sh /srv/audioserver/pipes
|
||||
```
|
||||
|
||||
---
|
||||
The script creates:
|
||||
|
||||
## Start the stack
|
||||
- `mopidy.fifo`
|
||||
- `turntable.fifo`
|
||||
- `cava.fifo`
|
||||
- `stream.fifo`
|
||||
|
||||
### 4. Add Music
|
||||
|
||||
Put local music in the path configured by `MUSIC_DIR`. By default:
|
||||
|
||||
```bash
|
||||
sudo mkdir -p /opt/audiocontrol/music
|
||||
sudo rsync -av /path/to/music/ /opt/audiocontrol/music/
|
||||
```
|
||||
|
||||
The directory is mounted read-only into the Mopidy container at `/music`.
|
||||
|
||||
### 5. Build And Start The Stack
|
||||
|
||||
```bash
|
||||
docker compose up -d --build
|
||||
docker compose logs -f # watch startup
|
||||
docker compose ps
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Service ports
|
||||
|
||||
| Service | Port | Purpose |
|
||||
|-------------|-------|-------------------------------|
|
||||
| Frontend | 80 | Web UI + API proxy |
|
||||
| Snapserver | 1704 | Snapcast audio streaming |
|
||||
| Snapserver | 1705 | JSON-RPC WebSocket |
|
||||
| Snapserver | 1780 | Snapcast HTTP API |
|
||||
| Mopidy | 6600 | MPD (optional, host access) |
|
||||
|
||||
Mopidy's HTTP port (6680) is **not** exposed on the host — accessed only via the frontend Nginx proxy.
|
||||
|
||||
---
|
||||
|
||||
## Updating
|
||||
Watch startup logs:
|
||||
|
||||
```bash
|
||||
# Pull latest changes, rebuild, restart
|
||||
docker compose down
|
||||
docker compose up -d --build
|
||||
docker compose logs -f
|
||||
```
|
||||
|
||||
## Mopidy local library scan
|
||||
Open the web UI:
|
||||
|
||||
```text
|
||||
http://<audio-server-host>:8180
|
||||
```
|
||||
|
||||
Use the port from `FRONTEND_PORT` if you changed it.
|
||||
|
||||
### 6. Scan The Mopidy Local Library
|
||||
|
||||
After adding files to `MUSIC_DIR`, scan the library:
|
||||
|
||||
```bash
|
||||
docker compose exec mopidy mopidy local scan
|
||||
```
|
||||
|
||||
## Useful commands
|
||||
Restart Mopidy if needed:
|
||||
|
||||
```bash
|
||||
docker compose ps # service status
|
||||
docker compose logs snapserver # snapserver logs
|
||||
docker compose exec mopidy bash # shell into mopidy
|
||||
docker compose restart snapserver # restart one service
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Audio routing
|
||||
|
||||
```
|
||||
Turntable
|
||||
→ HiFiBerry HAT (ALSA hw:0)
|
||||
→ turntable-capture.sh (host)
|
||||
→ /opt/audiocontrol/pipes/turntable.fifo
|
||||
→ Snapserver (Turntable stream)
|
||||
→ BeoCreate Pi (Snapclient)
|
||||
|
||||
Mopidy
|
||||
→ GStreamer filesink
|
||||
→ /opt/audiocontrol/pipes/mopidy.fifo
|
||||
→ Snapserver (Mopidy stream)
|
||||
→ BeoCreate Pi (Snapclient)
|
||||
```
|
||||
|
||||
Both are 48 kHz / 16-bit / stereo to match the BeoCreate DSP profile.
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
**Frontend shows "unreachable" for BeoCreate DSP**
|
||||
Check that `BEOCREATE_HOST` in `.env` resolves from the Pi 5. Test:
|
||||
```bash
|
||||
curl http://beocreate.local:5005/api/volume
|
||||
```
|
||||
|
||||
**No audio from turntable**
|
||||
Check the ALSA card name in `.env`:
|
||||
```bash
|
||||
arecord -l # lists available capture devices
|
||||
```
|
||||
|
||||
**Mopidy FIFO blocks on startup**
|
||||
Snapserver must open the FIFO before Mopidy can write to it.
|
||||
The `depends_on: snapserver` in docker-compose.yml handles this, but if Snapserver is slow, restart Mopidy:
|
||||
```bash
|
||||
docker compose restart mopidy
|
||||
```
|
||||
|
||||
**Snapclient on BeoCreate can't connect**
|
||||
Port 1704 must be reachable from the BeoCreate Pi. Check firewall:
|
||||
### 7. Install Turntable Capture
|
||||
|
||||
Turntable capture runs on the host, not in Docker, because it needs ALSA device
|
||||
access.
|
||||
|
||||
First check the capture card name:
|
||||
|
||||
```bash
|
||||
sudo ufw allow 1704/tcp # if ufw is active
|
||||
arecord -l
|
||||
```
|
||||
|
||||
Set `HIFIBERRY_CARD` in `.env` to the matching ALSA card name. Then install the
|
||||
service:
|
||||
|
||||
```bash
|
||||
sudo cp scripts/turntable-capture.service /etc/systemd/system/
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable --now turntable-capture
|
||||
```
|
||||
|
||||
Check logs:
|
||||
|
||||
```bash
|
||||
journalctl -u turntable-capture -f
|
||||
```
|
||||
|
||||
If the repo is not located at `/home/admin/appdata/audioserver`, edit
|
||||
`/etc/systemd/system/turntable-capture.service` before enabling it.
|
||||
|
||||
### 8. Optional: Install Now-Playing Service
|
||||
|
||||
The frontend proxies `/api/now-playing/` to a host service on port `8090`.
|
||||
|
||||
Install Python dependencies:
|
||||
|
||||
```bash
|
||||
pip3 install -r scripts/requirements.txt
|
||||
```
|
||||
|
||||
Install the service:
|
||||
|
||||
```bash
|
||||
sudo cp scripts/snapcast-now-playing.service /etc/systemd/system/
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable --now snapcast-now-playing
|
||||
```
|
||||
|
||||
Check logs:
|
||||
|
||||
```bash
|
||||
journalctl -u snapcast-now-playing -f
|
||||
```
|
||||
|
||||
As with the turntable service, update paths in the unit file if the repo lives
|
||||
somewhere other than `/home/admin/appdata/audioserver`.
|
||||
|
||||
## Service Ports
|
||||
|
||||
| Port | Service | Bind | Purpose |
|
||||
| ---: | --- | --- | --- |
|
||||
| `8180` | frontend | configurable via `FRONTEND_PORT` | Web UI, API proxy, `/stream.flac` proxy |
|
||||
| `1704` | Snapserver | `0.0.0.0` | Snapcast client audio stream |
|
||||
| `1705` | Snapserver TCP RPC | `RPC_BIND`, default `127.0.0.1` | Direct Snapcast JSON-RPC TCP |
|
||||
| `1780` | Snapserver HTTP RPC | `RPC_BIND`, default `127.0.0.1` | Direct Snapcast HTTP/WebSocket API |
|
||||
| `8000` | Icecast | `STREAM_BIND`, default `0.0.0.0` | Direct FLAC stream server |
|
||||
| `6600` | Mopidy MPD | Docker network only by default | MPD access inside stack |
|
||||
| `6680` | Mopidy HTTP | Docker network only by default | Proxied through frontend |
|
||||
| `8090` | now-playing helper | host service | Proxied through frontend |
|
||||
|
||||
Mopidy HTTP is intentionally not exposed on the host in `docker-compose.yml`.
|
||||
Use the frontend proxy for browser and mobile control.
|
||||
|
||||
## Important URLs
|
||||
|
||||
Replace `<host>` with your audio server hostname or IP.
|
||||
|
||||
```text
|
||||
Web UI: http://<host>:8180/
|
||||
Mopidy JSON-RPC proxy: http://<host>:8180/api/mopidy/rpc
|
||||
Mopidy WebSocket proxy: ws://<host>:8180/ws/mopidy
|
||||
Snapcast RPC proxy: http://<host>:8180/api/snapcast/rpc
|
||||
Snapcast WebSocket: ws://<host>:8180/ws/snapcast
|
||||
Icecast direct stream: http://<host>:8000/stream.flac
|
||||
Proxied stream: http://<host>:8180/stream.flac
|
||||
```
|
||||
|
||||
## Environment Reference
|
||||
|
||||
| Variable | Default | Description |
|
||||
| --- | --- | --- |
|
||||
| `BEOCREATE_HOST` | `beocreate.local` | Hostname/IP for the BeoCreate DSP REST API. |
|
||||
| `BEOCREATE_PORT` | `13141` | BeoCreate DSP REST API port. |
|
||||
| `AUDIO_PIPES_DIR` | `/opt/audiocontrol/pipes` | Host directory containing audio FIFOs. |
|
||||
| `MUSIC_DIR` | `/opt/audiocontrol/music` | Host music library mounted into Mopidy. |
|
||||
| `FRONTEND_PORT` | `8180` | Host port for the Nginx/React frontend. |
|
||||
| `AUDIOCONTROL_USERNAME` | `admin` | Basic Auth username when auth is enabled. |
|
||||
| `AUDIOCONTROL_PASSWORD` | empty | Basic Auth password. Empty disables auth. |
|
||||
| `RPC_BIND` | `127.0.0.1` | Host bind address for direct Snapserver RPC ports. |
|
||||
| `STREAM_BIND` | `0.0.0.0` | Host bind address for Icecast port `8000`. |
|
||||
| `TZ` | `Europe/Vienna` | Container timezone. |
|
||||
| `HIFIBERRY_CARD` | `sndrpihifiberry` | ALSA capture card name for turntable input. |
|
||||
| `ICECAST_SOURCE_PASSWORD` | `groove_source` | Source password used by `stream-relay`. |
|
||||
| `ICECAST_RELAY_PASSWORD` | `groove_relay` | Icecast relay password. |
|
||||
| `ICECAST_ADMIN_PASSWORD` | `groove_admin` | Icecast admin password. |
|
||||
| `ICECAST_LISTENER_PASSWORD` | `groove_listen` | Listener password used by mobile apps. |
|
||||
| `SPOTIFY_CLIENT_ID` | empty | Spotify application client ID for Mopidy Spotify. |
|
||||
| `SPOTIFY_CLIENT_SECRET` | empty | Spotify application client secret. |
|
||||
| `SNAPSERVER_HOST` | `192.168.178.100` | LAN address of this audio server, used by Snapserver/Iris. |
|
||||
| `BEETS_HOST` | `192.168.178.100` | Host running Beets web service. |
|
||||
| `TCP_POP_HOST` | `192.168.178.95` | TCP source host for Snapserver stream `pop`. |
|
||||
| `TCP_TP_HOST` | `192.168.178.89` | TCP source host for Snapserver stream `tp`. |
|
||||
| `TCP_FRAMEWORK_HOST` | `192.168.178.183` | TCP source host for Snapserver stream `framework`. |
|
||||
|
||||
## Operating The Stack
|
||||
|
||||
Start or restart everything:
|
||||
|
||||
```bash
|
||||
docker compose up -d --build
|
||||
```
|
||||
|
||||
Stop everything:
|
||||
|
||||
```bash
|
||||
docker compose down
|
||||
```
|
||||
|
||||
Show service status:
|
||||
|
||||
```bash
|
||||
docker compose ps
|
||||
```
|
||||
|
||||
Follow all logs:
|
||||
|
||||
```bash
|
||||
docker compose logs -f
|
||||
```
|
||||
|
||||
Follow one service:
|
||||
|
||||
```bash
|
||||
docker compose logs -f mopidy
|
||||
docker compose logs -f snapserver
|
||||
docker compose logs -f frontend
|
||||
docker compose logs -f icecast
|
||||
```
|
||||
|
||||
Restart one service:
|
||||
|
||||
```bash
|
||||
docker compose restart mopidy
|
||||
docker compose restart snapserver
|
||||
docker compose restart frontend
|
||||
```
|
||||
|
||||
Open a shell in a container:
|
||||
|
||||
```bash
|
||||
docker compose exec mopidy bash
|
||||
docker compose exec frontend sh
|
||||
```
|
||||
|
||||
Rebuild after config or source changes:
|
||||
|
||||
```bash
|
||||
docker compose build
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
## Updating
|
||||
|
||||
```bash
|
||||
git pull
|
||||
docker compose pull
|
||||
docker compose up -d --build
|
||||
docker compose ps
|
||||
```
|
||||
|
||||
If `.env.example` changed, compare it with your `.env` and copy over any new
|
||||
variables you need.
|
||||
|
||||
## Audio Routing
|
||||
|
||||
### Mopidy To Snapcast
|
||||
|
||||
Mopidy writes raw PCM into `/audio/mopidy.fifo`. Snapserver reads that FIFO as
|
||||
the `mopidy` stream:
|
||||
|
||||
```text
|
||||
Mopidy -> /audio/mopidy.fifo -> Snapserver stream "mopidy" -> Snapcast clients
|
||||
```
|
||||
|
||||
Mopidy also mirrors the same audio into:
|
||||
|
||||
- `/audio/cava.fifo` for visualization.
|
||||
- `/audio/stream.fifo` for Icecast streaming.
|
||||
|
||||
### Mopidy To Icecast
|
||||
|
||||
The `stream-relay` container reads `/audio/stream.fifo`, encodes FLAC with
|
||||
ffmpeg, and publishes to Icecast:
|
||||
|
||||
```text
|
||||
Mopidy -> /audio/stream.fifo -> stream-relay -> Icecast /stream.flac
|
||||
```
|
||||
|
||||
The stream is available directly on port `8000` and through the frontend proxy.
|
||||
|
||||
### Turntable To Snapcast
|
||||
|
||||
The host `turntable-capture` service records from ALSA and writes raw PCM to
|
||||
the turntable FIFO:
|
||||
|
||||
```text
|
||||
Turntable / HiFiBerry capture -> turntable-capture -> /audio/turntable.fifo
|
||||
-> Snapserver stream "turntable" -> Snapcast clients
|
||||
```
|
||||
|
||||
All primary PCM paths use 48 kHz, 16-bit, stereo audio.
|
||||
|
||||
## Web UI Development
|
||||
|
||||
The Docker stack builds the React app automatically from `audiocontrol/`.
|
||||
|
||||
For local frontend development:
|
||||
|
||||
```bash
|
||||
cd audiocontrol
|
||||
npm install
|
||||
npm run dev
|
||||
```
|
||||
|
||||
The Vite development server runs on:
|
||||
|
||||
```text
|
||||
http://localhost:5173
|
||||
```
|
||||
|
||||
Build manually:
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
|
||||
Preview the production build:
|
||||
|
||||
```bash
|
||||
npm run preview
|
||||
```
|
||||
|
||||
## Mobile Apps
|
||||
|
||||
The native clients live in:
|
||||
|
||||
- `GrooveAudio (Android)/`
|
||||
- `GrooveAudio (iOS)/`
|
||||
|
||||
They are designed to use:
|
||||
|
||||
- Port `8000` for the Icecast FLAC stream.
|
||||
- Port `8180` for proxied Mopidy and Snapcast control APIs.
|
||||
- `ICECAST_LISTENER_PASSWORD` from `.env` for stream authentication.
|
||||
|
||||
Default app settings assume:
|
||||
|
||||
```text
|
||||
Host: 192.168.178.100
|
||||
Password: groove_listen
|
||||
```
|
||||
|
||||
Change those in the app settings if your server IP or listener password differs.
|
||||
See `MOBILE_APP_INSTRUCTIONS.md` for additional notes about mobile and remote
|
||||
access.
|
||||
|
||||
### Android
|
||||
|
||||
```bash
|
||||
cd "GrooveAudio (Android)"
|
||||
./gradlew assembleDebug
|
||||
```
|
||||
|
||||
Or open the folder in Android Studio and run the app on a device.
|
||||
|
||||
### iOS
|
||||
|
||||
Open `GrooveAudio (iOS)/GrooveAudio.xcodeproj` in Xcode, select a device or
|
||||
simulator, and run the app.
|
||||
|
||||
## Spotify And Bandcamp
|
||||
|
||||
### Spotify
|
||||
|
||||
1. Create a Spotify application in the Spotify Developer Dashboard.
|
||||
2. Put the credentials in `.env`:
|
||||
|
||||
```dotenv
|
||||
SPOTIFY_CLIENT_ID=...
|
||||
SPOTIFY_CLIENT_SECRET=...
|
||||
```
|
||||
|
||||
3. Recreate Mopidy:
|
||||
|
||||
```bash
|
||||
docker compose up -d --build mopidy
|
||||
```
|
||||
|
||||
The frontend also includes a proxied credential store under `/api/spotify/`
|
||||
served by `bandcamp-api`.
|
||||
|
||||
### Bandcamp
|
||||
|
||||
The `bandcamp-api` service stores Bandcamp credentials or cookies in the
|
||||
`bandcamp_config` Docker volume. The frontend proxies it under
|
||||
`/api/bandcamp/`.
|
||||
|
||||
## Security Notes
|
||||
|
||||
- Set `AUDIOCONTROL_PASSWORD` before exposing the UI outside a trusted LAN.
|
||||
- Keep `RPC_BIND=127.0.0.1` unless direct Snapserver RPC access is required.
|
||||
- Prefer the frontend proxy for control APIs instead of exposing backend ports.
|
||||
- Icecast binds to `0.0.0.0` by default through `STREAM_BIND`; restrict it if
|
||||
you do not want direct LAN access to port `8000`.
|
||||
- Do not commit `.env`; it may contain passwords and API credentials.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Frontend Does Not Load
|
||||
|
||||
Check the frontend container and logs:
|
||||
|
||||
```bash
|
||||
docker compose ps frontend
|
||||
docker compose logs -f frontend
|
||||
```
|
||||
|
||||
Verify the configured port:
|
||||
|
||||
```bash
|
||||
docker compose port frontend 80
|
||||
```
|
||||
|
||||
### Basic Auth Fails
|
||||
|
||||
Check `AUDIOCONTROL_USERNAME` and `AUDIOCONTROL_PASSWORD` in `.env`, then
|
||||
recreate the frontend:
|
||||
|
||||
```bash
|
||||
docker compose up -d --force-recreate frontend
|
||||
```
|
||||
|
||||
### BeoCreate DSP Is Unreachable
|
||||
|
||||
Confirm the host and port in `.env`:
|
||||
|
||||
```bash
|
||||
set -a
|
||||
. ./.env
|
||||
set +a
|
||||
curl "http://$BEOCREATE_HOST:$BEOCREATE_PORT/api/volume"
|
||||
```
|
||||
|
||||
If that fails from the host, fix DNS/IP routing before debugging Docker.
|
||||
|
||||
### No Mopidy Audio In Snapcast
|
||||
|
||||
Confirm the FIFOs exist:
|
||||
|
||||
```bash
|
||||
ls -l "${AUDIO_PIPES_DIR:-/opt/audiocontrol/pipes}"
|
||||
```
|
||||
|
||||
Then check service logs:
|
||||
|
||||
```bash
|
||||
docker compose logs -f mopidy snapserver
|
||||
```
|
||||
|
||||
If Mopidy started before Snapserver was ready, restart Mopidy:
|
||||
|
||||
```bash
|
||||
docker compose restart mopidy
|
||||
```
|
||||
|
||||
### Local Music Is Missing
|
||||
|
||||
Confirm `MUSIC_DIR` contains music files and rescan:
|
||||
|
||||
```bash
|
||||
docker compose exec mopidy mopidy local scan
|
||||
docker compose restart mopidy
|
||||
```
|
||||
|
||||
### No Turntable Audio
|
||||
|
||||
Check ALSA devices:
|
||||
|
||||
```bash
|
||||
arecord -l
|
||||
```
|
||||
|
||||
Update `HIFIBERRY_CARD` in `.env`, then restart the service:
|
||||
|
||||
```bash
|
||||
sudo systemctl restart turntable-capture
|
||||
journalctl -u turntable-capture -f
|
||||
```
|
||||
|
||||
### Icecast Stream Is Silent Or Missing
|
||||
|
||||
Check Icecast and relay logs:
|
||||
|
||||
```bash
|
||||
docker compose logs -f icecast stream-relay
|
||||
```
|
||||
|
||||
Verify the stream URL:
|
||||
|
||||
```bash
|
||||
curl -I http://localhost:8000/stream.flac
|
||||
curl -I http://localhost:8180/stream.flac
|
||||
```
|
||||
|
||||
The stream only carries Mopidy audio. If Mopidy is stopped or idle, the stream
|
||||
may be silent.
|
||||
|
||||
### Snapcast Clients Cannot Connect
|
||||
|
||||
Snapcast clients need access to port `1704` on the audio server:
|
||||
|
||||
```bash
|
||||
sudo ufw allow 1704/tcp
|
||||
```
|
||||
|
||||
Confirm Snapserver is listening:
|
||||
|
||||
```bash
|
||||
docker compose logs -f snapserver
|
||||
```
|
||||
|
||||
### Now-Playing API Returns Errors
|
||||
|
||||
Check the host service:
|
||||
|
||||
```bash
|
||||
systemctl status snapcast-now-playing
|
||||
journalctl -u snapcast-now-playing -f
|
||||
```
|
||||
|
||||
Make sure the service unit paths match the actual repository path and that
|
||||
Python dependencies from `scripts/requirements.txt` are installed.
|
||||
|
||||
## Backup Notes
|
||||
|
||||
Important persistent state lives in:
|
||||
|
||||
- `.env`
|
||||
- `MUSIC_DIR`
|
||||
- Docker volume `audioserver_mopidy_data`
|
||||
- Docker volume `audioserver_bandcamp_config`
|
||||
- Any systemd unit overrides you create
|
||||
|
||||
List volumes:
|
||||
|
||||
```bash
|
||||
docker volume ls | grep audioserver
|
||||
```
|
||||
|
||||
Back up named volumes with your normal Docker volume backup process.
|
||||
|
||||
Reference in New Issue
Block a user