Users want to be able to view your video content on any device they choose, whether it’s the 65” TV in their living room the 20” monitor in their office or the 5” phone in their pocket.  Your goal as a developer is to get your users to use your web app as often as possible.  So, you’ve got the phone and laptop experience covered, but the other viewing formats are difficult or time consuming.

The <cast-*> polymer elements and this codelab are here to help.  

Creating a UX compliant cast sender integration can be an involved task.  There’s lot of syncing between the local video, casting video, queues and multiple senders.  The <cast-*> Polymer elements handles the complexity allowing you to focus on development of your app.

First let’s go over a demo of what we’ll create and the cast elements we offer.

Goal

Here’s what we’re going to create through this codelab.  It’s a fully UX compliant web video experience.  The user can control the locally playing video, manage a queue of videos and cast content.

 

Element breakdown

We’ll be leveraging several elements to create this demo:

The elements take a MVC approach, with cast-manager handling the logic between cast and the local video.  cast-video, cast-controller-bar, and cast-dialog are views which render the state and fire events to interact with the manager.

cast-manager

The cast-manager element is the controller of this MVC model.  It handles initializing cast, managing the queue, syncing between the sender and cast receiver, events and much more.  It also imports the media-item and queue-manager objects which represent each local media item and the local queue respectively.  It exposes a number of properties for the child elements to bind to or observe.

cast-manager should be the parent element that all wraps all of the elements which use its properties.

cast-video

The cast-video element defines the video element on the page.  It currently plays any HTML5 video format supported by the browser, and may support additional formats in the near future.

The cast-video element scales dynamically, so you can modify the size based on your needs.   It listens for iron events fired by cast-manager such as play, seek, pause, volume then forwards those requests to the contained video element.  It also updates the properties currentTime and localMedia, which are two way bound to cast-manager.

cast-controller-bar

The cast-controller-bar enables users to continue controlling the casting content outside of the video player controls.  This is useful when a user is casting but moves to a different page or video on your site.

If you enable queues, it will also show the current queue and allow you to control it.

The cast-controller-bar automatically transitions from hidden to minimized to maximized based on the current scrollTop of the scrolling element and casting state.

cast-dialog

The cast-dialog element notifies users that the site supports casting.  It also serves as a dialog to notify users of the next queued video and the time until that video starts.

cast-theme

cast-theme isn’t an element, but rather a stylesheet that’s included in most of the elements.  It defines the colors, fonts, and transitions to use in the app.  With it you can quickly and easily update the look and feel of multiple elements.

In this step, we’ll set up the environment.

Prerequisites

Clone the starter repo

git clone https://github.com/googlecodelabs/cast-polymer-codelab.git

The starter repo includes CSS, video data and elements.  It’ll be the foundation that we build upon.  If you need any points of reference, the repository branches serve as checkpoints for each step with branch cast-controller-bar-polymer-complete as the completed codelab sample.  You can view the source files for each branch on either github or by git stash-ing your changes and changing branches with git checkout [branch].  You can also check the difference between your current file and a branch using git diff master..[branch].

Setup dependencies

In the project’s directory, use bower to sync dependencies and install the cast polymer elements cast-manager-polymer, cast-dialog-polymer, cast-video-polymer, cast-theme-polymer and cast-controller-bar-polymer.

bower install
bower install --save googlecast/cast-manager-polymer
bower install --save googlecast/cast-dialog-polymer
bower install --save googlecast/cast-video-polymer
bower install --save googlecast/cast-theme-polymer
bower install --save googlecast/cast-controller-bar-polymer

Now let’s update index.html and the cast-manager element.

Open index.html in your favorite text editor.  In this step, we’ll import the cast-manager element, add it to the page, define the bindable properties, and load some media.

Import dependencies

This project already imports Polymer for the video carousel elements so we don’t need to import it again.  In <head> import the cast-manager element:

<head>
  ...
  <link rel="import" href="bower_components/cast-manager-polymer/cast-manager.html">
  ...
</head>

Add cast-manager element

