This developer guide describes how to add Google Cast support to your Web
Sender app using the Cast SDK.
**Note:** We recommend that you try the following:

- [**Cast Web Sender
  codelab tutorial**](https://developers.google.com/cast/codelabs/cast-videos-chrome) - Learn step-by-step how to modify an existing web video app to play content on a Google Cast device.
- [**CastVideos-chrome sample app**](https://github.com/googlecast/CastVideos-chrome) (GitHub) - Run, navigate, and view this reference sample app which complies with the [UX Guidelines](https://developers.google.com/cast/docs/ux_guidelines.md.txt) and [Design Checklist](https://developers.google.com/cast/docs/design_checklist.md.txt).

## Terminology

The mobile device or browser is the *sender* , which controls the playback;
the Google Cast device is the *receiver*, which displays the content on
the screen for playback.

The Web Sender SDK consists of two parts: the Framework API
([cast.framework](https://developers.google.com/cast/docs/reference/web_sender/cast.framework.md.txt))
and the Base API
([chrome.cast](https://developers.google.com/cast/docs/reference/web_sender/chrome.cast.md.txt))
In general, you make calls on the simpler, higher-level Framework API,
which are then processed by the lower-level Base API.

The *sender framework* refers to the Framework API, module and associated
resources that provide a wrapper around lower-level functionality. The
*sender app* or *Google Cast Chrome app* refers to a web (HTML/JavaScript) app
running inside a Chrome browser on a sender device. A *Web Receiver app* refers
to an HTML/JavaScript app running on Chromecast or a Google Cast device.

The sender framework uses an asynchronous callback design to inform the sender
app of events and to transition between various states of the Cast app life
cycle.

## Load the library

For your app to implement the features of Google Cast, it needs to know the
location of the Google Cast Web Sender SDK, as shown below. Add the
*loadCastFramework* URL query parameter to load the Web Sender Framework API
as well. All pages of your app must refer to the library as follows:

```javascript
<script src="https://www.gstatic.com/cv/js/sender/v1/cast_sender.js?loadCastFramework=1"></script>
```

## Framework

The Web Sender SDK uses the **cast.framework.**\*
namespace. The namespace represents the following:

- Methods or functions that invoke operations on the API
- Event listeners for listener functions in the API

The framework consists of these main components:

- The [`CastContext`](https://developers.google.com/cast/docs/reference/web_sender/cast.framework.CastContext.md.txt) is a singleton object that provides information about the current Cast state, and triggers events for Cast state and Cast session state changes.
- The [`CastSession`](https://developers.google.com/cast/docs/reference/web_sender/cast.framework.CastSession.md.txt) object manages the session -- it provides state information and triggers events, such as changes to device volume, mute state, and app metadata.
- The Cast button element, which is a simple HTML custom element that extends the HTML button. If the provided Cast button is not sufficient, you can use the Cast state to implement a Cast button.
- The [`RemotePlayerController`](https://developers.google.com/cast/docs/reference/web_sender/cast.framework.RemotePlayerController.md.txt) provides the data binding to simplify implementation of the remote player.

Review the
[Google Cast Web Sender API Reference](https://developers.google.com/cast/docs/reference/web_sender.md.txt) for a
complete description of the namespace.

## Cast button

The Cast button component in your app is handled entirely by the framework. This
includes visibility management, as well as click event handling.

```javascript
<google-cast-launcher></google-cast-launcher>
```

Alternatively, you can create the button programmatically:

```javascript
document.createElement("google-cast-launcher");
```

You can apply any additional styling, such as size or positioning, to the
element as necessary. Use the `--connected-color` attribute to
choose the color for the connected Web Receiver state, and
`--disconnected-color` for the disconnected state.

## Initialization

After loading the framework API, the app will call the handler
`window.__onGCastApiAvailable`. You should ensure that the app sets this handler
on the `window` before [loading the sender library](https://developers.google.com/cast/docs/web_sender/integrate.md.txt#load-the-library).

Within this handler, you initialize the Cast interaction by calling the
[`setOptions(options)`](https://developers.google.com/cast/docs/reference/web_sender/cast.framework.CastContext.md.txt#setOptions)
method of
[`CastContext`](https://developers.google.com/cast/docs/reference/web_sender/cast.framework.CastContext.md.txt).

For example:

```javascript
<script>
window['__onGCastApiAvailable'] = function(isAvailable) {
  if (isAvailable) {
    initializeCastApi();
  }
};
</script>
```

Then, you initialize the API as follows:

```javascript
initializeCastApi = function() {
  cast.framework.CastContext.getInstance().setOptions({
    receiverApplicationId: applicationId,
    autoJoinPolicy: chrome.cast.AutoJoinPolicy.ORIGIN_SCOPED
  });
};
```

First the app retrieves the singleton instance of the
[`CastContext`](https://developers.google.com/cast/docs/reference/web_sender/cast.framework.CastContext.md.txt) object
provided by the framework. It then uses
[`setOptions(options)`](https://developers.google.com/cast/docs/reference/web_sender/cast.framework.CastContext.md.txt#setOptions)
using a
[`CastOptions`](https://developers.google.com/cast/docs/reference/web_sender/cast.framework.CastOptions.md.txt) object
to set the `applicationID`.

If you are using the Default Media Receiver, which doesn't require registration,
you use a constant predefined by the Web Sender SDK, as shown below, instead of
the `applicationID`:

```javascript
cast.framework.CastContext.getInstance().setOptions({
  receiverApplicationId: chrome.cast.media.DEFAULT_MEDIA_RECEIVER_APP_ID
});
```

## Media control

Once the [`CastContext`](https://developers.google.com/cast/docs/reference/web_sender/cast.framework.CastContext.md.txt)
has been initialized, the app can retrieve the current
[`CastSession`](https://developers.google.com/cast/docs/reference/web_sender/cast.framework.CastSession.md.txt) at any
time using
[`getCurrentSession()`](https://developers.google.com/cast/docs/reference/web_sender/cast.framework.CastContext.md.txt#getCurrentSession).

```javascript
var castSession = cast.framework.CastContext.getInstance().getCurrentSession();
```

The `CastSession` can be used to load media to the connected Cast device using
[`loadMedia(loadRequest)`](https://developers.google.com/cast/docs/reference/web_sender/cast.framework.CastSession.md.txt#loadMedia).
First, create a
[`MediaInfo`](https://developers.google.com/cast/docs/reference/web_sender/chrome.cast.media.MediaInfo.md.txt),
using the `contentId` and `contentType` as well as any other information
related to the content. Then create a
[`LoadRequest`](https://developers.google.com/cast/docs/reference/web_sender/chrome.cast.media.LoadRequest.md.txt)
from it, setting all of the relevant information for the request. Finally,
call `loadMedia(loadRequest)` on your `CastSession`.

```javascript
var mediaInfo = new chrome.cast.media.MediaInfo(currentMediaURL, contentType);
var request = new chrome.cast.media.LoadRequest(mediaInfo);
castSession.loadMedia(request).then(
  function() { console.log('Load succeed'); },
  function(errorCode) { console.log('Error code: ' + errorCode); });
```

The `loadMedia` method will return a
[Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)
that can be used to perform any necessary operations for a successful result.
If the Promise is rejected, the function argument will be a
[`chrome.cast.ErrorCode`](https://developers.google.com/cast/docs/reference/web_sender/chrome.cast.md.txt#.ErrorCode).

You can access player state variables in
[`RemotePlayer`](https://developers.google.com/cast/docs/reference/web_sender/cast.framework.RemotePlayer.md.txt).
All interactions with the `RemotePlayer`, including media event callbacks and
commands, are handled with the
[`RemotePlayerController`](https://developers.google.com/cast/docs/reference/web_sender/cast.framework.RemotePlayerController.md.txt).

```javascript
var player = new cast.framework.RemotePlayer();
var playerController = new cast.framework.RemotePlayerController(player);
```

The `RemotePlayerController` gives the app full media control of
PLAY, PAUSE, STOP and SEEK for the loaded media.

- PLAY/PAUSE: `playerController.playOrPause();`
- STOP: `playerController.stop();`
- SEEK: `playerController.seek();`

The `RemotePlayer` and `RemotePlayerController` can be
used with data binding frameworks, such as Polymer or Angular, to implement a
remote player.

Here is a code snippet for Angular:

```
<button id="playPauseButton" class="playerButton"
  ng-disabled="!player.canPause"
  ng-click="controller.playOrPause()">
    {{player.isPaused ? 'Play' : 'Pause'}}
</button>
<script>
var player = new cast.framework.RemotePlayer();
var controller = new cast.framework.RemotePlayerController(player);
// Listen to any player update, and trigger angular data binding
update.controller.addEventListener(
  cast.framework.RemotePlayerEventType.ANY_CHANGE,
  function(event) {
    if (!$scope.$$phase) $scope.$apply();
  });
</script>
```

## Media status

During media playback, various events occur which can be captured by setting
listeners for various
[`cast.framework.RemotePlayerEventType`](https://developers.google.com/cast/docs/reference/web_sender/cast.framework.md.txt#.RemotePlayerEventType)
events on the
[`RemotePlayerController`](https://developers.google.com/cast/docs/reference/web_sender/cast.framework.RemotePlayerController.md.txt)object.

To get the media status information, use the
[`cast.framework.RemotePlayerEventType`](https://developers.google.com/cast/docs/reference/web_sender/cast.framework.md.txt#.RemotePlayerEventType)`.MEDIA_INFO_CHANGED`
event, which triggers when playback changes and when the
[`CastSession.getMediaSession().media`](https://developers.google.com/cast/docs/reference/web_sender/chrome.cast.media.Media.md.txt#media)
changes.

```javascript
playerController.addEventListener(
  cast.framework.RemotePlayerEventType.MEDIA_INFO_CHANGED, function() {
    // Use the current session to get an up to date media status.
    let session = cast.framework.CastContext.getInstance().getCurrentSession();

    if (!session) {
        return;
    }

    // Contains information about the playing media including currentTime.
    let mediaStatus = session.getMediaSession();
    if (!mediaStatus) {
        return;
    }

    // mediaStatus also contains the mediaInfo containing metadata and other
    // information about the in progress content.
    let mediaInfo = mediaStatus.media;
  });
```

When events such as pause, play, resume or seek occur, the app will need to act
on them and synchronize between itself and the Web Receiver app on the Cast
device. See [Status updates](https://developers.google.com/cast/docs/web_sender/advanced.md.txt#status-updates)
for more information.

## How session management works

The Cast SDK introduces the concept of a Cast session, the
establishment of which combines the steps of connecting to a device, launching (or joining) a Web
Receiver app, connecting to that app, and initializing a media control channel. See the Web Receiver
[Application life cycle guide](https://developers.google.com/cast/docs/web_receiver/basic.md.txt#application_life_cycle)
for more information about Cast sessions and the Web Receiver life cycle.

Sessions are managed by the class
[`CastContext`](https://developers.google.com/cast/docs/reference/web_sender/cast.framework.CastContext.md.txt),
which your app can retrieve via
[`cast.framework.CastContext.getInstance()`](https://developers.google.com/cast/docs/reference/web_sender/cast.framework.CastContext.md.txt#.getInstance).
Individual sessions are represented by subclasses of the class
[`Session`](https://developers.google.com/cast/docs/reference/web_sender/chrome.cast.Session.md.txt). For example,
[`CastSession`](https://developers.google.com/cast/docs/reference/web_sender/cast.framework.CastSession.md.txt)
represents sessions with Cast devices. Your app can access the currently active
Cast session via
[`CastContext.getCurrentSession()`](https://developers.google.com/cast/docs/reference/web_sender/cast.framework.CastContext.md.txt#getCurrentSession).

To monitor the session state, add a listener to the
[`CastContext`](https://developers.google.com/cast/docs/reference/web_sender/cast.framework.CastContext.md.txt) for
the
[`CastContextEventType`](https://developers.google.com/cast/docs/reference/web_sender/cast.framework.md.txt#.CastContextEventType)`.SESSION_STATE_CHANGED` event type.

```javascript
var context = cast.framework.CastContext.getInstance();
context.addEventListener(
  cast.framework.CastContextEventType.SESSION_STATE_CHANGED,
  function(event) {
    switch (event.sessionState) {
      case cast.framework.SessionState.SESSION_STARTED:
      case cast.framework.SessionState.SESSION_RESUMED:
        break;
      case cast.framework.SessionState.SESSION_ENDED:
        console.log('CastContext: CastSession disconnected');
        // Update locally as necessary
        break;
    }
  })
```

For disconnection, such as when the user clicks the "stop casting" button from
the Cast dialog, you can add a listener for the
[`RemotePlayerEventType`](https://developers.google.com/cast/docs/reference/web_sender/cast.framework.md.txt#.RemotePlayerEventType)`.IS_CONNECTED_CHANGED`
event type in your listener. In your listener check if
[`RemotePlayer`](https://developers.google.com/cast/docs/reference/web_sender/cast.framework.RemotePlayer.md.txt) is
disconnected. If so, update the local player state as necessary. For example:

```javascript
playerController.addEventListener(
  cast.framework.RemotePlayerEventType.IS_CONNECTED_CHANGED, function() {
    if (!player.isConnected) {
      console.log('RemotePlayerController: Player disconnected');
      // Update local player to disconnected state
    }
  });
```

While the user can directly control Cast termination via the framework Cast
button, the sender itself can stop casting using the current
[`CastSession`](https://developers.google.com/cast/docs/reference/web_sender/cast.framework.CastSession.md.txt)
object.

```javascript
function stopCasting() {
  var castSession = cast.framework.CastContext.getInstance().getCurrentSession();
  // End the session and pass 'true' to indicate
  // that Web Receiver app should be stopped.
  castSession.endSession(true);
}
```

### Stream transfer

Preserving session state is the basis of stream transfer, where
users can move existing audio and video streams across devices using voice commands, Google Home
App, or smart displays. Media stops playing on one device (the source) and continues on another (the
destination). Any Cast device with the latest firmware can serve as sources or destinations in a
stream transfer.

To get the new destination device during the stream transfer, call
[`CastSession#getCastDevice()`](https://developers.google.com/cast/docs/reference/web_sender/cast.framework.CastSession.md.txt#getCastDevice)
when the
[`cast.framework.SessionState`](https://developers.google.com/cast/docs/reference/web_sender/cast.framework.md.txt#.SessionState)`.SESSION_RESUMED`
event is called.

See
[Stream transfer on Web Receiver](https://developers.google.com/cast/docs/caf_receiver/core_features#stream_transfer)
for more information.