Cómo habilitar la compatibilidad de una app web con Cast

1. Descripción general

Logotipo de Google Cast

En este codelab, aprenderás a modificar una app de video web existente para transmitir contenido en un dispositivo compatible con Google Cast.

¿Qué es Google Cast?

Google Cast permite a los usuarios transmitir contenido desde un dispositivo móvil a una TV. De esa manera, los usuarios pueden usar su dispositivo móvil como control remoto de modo que se reproduzca contenido multimedia en la TV.

El SDK de Google Cast posibilita que extiendas tu app para controlar una TV o un sistema de sonido. Este SDK te permitirá agregar los componentes de la IU necesarios según la lista de tareas de diseño de Google Cast.

Te proporcionamos la lista de tareas de diseño de Google Cast con el fin de que la experiencia del usuario de Cast resulte sencilla y predecible en todas las plataformas compatibles.

¿Qué compilaremos?

Cuando completes este codelab, tendrás una app de video web de Chrome que podrá transmitir videos a un dispositivo Google Cast.

Qué aprenderás

  • Cómo agregar el SDK de Google Cast a una app de video de muestra
  • Cómo agregar el botón para transmitir a fin de seleccionar un dispositivo Google Cast
  • Cómo conectarse a un dispositivo de transmisión e iniciar un receptor de contenido multimedia
  • Cómo transmitir un video
  • Cómo integrar Cast Connect

Requisitos

  • El navegador Google Chrome más reciente
  • Un servicio de hosting HTTPS, como Firebase Hosting o ngrok
  • Un dispositivo compatible con Google Cast, como Chromecast o Android TV que esté configurado con acceso a Internet
  • Una TV o un monitor con entrada HDMI
  • Se requiere un Chromecast con Google TV para probar la integración de Cast Connect, pero es opcional para el resto del codelab. Si no tienes uno, no dudes en omitir el paso Agregar compatibilidad con Cast Connect, que se encuentra al final de este instructivo.

Experiencia

  • Debes tener conocimientos previos sobre desarrollo web.
  • También deberás tener experiencia como usuario de TV :)

¿Cómo usarás este instructivo?

Ler Leer y completar los ejercicios

¿Cómo calificarías tu experiencia con la compilación de apps web?

Principiante Intermedio Avanzado

¿Cómo calificarías tu experiencia cuando miras TV?

Principiante Intermedio Avanzado

2. Obtén el código de muestra

Puedes descargar el código de muestra completo a tu computadora…

y descomprimir el archivo ZIP que se descargó.

3. Ejecuta la app de muestra

Logotipo de Google Chrome

Primero, veamos el aspecto de la app de muestra completa. La app es un reproductor de video básico. El usuario podrá seleccionar un video de una lista y, a continuación, reproducirlo en un dispositivo local o transmitirlo a uno compatible con Google Cast.

Para poder usar el estado completado, este debe estar alojado.

Si no tienes un servidor disponible para usar, puedes usar Firebase Hosting o ngrok.

Ejecuta el servidor

Una vez que hayas configurado el servicio que elijas, navega a app-done y comienza a usar el servidor.

En el navegador, visita la URL HTTPS del ejemplo que alojaste.

  1. Deberías ver la app de video.
  2. Haz clic en el botón para transmitir y selecciona tu dispositivo Google Cast.
  3. Selecciona un video y haz clic en el botón de reproducción.
  4. El video comenzará a reproducirse en tu dispositivo Google Cast.

Imagen de un video que se reproduce en un dispositivo Cast

Haz clic en el botón de pausa en el elemento de video para pausarlo en el receptor. Haz clic en el botón de reproducción para reanudar el video nuevamente.

Haz clic en el botón para transmitir a fin de detener la transmisión al dispositivo compatible con Google Cast.

Antes de continuar, detén el servidor.

4. Prepara el proyecto inicial

Imagen de un video que se reproduce en un dispositivo Cast

Debemos agregar compatibilidad con Google Cast a la app inicial que descargaste. A continuación, se incluye la terminología de Google Cast que usaremos en este codelab:

  • una app emisora se ejecuta en un dispositivo móvil o una laptop.
  • una app receptora se ejecuta en el dispositivo Google Cast.

Ya puedes compilar sobre el proyecto inicial con tu editor de texto favorito:

  1. Selecciona el directorio ícono de carpetaapp-start de la descarga del código de muestra.
  2. Ejecuta la app con tu servidor y explora la IU.