Now, let’s add the cast-manager element.  We’ll add it inside the auto binding template as a child of #cast-content so we can define bindable properties outside the cast-manager element.

<div id="cast-content" class="center-box-shadow width bgcolor">
  <cast-manager>
  </cast-manager>
</div>

Define cast-manager properties

We’ll define some of the properties other elements can observe and bind with.  Here  {{ }} means two way binding, so when cast-manager updates a property the change updates the bound variables.

<cast-manager app-id="4F8B3483"
                cast-available="{{castAvailable}}"
                connection-status="{{connectionStatus}}"
                local-media="{{localMedia}}"
                queue="{{queue}}"
                volume="{{volume}}"
                has-cast-media="{{hasCastMedia}}"
                cast-device-name="{{castDeviceName}}"
                current-time="{{currentTime}}"
                is-fullscreen="{{isFullscreen}}"
                show-spinner="{{showSpinner}}"
                next-queue-media-item="{{nextQueueMediaItem}}"
                countdown-to-next-media-item="{{countdownToNextMediaItem}}">
</cast-manager>

Property definition

Property

Description

app-id

Receiver App ID.  In our codelab we’ll use the sample receiver ID 4F8B3483.  You can replace it with your own styled or custom receiver appId.  To create your own appId refer to the Cast Registration documentation.

cast-available

Boolean describing if a cast receiver is available.

local-media

Locally loaded media.

queue

Local queue of media items.

volume

Current volume, ranging from 0 to 1.

has-cast-media

Boolean describing if the cast device has media loaded.

cast-device-name

String name of the cast receiver.

current-time

The HTMLMediaElement’s  currentTime.

is-fullscreen

Boolean describing if the video is fullscreen.

show-spinner

Boolean describing if the spinner is currently displaying.

next-queue-media-item

The next media item in the queue.  Used to notify the user when the current media item is about to end.

countdown-to-next-media-item

Time in seconds until the next media item starts.

Create reference to cast-manager

We want to create a reference to cast-manager so we can preload media items into the queue.   A variable castManager and the dom-change event handler are already defined.  The dom-change event is fired when one of the template helper elements updates the DOM tree.  Inside the event handler we want to set our property to reference the cast-manager DOM node.

var t = document.querySelector('#t');
t.addEventListener('dom-change', function () {
  castManager = document.querySelector('cast-manager');
});

Load media into cast-manager queue

The template already makes a CORS request for sample media data.  So let’s load the media list into the queue.  We’ll add our code to the xhr.onload callback.

xhr.onload = function () {
  var content = JSON.parse(xhr.responseText);
  processMediaList(content);
  if (castManager) {
    castManager.addItemsToQueue(mediaArray);
  }
};

Start the webserver

If you’ve already placed the contents on a webserver you can just browse to the correct path in Chrome.  Otherwise, in terminal you can use python to start a simple http server with the following command.

python -m SimpleHTTPServer 8080

This will create a simple http server on port 8080 serving the contents of the current directory.  In Chrome navigate to localhost:8080 to load the page.  What you’ll see is pretty much an empty page so let’s add more stuff to it.

Now let’s add a castable video to the page and some carousels to allow the user to select videos to play.

Import dependencies

First we need to import the element in head just like we did for cast-manager.

<link rel="import" href="bower_components/cast-video-polymer/cast-video.html">

Layout video

Lets define a few elements as children of the cast-manager element to improve the layout of the video area.  

<div id="video-content" class="video-content">
  <div class="video-width video-height shadow">
  </div>
</div>

Add cast-video element

Add the cast-video element as a child of the inner div, defining the properties it binds to.

<cast-video id="video"
            local-media="{{localMedia}}"
            volume="{{volume}}"
            current-time="{{currentTime}}"
            is-fullscreen="{{isFullscreen}}"
            queue="[[queue]]"
            cast-available="[[castAvailable]]"
            connection-status="[[connectionStatus]]"
            show-spinner="[[showSpinner]]"
            cast-device-name="[[castDeviceName]]"></cast-video>

