Hide

Chrome Sender App Development

This overview describes how to build a Google Cast sender application for Chrome using the Google Cast SDK.

In this overview, sender application or Google Cast application refers to a web (HTML/JavaScript) app running inside a Chrome browser on a Mac/Windows/Linux/ChromeOS desktop/laptop device (the sender device); neither Chrome for Android, nor Chrome for iOS supports Cast applications (see Android Apps or iOS Apps instead). Receiver application refers to an HTML/Javascript application running on Chromecast or other Google Cast devices.

Setup

The Google Cast Chrome Sender SDK is provided by the Google Cast extension running on the user's installation of Chrome. See the Google Cast Release Notes for the details for each release.

No special setup steps are required in order to use the Google Cast Chrome Sender SDK. As long as you have the Google Cast extension installed within the Chrome instance you use for testing, it is possible for your web content to access and use the SDK. The SDK works with Chrome version 32 and higher - which covers all up-to-date installations of Chrome. Note that the extension is not currently available for Chrome on mobile devices.

Updates to the Google Cast extension occur automatically for all users, and are used to provide fixes, user-facing features, as well as SDK capabilities. Updates are backwards-compatible, and should be transparent to your site.

A public beta channel for the Google Cast extension is also available. New versions of the extension are pushed to the beta channel prior to a full release; the beta channel is also updated more often. This gives developers (and passionate early adopters) advance access to new features, and allows you to ensure that your site works with upcoming versions of the extension.

To use the public beta channel:

  • Disable (or remove) the stable extension, assuming that you already have it installed. Right-click on the Cast extension icon, select "Manage", and then clear the "Enabled" checkbox.
  • Install the beta extension from the Chrome Web Store.
  • Use the "Send Feedback" option to report issues. We can’t respond individually to most feedback, but we greatly value the input on the beta channel.
  • Under "Options", use the "Enable Log Window" feature to see detailed Cast extension logs. These may help you with debugging.
  • When pushing updates to your live site, ensure that you test with the current stable extension. Most visitors to your site will have the stable extension installed, and if you depend on beta-only features stable version users will be impacted.

Register your application and device, as described in Registration. Once you have your app ID, you're ready to develop your application.

Development

For your app to implement the features of Google Cast, it needs to know the location of the Google Cast Chrome Sender API library. All pages of your app must refer to the libary as follows:

<script type="text/javascript" src="https://www.gstatic.com/cv/js/sender/v1/cast_sender.js"></script>

A Google Cast Chrome Sender app may be described in several phases. This overview describes the code for each phase.

Working with a non-JavaScript player

Your sender application's properties and functions may be accessed or used with a non-JavaScript player such as Flash or Silverlight. These frameworks provide methods that hook into your JavaScript sender code and let you pass parameters and handle events in the Flash or Silverlight player.

For example, the ActionScript method, Externalinterface.call(external-JavaScript-function, parameter-1, parameter-2) may be used to hook into your media control methods, such as initializeCastApi. Likewise, the ActionScript method, ExternalInterface.addCallback("EVENT", ActionScriptAction) may be used to handle events like button clicks and progress bar updates.

See your framework's documentation for more information about hooking into your sender's JavaScript code.

Namespace

The Google Cast Chrome Sender SDK defines its top-level namespace as chrome.cast.*. The namespace represents the following:

  • Methods or functions that invoke operations on the API and their associated callbacks
  • Data objects that are passed to and from methods and callbacks
  • Event listeners for listener functions in the API

Review the Google Cast Chrome Sender API Reference for a complete description of the namespace.

Initialization

To determine if the API is available and initialize it, you can provide the callback function, window['__onGCastApiAvailable'] before the Cast API loads. It is invoked with loaded == true when the API loads, or with errorInfo when load fails (e.g. when no extension is discovered).

window['__onGCastApiAvailable'] = function(loaded, errorInfo) {
  if (loaded) {
    initializeCastApi();
  } else {
    console.log(errorInfo);
  }
}

