Personal Streaming Audio Server
For a while now, I’ve been looking for a good way to stream music from my home music collection on my phone.
There are quite a few options for music servers that support streaming. However, Android apps that can stream music from one of those servers tend to be unmaintained, clunky or slow (or more than one of those).
It is possible to use something that runs in a web server, but that means no offline caching - which can be quite convenient in spots without connectivity, such as the Underground or other random bits of London with poor cell coverage.
Server
Most music servers today support some form of the subsonic API.
I’ve tried a couple, with mixed results:
- supysonic; Python. Slow. Ran into some issues with subsonic clients. No real web UI.
- gonic; Go. Works well & fast enough. Minimal web UI, i.e. no ability to play music from a browser.
- airsonic; Java. Last in a chain of (abandoned) forks. More effort to get to work, and resource intensive.
Eventually, I’ve settled on Navidrome. It’s got a couple of things going for it:
- Good subsonic implementation that worked with all the Android apps I used it with.
- Great Web UI for use in a browser
I run Navidrome in Kubernetes. It’s surprisingly easy to get going. Here’s the deployment I’m using:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | apiVersion: apps/v1
kind: Deployment
metadata:
name: navidrome
spec:
replicas: 1
selector:
matchLabels:
app: navidrome
template:
metadata:
labels:
app: navidrome
spec:
containers:
- name: navidrome
image: deluan/navidrome:latest
imagePullPolicy: Always
resources:
limits:
cpu: ".5"
memory: "2Gi"
requests:
cpu: "0.1"
memory: "10M"
ports:
- containerPort: 4533
volumeMounts:
- name: navidrome-data-volume
mountPath: /data
- name: navidrome-music-volume
mountPath: /music
env:
- name: ND_SCANSCHEDULE
value: 1h
- name: ND_LOGLEVEL
value: info
- name: ND_SESSIONTIMEOUT
value: 24h
- name: ND_BASEURL
value: /navidrome
livenessProbe:
httpGet:
path: /navidrome/app
port: 4533
initialDelaySeconds: 30
periodSeconds: 3
timeoutSeconds: 90
volumes:
- name: navidrome-data-volume
hostPath:
path: /srv/navidrome
type: Directory
- name: navidrome-music-volume
hostPath:
path: /srv/media/music
type: Directory
---
apiVersion: v1
kind: Service
metadata:
name: navidrome
spec:
ports:
- port: 4533
name: web
selector:
app: navidrome
type: ClusterIP
|
At the moment, this deployment is still tied to the machine with my music on it since it relies on hostPath volumes, but I’m planning to move that to ceph in the future.
I then expose this service on /navidrome on my private domain (here replaced with example.com) using an Ingress:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: navidrome
spec:
ingressClassName: nginx
rules:
- host: example.com
http:
paths:
- backend:
service:
name: navidrome
port:
name: web
path: /navidrome(/|$)(.*)
pathType: Prefix
|
Client
On the desktop, I usually just use navidrome’s web interface. Clementine’s support for subsonic is also okay. sublime-music is meant to be a music player specifically for Subsonic, but I’ve not really found it stable enough for day-to-day usage.
There are various Android clients for Subsonic, but I’ve only really considered the Open Source ones that are hosted on F-Droid. Most of those are abandoned, but D-Sub works pretty well - as does my preferred option, Subtracks.