Here local-media, volume, current-time, and is-fullscreen are two way bound since the cast-video element is a source of truth for those properties.  The other properties are one way bound with [[ ]]meaning changes made in the element to those properties won’t propagate to other elements.

Add video-details element

In this step we’ll also add a details section that provides some info on the currently playing video.  As part of the template we already imported the element so we only need to include it in the DOM.  Define the video-details element as a child of the video-content div.  Video details uses localMedia to populate the information to display.

<div id="video-content" class="video-content">
  ...
  <video-details class="video-width"
               local-media="[[localMedia]]"></video-details>
</div>

Add video-carousels

After the video-content div, we want to add a few carousels to show available content.  Like the video-details element we’ve included the carousels as part of the template so you simply need to define the elements in the DOM.  We’ll define 3 of them as an example, but we’ll fill them all with the same content.  The carousels need to be bound to localMedia to mark the currently playing media.

<video-carousel genre="Comedy"
                local-media="[[localMedia]]">
</video-carousel>
<video-carousel genre="Action"
                local-media="[[localMedia]]">
</video-carousel>
<video-carousel genre="Drama"
                local-media="[[localMedia]]">
</video-carousel>

Load media into video-carousels

Just like how we loaded media into the queue, we need to fill our video carousels with media.  To do so, we’ll get a reference to each DOM node and set the mediaList property.  In the xhr.onload callback load media into the video-carousel elements.

xhr.onload = function() {
  ...
  var videoCarousels = document.querySelectorAll('video-carousel');
  for (var i = 0; i < videoCarousels.length; i++) {
    videoCarousels[i].set('mediaList', mediaArray);
  }
}

Preview your progress

Reload the page in your browser.  You should see the video and carousels now display.  Awesome—we’re almost there.

In this step we’ll add the cast dialog element.  Just like the other elements, first we’ll import the element, then include it in our DOM.

Import dependencies

Import the cast-dialog element in the head.

<link rel="import" href="bower_components/cast-dialog-polymer/cast-dialog.html">

Add cast-dialog element

Now let’s add the element to our DOM.  It’s positioned fixed on page so you can add it as a child of cast-manager.

<cast-dialog cast-available="[[castAvailable]]"
             countdown-to-next-media-item="[[countdownToNextMediaItem]]"
             next-queue-media-item="[[nextQueueMediaItem]]"></cast-dialog>

Now when a cast device is available on our network the page will notify users that content is cast enabled.

Preview your progress

Reload the page in your browser.  If you have a cast device on the network, you’ll see a notification that cast is enabled.

The element we’ll add last is the cast-controller-bar.  This element will allow us to control casting content if the video controls are off the screen.

Import dependencies

Import the cast-controller-bar element in the head.

<link rel="import" href="bower_components/cast-controller-bar-polymer/cast-controller-bar.html">

Add cast-controller-bar

Cast controller bar is also position fixed, so you should add it as a child of cast-manager.  It needs to know the video element id and the scrolling element to determine when to appear.

<cast-controller-bar volume="[[volume]]"
                     local-media="[[localMedia]]"
                     cast-available="[[castAvailable]]"
                     connection-status="[[connectionStatus]]"
                     has-cast-media="[[hasCastMedia]]"
                     cast-device-name="[[castDeviceName]]"
                     current-time="[[currentTime]]"
                     queue="[[ queue ]]"
                     video-element="video"
                     scroll-element="body"></cast-controller-bar>

And that’s all of the code you need!  Now let’s test the page by reloading it in your browser.

Congrats, you’ve finished integration and have a fully UX compliant castable video player with queuing!

In this codelab you’ve learned how to easily add a castable video player to your site.  If your content is in a browser-supported HTML5 video format, these elements can be a simple solution to enable your users to view your content on any screen.

If you have additional UX requirements, you can use the sub-elements which form the cast-video element such as the cast-button and cast-player-bar.  You can also add additional widgets to the player bar such as social interactions.

For an even greater level of control over cast such as modifying what happens on connect or disconnect, you can integrate using the cast sender API.

For more information about creating a styled or custom receiver, take a look at the receiver API documentation.

Resources

Sub-elements

API documentation