Write a Chromecast App In 3 Easy Steps

Today I would like to share how anyone can create a Chromecast app.

Requirements

For this tutorial, you’ll need:

Fundamentals of Chromecast

The Chromecast is basically a Chrome browser. So Chromecast apps are just websites. These websites are hosted somewhere on the internet on a server.

The app that runs on the Chromecast is called the receiver app – it receives commands and content. Then there are the sender applications. These are the ones that everyone knows best: Android and iOS apps as well as websites that allow to start something on a Chromecast (e.g. Spotify, YouTube, etc.).

There is one built-in Chromecast app, the [Default Media Receiver]. It’s the most basic application and allows sender applications to stream music and videos. It does not allow to be customized, not even a little. But the developer does not need to host a retriever application of his own on the internet.

Then there is the Styled Media Receiver app. It is hosted on Google servers and – as far as I understood – it is basically the same as the Default Media Receiver app. There is one important difference though: You, as developer, can provide a CSS to apply some styling to the Styled Media Receiver app.

But I wanted to build a Custom Receiver instead of using either of these apps, so this is what I will show you below. Custom Receiver apps are the most flexible option. They give allow us as developers almost full control. But there isn’t a lot to build upon either.

Communication

(In this example, the receiver Chromecast app will be launched from a website. Therefore the explanations are limited to this case.)

The communication flow to the Chromecast begins on the sender app. When the user clicks on the Chromecast button in the sender app, Chrome (the browser) will provide a list of all Chromecast (-compatible) devices it has discovered on the network. The user must select to which Chromecast a connection should get established. Chrome will then initiate the connection to the Chromecast and tell it an Application ID. Using this ID the Chromecast connects to Google’s server to determine the URL of the custom retriever app. This URL is used by the Chromecast device to load the receiver application from the respective webserver.

There will also be a permanent socket connection from Chrome to the Chromecast. This connection allows the sender application to transfer arbitrary commands to the receiver application. It also work vice-versa, i.e. to transmit messages from the receiver application on the Chromecast back to the sender application in Chrome.

Step 1: Make a Chromecast App

The first thing I’ll show you is what is required to create a basic Chromecast app.

As this demo application is static I decided to host it on Gitlab Pages.

Therefore I created a new repository at Gitlab. Then I cloned the repository to my computer and opened the folder in a text editor (I currently prefer Visual Studio Code).

cd ~/projects
git clone [email protected]:username/project-name.git
code .

The first file I created was a .gitlab-ci.yml file in the root of the git repository:

image: alpine:latest

pages:
  stage: deploy
  script:
  - echo 'Nothing to do...'
  artifacts:
    paths:
    - public
  only:
  - master

This file simply collects all files in the public folder. Gitlab will then publish everything in that public folder as a Gitlab Page.

Therefore I created a new folder called public. And to this folder I added two files: index.html and start.html.

The index.html file will be the receiver app. This means that this is the code that will be loaded and executed on the Chromecast device. I added the following code to the index.html file:

<html>
<head>
  <script type="text/javascript"
      src="//www.gstatic.com/cast/sdk/libs/caf_receiver/v3/cast_receiver_framework.js">
  </script>
</head>
<body style="color: white">
  <div>Hello World</div>
  <div id="message"></div>
  <script>
    const context = cast.framework.CastReceiverContext.getInstance();
    context.addCustomMessageListener('urn:x-cast:ch.cimnine.cromecast-test.text', function (customEvent) {
      if (customEvent.data.type == "message") {
        document.getElementById("message").innerHTML = customEvent.data.text;
      }
    });
    context.start();
  </script>
</body>
</html>

The other file, start.html, is the sender application. It contains the following code:

<html>
<head>
  <title>Start</title>
  <script src="https://www.gstatic.com/cv/js/sender/v1/cast_sender.js?loadCastFramework=1"></script>
