My ultimate guide to the Raspberry pi audio server I wanted — USB sticks

Mathieu Réquillart
4 min readApr 20, 2020

--

Part 5 — USB sticks

This part gave me more thinking than the others. What I want is automatically playing audio files contained on a usb stick when it’s plugged in. But as the pi is still headless, we need some kind of remote to control the queue.
MPD seems again a good choice to do this. Unfortunately, our MPD instance is already running in satellite mode so managing a library from a folder isn’t possible. But we can very well run another instance of MPD on the Pi, which will use usb sticks as media folder. So we need a new mpd.conf file, and a new sytemd unit to manage this new MPD instance.

/etc/mpd-usb.conf

music_directory “/media/USB”
db_file “/var/lib/mpd/mpd-usb.db”
log_file “/var/log/mpd/mpd-usb.log”
pid_file “/run/mpd/pid-usb”
state_file “/var/lib/mpd/state-usb”
sticker_file “/var/lib/mpd/sticker-usb.sql”

user “mpd”
bind_to_address “localhost”
bind_to_address “192.168.0.15”
port “6610”

auto_update “yes”
zeroconf_enabled “yes”
zeroconf_name “Onkyo MPD USB”

input {
plugin “curl”
}

audio_output {
type “pulse”
name “pulse audio”
server “127.0.01”
}
filesystem_charset “UTF-8”

We changed all file locations so that MPD instances do not collide between each other, and made it run on another port.
Don’t forget to create the /media/USB folder and set it appropriates permissions:

$ sudo mkdir /media/USB
$ sudo chown mpd:audio /media/USB
$ sudo chmod 775 mpd:audio /media/USB
$ # We also copy existing mpd systemd file and change only a few lines:
$ sudo cp /lib/systemd/system/mpd.service /etc/systemd/system/mpdusb.service

[Unit]
Description=Music Player Daemon USB

[Service]
Type=notify
ExecStart=/usr/bin/mpd --no-daemon /etc/mpd-usb.conf

Let’s enable and start it

$ sudo systemctl daemon-reload
$ sudo systemctl enable mpdusb.service
$ sudo systemctl start mpdusb.service
$ sudo systemctl status mpdusb.service
● mpdusb.service — Music Player Daemon USB
Loaded: loaded (/etc/systemd/system/mpdusb.service; enabled; vendor preset: enabled)
Active: active (running) since Sat 2020–04–18 19:58:30 CEST; 12min ago
Docs: man:mpd(1)
man:mpd.conf(5)
file:///usr/share/doc/mpd/user-manual.html
Main PID: 5086 (mpd)
Memory: 8.8M
CGroup: /system.slice/mpdusb.service
└─5086 /usr/bin/mpd --no-daemon /etc/mpd-usb.conf

Apr 18 19:58:17 Ampli-BT systemd[1]: Starting Music Player Daemon USB…
Apr 18 19:58:30 Ampli-BT systemd[1]: Started Music Player Daemon USB.

Our new MPD instance is running and ready to play music, but nothing happens yet when we insert an USB stick, it’s not even mounted.

I was very lost about how to automount USB sticks in the folder I wanted with the appropriate options, there are quite a few way to do it but none pleased me. I ended up tweaking a solution I found on a blog from a cybersecurity expert using just a udev rule, a systemd unit and 2 bash scripts.

/etc/udev/rules.d/99-local.rules

KERNEL==”sd[a-z]*”, SUBSYSTEM==”block”, SUBSYSTEMS==”usb”, ACTION==”add”, RUN+=”/bin/systemctl start usb-mount@%k.service”

KERNEL==”sd[a-z]*”, SUBSYSTEM==”block”, SUBSYSTEMS==”usb”, ACTION==”remove”, RUN+=”/bin/systemctl stop usb-mount@%k.service”

/etc/systemd/system/usb-mount@.service

[Unit]
Description=Mount USB Drive on %i

[Service]
Type=oneshot
RemainAfterExit=true
ExecStart=/usr/local/bin/usb-mount.sh add %i ExecStartPost=/usr/local/bin/mpc-usb.sh add %i

ExecStop=/usr/local/bin/mpc-usb.sh remove %i
ExecStop=/usr/local/bin/usb-mount.sh remove %i

/usr/local/bin/usb-mount.sh

#!/bin/bash

