Music – now with Google Cast integration

So it’s taken me the better part of two weeks to implement and many months of contemplation, but I finally have a fully-functional Google Cast implementation in the music portion of my home automation system.

Why two weeks?  Much of it was spent doing research.  Most of it was spent spinning my wheels before realizing that a lot of the pieces I’d need to complete the project were already in place.

I don’t recall how much detail I’ve gone into in this blog about the technical details of my web-based music system, so I’ll just summarize.  As far as playback is concerned there are two ways to actually listen to music on my network; either via a SHOUTcast server, or by accessing the music files directly over HTTP. SHOUTcast was the method of choice in the early years of development and eventually it became possible to add transport control functionality to control the SHOUTcast stream.  As a result the entire experience resembled a web-based player and the tunes were on-demand.  But it wasn’t really a web-based player, so the next phase of development was to implement a real web-based player that accessed the music files directly.  And as is the case with all modern web “apps”, that player uses HTML5, Javascript and CSS to work its magic.

So that’s the history.  When implementing Cast I followed much the same path; the first crack was to use the Default Media Receiver and have it stream from SHOUTcast.  This worked – surprisingly – but again the limitations of such a setup (mostly a result of buffering lag) proved onerous.  I deliberated, and researched, and deliberated some more, before deciding that the Cast device had to access the music files directly.  How?  Where to start?  And then it hit me.

IFRAMEs.

I don’t remember what came first; the Internet(tm) or my own “Aha!” moment.  The Internet(tm) said that it was possible to browse arbitrary websites on a Cast device by loading those sites into an IFRAME.  My “Aha!” moment came when I realized that my web player – the HTML5, Javascript and CSS player – used the very technologies that underpin Cast’s receiver “apps” and should therefore be able to run directly on a Cast device.

Put your web app in an IFRAME and by George you have it

Of course there was some “glue” to sort out.  Most important to a Cast implementation is that the receiver app stays resident, otherwise Bad Things(tm) happen.  Well, more like Undesirable Things(tm): the Cast device may go back to its default state, or at the very least your sender will lose connectivity to the (non-existent) receiver.  So I had to code a small receiver and get a little creative on the host side to make sure that the web app and receiver stayed in sync.

But mostly – it just kinda worked.  The web player runs in an IFRAME and the receiver app runs in “top”.  The web player – if left to its own devices – will just trundle through the server’s playlist until there are no more songs to play.  Or, with the correct settings, the player can be controlled from any other device accessing the music system.

How to control your Cast audio player

This is the interesting part.  Obviously you can’t interact with a web app running on a Cast device.  The Cast APIs have a robust messaging system that allows two-way communication between the sender app (which you can interact with) and the receiver app.  This is great, and I imagine it works well for transport control.  But I didn’t use it a great deal for two reasons:

  1. I had already developed a way for a “remote” to control a “renderer” in my music system (see the last couple of paragraphs of this post).  That is, any device – the “remote” – can access the system and see a representation of another device’s web player – the “renderer”.  The remote queues commands on the web server which are subsequently picked up by the renderer, effectively making transport controls available to the remote.
  2. While I appreciate Google’s concept of senders and receivers, my only desire is to have a device load the web player onto a Cast device and then have the Cast device communicate with the web server directly.  I don’t need the sender to maintain connectivity to the receiver.  This mirrors the existing status quo where any device – smartphone, tablet, PC – is just a client to the code running on the server.

I do use the messaging API to setup the receiver app and load the IFRAME.  But once the web app is loaded on the receiver, all messaging goes through my code running on the server.

So ya, add in some housecleaning and Bob’s my uncle.  I even designed a new web player interface specifically for display-capable Cast devices; something that looks a little more presentable on a TV.  The audio-only Cast devices just run the same player that any old smartphone/tablet/PC web browser gets.  I may reduce this to the bare essentials at some point but it’s really not necessary to do so.

I may post some pictures at a later date.  You know, if the adoring masses that frequent this blog demand as much.