</head>
<body>
  <google-cast-launcher></google-cast-launcher>
  <script>
  initializeCastApi = function() {
    cast.framework.CastContext.getInstance().setOptions({
      receiverApplicationId: 'XXXXXXX',
      autoJoinPolicy: chrome.cast.AutoJoinPolicy.ORIGIN_SCOPED
    });
  };

  window['__onGCastApiAvailable'] = function(isAvailable) {
    if (isAvailable) {
      initializeCastApi();
    }
  };

  function send() {
    var textEl = document.getElementById("text");
    sendText(textEl.value);
  }

  function sendText(txt) {
    var castSession = cast.framework.CastContext.getInstance().getCurrentSession();
    if (castSession) {
      castSession.sendMessage('urn:x-cast:ch.cimnine.cromecast-test.text', {
        type: "message",
        text: txt
      });
    }
  }
  </script>
</body>
</html>

Notice the this line in the code above:

receiverApplicationId: 'XXXXXXX',

Since our application ID is not known yet, we’ll put this placeholder value instead.

Go ahead and commit all files and push them to Gitlab:

git add .gitlab-ci.yml public/index.html public/start.html
git commit -m "Proof Of Concept"
git push

The final action of this first step was to change a configuration option in my Gitlab repository: I went to my Gitlab repository, then I chose Settings on the left. Now, in the General section, I clicked on the Expand button, which is next to Visibility, project features, permissions.

Where it says Pages I changed the value in the dropdown from Only Project Members to Everyone. This makes the Gitlab Page accessible to anyone who knows the URL.

For the next step it is required to know the URL to the Gitlab Page. I found the URL under Settings in the section Pages. Generally, it should be along the lines of https://username.gitlab.io/project-name. This URL is important in the next step, so I suggest to copy it to the clipboard.

It will take a few minutes for Gitlab to publish the page for the first time.

Step 2: Register a Chrome App

Before I was able to test the Chrome app from above, I had to register it with Google. Using my Google account I had registered at https://cast.google.com/publish and payed USD 5 with my credit card. (I used my TransferWise credit card because I’m not US-citizen and the currency-fees are way lower than those of my regular credit card.)

After I got access, I created a new Custom Receiver app. I chose a good name and I pasted the url to the Gitlab page. (Again: The url is along the lines of https://username.gitlab.io/project-name.)

After my app was registered I received an application ID. This application ID is important in the next step, so I suggest to copy it to the clipboard.

I then had to register my Chromecast as test device. This requires to enter the serial number of the Chromecast device, which is usually printed on the back of the Chromecast (and also on the Chromecast’s original box, should you still have it). Google says this will take up to 15 minutes, but mine was already working after a few minutes.

Just don’t forget to restart the Chromecast after you registered it!

Step 3: Test the Application

Since I now had my Chromecast application ID I was able to replace the XXXXXXX with the actual ID in the start.html code.

    cast.framework.CastContext.getInstance().setOptions({
      receiverApplicationId: '1234ABCD',
      autoJoinPolicy: chrome.cast.AutoJoinPolicy.ORIGIN_SCOPED
    });

Now I had to push that updated code to Gitlab:

git add public/start.html
git commit -m "Actual application ID"
git push

It took Gitlab about a minute or two to publish the change. Then I started Chrome and I went to the Gitlab page: https://username.gitlab.io/project-name/start.html

I was shown a huge Chromecast button. When I clicked it, Chrome offered me a list of Chromecasts on my network and I chose the Chromecast which I just registered as test device. When I looked at my TV I was greeted with a black screen and a tiny Hello World in white letters on the top-left corner of my screen.

This example application also contains code to send messages from the sender app to the retriever app. Just write some text in the text box and click Send Text. The text should appear instantly on your TV’s screen, just below the Hello World text.

Debugging

When I first tested the application, I was greeted with a black screen. I did not know that the default CSS was a black background with black text. So I had no idea what was going on on the Chromecast.

Therefore I was looking for how to debug my application on the Chromecast. It turned out that this is pretty easy:

While my Chromecast app was running, I opened a new tab in Chrome and typed chrome://inspect. This page allows to open the remote inspector in Chrome. Which means: I was able to use the regular web developer tools of Chrome, but to inspect, debug and modify the application on my Chromecast. So cool!