# Migrate to Web Receiver

This guide explains how to migrate a Cast Receiver v2 app to the latest Web
Receiver app.

The new Cast Application Framework (CAF) SDK, also known as Web Receiver v3, is
a major upgrade from the Receiver v2 SDK. The Web Receiver SDK provides an
easy, streamlined SDK for developing media Web Receiver applications.

The Web Receiver provides an API that is more consistent with the new CAF sender
APIs. It provides full integration of a player (MPL and Shaka) and full
implementation and support for the Cast media and Google Assistant
voice commands. CAF SDK also provides a default UI that can be easily styled
using CSS, and a data binding service to simplify UI implementation.

## Why migrate?

By migrating a Receiver v2 application to Web Receiver, a lot of code that deals
with the player can be eliminated, so you can concentrate on writing
application-specific business logic.

CAF seamlessly integrates MPL and Shaka players to support a wider range of
content types including---HTTP Live Streaming (TS and CMAF), MPEG-DASH, Smooth
Streaming and types supported by the Media Element source property (MP3, MP4,
Icecast, etc...). For a complete list see [Supported Media for Google Cast](https://developers.google.com/cast/docs/media).
*Currently CAF does not support a user-provided player.*

Migrating to CAF will add the support for voice control with Google Assistant.
Any new Google Assistant voice command will automatically be supported when
using CAF.

In addition to supporting new media commands---like "change tracks by language"
and "change playback rate"---CAF also provides better queueing, built-in ads
support, and better live support.

## What changed?

The Web Receiver API tries to follow the conventions that were introduced by
CAF senders for
[Android](https://developers.google.com/cast/docs/android_sender_integrate) and
[iOS](https://developers.google.com/cast/docs/ios_sender_integrate),
and is quite different from v2.

The Web Receiver is using a new namespace
[`cast.framework`](https://developers.google.com/cast/docs/reference/caf_receiver/cast.framework)
instead of `cast.receiver` namespace for all exposed APIs. Many of
the data objects that were used by v2 are the same in CAF and are exposed under
the
[`cast.framework.messages`](https://developers.google.com/cast/docs/reference/caf_receiver/cast.framework.messages)
namespace (they were mostly under `cast.receiver.media`).

The following v2 services are replaced by corresponding CAF services:

- `CastReceiverManager` class is replaced by [`CastReceiverContext`](https://developers.google.com/cast/docs/reference/caf_receiver/cast.framework.CastReceiverContext) which is a singleton that manages the cast session, senders, sending custom messages, and global system events. The [`CastReceiverOptions`](https://developers.google.com/cast/docs/reference/caf_receiver/cast.framework.CastReceiverOptions) can be used to provide global application options (such as queue, receiver version, playback config, etc.) to the context.
- `MediaManager` class is replaced by [`PlayerManager`](https://developers.google.com/cast/docs/reference/caf_receiver/cast.framework.PlayerManager) which is a property of the [`CastReceiverContext`](https://developers.google.com/cast/docs/reference/caf_receiver/cast.framework.CastReceiverContext) singleton, and it manages the media session, media requests, Google Assistant voice requests (`CommandAndControlManager` in v2), and fires media events. Configuration for the players (`cast.player.api.Host` in MPL) is provided by [`PlaybackConfig`](https://developers.google.com/cast/docs/reference/caf_receiver/cast.framework.PlaybackConfig), which can be provided globally or per load request.

The `PlayerManager` also exposes the new sub-manager classes:

- [`TextTracksManager`](https://developers.google.com/cast/docs/reference/caf_receiver/cast.framework.TextTracksManager) - manage media text tracks.
- [`AudioTracksManager`](https://developers.google.com/cast/docs/reference/caf_receiver/cast.framework.AudioTracksManager) - manage audio tracks.
- [`QueueManager`](https://developers.google.com/cast/docs/reference/caf_receiver/cast.framework.QueueManager) - manage the queue.
- [`BreakManager`](https://developers.google.com/cast/docs/reference/caf_receiver/cast.framework.breaks.BreakManager) - manage ads.

    const context = cast.framework.CastReceiverContext.getInstance();
    const playerManager = context.getPlayerManager();

    // Set global options.
    const options = new cast.framework.CastReceiverOptions();
    options.versionCode = DEVELOPERS_APP_VERSION;

    context.start(options);

## Receiver business logic

Receiver v2 exposed event handlers (such as `CastReceiverManager.onReady` or
`MediaManager.onLoad`) to add business logic. In CAF the event handlers are
replaced by event listeners
([`CastReceiverContext.addEventListener`](https://developers.google.com/cast/docs/reference/caf_receiver/cast.framework.CastReceiverContext#addEventListener))
and message interceptors
([`PlayerManager.setMessageInterceptor`](https://developers.google.com/cast/docs/reference/caf_receiver/cast.framework.PlayerManager#setMessageInterceptor)).
Web Receiver can have multiple event listeners for an event (the listener
does not affect the event), and one interceptor per message. The interceptor
can update the request or handle it (return a modified request, a success
message, or error message), and can be an async handler that returns a promise.

The load request interceptor is the most common place to add
application-specific logic. For load requests from a sender, the load
interceptor can convert the content ID to content URL. The load interceptor is
also being called for preload and precache requests if no explicit interceptor
was provided for preload or precache.

    playerManager.setMessageInterceptor(
        cast.framework.messages.MessageType.LOAD,
        request => {
          // Resolve entity to content id
          if (request.media.entity && !request.media.contentId) {
            return getMediaByEntity(request.media.entity).then(
                media => {
                  request.media.contentId = media.url;
                  return request;
                });
          }
          return request;
        });

The v2 customized media status handler is also replaced with a message
interceptor for the media status message. Web Receiver apps that do not want to
expose the media URL in the media status can provide a URL resolver
([`PlayerManager.setMediaUrlResolver`](https://developers.google.com/cast/docs/reference/caf_receiver/cast.framework.PlayerManager#setMediaUrlResolver)),
which provides the media URL for a load request. That URL is used by CAF
internally and is not provided in the media status.

    playerManager.setMessageInterceptor(
        cast.framework.messages.MessageType.MEDIA_STATUS,
        status => {
          // Disable seek.
          status.supportedMediaCommands &=
              ~cast.framework.messages.Command.SEEK
          return status;
        });

## Events

Web Receiver provides an extensive set of events both from
[`CastReceiverContext`](https://developers.google.com/cast/docs/reference/caf_receiver/cast.framework.CastReceiverContext)
and
[`PlayerManager`](https://developers.google.com/cast/docs/reference/caf_receiver/cast.framework.PlayerManager).
Web Receiver apps can have multiple listeners on any event, and
can also provide one listener to multiple events. (See
[`cast.framework.events.category`](https://developers.google.com/cast/docs/reference/caf_receiver/cast.framework.events.category)
for some groups of events.)

The events cover any user request, playback progress, player processing, and any
low-level media element event (CAF does not expose the media element itself).

The Web Receiver app can add event listeners to act upon (for example, add text
tracks definition when load completes), or for analytics.

    // Log all media commands
    playerManager.addEventListener(
        cast.framework.events.category.REQUEST,
        event => logEvent(event.type));

## Custom message bus

CAF does not expose the message bus in the API, instead it provides
[`CastReceiverContext.addCustomMessageListener`](https://developers.google.com/cast/docs/reference/caf_receiver/cast.framework.CastReceiverContext#addCustomMessageListener)
to add a message listener for a specific namespace (only one per namespace) and
[`CastReceiverContext.sendCustomMessage`](https://developers.google.com/cast/docs/reference/caf_receiver/cast.framework.CastReceiverContext#sendCustomMessage)
to send a message on a namespace. All namespaces need to be declared before
starting the Web Receiver (that is, before calling
[`CastReceiverContext.start`](https://developers.google.com/cast/docs/reference/caf_receiver/cast.framework.CastReceiverContext#start)).
The namespaces can be declared by
adding a message listener to them or can be provided as a start option in
[`CastReceiverOptions.customNamespaces`](https://developers.google.com/cast/docs/reference/caf_receiver/cast.framework.CastReceiverOptions#customNamespaces).

    const options = new cast.framework.CastReceiverOptions();
    options.customNamespaces = {
        CUSTOM_NS: cast.framework.system.MessageType.JSON
    };
    context.start(options);

    context.sendCustomMessage(CUSTOM_NS, {
      type: 'status'
      message: 'Playing'
    });

## Default UI

CAF provides a default Web Receiver UI that displays a playback progress bar and
media metadata as needed. The default UI is provided as a custom element
(`https://developers.google.com/cast/docs/caf_receiver_basic#create-a-basic-receiver-app`)
that can be styled with CSS-like styling.

    <style>
       cast-media-player { --splash-image: url("splash.png"); }
    </style>
    <cast-media-player></cast-media-player>

For more customization, a Web Receiver app can implement its own UI. The
Web Receiver provides the
[`cast.framework.ui.PlayerDataBinder`](https://developers.google.com/cast/docs/reference/caf_receiver/cast.framework.ui.PlayerDataBinder)
class to help bind a UI object to the Web Receiver playback state.