Sound Juicer "Tiredness Fuels Empty Thoughts" 2.20.1

Sound Juicer "Tiredness Fuels Empty Thoughts" 2.20.1 is out. Tarballs are available on burtonini.com, or from the GNOME FTP servers. Hopefully this fixes the common crashes that people are seeing, if it does then I'll backport the fixed to 2.16 so that more distributions can release updated packages.

NP: Aerial, Kate Bush

15:30 Sunday, 14 Oct 2007 [#] [computers/sound-juicer] (2 comments)

Experiments with GUPnP

Now that through black magic, voodoo, and a working network driver I have Avahi working on my NAS and UPnP working on my SoundBridge, I can get back to the task of learning a bit about GUPnP, a GObject-based library for UPnP. My first hack is a simple tool that pops up notification bubbles when the currently playing track changes, and it was surprisingly easy.

First, wecreate a Control Point for the service we want to control. This object will emit signals when devices on the network are discovered which provide this service, so by connecting to that signal all of the discovery is handled for us.

GUPnPContext *context = gupnp_context_new (NULL, NULL, 0, &error);
GUPnPControlPoint *cp = gupnp_control_point_new (context, "urn:schemas-upnp-org:service:AVTransport:1");
g_signal_connect (cp, "service-proxy-available",
                  G_CALLBACK (service_proxy_available_cb), NULL);
gssdp_resource_browser_set_active (GSSDP_RESOURCE_BROWSER (cp), TRUE);

Now in service_proxy_available_cb we are passed a Service Proxy object to which represents a device providing the service we asked for. Service proxies can have actions invoked on them, or we can be notified when a State Variable change. There is a state variable in AVTransport called CurrentTrackMetaData but don't let that fool you: for reasons too boring to detail that doesn't cause notifications. The only interesting state variable in AVTransport is LastChange, which is basically a meta-variable which contains the name and value of the last variable which changed. Madness, I agree. This is where we come to the problem with GUPnP: it makes the protocol seem so clean and simple that when warts like this become obvious, they stand out.

Anyway, we want to listen for changes to the LastChange state variable. This involves adding a notify and then subscribing to the proxy. Luckily state variables emit their current value when we subscribe to them, so we never need to fetch the current value.

static void
service_proxy_available_cb (GUPnPControlPoint *cp, GUPnPServiceProxy *proxy)
{
    gupnp_service_proxy_add_notify (proxy, "LastChange",
                                    G_TYPE_STRING, notify_cb, NULL);
    gupnp_service_proxy_set_subscribed (proxy, TRUE);
}

Believe it or not, we're actually nearly finished. Now to implement notify_cb. This is passed the variable name and a GValue containing the new value. A basic implementation is pretty simple.

static void
notify_cb (GUPnPServiceProxy *proxy,
           const char        *variable,
           GValue            *value,
           gpointer           user_data)
{
    g_print ("%s changed to %s\n", variable, g_value_get_string (value));
}

And we're done! When the program starts it discovers any devices on the network, creates proxies and watches the variables, printing them as they change. Devices can come and go, GUPnP handles that automatically. Easy as pie.

Well, sort of. The string is an XML document which could contain any variable, so we need to parse it looking for a CurrentTrackMetaData node. On that node the val attribute contains an escaped XML document describing the metadata in the (and I kid you not) DIDL-Lite format. The saving grace here is that at least its partially Dublin Core, but that needs to be parsed for the title and artist information. This is all standard XML mojo, and quite boring. The end result is that my first hack application is 150 lines long, the first 100 of which are entirely devoted to XML parsing. The next step is to write a convenience library around DIDL to avoid having to parse it manually. It's not exactly a complicated task, but quite tiresome.

For the curious, the full source is in this Bazaar branch.

NP: Directions EP, Variou (from Acroplane I think)

17:50 Tuesday, 09 Oct 2007 [#] [computers] (0 comments)

Something Ate My Avahi

So the new NAS is happily running Debian now, and I'll write a long blog for anyone who wants to do the same once I have one remaining problem sorted out... Avahi doesn't work. If I start Avahi on the NAS other machines see the announcement and the names it provides will resolve, but after a few minutes they fail to resolve as they timeout. Unless my router is incredibly brain-dead it can't be the cause, because the old NAS is connected in exactly the same way and it works fine. For extra fun, the NAS can't see the rest of the mDNS network. It's almost like the network driver is dropping incoming multicast packets.

Before anyone asks, there is no firewall running on the NAS. Does anyone have any ideas?

NP: Remembranza, Murcof

10:00 Monday, 08 Oct 2007 [#] [computers] (8 comments)

Roku SoundBridge

Yesterday my new NAS arrived, to replace my aging and failing hacked Linkstation. As part of the bundle I also received a Roku SoundBridge, which was a nice surprise. Basically, it's a consumer-orientated device which plays music from iTunes or Internet radio, which you would plug into a hifi or powered speakers. I'd heard of these before but I've been using my old ThinkPad X22 for this duty for a while now, and MPD has served me well. I thought I'd give it a go, and I'm actually really impressed with it.

Physically the SoundBridge is pretty good looking: a sliver and black ten inch cylinder about two inches in diameter, with a large LCD panel on the front. When turned on it found my wireless network, asked for the WEP key, and promptly upgraded its firmware. Once all that was done, it let me select from two libraries: Vicky's Music or Internet Radio. Vicky was running iTunes on her laptop which exports the library over DAAP, so I listened to Tori Amos whilst I explored the Internet Radio options. Then I listened to the most excellent Groove Salad on SomaFM (apparently the #4 station on the Roku Radio charts). At this point I discovered that there was a SoundBridge link in Epiphany, the SoundBridge uses mDNS to publish the web control panel: a useful application of clue from Roku. Then it just got better. The SoundBridge will stream from DAAP and UPnP servers (they pimp mt-daapd and SlimServer), and announces the web interface over mDNS and UPnP. There is a web site which indexes Internet radio streams, currently it has over 5000 entries. This site uses a Java applet (currently only tested in Windows though, I haven't installed Java yet) to talk to your SoundBridge so it can show the currently playing station and tell it to play another station. Then I discovered this in the manual.

Geeks - read this. The M-bridge has a command line interface that you can telnet to for piddling abut. You will need to telnet to port 4444. Type "?" at the command prompt to see a list of commands. ... M-bridge has a built-in UPnP AV "media renderer". This protocol can be used to control the M-bridge from your own software.

The SoundBridge supports both a custom protocol (documented in a 200-page PDF) and the standard UPnP protocol for controlling it. They even documented the signals the remote control uses. This is probably one of the most hackable "consumer" devices I've seen for a long time, short of the N800. Well done Roku, you've created a damn neat product which actually does just work out of the box.

NP: theJazz, Internet radio

11:15 Wednesday, 03 Oct 2007 [#] [life] (11 comments)