Another way to initialize the API (still supported) is, upon page load set a timer, wait for the DOM to complete loading and for the Chrome Sender API to become available. For example, check for the API's availability with the following code:

if (!chrome.cast || !chrome.cast.isAvailable) {
  setTimeout(initializeCastApi, 1000);
}

Then, you initialize the API as follows:

initializeCastApi = function() {
  var sessionRequest = new chrome.cast.SessionRequest(applicationID);
  var apiConfig = new chrome.cast.ApiConfig(sessionRequest,
    sessionListener,
    receiverListener);
  chrome.cast.initialize(apiConfig, onInitSuccess, onError);
};

You at first create a sessionRequest object based on your own applicationID, if you are using a registered receiver application. If you are using the default receiver, for which no registration is required, you use a constant predefined by the Chrome Sender SDK, as shown below, instead of the applicationID:

var sessionRequest = new chrome.cast.SessionRequest(
                     chrome.cast.media.DEFAULT_MEDIA_RECEIVER_APP_ID);

Next, you define an ApiConfig object using the sessionRequest object, along with two callback functions, namely sessionListener and receiverListener. Then you call the chrome.cast.initialize method by passing the ApiConfig object.

The call to the method chrome.cast.initialize has two callbacks, one for success, one for error. The sessionListener function is discussed further in the Session management section, below. Here, assuming the initialize function returns success, your application is ready to use the Cast features.

Device selection

Device selection is managed by the Cast extension. The Cast features in your app are available to your users once the initialize call returns success and the receiverListener callback function returns with the availability of device(s). Here's the receiverListener callback:

function receiverListener(e) {
  if( e === chrome.cast.ReceiverAvailability.AVAILABLE) {
  }
}

The receiverListener callback only reports whether Cast devices are available; it does not report which devices are available. The available devices are known to the Cast extension.

The user performs device selection through requestSession API call. That action must be triggered by clicking on the Google Cast icon, which must display in the media control bar, as described in the User Experience Guidelines. When the user clicks on the Cast icon, your app can request a session, which automatically triggers the Cast extension to present a list of Cast devices to connect.

This is one of the two ways for your app to get hold of a session object. Another is to connect to an existing session, discussed in Session management, below.

Launch

When the user clicks the Cast icon, launch your application and create a Cast session, as follows:

chrome.cast.requestSession(onRequestSessionSuccess, onLaunchError);

The onRequestSessionSuccess callback function returns a chrome.cast.Session object between your sender app and Cast receiver app for the selected Cast receiver device.

function onRequestSessionSuccess(e) {
      session = e;
 }

The Session object also has a Receiver which you can use to display the friendly name of the receiver.

The connection to your receiver doesn't occur until your sender issues its first message, such as loadRequest, described below.

Media control

Now that you have a chrome.cast.Session object, you may load media to the selected Cast device by creating a MediaInfo object for the currentMediaURL, creating a LoadRequest object from it, and then calling the loadMedia method of the session object.

var mediaInfo = new chrome.cast.media.MediaInfo(currentMediaURL);
var request = new chrome.cast.media.LoadRequest(mediaInfo);
session.loadMedia(request,
   onMediaDiscovered.bind(this, 'loadMedia'),
   onMediaError);

function onMediaDiscovered(how, media) {
   currentMedia = media;
}

Upon successful callback of onMediaDiscovered, you get a chrome.cast.media.Media object, which grants you full media control of PLAY, PAUSE, RESUME, STOP and SEEK for the loaded media.

  • PLAY/RESUME: currentMedia.play(null, success, error);
  • PAUSE: currentMedia.pause(null, success, error);
  • STOP: currentMedia.stop(null, success, error);
  • SEEK: currentMedia.seek(null, success, error);

Media status

During media playback various events occur, so you need to add the following event listener when the media is successfully loaded.

