I searched and didn't find, and had to figure stuff out... I hope to save you the trouble.

Sunday, January 24, 2010

Firefly mt-daapd media server on Mac OS-X

I want to share my iTunes library from my mac without needing to keep iTunes running all the time, and I want the share to work before even logging in.

I used MacPorts to install the Firefly media server (mt-daapd), which is an open-source implementation of the daap protocol that is the guts of iTunes sharing.
sudo port install mt-daapd


Then as root I edited /etc/mt-daapd.conf to be sure these lines were right
web_root /opt/local/share/mt-daapd/admin-root
admin_pw ## (whatever you want besides the default)
db_dir /opt/local/var/db/mt-daapd
mp3_dir /path/to/your/Music/iTunes/iTunes Music
servername ## (whatever you want to show up in iTunes when connecting)
runas daemon ## (or whatever user you want who can read your iTunes music)
playlist /opt/local/etc/mt-daapd/mt-daapd.playlist



It's not so straightforward to get mt-daapd to run when the Mac reboots....

For one, my music is on an external drive which doesn't get mounted until somebody logs in. This post solved that one so now my external drive mounts right away when the mac reboots. As root, edit the file /Library/Preferences/SystemConfiguration/autodiskmount.plist and put this in it:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>AutomountDisksWithoutUserLogin</key><true/>
</dict>
</plist>


The next problem is that Apple runs daemons a little differently than *nix does. Since mt-daapd does the normal *nix thing and daemonizes itself (i.e. fork a child and then exit the originally launched program), it doesn't play well with Apple's launchd, which expects the processes it starts not to exit. I tried running mt-daapd in the foreground, but then it can't be started as root (which is the default do Apple's launchd), and the logs it produces don't show timestamps.

The other problem is that there's a race for getting the disk mounted (from the previous step) and starting the Firefly server.

In the end, I made a wrapper script that waits for the disk to mount and then starts the server and keeps running as long as the server is still running. I put this in /opt/local/sbin/mt-daapd-wrapper
#! /bin/bash

MT_DAAPD=$(dirname $0)/mt-daapd
CONF=/etc/mt-daapd.conf
RUNAS=$(sed -n '/^runas/{s/[^[:space:]]*[[:space:]]*//;p;}' $CONF)
MP3_DIR=$(sed -n '/^mp3_dir/{s/[^[:space:]]*[[:space:]]*//;p;}' $CONF)

# Kill the server if launchd kills us
trap 'echo $(date) Killed; killall mt-daapd; exit' TERM

killall mt-daapd

while [ ! -d "$MP3_DIR" ]; do
echo "$(date) Waiting for: $MP3_DIR"
sleep 10
done
echo "$(date) Music in: $MP3_DIR"

if [ -d "$MP3_DIR" ]; then
echo "$(date) Starting $MT_DAAPD"
$MT_DAAPD -c $CONF
sleep 1
PID=$(ps -u $RUNAS | awk '/mt-daapd/{print $2}' | head -n 1)
echo "$(date) mt-daapd pid: ${PID=-1}"
while ps -p $PID > /dev/null; do
sleep 10
done
fi

echo "$(date) $MT_DAAPD exited"
killall mt-daapd


Now that I have something that launchd will be happy with, I went ahead and set up a LaunchDaemon that will run it when the Mac starts up, before anyone logs in. I put this in /Library/LaunchDaemons/org.firefly.mt-daapd.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>org.firefly.mt-daapd</string>
<key>ProgramArguments</key>
<array>
<string>/opt/local/sbin/mt-daapd-wrapper</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
<key>StandardErrorPath</key>
<string>/opt/local/var/log/mt-daapd.stderr.log</string>
<key>StandardOutPath</key>
<string>/opt/local/var/log/mt-daapd.stdout.log</string>
</dict>
</plist>


If you want to manually start/stop the Firefly server, just use launchctl
sudo launchctl load /Library/LaunchDaemons/org.firefly.mt-daapd.plist

sudo launchctl unload /Library/LaunchDaemons/org.firefly.mt-daapd.plist

2 comments:

  1. Great, works a treat, thanks. And the article serves as a nice primer on launchd, too.

    ReplyDelete

Followers