WebRTC DataChannels or: How I Learned To Stop Worrying And Flap My Arms

I had an idea. A stupid idea.

Screenshot 2014-03-07 10.16.50I had discovered that mobile browsers have JavaScript APIs for accessing accelerometer and gyroscope data and wanted to play around with the concept – I hadn’t seen them used in many places. So naturally my thoughts turned to creating a version of Flappy Bird where you paired your phone and computer together, then used the phone as a Wii-like controller to flap your arms.

Now, hear me out – it made sense. Sort of. After the meteoric rise and disappearance of Flappy Bird there were dozens of open-sourced clones out there. And a ‘flapping’ motion seemed like it would be relatively simple to detect. But there was a problem. How do I pair the computer and phone together? My first thought was to use WebSockets – so off I went. One npm install later I had socket.io installed on a server. Pretty quickly I had a system set up where the ‘host’ (that is, the big-screen device) is assigned a random number, and the ‘client’ (phone) prompts the use to enter it. Then it just takes a simple chunk of code to get them talking:

So far, pretty simple. Try it out! …and get very, very frustrated very quickly.

The latency is too damn high

You flap your arms. Anything up a second later the bird might do the same. So, why is it so slow? This is where WebSockets shows its weakness – it still relies on a central server to post messages between clients. And that central server is in Amazon’s data centre in Northern Virginia. Even from my desk in New York, the route there isn’t exactly simple:

doneI dread to think what it’s like in Europe. A better solution was needed. I started googling “peer to peer websockets” and discovered a Stack Overflow question that led me in the direction of WebRTC.

But WebRTC is for webcams

I’d read about WebRTC before, in the context of replacing Flash and Skype for video chats. In my ill-informed way, that’s what I thought the “communication” part in “real time communication” meant. But no – it also has a capability called DataChannels, which are exactly what they sound like: peer to peer data connections. You can do a variety of things with themĀ  like share files or instant message, but let’s focus on the very important goal of making this arm flapping game more responsive.

“Marco”

So, a utopian server-less future? Unfortunately not. WebRTC’s peer to peer communication can do many things – but find other peers is not among them. So we still need a server to match client with server – just like we’re doing with WebSockets.

For this, I turned to PeerJS – a combination of node-powered server and client-side JS library that wraps around WebRTC functions. So, at this point I have both socket.io and PeerJS running on my server, and socket.io and PeerJS client libraries on the client. Feels like a waste. So we should get rid of socket.io now, right?

“Polo”

Wrong. For two reasons:

  1. WebRTC DataChannel browser support is not great. Especially on mobile – Apple deserves a lot of shaming for not supporting WebRTC at all.
  2. Peer to peer connections are tricky. Maybe you’re behind a firewall, or maybe there’s a NAT in the way. With WebRTC you can use a TURN server as a proxy between two clients, but in our case we’re already doing that with WebSockets.

So, we’ll keep WebSockets as a backup. Negotiate the pairing with WebSockets, then ‘elevate’ to WebRTC if both clients are capable and accessible – as demonstrated in this pretty awful set of diagrams:

There’s an added benefit here: the server is only used to create connections. Once that’s done, the clients disconnect, freeing up server resources for other players. If at any point in that process the WebRTC route fails, we just keep WebSockets open and communicate through that.

Our simplified code is only slightly more complex:

So, try it out. I think you’ll prefer it. Faster reactions, fewer server resources used, happier users. Unless they’re using an iPhone, of course.

Postscript: The Source Code

If you want to take a peek under the hood at FlappyArms, all the code is on GitHub. It’s really messy for the time being (being a two-day hack project and all), but I’m still adding features to it, and I hope to get it tidied up along the way.