How to setup mpd on debian

/media/images/cat-with-headphones.jpg

mpd, the music player daemon, runs as a background process and plays or streams your music under command from a mpd client communicating via a tcp socket. Once you've got it working it's great, your music is always available, it can play every possible weird format in any configuration, and it's tolerant of missing files but setting it up is painful because the debian packages are old and broken.

The main issue is the binary package sets mpd to run at the system level but pulseaudio expects apps with user privileges. A system level audio stream will block sounds generated in userspace. This causes firefox to hang where it should mix with your other audio and if you have a notification that plays a sound it will block all of these until you run out of memory from thousands of pending streams. In the mpd config file you can tell it to drop privileges but this doesn't work. Also frustrating is the binary runs as a daemon by default so it's easy to get into situations where there are multiple instances all wrestling for the audio stream.

The solution is to setup mpd as a user process. Systemd can do this but it's not well known and the recommended hack for fixing audio privilege issues was a hack where you setup a tcp socket stream from your system level mpd and connect to this using another pulseaudio hack. I used this for several years until I finally learned the right way of doing things.

Installing mpd

First uninstall the mpd package and install dependencies. mpd has a massive list of dependencies.

sudo apt remove mpd
sudo apt build-dep mpd

Download the latest release from their webpage

They suggest running:

sudo apt install meson g++ \
libpcre3-dev \
libmad0-dev libmpg123-dev libid3tag0-dev \
libflac-dev libvorbis-dev libopus-dev libogg-dev \
libadplug-dev libaudiofile-dev libsndfile1-dev libfaad-dev \
libfluidsynth-dev libgme-dev libmikmod-dev libmodplug-dev \
libmpcdec-dev libwavpack-dev libwildmidi-dev \
libsidplay2-dev libsidutils-dev libresid-builder-dev \
libavcodec-dev libavformat-dev \
libmp3lame-dev libtwolame-dev libshine-dev \
libsamplerate0-dev libsoxr-dev \
libbz2-dev libcdio-paranoia-dev libiso9660-dev libmms-dev \
libzzip-dev \
libcurl4-gnutls-dev libyajl-dev libexpat-dev \
libasound2-dev libao-dev libjack-jackd2-dev libopenal-dev \
libpulse-dev libshout3-dev \
libsndio-dev \
libmpdclient-dev \
libnfs-dev \
libupnp-dev \
libavahi-client-dev \
libsqlite3-dev \
libsystemd-dev \
libgtest-dev \
libboost-dev \
libicu-dev \
libchromaprint-dev \
libgcrypt20-dev

But I remove gnutls from this list because I'm not sure about installing a package that wants to replace one I already have.

Configure, compile, and install the source with meson and ninja:

meson . output/release --buildtype=debugoptimized -Db_ndebug=true
ninja -C output/release
ninja -C output/release install

During the configuration step you may see missing features because of missing dependencies, this is ok. I've never succeeded in fulfilling the entire list of dependencies. Next go into /etc and remove any service files the binary package may have installed:

cd /etc/
rm systemd/system/multi-user.target.wants/mpd.service
rm systemd/system/multi-user.target.wants/mpd.socket
rm systemd/user/mpd.service
rm systemd/user/mpd.socket
rm systemd/user/default.target.wants/mpd.service

Copy the service file and symlink it to the user level systemd directory. I haven't had to setup a socket file. Note that in the source they include the service files as intermediate files so you have to pull them from your output (build) directory:

cd <source directory>/output/release/systemd/user/
sudo cp mpd.service /usr/local/lib/systemd/user/
cd systemd/user/default.target.wants/
sudo ln -s /usr/local/lib/systemd/user/mpd.service .

Copy the mpd.conf file to your home directory. Apparently they don't ship a template of this file with the source code, generate it in the compiled output, or install it to /usr/local/share/.

cd ~/
mkdir .mpd
sudo mv /etc/mpd.conf ~/.mpd/

The man.conf(5) page says mpd looks for it's configuration in these four places and in this order:

$XDG_CONFIG_HOME/mpd/mpd.conf
~/.mpdconf
~/.mpd/mpd.conf
/etc/mpd.conf

Make sure you only have one file. I prefer ~/.mpd/mpd.conf.

Modify this file with your settings. Here's mine:

music_directory         "/home/na/mp3"
playlist_directory      "/home/na/.mpd/playlists"
db_file                 "/home/na/.mpd/mpd.db"
log_file                "/home/na/.mpd/mpd.log"
pid_file                "/home/na/.mpd/pid"
state_file              "/home/na/.mpd/state"
sticker_file            "/home/na/.mpd/sticker.sql"
user                    "na"
bind_to_address         "localhost"
port                    "6600"
log_level               "default"
auto_update             "yes"
audio_output {
        type            "pulse"
        name            "My Pulse Output"
}
connection_timeout      "60"
max_connections         "50"
max_playlist_length     "16384"
max_command_list_size   "2048"
max_output_buffer_size  "8192"

Before you start the service run it by hand to see if everything works.

ps ax | grep mpd   # make sure there isn't some service already running!
mpd --no-daemon /etc/mpd.conf

Use mpc as a simple client to setup the playlist

mpc update      # update the database of files
mpc add /       # add everything to the current playlist
mpc toggle      # play/pause

Running it by hand should make the problem immediately obvious but you can also look at ~/.mpd/log. Finally setup the systemd user service:

systemctl enable mpd --user
systemctl start mpd --user

I use vimpc as a console client - it's great.