function onMediaDiscovered(how, media) {
  media.addUpdateListener(onMediaStatusUpdate);
}

When events such as pause, play, resume or seek occur, you need to act on them and synchronize between your sender app and the receiver app on the Cast device. See also, Status updates for more information.

Session management

Creating a new session when launching your app in response to a user action is described in Launch, above. There is a second way of getting hold of a session. For example, after a video has been cast to the receiver device and your app has created a session, a user may browse your site and visit other pages or simply reload. In this case it’s possible for your app to get hold of the existing session, using the sessionListener callback function, as follows:

function sessionListener(e) {
  session = e;
  if (session.media.length != 0) {
    onMediaDiscovered('onRequestSessionSuccess', session.media[0]);
  }
}

This enables your app to auto-join an existing session on any page of your app, manage a session’s lifecycle, and ultimately provide a seamless user experience in your app.

There is also a third way of getting a Cast session. A user with the Cast extension installed in their Chrome browser can mirror any Chrome tab to a Cast device. If the user lands on your site, for which you have implemented a Cast app, tab mirroring will automatically trigger a new Cast session instead of putting the browser in mirroring mode.

As described in Launch above, the connection to your receiver doesn't occur until your sender issues its first message.

Termination

To stop casting, you need a valid Session object. Then call the session's stop function:

function stopApp() {
  session.stop(onSuccess, onError);
}

Using the Tracks APIs

A track can be a text (subtitle or caption), an audio or a video stream object. The Tracks APIs let you work with these objects in your application.

A Track object represents a track in the SDK. You can configure a track and assign a unique ID to it like this:

var englishSubtitle = new chrome.cast.media.Track(1, // track ID
   chrome.cast.media.TrackType.TEXT);
englishSubtitle.trackContentId = 'https://some-url/caption_en.vtt';
englishSubtitle.trackContentType = 'text/vtt';
englishSubtitle.subtype = chrome.cast.media.TextTrackType.SUBTITLES;
englishSubtitle.name = 'English Subtitles';
englishSubtitle.language = 'en-US';
englishSubtitle.customData = null;

var frenchSubtitle = new chrome.cast.media.Track(2, // track ID
   chrome.cast.media.TrackType.TEXT);
frenchSubtitle.trackContentId = 'https://some-url/caption_fr.vtt';
frenchSubtitle.trackContentType = 'text/vtt';
frenchSubtitle.subtype = chrome.cast.media.TextTrackType.SUBTITLES;
frenchSubtitle.name = 'French Subtitles';
frenchSubtitle.language = 'fr';
frenchSubtitle.customData = null;

var frenchAudio = new chrome.cast.media.Track(3, // track ID
   chrome.cast.media.TrackType.AUDIO);
frenchAudio.trackContentId = 'trk0001';
frenchAudio.trackContentType = 'audio/mp3';
frenchAudio.subtype = null;
frenchAudio.name = 'French Audio';
frenchAudio.language = 'fr';
frenchAudio.customData = null;

A media item may have multiple tracks; for example, it can have multiple subtitles (each for a different language) or multiple alternative audio streams (for different languages).

MediaInfo is the class that models a media item. To associate a collection of Track objects with a media item, you update its tracks property. This association needs to be made before the media is loaded to the receiver:

var tracks = [englishSubtitle, frenchSubtitle, frenchAudio];
var mediaInfo = new chrome.cast.media.MediaInfo(mediaURL);
mediaInfo.contentType = 'video/mp4';
mediaInfo.metadata = new chrome.cast.media.GenericMediaMetadata();
mediaInfo.customData = null;
mediaInfo.streamType = chrome.cast.media.StreamType.BUFFERED;
mediaInfo.textTrackStyle = new chrome.cast.media.TextTrackStyle();
mediaInfo.duration = null;
mediaInfo.tracks = tracks;

You can set the active tracks in the media Load request.