Ten en cuenta que, a medida que trabajes en este codelab, deberás volver a alojar el ejemplo en tu servidor según el servicio.

Diseño de apps

La app recuperará una lista de videos de un servidor web remoto y proporcionará una lista para que el usuario explore. Los usuarios podrán seleccionar un video de forma que vean los detalles o reproducirlo localmente en el dispositivo móvil.

La app consta de una vista principal, definida en index.html, y el controlador principal, CastVideos.js..

index.html

Este archivo html declara casi toda la IU para la aplicación web.

Hay algunas secciones de vistas. Tenemos nuestro div#main_video, que contiene el elemento de video. En relación con nuestro div de video, contamos con div#media_control, que define todos los controles para el elemento de video. Debajo, se encuentra media_info, que muestra los detalles del video en la vista. Por último, el elemento div carousel muestra una lista de videos en un elemento div.

El archivo index.html también inicia el SDK de Cast y le indica a la función CastVideos que cargue.

La mayor parte del contenido que propagará estos elementos se define, inserta y controla en CastVideos.js. Echemos un vistazo.

CastVideos.js

Esta secuencia de comandos administra toda la lógica para la aplicación web de videos de Cast. La lista de videos y los metadatos asociados, definidos en CastVideos.js, se encuentran en un objeto llamado mediaJSON.

Hay varias secciones principales que, en conjunto, son responsables de administrar y reproducir el video de forma local y remota. En general, es una aplicación web bastante intuitiva.

CastPlayer es la clase principal que administra toda la app, configura el reproductor, selecciona contenido multimedia y vincula eventos a PlayerHandler para reproducir contenido multimedia. CastPlayer.prototype.initializeCastPlayer es el método que configura todas las funciones de Cast. CastPlayer.prototype.switchPlayer cambia el estado entre reproductores locales y remotos. CastPlayer.prototype.setupLocalPlayer y CastPlayer.prototype.setupRemotePlayer inicializan reproductores locales y remotos.

PlayerHandler es la clase responsable de administrar la reproducción de contenido multimedia. Existen otros métodos responsables de los detalles para administrar el contenido multimedia y la reproducción.

Preguntas frecuentes

5. Agrega el botón para transmitir

Imagen de una app compatible con Cast

Una app compatible con Cast muestra el botón para transmitir en el elemento de video. Al hacer clic en ese botón, se mostrará la lista de dispositivos de transmisión que un usuario puede seleccionar. Si el usuario estaba reproduciendo contenido de forma local en el dispositivo emisor, al seleccionar un dispositivo de transmisión podrá iniciar o reanudar la reproducción en ese dispositivo. En cualquier momento de una sesión de transmisión, el usuario podrá hacer clic en el botón para transmitir y dejar de transmitir tu aplicación al dispositivo de transmisión. El usuario debe poder conectarse al dispositivo de transmisión o desconectarse de él desde cualquier pantalla de la aplicación, como se describe en la lista de tareas de diseño de Google Cast.

Configuración

El proyecto inicial requiere las mismas dependencias y configuración que la de la app de ejemplo completa, pero esta vez aloja el contenido de app-start.

En tu navegador, visita la URL https de la muestra que alojaste.

Recuerda que, a medida que realices cambios, deberás volver a alojar la muestra en tu servidor según el servicio.

Inicialización

El framework de Cast tiene un objeto singleton global, el CastContext, que coordina todas las actividades del framework. Este objeto debe inicializarse con anticipación en el ciclo de vida de la aplicación, que generalmente se llama desde una devolución de llamada asignada a window['__onGCastApiAvailable'], que se realiza después de cargar el SDK de Cast, y está disponible para su uso. En este caso, se llama a CastContext en CastPlayer.prototype.initializeCastPlayer, que, a su vez, se llama desde la devolución de llamada mencionada anteriormente.

Cuando se inicializa el CastContext, se debe proporcionar un objeto JSON options. Esta clase contiene opciones que afectan el comportamiento del framework. Lo más importante de esto es el ID de aplicación del receptor, que se utiliza para filtrar la lista de dispositivos de transmisión disponibles a fin de mostrar solo los que permiten ejecutar la aplicación especificada y para ejecutar la aplicación receptora cuando se inicia una sesión de transmisión.

