Introduction
If you’ve been following along with my previous articles [Part 1] [Part 2], you now have the ability to telnet into your NSLU2 and start up NFS. Those are valuable capabilities, but this time we’re going for the entertainment value.
Like many people, my MP3 collection is beginning to eat up some serious disk space. As well as getting my music moved to central storage, it would also be nice to share it among different computers in the household. Does the NSLU2 have the right stuff to be a music server? It’s small enough to tuck into your entertainment center. It’s silent, and its storage capabilities are limited only by the the size of the disk you plug into it. It looks promising to me!
A reader of my previous articles suggested a look at an iTunes server called mt-daapd. Running
An interesting feature of
|
Gathering the sources
I’m assuming that you’ve followed my previous article and have installed the tool-chain we’ll be using to build our server. I’ll also be writing this assuming bash syntax. If you use a different shell, you’ll have to adjust. As in my last article, I’ll be doing the build from a Mandrake machine. But this time I’ll be NFS mounting my NSLU2 disk so that my build will automatically end up where I need to run it.
The first step in this process is to create a work area for the packages that we’re going to build. I created a directory called iTunes under my home directory on the NSLU2. Next we’ll need to get all of the various source packages required. We’ll naturally start with the
A glance at the documentation shows that we’ll need libid3tag, the library used for ID3 tag reading and gdbm, the GUN database manager. A quick test I did showed that we will also need the zlib compression library. I fetched libid3tag from here, gdbm from here and zlib from here. I placed all of the required packages in my iTunes directory. After un-tarring them, you’ll end up with a gdbm-1.8.3 directory, a libid3tag-0.15.1b directory, a
Before we start the build, we’ll set up some common environment variables that will be used during the
I created a setup.sh file with the following definitions :
export BASE=/mnt/nslu2/data/jim/iTunes/ export LINUX=$HOME/snapgear/linux-2.4.x/include/ export TOOLSBASE=$HOME/gpl_code_2.03/usr/
local/openrg/armsaeb/bin/armv4b-hardhat-linux export CC=$TOOLSBASE-gcc export STRIP=$TOOLSBASE-strip export RANLIB=$TOOLSBASE-ranlib export LDFLAGS=-L$BASE/lib export CFLAGS="-I$BASE/include/ -I$LINUX"
(Note that in the setup.sh file the line starting with “export TOOLSBASE” and the next indented line are entered as one line with no space between them.)
BASE is defined to be the top level of my working area while LINUX points to the snapgear Linux source tree. TOOLSBASE is where my
Easy builds first
It’s important to build our packages in the right order. The most basic package seems like zlib since it shouldn’t have any external dependencies. In the zlib directory enter the following command:
./configure --prefix=$BASE
The prefix argument tells Autoconf where to place the result of the build. When executing the script, you should get a few lines of output and should see your arm-gcc compiler referenced. Now that it’s properly configured, just do a simple:
make install
After a number of files are compiled and a library created, the resultant files are copied into our base directory. That was surprisingly simple. One package down, three more to go.
We’ll tackle the gdbm package next. It should also have no external dependencies, but we’ll have to tell it a little more about how we want the package configured. In the gdbm directory execute the following command:
./configure --host=arm-linux --prefix=$BASE
This Autoconf setup requires us to tell it which architecture we are building for and the host argument is used for that. Executing this command causes a much longer configuration listing than our last one, but it should finish up in a few seconds. Next do the build by issuing the command:
make install
This build is a little bit ugly. You should see a long compilation, followed by ldconfig complaining about the resultant shared library because it doesn’t understand arm binaries. We’re not concerned with this because we’re obviously not going to be using the libraries on this box. You may also see an error regarding changing the ownership of gdbm.h. This error is also harmless to our build.
Now on to libid3tag. From the libid3tag directory:
./configure --host=arm-linux --prefix=$BASE
This generates a long listing, then as before:
make install
This build will complete as before with a harmless complaint from ldconfig. Our libraries are now complete. This has been all too easy right? Well now it will get just a little more difficult as we move on to
Building mt-daapd
As I said, the mt-daapd build is somewhat more involved. But don’t worry, we’ll get through it.
From the
./configure --host=arm-linux --prefix=$BASE
LIBS="-lgdbm -lid3tag -lz" ac_cv_func_setpgrp_void=yes
(Note that the above command is entered on one line with a space between $BASE and LIBS.)
This deserves a bit of explanation. The host and the prefix options we’ve seen before. The LIBS options is specific to this package. For whatever reason, the stock build was listing the libraries before the .o files during the link phase, causing the link to fail with undefined references.
Investigation of the configure script showed an option, LIBS, that could be used to add extra libraries to the link. So I’m using it here to add back in our libraries. It’s a hack, but it saves us from having to make modifications to the configure script itself.
The other new option, ac_cv_func_setpgrp_void is also a bit of a hack. When I first ran the configure script I was getting an error from a specific portion that wanted to run a test program to determine the behavior of a particular function. Of course, with
NOTE: From my experience, this is a common problem when doing
cross-compilation and using Autoconf. The authors of a package often don’t have a chance to build for a different architecture so the configure script is just not quite correct for across-compile . This technique, while a bit ugly, will at least allow you to complete the configuration process.
After running the above command, we’ll still have to fix a couple of things before we can do our build. First, in order to simplify our installation, we’re going to remove the shared libraries that we just built. When the shared libraries are removed, the link will occur against the static versions. This keeps us from having to add additional libraries that no other process is likely to use. If you find other processes that need these libraries, you can skip this step and add the libraries to your system. Execute the following command from the
rm -f../lib/*.so*
Next, due to the way that the arm-compiler deals with structures and unions, we’ll have to make a code change. By default, the arm compiler pads out structures and unions to 16 bit boundaries. Normally this wouldn’t cause a problem, but in our case, structures are read and written directly to the network. The iTunes program on the other side of the network connection doesn’t have the padding, resulting in a garbled conversation. The file we’ll have to change is src/mDNSClientAPI.h, and the change we’ll make is to add an
The following types also need to have the packed attribute added:
- mDNSOpaque16
- mDNSOpaque32
- mDNSOpaque128
- mDNSAddr
- rdataSRV
- rdataMX
After the change, my definition of mDNSOpaque16 looks like this:
typedef union { mDNSu8 b[2]; mDNSu16 NotAnInteger; }
__attribute__ ((packed)) mDNSOpaque16;
(Again, entered as one line, no space between the } and __.)
The special compilation attribute falls between the right brace and the typedef name. I passed these changes on to the author of
After adding these attributes, a “make install” will finish up the build and deposit the result in ../sbin/. Finally strip the resultant binary to reduce its size:
$STRIP../sbin/mt-daapd
and we’re done! On to the install!
Installing to the NSLU2
Now it’s time to install. First we’ll modify the
Inside this, I copied the
When you’ve modified the configuration file to suit your needs, copy it to the /share/hdd/conf/etc directory, and create a symbolic link from etc:
ln -s /share/hdd/conf/etc/mt-daapd .conf /etc/mt-daapd.conf
Now copy the actual binary, src/
As we did with NFS in my last article, you should create an rc script that creates the symbolic link and starts the actual process. I’ve been using /etc/rc.d/rc.samba as a starting point. Copy it to /share/hdd/conf/rc.d/rc.mt-daapd, modify it for mt-daapd and start it up:
/share/hdd/conf/rc.d/rc.mt-daapd
A quick check of /var/log/
Play that funky music
Of course the final test is streaming music to your PC. This server will support either Windows or Mac OSX versions of iTunes so whichever version you have, start it up. On the left hand side, in the “source” pane of the iTunes window, you should see a little blue icon with the name of your server as specified in the
If you’ve gotten this far, I shouldn’t have to tell you what to do next. Select the blue icon, see your list of music, choose one and play it! I’ve successfully served music to three wireless laptops simultaneously. This little box has a lot more potential than Linksys gave it credit for!
iTunes in action, courtesy of your modified NSLU2
Up to this point, we’ve limited ourselves to adding new packages to the NSLU2. Next time, prepare to shred your warranty, dig deeper and make some permanent changes. We’ll burn our own flash, giving us a hook to automatically start our new processes. In the meantime, you can follow my adventures on my Linux on the NSLU2 page.
Tip: If you want to skip all this stuff and just want a binary that you can load onto your NSLU2, you can download the 185 kB file from here.