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

  • La versión más reciente del navegador Google Chrome
  • Servicio de hosting HTTPS, como Firebase Hosting o ngrok.
  • Un dispositivo 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 una, puedes omitir el paso Agregar compatibilidad con Cast Connect 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 la versión completa, debe estar alojada.

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

Ejecuta el servidor

Una vez que hayas configurado el servicio que elijas, navega a app-done y, luego, inicia tu servidor.

En tu navegador, visita la URL HTTPS de la muestra 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 video que se reproduce en un dispositivo de transmisión

Haz clic en el botón de pausa del elemento de video para pausarlo en la app receptora. Haz clic en el botón de reproducción del elemento de video para seguir reproduciendo el video nuevamente.

Haz clic en el botón para transmitir y deja de transmitir al dispositivo Google Cast.

Antes de continuar, detén el servidor.

4. Prepara el proyecto inicial

Imagen de video que se reproduce en un dispositivo de transmisión

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 tienes todo listo para compilar sobre el proyecto inicial usando 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 la muestra en tu servidor en función del 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 de 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 del 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 de la aplicación web de videos de transmisión. La lista de videos y sus metadatos asociados definidos en CastVideos.js se encuentran en un objeto llamado mediaJSON.

Hay algunas secciones principales que, en conjunto, se encargan de administrar y reproducir el video de forma local y remota. En términos generales, es una aplicación web bastante sencilla.

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 de la administración del 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 en función del 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, por lo general, se llama desde una devolución de llamada asignada a window['__onGCastApiAvailable'], que se llama después de que se carga el SDK de Cast, y está disponible para su uso. En este caso, se llama a CastContext en CastPlayer.prototype.initializeCastPlayer, al que se llama desde la devolución de llamada mencionada anteriormente.

Cuando se inicializa CastContext, se debe proporcionar un objeto JSON options. Esta clase contiene opciones que afectan el comportamiento del framework. La más importante es el ID de aplicación receptora, que se usa para filtrar la lista de dispositivos de transmisión disponibles para mostrar solo los dispositivos que pueden ejecutar la app especificada y para iniciar 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 de 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 de "castbutton". Se puede agregar al elemento de video de la aplicación con solo agregar un button en la sección media_control.

Así 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, cuando hagas clic en él, se mostrarán los dispositivos de transmisión en tu 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 estableció compatibilidad con la reproducción de contenido multimedia, por lo que aún no puedes reproducir videos en el dispositivo de transmisión. Haz clic en el botón para transmitir a fin de detener la transmisión.

6. Transmite contenido de video

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

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 términos generales, si quieres reproducir contenido multimedia en un dispositivo de transmisión, debe ocurrir lo siguiente:

  1. Crea un objeto MediaInfo JSON desde el SDK de Cast que modela 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 entiende y mediaJSON es el encapsulamiento de nuestra app para un elemento multimedia. podemos asignar fácilmente un mediaJSON a un MediaInfo. Ya realizamos el paso 2 en la sección anterior. El paso 3 es fácil de realizar con el SDK de Cast.

La app de ejemplo CastPlayer ya distingue entre la reproducción local y la 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. Del mismo modo, 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 (o unirse a una sesión 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 la sesión de un receptor debido a 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 la creación, la suspensión, la reanudación y la finalización.

En nuestra aplicación actual, toda la administración de la sesión y el estado se controla por nosotros 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 necesitamos vincular todos los eventos de las devoluciones de llamada y controlar todos los eventos entrantes. Esta tarea es bastante sencilla, así que veámosla:

/**
 * 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, RemotePlayer y RemotePlayerController proporcionan un conjunto de APIs convenientes para administrar la reproducción de contenido multimedia remoto en la app receptora. En el caso de una 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 cargar el video seleccionado actualmente en la app receptora. Para ello, debemos crear un objeto MediaInfo para que el SDK procese y pase la solicitud. 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 los mensajes 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 de Android TV a través del protocolo de transmisión. Cast Connect se basa en la infraestructura de transmisión y tu app para Android TV actúa como receptora.

Dependencias

  • Navegador Chrome versión M87 o posterior

Configurar Android Receiver Compatible

Para iniciar la aplicación para Android TV, también conocida como Android Receiver, 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);

Configurar credenciales de lanzamiento

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

Para configurar las credenciales de lanzamiento, se debe definir CredentialsData en cualquier momento después de establecer 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);
...

Configurar credenciales en una solicitud de carga

En caso de que tu app de receptor web y tu app de Android TV controlen credentials de manera diferente, es posible que debas definir credenciales separadas para cada una. Para solucionarlo, 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 la emisora transmita, el SDK ahora controlará automáticamente las credenciales que se deben 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. Generalmente, está disponible en Configuración > Redes y Internet > (Nombre de la red a la que está conectado tu dispositivo). A la derecha, se mostrarán los detalles y la IP del dispositivo en la red.
  2. Usa la dirección IP para que tu dispositivo se conecte a través de ADB desde la terminal:
$ adb connect <device_ip_address>:5555
  1. Desde la ventana de tu terminal, navega a la carpeta de nivel superior de las muestras de codelab que descargaste al comienzo de este codelab. Por ejemplo:
$ cd Desktop/chrome_codelab_src
  1. Instala el archivo .apk en esta carpeta en tu Android TV ejecutando lo siguiente:
$ adb -s <device_ip_address>:5555 install android-tv-app.apk
  1. Ahora deberías poder ver una app con el nombre Transmitir videos en el menú Tus apps de tu dispositivo Android TV.
  2. Ejecuta el código de remitente web actualizado y establece una sesión de transmisión con tu dispositivo Android TV. Para ello, presiona el ícono de transmisión o selecciona Cast.. en el menú desplegable del navegador Chrome. Esto ahora debería iniciar la app de Android TV en tu Android Receiver, y te permitirá controlar la reproducción con el control remoto de Android TV.

8. Felicitaciones

Ahora sabes cómo habilitar la transmisión de contenido en una app de video con los widgets del SDK de Cast en una app web de Chrome.

Para obtener más información, consulta la guía para desarrolladores de Web Sender.