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

See more posts

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

Easy image rollovers

Robin Whittleton

Recently themeforest.net ran a quick tutorial on how to achieve an image slide effect similar to our homepage. I thought I’d go into some more detail about the design decisions we made.

Kyan.com design process

Lee Whitelock

It’s great when you get a project you can really sink your teeth into. We pride ourselves on the effort we put into all our projects, of course, but when it’s for your own agency you can really ‘go to town’ and try new things. Our current website was out…

Web Meet Guildford, join us for a drink

Paul Sturgess

It’s been over a year now since we moved to Guildford and we’re really feeling settled in our new home on the High Street. We’ve got our artwork on the walls, an arcade machine setup and we’ve even hosted a live gig. However, one thing we haven’t done yet is meet our fellow web …