Friday, June 30, 2006

I Need More Heavy Fuel

I thought I didn't have much to report tonight, but upon reflection it seems that I might have been wrong. I found (and fixed) the problem with ogg playback that caused it to play the same song over and over. Then I thought I had a problem when the first file in an album was an ogg file, but it turned out that mt-daapd was having database problems and could no longer find that particular file. Forcing it to update its database entry for that song ("Dire Straits - Calling Elvis") allowed the song to play again. The tip-off was when I logged into the wmaa11b and ran wmamp myself: whenever I tried to play this song it received a 404 from mt-daapd, but the file was clearly present in the directory on the server.

My other small accomplishment for the evening was fixing the basic playback functions. My earlier builds would not pause, stop, back up a track or skip ahead a track. That's working now, which is pretty sweet. I let them wma11b run for a while, playing The Cars Greatest Hits album. I wasn't really paying attention to the music, and then I noticed that it seemed to be playing the last song over and over. And it does. Once the list is complete it just keeps playing the last song. I figured this was probably another bug I'd introduced, but the wmamp 0.6 image that I have does the same thing. I would have expected the playlist to loop, or for play to simply end when the list was exhausted, but neither happens. I wonder what the right behaviour is...

I think I have learned why libopendaap isn't being used by wmamp (a question I was pondering in yesterday's entry): it's more than a little tricky to use, and the memory profile may not fit very well with the wma11b. When you make a song request with libopendaap it writes the data to a file descriptor. The fd could be a file, but the recommendation is to use a pipe. This is a cool idea - threads in libopendaap are pulling all the data over the network and all the playback thread has to do is take as much data as it needs from the pipe. The problem is that libopendaap will almost certainly pull megabytes of data in long before (in processor time) it is needed. The wma11b has only 16MB, and a lot of that is already being used by the kernel, the root filesystem and the application file system. This does not leave a lot for applications to run in. I seem to recall reading somewhere that after everything is loaded there's only 5-6MB available for application use. An entire mp3 buffered in memory suddenly means there's nothing available for the application to use any more. wmamp uses more of a just-in-time principle - the data is pulled over the network just before its needed, and it seems to work pretty well. What I do think is worthwhile is to replace Apple's mDNSResponder software with the mdnsd the libopendaap is using. I believe that will be my project for tomorrow night.

Labels:

Thursday, June 29, 2006

wmamp: ogg and mp3 work again

It took about 30 minutes of poking around tonight and I had mp3s playing again, and then probably another 30 minutes and ogg was working. It turns out that my ogg problems had to do with the fact that mt-daapd was sending me ogg files as Content-Type "audio/ogg" but wmamp was expecting "application/ogg". A quick compile and ogg works. What I'm seeing now is that it keeps playing the same song over and over, rather than progressing to the next song in the album, so I expect I've broken something else.

I made another discovery today - apparently I've never needed libopendaap - some code was lifted from the project to allow wmamp to authentication to iTunes, but that's it. Looking at the code now, I'm not sure why wmamp doesn't just use libopendaap - it has more features (like supporting playlists), and it uses an mDNS client that's designed for embedded systems.

And speaking of embedded systems, the wmamp image includes telnetd so that you can log in to the wma11b and do stuff (like killing and restarting wmamp so you can watch all the debug output it dumps to stderr). I spent a little time poking around the filesystem, and I noticed that the root filesystem contains a copy of uClibc - an implementation of the standard libc that's designed to be small (for, say, embedded systems like this). At less than 200kB it may not contain everything I'd like, but the concept is solid. Conversely, the image that Linksys provides to download contains a version of glibc that's over 3MB. I don't even know how they got it that big - the one I have is only about 1.1MB. But why have two different versions of libc at all? The only thing I can think of is that they needed a libc to boot, but glibc wouldn't fit, so they had to use uClibc. For the main application though, it was probably easier to develop with glibc, and so they took the hit. I'm sure a lot more RAM could be freed for application use if we were using uClibc instead. I'm hoping to be able to pursue this, but the disk requirements might exceed what I have here (have I mentioned that I'm doing all my development on a 200MHz Pentium machine with 32MB of RAM and about 8GB of disk space?). Hope springs eternal - maybe I can make it fit. Then I just have to coerce all the stuff I've already cross-compiled into building again against uClibc. Yeah, that's all.

Labels:

Wednesday, June 28, 2006

Mind Meld Part III: the Return of the Ogg

(Okay, that is the last of my lame attempts at clever titles.)