Cuando desarrolles tu propia app compatible con Cast, tendrás que registrarte como desarrollador de Cast y, luego, obtener el ID de aplicación correspondiente a tu app. Para este codelab, usaremos un ID de app de muestra.

Agrega el siguiente código a index.html al final de la sección body:

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

Agrega el siguiente código a index.html para inicializar la app CastVideos y también inicializar CastContext:

<script src="CastVideos.js"></script>
<script type="text/javascript">
var castPlayer = new CastPlayer();
window['__onGCastApiAvailable'] = function(isAvailable) {
  if (isAvailable) {
    castPlayer.initializeCastPlayer();
  }
};
</script>

Ahora, debemos agregar un nuevo método en CastVideos.js, que corresponde al método que acabamos de llamar en index.html. Agreguemos un nuevo método, llamado initializeCastPlayer, que establece las opciones en CastContext e inicializa nuevos RemotePlayer y RemotePlayerControllers:

/**
 * This method sets up the CastContext, and a few other members
 * that are necessary to play and control videos on a Cast
 * device.
 */
CastPlayer.prototype.initializeCastPlayer = function() {

    var options = {};

    // Set the receiver application ID to your own (created in
    // the Google Cast Developer Console), or optionally
    // use the chrome.cast.media.DEFAULT_MEDIA_RECEIVER_APP_ID
    options.receiverApplicationId = 'C0868879';

    // Auto join policy can be one of the following three:
    // ORIGIN_SCOPED - Auto connect from same appId and page origin
    // TAB_AND_ORIGIN_SCOPED - Auto connect from same appId, page origin, and tab
    // PAGE_SCOPED - No auto connect
    options.autoJoinPolicy = chrome.cast.AutoJoinPolicy.ORIGIN_SCOPED;

    cast.framework.CastContext.getInstance().setOptions(options);

    this.remotePlayer = new cast.framework.RemotePlayer();
    this.remotePlayerController = new cast.framework.RemotePlayerController(this.remotePlayer);
    this.remotePlayerController.addEventListener(
        cast.framework.RemotePlayerEventType.IS_CONNECTED_CHANGED,
        this.switchPlayer.bind(this)
    );
};

Por último, debemos crear las variables para RemotePlayer y RemotePlayerController:

var CastPlayer = function() {
  //...
  /* Cast player variables */
  /** @type {cast.framework.RemotePlayer} */
  this.remotePlayer = null;
  /** @type {cast.framework.RemotePlayerController} */
  this.remotePlayerController = null;
  //...
};

Botón para transmitir

Ahora que se inicializó CastContext, debemos agregar el botón para transmitir a fin de permitir que el usuario seleccione un dispositivo de transmisión. El SDK de Cast proporciona un componente de botón para transmitir llamado google-cast-launcher con un ID "castbutton"". Se puede agregar al elemento de video de la aplicación con solo agregar un button en la sección media_control.

Así es como se verá el elemento del botón:

<google-cast-launcher id="castbutton"></google-cast-launcher>

Agrega el siguiente código a index.html en la sección media_control:

<div id="media_control">
  <div id="play"></div>
  <div id="pause"></div>
  <div id="progress_bg"></div>
  <div id="progress"></div>
  <div id="progress_indicator"></div>
  <div id="fullscreen_expand"></div>
  <div id="fullscreen_collapse"></div>
  <google-cast-launcher id="castbutton"></google-cast-launcher>
  <div id="audio_bg"></div>
  <div id="audio_bg_track"></div>
  <div id="audio_indicator"></div>
  <div id="audio_bg_level"></div>
  <div id="audio_on"></div>
  <div id="audio_off"></div>
  <div id="duration">00:00:00</div>
</div>

A continuación, actualiza la página en el navegador Chrome. Deberías ver un botón para transmitir en el elemento de video y, al hacer clic en él, se mostrarán los dispositivos de transmisión en la red local. El navegador Chrome administra automáticamente la detección de dispositivos. Selecciona tu dispositivo de transmisión. La app receptora de muestra se cargará en él.

No se conectó ningún servicio de reproducción multimedia; por lo tanto, aún no puedes reproducir videos en el dispositivo de transmisión. Haz clic en el botón para transmitir y detén la transmisión.

6. Transmite contenido de video

Imagen de una app compatible con Cast con el menú de selección de dispositivos Cast

