A few weeks ago Google released Chromecast, a device which plugs into the HDMI port of a TV, and can stream content directly to the TV, with controls from either a mobile device or a computer.
The Chromecast device is a powerful tool that utilizes the latest features HTML5 to provide an environment capable of rich media playback. The Chromecast is specifically designed for this task, as evidenced by the great YouTube and Netflix applications that are already available.
The idea is that the Chromecast is a small dedicated computer that is capable of playing media all by itself; it simply needs somebody else to tell it what to play.
There are two pieces to the Chromecast puzzle.
1) The sender application.
The sender application can be written in several languages. The available options are Android, iOS, or JavaScript (running from a Chrome browser with the ChromeCast extension installed). For Android and iOS you’ll include a framework into a native project. For JavaScript you’ll need to add a bit of code to the html node of the page which prompts the ChromeCast extension to inject the required JavaScript methods into the page.
2) The receiver application.
The receiver application is always written is HTML/JavaScript/CSS. A particular javascript file will be included which has the ChromeCast code. Our application, and Google’s samples, are written in AngularJS. The receiver application is hosted by its owner on a web address that is shared with Google. Google will give the developer an application ID which is mapped to this known web address.
Receiver bits.
You’ll need to include the javascript file at https://www.gstatic.com/cast/js/receiver/1.0/cast_receiver.js to get the ChromeCast API methods. Somewhere on your page you’ll want a video tag to display your content. You can add anything else you want to this page. We are using a fancy animated CSS3 loading spinner (among other UI pieces).
After the page has loaded you’ll want to start up ChromeCast by creating, setting up, and starting a Receiver object.
The ChromeCast opens up a socket between the Sender and Receiver applications. Channels can be created on the socket to send messages back and forth between the two applications. The default media player uses a RAMP channel to communicate media messages. I haven’t been able to piggyback onto the default RAMP channel yet. Our application creates a new channel and sends messages there.
Creating a custom channel is fairly straightforward. You create a ‘protocol’ which is really just a string value. Both the receiver and sender then open a channel using the protocol value then they can send messages with data over the channel.
After the receiver starts up and the channels are configured, the application will just wait for the sender to say what media to play. Once the sender has provided that information the receiver application needs to load the media into the video element.
Sender bits.
For an HTML sender, the html node has to have the data-cast-api-enabled attribute added and set to true. This prompts the Chrome ChromeCast extension to inject the JavaScript for the API into the page.
After the page has loaded the sender needs to create an instance of the ChromeCast API and ask what ChromeCast devices are on the network. When asking for available ChromeCast devices you need to provide the application id that your sender wants the device to load.
When looking for devices the Google servers are going to verify that the ChromeCast devices on the network are eligible to load the requested application. At the moment this means that your device must be whitelisted for that app id on the Google server.
After all known devices are collected, the Cast API sends out an event for the sender to catch. The list needs to be presented to the user so that they can select which device to cast to.
After the device has been chosen, the application is launched on the device by sending a LaunchRequest to the api’s launch() method. The LaunchRequest contains the app id and the desired device. This will tell the device to ask google what the URL is that corresponds to the app id, and then that URL is loaded by the device. The pipes between the sender and receiver are then opened.
At this point the sender simply needs to send messages to the receiver and listen for messages from the receiver.
DASH bits.
For those that don’t know, MPEG-DASH is a fragmented HTTP streaming protocol. This means that a single video file is divided into many discrete chunks of video/audio data. These media fragments are then loaded as needed by the player and fed directly into a video buffer.
The fragments can be fed to the buffers using the HTML5 MediaSource Extensions (MSE). The MSE implementation on the Chromecast is very close, if not identical, to the implementation on desktop Chrome. In fact, the MSE implementation on the Chromecast is likely more advanced as it also supports Smooth Streaming and various DRM protocols that desktop Chrome does not.
Luckily we already had a DASH player written in JavaScript (dash.js). It was ported with zero code changes to the Chromecast and it generally plays really well. It looks like there are some potential bottlenecks with the processing power of the device as evidenced by streams stuttering more often on the Chromecast than on the desktop. Also, it appears that desktop Chrome has more robust codec support.
You can debug the ChromeCast device by going to a Chrome browser and navigating to :9222. This will open a page with a link to the running application. Click on it and you’ll see Chrome debug tools. You can do pretty much everything you can normally with the Chrome debug tools, including seeing full console output and using breakpoints.
You can see this running on your own Chromecast as long as you have Chrome with the Chromecast extensions installed.
The relavent urls are:
Dash.JS receiver – www.digitalprimates.net/dash/chromecast/index.html
Dash.JS sender – http://www.digitalprimates.net/dash/chromecast/sender/index.html
Some useful references are here:
Developer guide – https://developers.google.com/cast/
Google examples – https://github.com/googlecast
Thanks to Nathan who wrote most of this article.