LPD Music Hack – How it’s Done

People have been asking how to achieve the lpd music hack, which was used at Friday night geekery #1.

First of all I would like to explain that the idea is not my own. OpenBSD developers have been using this technique at their hackathons for years now. I was first exposed to this hack at p2k9 when I was enrolled as an OpenBSD dev, then i asked for the configs at p2k10. So basically the message is “this was not my idea, but it’s awesome”.

Requirements

A single music server which maintains a playlist, playing tracks one at a time. Users should be able to queue their own music from their own machines without having to put anything into a database up-front (which is why mpd sucks for this). Users should be able to view the playlist.

Seems simple huh? Well no software I know does this.

Configure Server

  • Find a machine capable of playing audio and install OpenBSD on it. Do not enable aucat, or if you do, make sure the daemon user can use the aucat socket.
  • Set up a print spool that will use a shell script as it’s filter. An /etc/printcap like this:
    mp3|lp:\
      :lp=/dev/null:mx#0:if=/opt/bin/mp3spool:sd=/var/spool/output
    
  • Permit remote printing
  • Set up an /etc/hosts.lpd and list hosts that should be able to play music. If you are in a trusted network, you can just stick in a ‘+’, meaning “everyone with a reverse lookup name”. If your hosts do not have reverse DNS records, then list them in /etc/hosts instead. Make sure that /etc/resolv.conf is configured correctly to do so.

  • Make the spooling script
  • Make the script that ‘if’ refers to in the print spooler, so in our case /opt/bin/mp3spool.

    /usr/local/bin/mplayer -vo null -af resample=48000 - || \
    true > /dev/null 2>&1
    

    Make sure the script is executable.

  • Start lpd
  • Just type `lpd` as root. If you want lpd to start at boot

    echo 'lpd_flags=""' >> /etc/rc.conf.local
  • Test the server
  • `lpq` should display ‘no entries’ and you should be able to queue songs using

    lpr /some/song.mp3

Configure Clients

  • Set up spooler
  • In /etc/printcap:

    lp:\
      :lp=:rm=:rp=lp:sd=/var/spool/output:lf=/var/log/lpd-errs:
    
  • Start spooler in the same way as the server, `lpd`
  • Test clients
  • `lpq` and `lpr` should work in the same way as on the server.

That’s it!

A few extra notes:

  • When you are using `lpq`, song names may be too long and truncated to ‘…’, in which case, you would use `lpq -l`.
  • User’s may de-queue their own tracks using `lprm jobnumber`, as long as the song is not already playing. The job number is found in the short `lpq` output.
  • Assign a “queue admin” who has root access on the server. If a crap song comes on and 3 people vote it off, the queue admin can kill the job using lprm as root.
  • If others don’t use lpd or can’t be arsed to set up cups (i don’t blame you), then you can distribute a script to queue songs locally from the server. This is what we used:
    #!/bin/sh
    
    host="[email protected]"
    path="/tmp/"
    
    if [ "$1" = "" ]; then
            echo "       q.sh "
            echo "       q.sh -l"
            exit 1
    elif [ "$1" = "-l" ]; then
            ssh ${host} lpq -l
            exit 0
    fi
    
    file="`basename \"$1\"`"
    scp "$1" "${host}:${path}\"${file}\""
    ssh ${host} "lpr ${path}\"${file}\""
    ssh ${host} "rm ${path}\"${file}\""
    

    If you do this you will either have to set up a user account for each user (if you want to see who queued what in the playlist), or if you are lazy, use a single user account on the server.

So, it’s quite a hack and it amazes me that there is no better solution yet. Please someone write one.

Please leave know-it-all comments underneath, if you must.

About Edd

Edd is a open-source enthusiast, PhD student, OpenBSD developer and general computer pessimist :)
This entry was posted in Unix. Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>