Yet another milestone has been reached: I was able to build a downloadable image containing the copy of wmamp 0.6 that I compiled myself and the darn thing ran. So at the very least I know I can build something that works.

Adding (or rather, re-adding) ogg Vorbis support is quite another story. James Pitts originally wrote wmamp (thank you, James!), and then Steve comes along and adds support for ogg vorbis files. According to Steve's blog, he pushed his ogg patches back to the maintainers of wmamp (whoever they were at the time, maybe James, or maybe these guys) and daapd. The funny thing is that none of the later versions of daapd or wmamp have this work, but the reasons are probably lost in the mists of last year. The work on daapd is moot for me since I have mt-daapd running, and it already has support for sending ogg files (if you explicitly enable it with --enable-oggvorbis, which I had not, so I had to rebuild it again last night). The changes to wmamp are still very relevant to me though, and so I figured I'd take a stab at merging them forward. Steve's patch applies cleanly to the wmamp-0.4 sources, so I created two versions: wmaamp-0.4-canon (canonical) and wmamp-0.4-ogg (with Steve's patch applied). Then I created two versions of wmamp-0.6 with the same names. Then comes the really hairy part: compare the differences between the two 0.4 source files (should only be the ogg changes) and try to make the same changes to the wmamp-0.6-ogg sources. I had to do it this way because the source for 0.6 has changed significantly from 0.4. There has been a lot of restructuring of the code, and most of the chunks of Steve's patch would not apply at all to 0.6 (some of the files are no longer there).

Oh yeah, I had to cross-compile Tremor too, but thankfully the xiph people had everything already set up so this was completely uneventful.

In an effort to make sure I was on the right path, I built an image using vorbis-0.4-ogg and downloaded it to the WMA11b, but it would segfault after selecting a DAAP server. I wasn't ready to give up yet though, so I got wmamp-0.6-ogg to compile and built an image with that. It does better then the 0.4 version - it dies only when I try to start playing a song. So that kinda blows, but it's still better then 0.4, and I have some idea of what is wrong. It probably didn't help that it was rather late in the evening when I was doing my merges and such, and so I expect that I made more than a couple of mistakes.

I can't believe all that I've been able to do in a couple of evenings. This is exactly why I love programming. More precisely, it's why I love programming with Free Software (or Open Source, if you prefer). I am starting to make this device my own. One day soon, I will grok the fullness of it.

Labels:

Monday, June 26, 2006

Mind Meld Part II - The Clienting

Woo hoo! wmamp builds! This is no small accomplishment. wmamp requires FreeType2, libhttpd, libid3tag, libmad, libopendaap and zlib just for starters, and they have to be cross-compiled for ARM. Oh yeah, about cross-compiling - there's this great Debian sub-project called emDebian that
has an apt repository with pre-built cross-compilers and a few libraries (like libc) to link against. Very handy indeed.

Luckily most of the aforementioned libraries cross-compile pretty easily, with the exception of freetype - it creates a program (apinames) to run that extracts data from the .o files, but apinames also gets cross-compiled and so it won't run and the build fails. Thankfully apinames is only a single source file, so it was a simple matter to compile it manually (and natively), copy the binary where it was needed and then run "make" again.

wmamp needs one more library - mDNSResponder from Apple. wmamp was built against version 58.8, but good luck finding it. The original author of wmamp - James Pitts - has archived a version here. What I don't understand yet is why this is necessary - libopendaap builds and uses another multicast-DNS library mdnsd, and so it seems that wmamp, if it needs direct access to an mdns API should be able to use that instead. I'm sure there's some duplication of functionality here that could be trimmed. mDNSResponder, BTW, cross-compiles just fine.

With all these libraries built and installed, it's time to build wmamp itself, and that's when things go wrong yet again - emDebian installed kernel headers for 2.6, but the WMA11b runs a 2.4 kernel, and at least one header file - fb.h - has changed in a way that is incompatible with wmamp. The solution is to unpack all the stuff Linksys provides here (warning, zipped tarball of truly unholy size), install it and create a local symlink to the kernel headers Linksys provides. All of this might not be strictly necessary, but until I know just how many changes were made to the standard 2.4.17 kernel for the WMA11b this was the safest and most expedient route to a successful compile.

And that's that. I still have to build a disk image with my wmamp to be sure what I've compiled runs, but a clean build is 90% of the work, IMHO.

