mirror of
https://gitlab.com/EternalWanderer/voidcruiser.nl
synced 2024-11-29 04:13:51 +01:00
176 lines
5.9 KiB
Markdown
176 lines
5.9 KiB
Markdown
---
|
|
title: "Mpd and Icecast on Nix"
|
|
date: "2022-11-06T22:11:10+01:00"
|
|
author: "$HUMANOID"
|
|
tags: ["nix", "linux"]
|
|
description: "Ramble about setting up MPD + Icecast on NixOS"
|
|
---
|
|
# Introduction
|
|
|
|
For quite some time now, I've been wanting to move my home server from Debian to
|
|
NixOS. There were a few things that kept me from starting with the migration.
|
|
The main one being that the Debian installation still worked reasonably well. I
|
|
only had occasional hickups in regards to the two USB disks hooked up to my
|
|
Raspberry Pi 4. Every now and then they'd disappear. My guess is that it was due
|
|
to power draw as it would consistently happen when putting heavy IO loads on
|
|
either disk. One of these disks is home to my music collection and used by my
|
|
internet radio setup (in other words, the main thing I listen to when at home).
|
|
And this nicely brings my to my next issue.
|
|
|
|
{{< img class="stickers" src="/images/graphs/radio.png" mouse="Flowchart demonstrating software stack">}}
|
|
|
|
This radio consists of an MPD instance streaming to an Icecast2 instance,
|
|
being reverse proxied through an NGINX instance (future plans include managing
|
|
the music collection through Git Annex...). I have tried setting up MPD on NixOS
|
|
in the past, but couldn't get it to work for some odd reason. I don't remember
|
|
why I never managed it. I just know that I gave up after a few hours. Today I
|
|
decided to spend as much time as necessary to get at least the MPD + Icecast2
|
|
portion to work. The rest of this post will be detailing how I went about
|
|
setting configuring MPD + Icecast2 on NixOS as there were a few non-obvious
|
|
things I bumped into.
|
|
|
|
# Setting up MPD
|
|
|
|
To prevent my `/etc/nixos/configuration.nix` from ballooning into absurdity,
|
|
you'll want to create something like a `/etc/nixos/services/radio.nix` file
|
|
containing everything related to the radio stack. This file is then imported in
|
|
`/etc/nixos/configration.nix` in the `imports` section as follows:
|
|
|
|
```nix
|
|
{ config, pkgs, ... }: {
|
|
imports =
|
|
[ # Include the results of the hardware scan.
|
|
./hardware-configuration.nix
|
|
./drives.nix
|
|
./services/radio.nix
|
|
|
|
...
|
|
|
|
];
|
|
...
|
|
|
|
}
|
|
```
|
|
|
|
The first thing you'll want to do is enable the MPD service:
|
|
```nix
|
|
{ config, pkgs, ... }: {
|
|
services.mpd = {
|
|
enable = true;
|
|
...
|
|
|
|
```
|
|
|
|
From here, there are a few rather basic options that you'll want to set:
|
|
```nix
|
|
...
|
|
musicDirectory = "/path/to/music-collection/";
|
|
network.listenAddress = "any"; # not quite sure if this is needed
|
|
...
|
|
```
|
|
|
|
At the `extraConfig` section is where things get interesting. Here I assumed you
|
|
could point Nix to an existing config file with `(builtins.readFile
|
|
/path/to/mpd.conf)` but it seems I am wrong. It doesn't throw any errors when
|
|
switching to a new build, but it doesn't read the given config file either. I'm
|
|
probably missing something here. Please shout at me if you happen to know what
|
|
it is.
|
|
|
|
Regardless, you're going to want to add at least one audio output method. Since
|
|
we're going to make MPD talk to Icecast2, we're going to add `audio_output`
|
|
section of type "shout":
|
|
|
|
```nix
|
|
...
|
|
musicDirectory = "/path/to/music-collection/";
|
|
extraConfig = ''
|
|
audio_output {
|
|
type "shout"
|
|
encoder "vorbis" # FOSS codec for the win
|
|
name "My Shouty Stream"
|
|
host "<name found in the networking.hostName variable>"
|
|
port "8000" # or use whatever meme you like
|
|
mount "/mpd.ogg"
|
|
password "hunter2"
|
|
quality "5.0"
|
|
format "44100:16:2"
|
|
genre "Rythmic Noise!"
|
|
protocol "icecast2"
|
|
}
|
|
'';
|
|
};
|
|
...
|
|
```
|
|
|
|
Please don't take this snippet as gospel and read through the MPD configuration.
|
|
Whatever is found in `extraConfig` will be directly given to MPD as if through
|
|
`/etc/mpd.conf` on e.g. Debian. For instance, if you only locally want to listen
|
|
to your music through say PulseAudio, than you'll need a corresponding output
|
|
section.
|
|
|
|
{{< start-details summary="Example PulseAudio configuration I have on my laptop" >}}
|
|
```conf
|
|
...
|
|
audio_output {
|
|
type "pulse"
|
|
name "Pulse output"
|
|
audio_output_format "44100:16:2"
|
|
samplerate_converter "Medium Sinc Interpolator"
|
|
mixer_type "software"
|
|
replaygain "album"
|
|
volume_normalization "no"
|
|
}
|
|
...
|
|
```
|
|
{{< end-details >}}
|
|
|
|
## Mounting a music disk
|
|
|
|
In order to automount a disk on NixOS, add an expression something like the
|
|
following (indirectly) in your `/etc/nixos/configration.nix`:
|
|
|
|
```nix
|
|
fileSystems."/srv/music" = {
|
|
device = "/dev/sdb1"; # assuming that sdb1 is the partition with your music on it
|
|
# device = "/dev/disk/by-label/Sauserer"; # or ideally, if you have a labelled disk
|
|
fsType = "ext4"; # assuming it has a ext4 filesystem on it
|
|
};
|
|
```
|
|
I have my drives listed in `/etc/nixos/drives.nix` and import that in my
|
|
`configration.nix`
|
|
|
|
# Setting up Icecast2
|
|
|
|
The next step is to set up Icecast2. Same as with MPD, the first thing you'll
|
|
want to do is enable it:
|
|
|
|
```nix
|
|
...
|
|
services.icecast = {
|
|
enable = true;
|
|
extraConf = ''
|
|
<location>Floating around in an example configuration snippet on the internet</location>
|
|
<admin>icemaster@localhost</admin>
|
|
<authentication>
|
|
<source-password>hunter2</source-password>
|
|
<relay-password>even-more-super-secret-password</relay-password>
|
|
</authentication>
|
|
|
|
<limits>
|
|
<clients>100</clients>
|
|
<sources>2</sources>
|
|
<queue-size>524288</queue-size>
|
|
<client-timeout>30</client-timeout>
|
|
<header-timeout>15</header-timeout>
|
|
<source-timeout>10</source-timeout>
|
|
<burst-on-connect>1</burst-on-connect>
|
|
<burst-size>65535</burst-size>
|
|
</limits>
|
|
'';
|
|
hostname = "hostname:8000";
|
|
listen.port = 8000;
|
|
admin.password = "it gives me a headache that I can't get Nix to read this from a file";
|
|
};
|
|
}
|
|
```
|