ACTION=$1
DEVBASE=$2
DEVICE=”/dev/${DEVBASE}”
BASE_MOUNT_POINT=”/media/USB”

# See if this drive is already mounted
MOUNT_POINT=$(/bin/mount | /bin/grep ${DEVICE} | /usr/bin/awk ‘{ print $3 }’)


do_mount()
{
if [[ -n ${MOUNT_POINT} ]]; then
# Already mounted, exit
exit 1
fi

# Get info for this drive: $ID_FS_LABEL, $ID_FS_UUID, and $ID_FS_TYPE
eval $(/sbin/blkid -o udev ${DEVICE})

# Figure out a mount point to use
LABEL=${ID_FS_LABEL}
if [[ -z “${LABEL}” ]]; then
LABEL=${DEVBASE}
elif /bin/grep -q “ $BASE_MOUNT_POINT/${LABEL} “ /etc/mtab; then
# Already in use, make a unique one
LABEL+=”-${DEVBASE}”
fi
MOUNT_POINT=”${BASE_MOUNT_POINT}/${LABEL}”

/bin/mkdir -p ${MOUNT_POINT}

# Global mount options
OPTS=”rw,relatime,uid=111,gid=29,umask=0002"

# File system type specific mount options
if [[ ${ID_FS_TYPE} == “vfat” ]]; then
OPTS+=”,users,shortname=mixed,utf8=1,flush”
fi

if ! /bin/mount -o ${OPTS} ${DEVICE} ${MOUNT_POINT}; then
# Error during mount process: cleanup mountpoint
/bin/rmdir ${MOUNT_POINT}
exit 1
fi
}

do_unmount()
{
if [[ -n ${MOUNT_POINT} ]]; then
/bin/umount -l ${DEVICE}
fi

# Delete all empty dirs in /media that aren’t being used as mount points.
for f in ${BASE_MOUNT_POINT}/* ; do
if [[ -n $(/usr/bin/find “$f” -maxdepth 0 -type d -empty) ]]; then
if ! /bin/grep -q “ $f “ /etc/mtab; then
/bin/rmdir “$f”
fi
fi
done
/bin/echo “${MOUNT_POINT} unmounted”
}
case “${ACTION}” in
add)
do_mount
;;
remove)
do_unmount
;;
esac

/usr/local/bin/mpc-usb.sh

#!/bin/bashACTION=$1
DEVICE=$2
MPDPORT=6610
MPC="/usr/bin/mpc -p ${MPDPORT}"
MOUNT_POINT=$(/bin/mount | /bin/grep ${DEVICE} | /usr/bin/awk '{ print $3 }')
LABEL=$(/usr/bin/basename ${MOUNT_POINT})
do_mount() {
/bin/echo "clearing previous queue"
${MPC} clear
/bin/echo "updating mpd database..."
${MPC} update --wait
/bin/echo "adding ${LABEL} files to queue"
${MPC} add ${LABEL}
/bin/echo "playing queue"
${MPC} play
}
do_unmount() {
/bin/echo "clearing previous queue from ${LABEL} files"
${MPC} -f "%position% %file%" playlist | /bin/grep ${LABEL} | /usr/bin/awk '{ print $1 }' | ${MPC} del
}
case "${ACTION}" in
add)
do_mount
;;
remove)
do_unmount
;;
esac

Now let’s reload udev and systemd

$ sudo udevadm control --reload-rules
$ systemctl daemon-reload

USB sticks are now mounted in a folder created automatically in /media/USB with mpd:audio rights and 775 permissions (thanks to mount options) to make inotify and autoupdate work.
With my first test, there was a GoT episode on the key I used alongside MP3, which was detected and played by mpd when I inserted the key.
So I created file /media/USB/.mpdignore to ignore video files when scanning for media

*.mkv
*.mp4
*.mpg
*.mpeg
*.wmv
*.avi

So now when inserting a USB stick, files start playing after a few seconds, time for mouting and updating MPD-USB database. If another stick was already playing, queue is replaced with new stick content and starts playing, but old content is still accessible in MPD-USB database from M.A.L.P. or ympd when using MPD-USB server.

ympd on MPD-USB
M.A.L.P. on MPD-USB

Now I feel also should install a minidlna server on the Pi to make sticks content also available on DLNA ? Maybe another time.

Part 6 : Audio CD

--

--