Robin Whittleton

Behind our jukebox

If you take on Kyan as a client you’ll soon be aware that we love our music in the office.

We used to use a 3rd party music player, but decided a few years ago to build our own; this gives you a lot more flexibility in exactly how it works.

The interface to our jukebox, showing the controls, status and playlist.

The basics

At the most basic, the jukebox is comprised of everyone’s music shared in from their machines, a command line player called MPD hooked up to an amp and speakers, and a Rails app that controls music selection. On top of that we’ve added a bunch of extras: last.fm scrobbling for our account, stats on everything, voting on tracks and lots more.

Where it gets interesting

Fairly soon after building our initial implementation we ran into scaling problems. Think about it: a jukebox doesn’t just display what track is currently playing, but also the state of the entire interface including the volume and (problematically) the current state of play of the track. It’s this last one that caused us issues as each client was polling the jukebox every second to update its interface. That meant that an average of twenty-five clients were putting 90,000 hits an hour onto the little Dell the system was running on. We needed a better solution.

Luckily, at about that time one presented itself: WebSockets. Simply put, this tech lets the server push out updates to the client rather than the client request them. On top of that, as the server knows its own state, it only needs to push out updates when that state changes. Finally, we changed the ‘current track time’ to increment automatically on the client and sync up only when another part of the system state changes.

WebSockets haven’t been flawless: the spec has changed several times and they got removed from browsers entirely for a period due to a security hole in the spec. When they work though they work exceptionally well. So let’s have a look at how they work in our system:

var conn, uri = "ws://jukebox:8080";
if ("WebSocket" in window) {
  conn = new WebSocket(uri);
} else if ("MozWebSocket" in window) {
  conn = new MozWebSocket(uri);
}

Unfortunately WebSockets are still a prefixed interface in Firefox. This changes in Firefox 11 so we’ll remove the check at some point after that (the benefits of a limited audience!). This code simply tries to create a new WebSocket connection to the jukebox server. We then bind a listener to the socket:

conn.onmessage = function(msg){ 
  var data = JSON.parse(msg.data);
  for (var key in data) {
    switch(key) {
      case "state":
        updatePlayPauseButton(data[key]);
        break;
      case "time":
        updateCurrentTime(data[key]);
        break;
      case "rating":
        updateRating(data[key]);
        break;
      case "track_added":
        addStatusUpdate(data[key]);
        break;
      case "raters":
        setVotedState(data[key]);
        break;
      case "track": // The track has changed
        updateCurrentSong(data[key]);
        break;
      case "playlist": // Track added or removed
        updatePlaylist(data[key]);
        break;
      case "volume":
        volume.slider({value: data[key]});
        break;
      case "refresh":
        window.location.reload(true); // force the browser to reload the page from the server (not from cache)
        break;
      default: console.error('Unrecognised action: '+key);
    }
  }
}

Every time we intercept a JSON message from the server we parse it into an object, then look over it for data to apply to our interface. Not every update contains every key but that’s not a problem: we just update with the data we get from the server.

From the server’s point of view there are two parts to the puzzle. For the first (the actual WebSocket server) we used the em-websocket gem which leverages eventmachine for an asynchronous socket server. Behind that we built a status dispatcher that monitors the system for state changes, bundles them up every second, builds a JSON object out of them, and passes them over to the WebSocket server to be distributed.

This is remarkably elegant in practise and makes for a very responsive application interface, whilst massively reducing overall load! Of course, there’s a downside: no WebSockets in IE (until 10) or Opera (yet). It’s only a matter of time until support lands though.

The real benefits

Due to the predominance of up-to-date browsers in the office, we can use internal systems as a testbed for new technologies before we get a chance to implement them on client projects. The jukebox has turned out to be a fantastic system to try out new stuff on. WebSockets is only the start of it: the system was HTML5 before anything else we did and has given us valuable insights into CSS3 specifications such as webfonts and gradients.

Every front-end developer needs some way to play around with upcoming specifications and having a project that is used by multiple people every day is a great way to push yourself and hone your skills.

Tags: rails, javascript, jukebox

Comments: 4

lawrence
commented on

i have to say i love the sensitive use of fonts on your website, alternate gothic,avenirs etc nice

Bernardo
commented on

Fancy jukebox! I didn't know that a musicplayer like that existed, i'm gonna check it out :D

You guys are awsome! ^^

ali stone
commented on

any chance you can make this available for other agencies, this is exactly what we need and it looks great!!!

Gavin
commented on

Hi Ali, we did consider making the project Open Source but currently it's a bit too raw and we thought it might cause people more issues than it solved ... However if you think you're tech dept is up to the challenge then send us a DM or mail to info [at] kyan and we'll see if we can hook you up.

Add a comment

Note: comments are moderated before publication.

Most Popular

Now residing at 171 High Street, Guildford

Peter Roome

NEW ADDRESS: Kyanmedia, Guildford, 171 High Street, Guildford, Surrey, GU1 3AJ Yes thats right, we have made the big move, a week earlier than the scheduled 24th July. The impromptu decision was made mid morning Friday (17th July, 2009) after discovering, Smithbrook was…

"DO NOT EAT" THROW AWAY

Steven Wake

I have the driest draw here at Kyan towers. You see, I am the proud owner of a Silica Gel collection. There is just something about them which compels me to not throw away the little fellas.

Is imitation really the sincerest form of flattery?

Piers Palmer

A new site has appeared on the wonderful inter-tubes, brought to us by a web design firm in Minnesota – Rocket 55 – that looks remarkably similar to ours. As designers we all stand on the shoulders of giants, borrowing ideas and concepts, using the same typefaces, co…

Web Meet Guildford is back

Paul Sturgess

After the resounding success of the first Web Meet Guildford (WMG) we’re excited to announce that we’ll be hosting another meetup later this month. So if you make websites and you live or work in the Guildford area, please do join us in the 3 Pigeon’s pub on Guildford High Stree…