<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0" xmlns:admin="http://webns.net/mvcb/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:creativeCommons="http://backend.userland.com/creativeCommonsRssModule" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:html="http://www.w3.org/1999/html" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>Ross Burton</title><link>http://www.burtonini.com/blog</link><description>A potted account of Ross' life</description><language>en</language><ttl>60</ttl><dc:creator>Ross Burton</dc:creator><admin:generatorAgent rdf:resource="http://pyblosxom.sourceforge.net/"/><admin:errorReportsTo rdf:resource="mailto:ross@burtonini.com"/><item><title>Sound Juicer &quot;Tiredness Fuels Empty Thoughts&quot; 2.20.1</title><guid isPermaLink="false">computers/sound-juicer/sj-2.20.1</guid><link>http://www.burtonini.com/blog/computers/sound-juicer/sj-2.20.1</link><description>Sound Juicer &quot;Tiredness Fuels Empty Thoughts&quot; 2.20.1 is out. Tarballs are available on burtonini.com , or from the GNOME FTP ...</description><content:encoded><![CDATA[    <p>
      Sound Juicer "Tiredness Fuels Empty Thoughts" 2.20.1 is out.
      Tarballs are available <a
      href="http://www.burtonini.com/computing/sound-juicer-2.20.1.tar.bz2">on
      <tt>burtonini.com</tt></a>, or from the <a
        href="ftp://ftp.gnome.org/pub/gnome/sources/sound-juicer/2.20/">GNOME
        FTP servers</a>.  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.
    </p>
    <ul>
      <li>Unset temporary iterators after ripping, hopefully fixing a very common crash (#403870).</li>
      <li>Only lock the drive when extracting, and ensure its unlocked when finished. This should fix another common crash (#484535).</li>
      <li>Fix logic bug when creating directories (#481025, thanks William Lachance).</li>
      <li>Reference the initial profile to stop crashing when profiles are edited (#440400, Stefan Röllin)</li>
    </ul>

    <p>
      <small>NP: <cite>Aerial</cite>, Kate Bush</small>
    </p>
]]></content:encoded><category domain="http://www.burtonini.com">/computers/sound-juicer</category><dc:date>2007-10-14T14:30:23Z</dc:date></item><item><title>Experiments with GUPnP</title><guid isPermaLink="false">computers/gupnp-2007-10-09-17-50</guid><link>http://www.burtonini.com/blog/computers/gupnp-2007-10-09-17-50</link><description>Now that through black magic, voodoo, and a working network driver I have Avahi working on my NAS and UPnP ...</description><content:encoded><![CDATA[    <p>
      Now that through black magic, voodoo, and a working network driver I have
      Avahi working on my NAS <em>and</em> UPnP working on my SoundBridge, I can
      get back to the task of learning a bit about <a
      href="http://gupnp.org">GUPnP</a>, 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.
    </p>
    <p>
      First, wecreate a <cite>Control Point</cite> 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.
    </p>
    <pre>GUPnPContext *context = gupnp_context_new (NULL, NULL, 0, &amp;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);</pre>
    <p>
      Now in <tt>service_proxy_available_cb</tt> we are passed a <cite>Service
      Proxy</cite> object to which represents a device providing the service we
      asked for.  Service proxies can have <cite>actions</cite> invoked on them,
      or we can be notified when a <cite>State Variable</cite> change.  There
      is a state variable in AVTransport called <tt>CurrentTrackMetaData</tt>
      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 <tt>LastChange</tt>, 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.
    </p>
    <p>
      Anyway, we want to listen for changes to the <tt>LastChange</tt> 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.
    </p>
    <pre>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);
}</pre>
    <p>
      Believe it or not, we're actually nearly finished.  Now to implement
      <tt>notify_cb</tt>.  This is passed the variable name and a
      <tt>GValue</tt> containing the new value.  A basic implementation is
      pretty simple.
    </p>
<pre>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));
}</pre>
    <p>
      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.
    </p>
    <p>
      Well, sort of.  The string is an XML document which could contain any
      variable, so we need to parse it looking for a
      <tt>CurrentTrackMetaData</tt> node.  On that node the <tt>val</tt>
      attribute contains an escaped XML document describing the metadata in the
      (and I kid you not) <cite>DIDL-Lite</cite> 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.
    </p>
    <p>
      For the curious, the full source is in <a
      href="http://burtonini.com/bzr/tracknotify">this Bazaar branch</a>.
    </p>
    <p>
      <small>NP: <cite>Directions EP</cite>, Variou (from Acroplane I think)</small>
    </p>
]]></content:encoded><category domain="http://www.burtonini.com">/computers</category><dc:date>2007-10-09T16:50:00Z</dc:date></item><item><title>Something Ate My Avahi</title><guid isPermaLink="false">computers/avahi-2007-10-08-10-00</guid><link>http://www.burtonini.com/blog/computers/avahi-2007-10-08-10-00</link><description>So the new NAS is happily running Debian now, and I'll write a long blog for anyone who wants to ...</description><content:encoded><![CDATA[    <p>
      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.
    </p>
    <p>
      Before anyone asks, there is no firewall running on the NAS.  Does anyone
      have any ideas?
    </p>
    <p>
      <small>NP: <cite>Remembranza</cite>, Murcof</small>
    </p>
]]></content:encoded><category domain="http://www.burtonini.com">/computers</category><dc:date>2007-10-08T09:00:00Z</dc:date></item><item><title>Roku SoundBridge</title><guid isPermaLink="false">life/soundbridge-2007-10-03-11-15</guid><link>http://www.burtonini.com/blog/life/soundbridge-2007-10-03-11-15</link><description>Yesterday my new NAS arrived, to replace my aging and failing hacked Linkstation. As part of the bundle I also ...</description><content:encoded><![CDATA[    <p>
      Yesterday my new NAS arrived, to replace my aging and failing hacked
      Linkstation.  As part of the bundle I also received a <a
      href="http://www.rokulabs.co.uk/stores/product_family_view.do?pubID=4409&familyID=72287">Roku
      SoundBridge</a>, 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.
    </p>
    <p>
      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 <a href="http://www.rokuradio.com">web site</a>
      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.
      <em>Then</em> I discovered this in the manual.
    </p>
    <blockquote>
      <p>
        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.
      </p>
    </blockquote>
    <p>
      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.
    </p>
    <p>
      <small>NP: <cite>theJazz</cite>, Internet radio</small>
    </p>
]]></content:encoded><category domain="http://www.burtonini.com">/life</category><dc:date>2007-10-03T10:15:00Z</dc:date></item></channel></rss>