You can also activate one or more tracks that were associated with the media item, after the media is loaded, by calling EditTracksInfoRequest(opt_activeTrackIds, opt_textTrackStyle) and passing the IDs of the tracks to be activated in opt_activeTrackIds. Note, both parameters are optional and you may choose which, active tracks or styles, to set at your discretion. For example, here is how to activate the French subtitle (2) and French audio (3):

var activeTrackIds = [2, 3];
var tracksInfoRequest = new chrome.cast.media.EditTracksInfoRequest(activeTrackIds);
media.editTracksInfo(tracksInfoRequest, successCallback, errorCallback);

To remove all the tracks from the current media (for example turning off subtitles), simply set mediaInfo.tracks=null and reload the media.

Styling text tracks

TextTrackStyle is the object that encapsulates the styling information of a text track. After creating or updating an existing TextTrackStyle object, you can apply that to the currently playing media item by calling its editTracksInfo method, like this:

var textTrackStyle = new chrome.cast.media.TextTrackStyle();
var tracksInfoRequest = new chrome.cast.media.EditTracksInfoRequest(textTrackStyle);
media.editTracksInfo(tracksInfoRequest, successCallback, errorCallback);

You can track the status of the request with result of the callbacks, either success or error, and update the originating sender accordingly.

Applications should allow users to update the style for text tracks, either using the settings provided by the system or by the application itself.

You can style the following text track style elements:

  • Foreground (text) color and opacity
  • Background color and opacity
  • Edge type
  • Edge Color
  • Font Scale
  • Font Family
  • Font Style

For example, set the text color to red with 75% opacity as follows:

var textTrackStyle = new chrome.cast.media.TextTrackStyle();
textTrackStyle.foregroundColor = '#80FF0000';

Volume control

The sender app should adhere to the following guidelines for controlling volume:

  • The sender application must synchronize with the receiver so that the sender UI always reports the volume per the receiver. Use the addUpdateListener() callback to maintain the volume on the sender. See Status updates for more information.
  • Sender apps must not set the volume level at a specific, pre-defined level or set the volume level to the sender device's ringer/media volume when the app loads on the receiver.

See Sender volume controls in the Design Checklist for more specific UI guidelines.

Status updates

When multiple senders are connected to the same receiver, it is important for each sender to be aware of the changes on the receiver even if those changes were initiated from other senders.

To this end, your application should register an UpdateListener for that session. If the TextTrackStyle of the current media changes, then all of the connected senders will be notified and the corresponding properties of the current media session, such as activeTrackIds and textTrackStyle of the MediaInfo field will be sent to senders in callbacks. In this case, the receiver SDK does not verify whether the new style is different from the previous one and notifies all the connected senders regardless.

Progress indicator

Showing the playback location with a progress indicator on the sender is a requirement for most apps. The Cast APIs use the Cast media protocol, which optimizes bandwidth consumption for this and other scenarios, so you do not need to implement your own status synchronization. For the proper implementation of a progress indicator for media playback using the APIs, see the CastVideos-chrome sample app.

CORS requirements

For adaptive media streaming, Google Cast requires the presence of CORS headers, but even simple mp4 media streams require CORS if they include Tracks. If you want to enable Tracks for any media, you must enable CORS for both your track streams and your media streams. So, if you do not have CORS headers available for your simple mp4 media on your server, and you then add a simple subtitle track, you will not be able to stream your media unless you update your server to include the appropriate CORS header. In addition, you need to allow at least the following headers: Content-Type, Accept-Encoding, and Range. Note that the last two headers are additional headers that you may not have needed previously.

Sample apps

See the following samples for a completely coded app:

  • Hello Video sample app - demonstrates the essential API objects, methods and event listeners.
  • CastVideos sample app - provides an implementation of an HTML5/Javascript media player that acts as a Chrome sender, is fully compliant with our UX guidelines, and demonstrates typical features such as transition between local playback mode and cast mode, states and progress bar synchronization between the two modes, and auto-join during page reload.