Extenderemos la app de muestra de modo que también reproduzca videos de forma remota en un dispositivo de transmisión. Para ello, tenemos que escuchar los diferentes eventos generados por el framework de Cast.

Transmisión de contenido multimedia

En un nivel alto, si quieres reproducir contenido multimedia en un dispositivo de transmisión, debe suceder lo siguiente:

  1. Crea un objeto MediaInfo JSON desde el SDK de Cast que modele un elemento multimedia.
  2. El usuario se conecta al dispositivo de transmisión para iniciar la aplicación receptora.
  3. Cargar el objeto MediaInfo en tu receptor y reproducir el contenido
  4. Realizar un seguimiento del estado del contenido multimedia
  5. Enviar comandos de reproducción al receptor según las interacciones del usuario

El paso 1 equivale a asignar un objeto a otro. MediaInfo es algo que el SDK de Cast interpreta y mediaJSON es el encapsulamiento de nuestra app para un elemento multimedia. Podemos asignar fácilmente un mediaJSON a un objeto MediaInfo. Ya realizamos el paso 2 en la sección anterior. El paso 3 es fácil de completar con el SDK de Cast.

La app de ejemplo CastPlayer ya distingue entre la reproducción local y remota en el método switchPlayer:

if (cast && cast.framework) {
  if (this.remotePlayer.isConnected) {
    //...

En este codelab, no es importante que comprendas exactamente cómo funciona toda la lógica del reproductor de muestra. Sin embargo, es importante comprender que el reproductor multimedia de tu app deberá modificarse para que tenga en cuenta la reproducción local y remota.

Por el momento, el reproductor local siempre estará en el estado de reproducción local porque aún no conoce los estados de transmisión. Deberemos actualizar la IU en función de las transiciones de estado que ocurran en el framework de Cast. Por ejemplo, si comenzamos a transmitir, deberemos detener la reproducción local e inhabilitar algunos controles. De manera similar, si dejamos de transmitir contenido cuando estamos en este controlador de vista, debemos hacer la transición a la reproducción local. Para ello, tenemos que escuchar los diferentes eventos generados por el framework de Cast.

Administración de sesiones de transmisión

En el framework de Cast, una sesión de transmisión combina los pasos para conectarse a un dispositivo, iniciar una sesión (o unirse a una existente), conectarse a una aplicación receptora e inicializar un canal de control de contenido multimedia, si corresponde. El canal de control de contenido multimedia es la forma en que el framework de Cast envía y recibe mensajes relacionados con la reproducción de contenido multimedia de la app receptora.

La sesión de transmisión se iniciará automáticamente cuando el usuario seleccione un dispositivo desde el botón para transmitir y se detendrá automáticamente cuando el usuario se desconecte. El framework de Cast también administra automáticamente la reconexión a una sesión del receptor a causa de problemas de red.

El CastSession administra las sesiones de transmisión, a las que se puede acceder a través de cast.framework.CastContext.getInstance().getCurrentSession(). Las devoluciones de llamada de EventListener se pueden usar para supervisar los eventos de sesión, como crear, suspender, reanudar y finalizar.

En nuestra aplicación actual, toda la administración de la sesión y el estado se controla automáticamente en el método setupRemotePlayer. Para comenzar a configurar eso en tu app, agrega el siguiente código a tu CastVideos.js:

/**
 * Set the PlayerHandler target to use the remote player
 */
CastPlayer.prototype.setupRemotePlayer = function () {
    var castSession = cast.framework.CastContext.getInstance().getCurrentSession();

    this.playerHandler.setTarget(playerTarget);

    // Setup remote player volume right on setup
    // The remote player may have had a volume set from previous playback
    if (this.remotePlayer.isMuted) {
        this.playerHandler.mute();
    }
    var currentVolume = this.remotePlayer.volumeLevel * FULL_VOLUME_HEIGHT;
    var p = document.getElementById('audio_bg_level');
    p.style.height = currentVolume + 'px';
    p.style.marginTop = -currentVolume + 'px';

    this.hideFullscreenButton();

    this.playerHandler.play();
};

Aún debemos vincular todos los eventos de las devoluciones de llamada, además de controlar todos los eventos entrantes. Esta tarea es bastante sencilla, así que pongamos manos a la obra:

/**
 * Set the PlayerHandler target to use the remote player
 */
CastPlayer.prototype.setupRemotePlayer = function () {
    var castSession = cast.framework.CastContext.getInstance().getCurrentSession();

    // Add event listeners for player changes which may occur outside sender app
    this.remotePlayerController.addEventListener(
        cast.framework.RemotePlayerEventType.IS_PAUSED_CHANGED,
        function() {
            if (this.remotePlayer.isPaused) {
                this.playerHandler.pause();
            } else {
                this.playerHandler.play();
            }
        }.bind(this)
    );

    this.remotePlayerController.addEventListener(
        cast.framework.RemotePlayerEventType.IS_MUTED_CHANGED,
        function() {
            if (this.remotePlayer.isMuted) {
                this.playerHandler.mute();
            } else {
                this.playerHandler.unMute();
            }
        }.bind(this)
    );

    this.remotePlayerController.addEventListener(
        cast.framework.RemotePlayerEventType.VOLUME_LEVEL_CHANGED,
        function() {
            var newVolume = this.remotePlayer.volumeLevel * FULL_VOLUME_HEIGHT;
            var p = document.getElementById('audio_bg_level');
            p.style.height = newVolume + 'px';
            p.style.marginTop = -newVolume + 'px';
        }.bind(this)
    );

    // This object will implement PlayerHandler callbacks with
    // remotePlayerController, and makes necessary UI updates specific
    // to remote playback
    var playerTarget = {};

    playerTarget.play = function () {
        if (this.remotePlayer.isPaused) {
            this.remotePlayerController.playOrPause();
        }

        var vi = document.getElementById('video_image');
        vi.style.display = 'block';
        var localPlayer = document.getElementById('video_element');
        localPlayer.style.display = 'none';
    }.bind(this);

    playerTarget.pause = function () {
        if (!this.remotePlayer.isPaused) {
            this.remotePlayerController.playOrPause();
        }
    }.bind(this);

    playerTarget.stop = function () {
         this.remotePlayerController.stop();
    }.bind(this);

    playerTarget.getCurrentMediaTime = function() {
        return this.remotePlayer.currentTime;
    }.bind(this);

    playerTarget.getMediaDuration = function() {
        return this.remotePlayer.duration;
    }.bind(this);

    playerTarget.updateDisplayMessage = function () {
        document.getElementById('playerstate').style.display = 'block';
        document.getElementById('playerstatebg').style.display = 'block';
        document.getElementById('video_image_overlay').style.display = 'block';
        document.getElementById('playerstate').innerHTML =
            this.mediaContents[ this.currentMediaIndex]['title'] + ' ' +
            this.playerState + ' on ' + castSession.getCastDevice().friendlyName;
    }.bind(this);

    playerTarget.setVolume = function (volumeSliderPosition) {
        // Add resistance to avoid loud volume
        var currentVolume = this.remotePlayer.volumeLevel;
        var p = document.getElementById('audio_bg_level');
        if (volumeSliderPosition < FULL_VOLUME_HEIGHT) {
            var vScale =  this.currentVolume * FULL_VOLUME_HEIGHT;
            if (volumeSliderPosition > vScale) {
                volumeSliderPosition = vScale + (pos - vScale) / 2;
            }
            p.style.height = volumeSliderPosition + 'px';
            p.style.marginTop = -volumeSliderPosition + 'px';
            currentVolume = volumeSliderPosition / FULL_VOLUME_HEIGHT;
        } else {
            currentVolume = 1;
        }
        this.remotePlayer.volumeLevel = currentVolume;
        this.remotePlayerController.setVolumeLevel();
    }.bind(this);

    playerTarget.mute = function () {
        if (!this.remotePlayer.isMuted) {
            this.remotePlayerController.muteOrUnmute();
        }
    }.bind(this);

    playerTarget.unMute = function () {
        if (this.remotePlayer.isMuted) {
            this.remotePlayerController.muteOrUnmute();
        }
    }.bind(this);

    playerTarget.isMuted = function() {
        return this.remotePlayer.isMuted;
    }.bind(this);

    playerTarget.seekTo = function (time) {
        this.remotePlayer.currentTime = time;
        this.remotePlayerController.seek();
    }.bind(this);

    this.playerHandler.setTarget(playerTarget);

    // Setup remote player volume right on setup
    // The remote player may have had a volume set from previous playback
    if (this.remotePlayer.isMuted) {
        this.playerHandler.mute();
    }
    var currentVolume = this.remotePlayer.volumeLevel * FULL_VOLUME_HEIGHT;
    var p = document.getElementById('audio_bg_level');
    p.style.height = currentVolume + 'px';
    p.style.marginTop = -currentVolume + 'px';

    this.hideFullscreenButton();

    this.playerHandler.play();
};

Carga de contenido multimedia

En el SDK de Cast, el RemotePlayer y el RemotePlayerController proporcionan un conjunto de APIs convenientes para administrar la reproducción de contenido multimedia remoto en el receptor. En el caso de un CastSession que admita la reproducción de contenido multimedia, el SDK creará automáticamente las instancias de RemotePlayer y RemotePlayerController. Para acceder a ellos, crea instancias de cast.framework.RemotePlayer y cast.framework.RemotePlayerController, respectivamente, como se mostró antes en el codelab.

A continuación, debemos compilar un objeto MediaInfo para que el SDK procese y pase la solicitud y, luego, cargar el video seleccionado actualmente en el receptor. Para ello, agrega el siguiente código a setupRemotePlayer:

/**
 * Set the PlayerHandler target to use the remote player
 */
CastPlayer.prototype.setupRemotePlayer = function () {
    //...

    playerTarget.load = function (mediaIndex) {
        console.log('Loading...' + this.mediaContents[mediaIndex]['title']);
        var mediaInfo = new chrome.cast.media.MediaInfo(
            this.mediaContents[mediaIndex]['sources'][0], 'video/mp4');

        mediaInfo.metadata = new chrome.cast.media.GenericMediaMetadata();
        mediaInfo.metadata.metadataType = chrome.cast.media.MetadataType.GENERIC;
        mediaInfo.metadata.title = this.mediaContents[mediaIndex]['title'];
        mediaInfo.metadata.images = [
            {'url': MEDIA_SOURCE_ROOT + this.mediaContents[mediaIndex]['thumb']}];

        var request = new chrome.cast.media.LoadRequest(mediaInfo);
        castSession.loadMedia(request).then(
            this.playerHandler.loaded.bind(this.playerHandler),
            function (errorCode) {
                this.playerState = PLAYER_STATE.ERROR;
                console.log('Remote media load error: ' +
                    CastPlayer.getErrorMessage(errorCode));
            }.bind(this));
    }.bind(this);

    //...
};

Ahora, agrega un método para alternar entre la reproducción local y la remota:

/**
 * This is a method for switching between the local and remote
 * players. If the local player is selected, setupLocalPlayer()
 * is run. If there is a cast device connected we run
 * setupRemotePlayer().
 */
CastPlayer.prototype.switchPlayer = function() {
    this.stopProgressTimer();
    this.resetVolumeSlider();
    this.playerHandler.stop();
    this.playerState = PLAYER_STATE.IDLE;
    if (cast && cast.framework) {
        if (this.remotePlayer.isConnected) {
            this.setupRemotePlayer();
            return;
        }
    }
    this.setupLocalPlayer();
};

Por último, agrega un método para controlar cualquier mensaje de error de Cast:

/**
 * Makes human-readable message from chrome.cast.Error
 * @param {chrome.cast.Error} error
 * @return {string} error message
 */
CastPlayer.getErrorMessage = function(error) {
  switch (error.code) {
    case chrome.cast.ErrorCode.API_NOT_INITIALIZED:
      return 'The API is not initialized.' +
        (error.description ? ' :' + error.description : '');
    case chrome.cast.ErrorCode.CANCEL:
      return 'The operation was canceled by the user' +
        (error.description ? ' :' + error.description : '');
    case chrome.cast.ErrorCode.CHANNEL_ERROR:
      return 'A channel to the receiver is not available.' +
        (error.description ? ' :' + error.description : '');
    case chrome.cast.ErrorCode.EXTENSION_MISSING:
      return 'The Cast extension is not available.' +
        (error.description ? ' :' + error.description : '');
    case chrome.cast.ErrorCode.INVALID_PARAMETER:
      return 'The parameters to the operation were not valid.' +
        (error.description ? ' :' + error.description : '');
    case chrome.cast.ErrorCode.RECEIVER_UNAVAILABLE:
      return 'No receiver was compatible with the session request.' +
        (error.description ? ' :' + error.description : '');
    case chrome.cast.ErrorCode.SESSION_ERROR:
      return 'A session could not be created, or a session was invalid.' +
        (error.description ? ' :' + error.description : '');
    case chrome.cast.ErrorCode.TIMEOUT:
      return 'The operation timed out.' +
        (error.description ? ' :' + error.description : '');
  }
};

Ahora, ejecuta la app. Conéctate a tu dispositivo de transmisión y comienza a reproducir un video. Deberías ver que el video se reproduce en el receptor.

7. Cómo agregar compatibilidad con Cast Connect

La biblioteca de Cast Connect permite que las aplicaciones emisoras existentes se comuniquen con las aplicaciones para Android TV a través del protocolo de Cast. Cast Connect se compila sobre la infraestructura de Cast, y tu app de Android TV actúa como receptora.

Dependencias

  • Navegador Chrome versión M87 o posterior

Cómo configurar el receptor de Android como compatible

Para iniciar la aplicación para Android TV, también conocida como receptor de Android, debemos establecer la marca androidReceiverCompatible como verdadera en el objeto CastOptions.

Agrega el siguiente código a tu CastVideos.js en la función initializeCastPlayer:

var options = {};
...
options.androidReceiverCompatible = true;

cast.framework.CastContext.getInstance().setOptions(options);

Configura las credenciales de lanzamiento

En el lado del remitente, puedes especificar CredentialsData para representar quién se unirá a la sesión. credentials es una cadena que puede definir el usuario, siempre y cuando tu app para ATV pueda comprenderla. El CredentialsData solo se pasa a tu app para Android TV durante el inicio o el tiempo de unión. Si lo vuelves a configurar mientras estás conectado, no se pasará a tu app para Android TV.

Para establecer las credenciales de inicio, CredentialsData se debe definir en cualquier momento después de configurar las opciones de inicio.

Agrega el siguiente código a tu clase CastVideos.js en la función initializeCastPlayer:

cast.framework.CastContext.getInstance().setOptions(options);
...
let credentialsData = new chrome.cast.CredentialsData("{\"userId\": \"abc\"}");
cast.framework.CastContext.getInstance().setLaunchCredentialsData(credentialsData);
...

Cómo establecer credenciales en la solicitud de carga

En caso de que tu app de receptor web y tu app para Android TV controlen credentials de manera diferente, es posible que debas definir credenciales independientes para cada una. Para ello, agrega el siguiente código a tu CastVideos.js en playerTarget.load en la función setupRemotePlayer:

...
var request = new chrome.cast.media.LoadRequest(mediaInfo);
request.credentials = 'user-credentials';
request.atvCredentials = 'atv-user-credentials';
...

Según la app receptora a la que transmite el remitente, el SDK ahora controlará automáticamente qué credenciales usar para la sesión actual.

Prueba Cast Connect

Pasos para instalar el APK de Android TV en Chromecast con Google TV:

  1. Busca la dirección IP de tu dispositivo Android TV. Por lo general, está disponible en Configuración > Internet y redes > (Nombre de la red a la que está conectado el dispositivo). A la derecha, se mostrarán los detalles y la IP de tu dispositivo en la red.
  2. Usa la dirección IP de tu dispositivo para conectarte a él a través de ADB con la terminal:
$ adb connect <device_ip_address>:5555
  1. En la ventana de la terminal, navega a la carpeta de nivel superior de las muestras del codelab que descargaste al comienzo de este codelab. Por ejemplo:
$ cd Desktop/chrome_codelab_src
  1. Para instalar el archivo .apk de esta carpeta en tu Android TV, ejecuta el siguiente comando:
$ adb -s <device_ip_address>:5555 install android-tv-app.apk
  1. Ahora deberías poder ver una app llamada Cast Videos en el menú Tus apps de tu dispositivo Android TV.
  2. Ejecuta el código del emisor web actualizado y establece una sesión de transmisión con tu dispositivo Android TV usando el ícono de transmisión o seleccionando Cast.. en el menú desplegable del navegador Chrome. Ahora debería iniciarse la app de Android TV en tu receptor Android y permitirte controlar la reproducción con el control remoto de Android TV.

8. Felicitaciones

Ahora sabes cómo hacer que una app de video sea compatible con Cast mediante los widgets del SDK de Cast en una app web de Chrome.

Para obtener más detalles, consulta la guía para desarrolladores del Receptor web.