In my first WMA11b post I neglected to mention a couple of things. First, turthalion was the guy who put me on to the WMA11b in the first place when he got one back in January, and when I told him about my weekend he kindly linked back to me, and then proceeded to (rightly) berate me for not providing the explicit commands to start and stop the Windows(TM) services that I had mentioned. I don't know why, but a lot of sites tell you to stop and then restart these services "and if you don't know how, then just reboot". No one seems to want to reveal the dark secrets of the "net" command for whatever reason. Well screw that. If you want to stop the services, use these commands:

net stop XWPCHostService
net stop XWPCApplicationLoaderService

To start them up again, use:

net start XWPCApplicationLoaderService
net start XWPCHostService

Stay tuned for Part III - adding ogg vorbis support (well, that and creating an image I can actually load onto the WMA11b).

Labels:

Sunday, June 25, 2006

Mind Meld

The better half is away for a while, and my WMA11b just showed up, so I figure I have a golden opportunity for some serious hacking. Out-of-the-box it's already pretty sweet - you fire it up and do a little configuration (stupidly, it defaults to a static IP address), attach it to your stereo system and install some software on your Windows(TM) PC and you're ready to listen to music (or look at pictures). The software on the WMA11b itself isn't bad, it looks good and the controls are sensible. The other software though, to be blunt, sucks.

Two Windows "services" are started on your machine, but they don't actually show up in the usual place. You have to know to use "net stop" and "net start" if you need to stop or start these without rebooting - that's just sad. I can't figure out if they were lazy or just didn't want people messing with them. Maybe stopping and starting them a lot causes problems over time or something. Also, some part of the software required the ".Net Framework". Now I already had ".Net Framework 2.0" installed for some other reason that escapes me just now, but the installer insists on installing ".Net Framework 1.0" (not even 1.1!) anyway. Who knows what kind of problems that's going to cause in the future.

But back to hacking. The most basic thing people do is to replace the "player" software. The WMA11b loads the player every time it starts up, so if you know what you are doing you can load all kinds of things on there. The most popular player is wmamp, which is also open source. The neat thing about it (vs. the standard software) is that it uses the iTunes DAAP protocol and can see any and all iTunes servers on your LAN. Even better, there are open source implementations of DAAP for use on Linux et al. Getting them up and running is another issue.

This guy recommends daapd but it requires howl which is no longer under development. The howl guys mentioned avahi which has a howl-compatibility layer, but as it turns out there is another DAAP server mt-daapd which already has patches to use avahi natively, so I figured I'd check that out. I downloaded the sources for avahi and mt-daapd, and dropped into dependency hell.

Back in the days when I first got into Linux I installed Debian because a) I was technically savvy and b) it had a reputation of being the hardest to install. I figured if I managed to get it installed I would have already learned a lot about Linux, and I was right. But more to the point, I've stuck with Debian for all these years because it has always worked well for me and the package management rocks. Debian also has a reputation for being a little (or a lot) behind the times when it comes to its packages. When I installed apache a couple of months ago I got Apache 1.3. Well, avahi needed some libraries that were newer than I had installed. Debian has an avahi package, but it's in testing/unstable (ie. will be in the next stable release). I decided to take a chance and upgrade to "testing" and grab the canned avahi rather than try to build it myself. As it turns out, this was probably the easiest part of the whole process. The upgrade went perfectly smoothly, but avahi wouldn't run. I kept getting an error telling me avahi wasn't allowed to open the socket it was trying to open. It took a long time, but I finally figured out that my "old" kernel - 2.4.18 - only allowed very privileged processes to open such a socket, and avahi was not built with such privileges. It took a while, but I was able to upgrade the kernel to 2.4.32, and avahi started the first time I successfully booted the new kernel. Cool!

mt-daapd needed to be patched (link found on avahi's site), and the patch applied cleanly, but it couldn't quite build. The new source file that allows mt-daapd to use avahi wasn't being compiled or linked into the source. A quick hack of the makefile and I had a working (well, running) iTunes server.

From the same page as the daapd recommendation comes a program called wmaloader that allows the player software - Linksys suppied or other - to be loaded from a linux box too. wmamp is no longer under development by the original author, but these folks have been doing a lot of good work. I grabbed the latest wmamp image from them and used wmaloader to get it installed. Success! Not only is the new software installed, but I can see mt-daapd, and I can see the iTunes server on the Windows(TM) machine.

So I consider phase one complete. The server-end software appears to be pretty mature, so I expect there's little work to be done there. Stay tuned for phase two - building wmamp.

Labels: