HTML5 Video Streaming over WebSockets using Pusher
Using the new getUserMedia it’s possible to send a stream of images over websockets. An experiment with Node.js and Pusher Pipe.
There’s a new feature in the latest Chrome browser’s (Chrome 18 and 19, and Canary 21) called getUserMedia.
It’s still an experimental feature and it’s hidden behind chrome://flags
Enable Media Source API on <video> elements.
It’s a trivial task to grab a screenshot using video and canvas, and it’s also very easy to send
this image over websockets using pusher.
Express.js and Pusher Pipe
We’ll use Express.js and Pusher Pipe. A quick
note on pusher pipe, instead of sending requests using a typical
REST API, using the Pipe we can enable our Node server and the browsers to communicate with Pusher services
The following code is written in Coffescript. We tell our server to render two pages, stream is used
to send a stream of images, and mirror is used to receive the images and display them:
Now we connect to the Pipe. The following code sends to the channel mirror the data received on the channel stream
Note that the urls /stream and /mirror are served with Express, and they respond to the usual http GET
method. The channels ‘stream’ and ‘mirror’ instead are opened with Pusher.
Magic Mirror on the Wall…
Let’s have a look first at the page receiving the stream of images. The user hits /mirror, the server
renders this jade template:
We use the class Player to connect with the websocket and update the <img> with a stream of data:
The idea is to update the src of an img tag with the data sent over websockets, and it’s simply done
by binding the @mirror channel to the frame event.
Meanwhile our Hero…
The /stream page contains the following template:
We use two buttons, one to start the streaming, and one to stop it. The coffescript code is the following:
The getUserMedia is a wrapper around webkitGetUserMedia. We need it because Chrome 18/19 and Chrome 21
have a slightly different syntax.
After the user clicks the button, we start a timer and we refresh the image taken from the video and send
this data to the @channel.
The first problem lies in the way images are encoded, they are Base64 images. Ideally we could send
binary data over a websocket. Pusher also has a rate limit on the number of messages per second.
Can we use websockets for video streaming? Not with this setup, after all it was just an experiment.