Cómo compilar un receptor web personalizado

1. Descripción general

Logotipo de Google Cast

En este codelab, aprenderás a compilar una app receptora web personalizada para reproducir contenido en dispositivos compatibles con Cast.

¿Qué es Google Cast?

Google Cast permite a los usuarios transmitir contenido desde un dispositivo móvil a una TV. Luego, los usuarios pueden usar su dispositivo móvil o el navegador Chrome para computadoras de escritorio como control remoto para reproducir contenido multimedia en la TV.

El SDK de Google Cast permite que tu app controle dispositivos compatibles con Google Cast (por ejemplo, una TV o un sistema de sonido). Este SDK te proporciona los componentes de 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. Obtén más información aquí.

¿Qué compilaremos?

Cuando completes este codelab, tendrás una app HTML5 que funcionará como tu propia receptora personalizada capaz de mostrar contenido de video en dispositivos compatibles con Cast.

Qué aprenderás

  • Cómo prepararse para el desarrollo de la app receptora
  • Conceptos básicos de una app receptora compatible con Cast basados en el framework de la aplicación de Cast
  • Cómo recibir un video transmitido
  • Cómo integrar el registro de depuración
  • Cómo optimizar tu app receptora para pantallas inteligentes

Requisitos

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 en la compilación de aplicaciones 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. Implementa tu app receptora de forma local

Para poder usar tu receptor web con un dispositivo de transmisión, este debe estar alojado en un lugar donde el dispositivo pueda alcanzarlo. Si ya tienes un servidor disponible que admita https, omite las siguientes instrucciones y anota la URL, ya que la necesitarás en la siguiente sección.

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

Ejecuta el servidor

Una vez que hayas configurado el servicio que deseas, navega hasta app-start y, luego, inicia tu servidor.

Toma nota de la URL de tu receptor alojado. Lo utilizarás en la próxima sección.

4. Registra una aplicación en la Consola para desarrolladores de Cast

Debes registrar tu aplicación para poder ejecutar una app receptora personalizada, como se compiló en este codelab, en dispositivos Chromecast. Una vez que hayas registrado tu aplicación, recibirás un ID de aplicación que la aplicación emisora debe usar para realizar llamadas a la API, por ejemplo, para iniciar una aplicación receptora.

Imagen de la consola para desarrolladores del SDK de Google Cast con el botón "Agregar aplicación nueva" destacado

Haz clic en "Agregar nueva aplicación".

Imagen de la pantalla “New Receiver Application” con la opción “Custom Receiver” destacada

Selecciona "Custom Receiver", que es lo que estamos creando.

Imagen de la pantalla "Nuevo receptor personalizado" en la que se muestra una URL que alguien está escribiendo en el campo "URL de la aplicación del receptor"

Ingresa los detalles de la nueva app receptora; asegúrate de usar la URL final

en la última sección. Toma nota del ID de aplicación asignado a tu app receptora nueva.

También debes registrar tu dispositivo Google Cast para que pueda acceder a la aplicación receptora antes de publicarla. Una vez que publiques tu aplicación receptora, estará disponible para todos los dispositivos Google Cast. Para los fines de este codelab, se recomienda trabajar con una aplicación receptora no publicada.

Imagen de la consola para desarrolladores del SDK de Google Cast con el botón "Agregar dispositivo nuevo" destacado

Haz clic en "Agregar nuevo dispositivo".

Imagen del diálogo "Agregar un dispositivo receptor de transmisión"

Ingresa el número de serie impreso en la parte posterior de tu dispositivo de transmisión y asígnale un nombre descriptivo. También puedes encontrar el número de serie si transmites la pantalla en Chrome cuando accedes a la Consola para desarrolladores del SDK de Google Cast.

El receptor y el dispositivo demorarán entre 5 y 15 minutos en estar listos para la prueba. Después de esperar entre 5 y 15 minutos, debes reiniciar tu dispositivo de transmisión.

5. Ejecuta la app de muestra

Logotipo de Google Chrome

Mientras esperamos a que nuestra nueva aplicación receptora esté lista para la prueba, veamos cómo se ve una muestra de una app receptora completa. La app receptora que compilaremos podrá reproducir contenido multimedia mediante una transmisión con tasa de bits adaptable (utilizaremos contenido de muestra codificado para la Transmisión adaptable y dinámica a través de HTTP [DASH]).

En tu navegador, abre la herramienta de comando y control (CaC).

Imagen de la pestaña “Cast Connect & Logger Controls” de la herramienta de comando y control (CaC)

  1. Deberías ver nuestra herramienta de CaC.
  2. Usa el ID del receptor de muestra predeterminado "CC1AD845" y haz clic en el botón "Establecer ID de app".
  3. Haz clic en el botón para transmitir en la parte superior izquierda y selecciona tu dispositivo Google Cast.

Imagen de la pestaña “Cast Connect & Logger Controls” de la herramienta de comando y control (CaC) que indica que está conectado a una app receptora

  1. Navega a la pestaña "Load Media" en la parte superior.

Imagen de la pestaña "Load Media" de la herramienta de comando y control (CaC)

  1. Haz clic en el botón "Load by Content" para reproducir un video de muestra.
  2. El video comenzará a reproducirse en tu dispositivo Google Cast para mostrar la funcionalidad básica de la app receptora si se usa la app receptora predeterminada.

6. Prepara el proyecto inicial

Debemos agregar compatibilidad con Google Cast a la app inicial que descargaste. Estos son algunos términos relacionados con 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.

Ahora 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. Abre js/receiver.js y index.html

Ten en cuenta que, mientras trabajas en este codelab, http-server debería detectar los cambios que hagas. De lo contrario, intenta finalizar y reiniciar http-server.

Diseño de la app

La app receptora inicializa la sesión de transmisión y permanecerá en espera hasta que llegue una solicitud de CARGA (en otras palabras, el comando para reproducir un contenido multimedia) de un remitente.

La app consta de una vista principal, definida en index.html, y un archivo JavaScript llamado js/receiver.js, que contiene toda la lógica para que funcione nuestra app receptora.

index.html

Este archivo html contendrá la IU de nuestra app receptora. Por ahora, está vacío, y lo agregaremos a lo largo de todo el codelab.

receiver.js

Esta secuencia de comandos administrará toda la lógica de la app receptora. Por el momento, es solo un archivo vacío, pero lo convertiremos en una app receptora de transmisión completamente funcional con solo unas pocas líneas de código en la siguiente sección.

7. Un receptor de transmisión básico

Un receptor de Cast básico inicializará la sesión de transmisión al inicio. Esto es necesario para indicarles a todas las aplicaciones emisoras conectadas que la activación de la app receptora se realizó correctamente. Además, el nuevo SDK viene preconfigurado para controlar medios de transmisión con tasa de bits adaptable (con DASH, HLS y Smooth Streaming) y archivos MP4 sin formato listos para usar. Hagamos una prueba.

Inicialización

Agrega el siguiente código a index.html en el encabezado:

<head>
  ...

  <script src="//www.gstatic.com/cast/sdk/libs/caf_receiver/v3/cast_receiver_framework.js"></script>
</head>

Agrega el siguiente código a index.html <body> antes de <footer> cargando receiver.js, a fin de proporcionarle al SDK de la app receptora espacio para abrir la IU predeterminada de la app receptora que se enviará con la secuencia de comandos que acabas de agregar.

<cast-media-player></cast-media-player>

Ahora, debemos inicializar el SDK en js/receiver.js, lo que incluye lo siguiente:

  • adquirir una referencia a CastReceiverContext, tu punto de entrada principal a todo el SDK de la app receptora
  • almacenar una referencia a PlayerManager, el objeto que maneja la reproducción y te proporciona todos los hooks que necesitas para complementar tu propia lógica personalizada
  • inicializar el SDK llamando a start() en CastReceiverContext

Agrega lo siguiente a js/receiver.js:

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

context.start();

8. Transmite contenido "básico" de video

En este codelab, usa la herramienta de CaC para probar tu nueva app receptora.

Dirige tu navegador web a la Herramienta de comando y control (CaC).

Imagen de la pestaña “Cast Connect & Logger Controls” de la herramienta de comando y control (CaC)

Asegúrate de sustituir tu propio ID de la app como se registró antes en el campo y haz clic en "Set App ID". Esto le indica a la herramienta que use la app receptora cuando se inicia la sesión de transmisión.

Transmisión de contenido multimedia

En términos generales, para reproducir contenido multimedia en un dispositivo de transmisión, debe suceder lo siguiente:

  1. El remitente crea un objeto MediaInfo JSON desde el SDK de Cast que modela un elemento multimedia.
  2. La app emisora se conecta al dispositivo de transmisión para iniciar la aplicación receptora.
  3. La app receptora carga el objeto MediaInfo a través de una solicitud LOAD para reproducir el contenido.
  4. La app receptora supervisa y realiza un seguimiento del estado del contenido multimedia.
  5. La app emisora envía comandos de reproducción al receptor para controlar la reproducción en función de las interacciones del usuario con la app emisora.

En este primer intento básico, propagaremos MediaInfo con una URL de elemento reproducible (almacenada en MediaInfo.contentUrl).

Una remitente real usa un identificador multimedia específico de la aplicación en MediaInfo.contentId. La app receptora usa el contentId como identificador para realizar llamadas adecuadas a la API de backend a fin de resolver la URL real del activo y establecerla en MediaInfo.contentUrl.. La app receptora también se encargará de tareas como la adquisición de licencias de DRM o la inserción de información sobre las pausas publicitarias.

Ampliaremos la app receptora para que haga algo parecido en la próxima sección. Por ahora, haz clic en el ícono de transmisión y selecciona tu dispositivo para abrir la app receptora.

Imagen de la pestaña “Cast Connect & Logger Controls” de la herramienta de comando y control (CaC) que indica que está conectado a una app receptora

Ve a la pestaña "Load Media" y haz clic en el botón "Load by Content". La app receptora debería comenzar a reproducir el contenido de muestra.

Imagen de la pestaña &quot;Load Media&quot; de la herramienta de comando y control (CaC)

Así que, listo para usar, el SDK del receptor controla lo siguiente:

  • Cómo inicializar la sesión de transmisión
  • Controlar solicitudes LOAD entrantes de remitentes que contengan elementos reproducibles
  • Proporciona una IU de reproductor básica lista para mostrarse en la pantalla grande.

Siéntete libre de explorar la herramienta de CaC y su código antes de pasar a la siguiente sección, en la que extenderemos nuestra app receptora para que se comunique con una API de muestra simple a fin de completar las solicitudes LOAD entrantes de los remitentes.

9. Cómo realizar la integración con una API externa

En línea con la manera en que la mayoría de los desarrolladores interactúan con sus receptores de transmisión en las aplicaciones del mundo real, modificaremos nuestra app receptora para controlar las solicitudes LOAD que hacen referencia al contenido multimedia previsto por su clave de API en lugar de enviar la URL de un elemento reproducible.

Las aplicaciones suelen hacer esto por los siguientes motivos:

  • Es posible que el remitente no conozca la URL del contenido.
  • La aplicación de Cast está diseñada para controlar la autenticación, otra lógica empresarial o llamadas a la API directamente en la app receptora.

Esta funcionalidad se implementa principalmente en el método PlayerManager setMessageInterceptor(). Esto te permite interceptar mensajes entrantes por tipo y modificarlos antes de que lleguen al controlador de mensajes interno del SDK. En esta sección, nos ocuparemos de las solicitudes de LOAD. Para ello, haremos lo siguiente:

  • Leer la solicitud LOAD entrante y su contentId personalizado
  • Realiza una llamada GET a nuestra API para buscar el elemento que se puede transmitir por su contentId.
  • Modifica la solicitud LOAD con la URL de la transmisión.
  • Modifica el objeto MediaInformation para establecer los parámetros del tipo de transmisión.
  • Pasa la solicitud al SDK para su reproducción o rechaza el comando si no podemos buscar el contenido multimedia solicitado.

La API de muestra proporcionada muestra los hooks del SDK para personalizar tareas comunes de la app receptora, a la vez que se basa en una experiencia casi lista para usar.

API de muestra

Dirige tu navegador a https://storage.googleapis.com/cpe-sample-media/content.json y consulta nuestro catálogo de videos de muestra. El contenido incluye URLs de imágenes de póster en formato PNG y también transmisiones DASH y HLS. Las transmisiones DASH y HLS apuntan a fuentes de audio y video de multiplexadas que se almacenan en contenedores mp4 fragmentados.

{
  "bbb": {
    "author": "The Blender Project",
    "description": "Grumpy Bunny is grumpy",
    "poster": "https://[...]/[...]/BigBuckBunny/images/screenshot1.png",
    "stream": {
      "dash": "https://[...]/[...]/BigBuckBunny/BigBuckBunny_master.mpd",
      "hls": "https://[...]/[...]/BigBuckBunny/BigBuckBunny_master.m3u8",
    "title": "Big Buck Bunny"
  },
  "fbb_ad": {
    "author": "Google Inc.",
    "description": "Introducing Chromecast. The easiest way to enjoy [...]",
    "poster": "https://[...]/[...]/ForBiggerBlazes/images/screenshot8.png",
    "stream": {
      "dash": "https://[...]/[...]/ForBiggerBlazes/ForBiggerBlazes.mpd",
      "hls": "https://[...]/[...]/ForBiggerBlazes/ForBiggerBlazes.m3u8",
    "title": "For Bigger Blazes"
  },

  [...]

}

En el siguiente paso, asignaremos la clave de cada entrada (por ejemplo, bbb, fbb_ad) a la URL de la transmisión después de que se llame al receptor con una solicitud LOAD.

Intercepta la solicitud LOAD

En este paso, crearemos un interceptor de carga con una función que realice una solicitud XHR al archivo JSON alojado. Una vez que se obtenga el archivo JSON, analizaremos el contenido y configuraremos los metadatos. En las siguientes secciones, personalizaremos los parámetros de MediaInformation para especificar el tipo de contenido.

Agrega el siguiente código a tu archivo js/receiver.js, justo antes de la llamada a context.start().

function makeRequest (method, url) {
  return new Promise(function (resolve, reject) {
    let xhr = new XMLHttpRequest();
    xhr.open(method, url);
    xhr.onload = function () {
      if (this.status >= 200 && this.status < 300) {
        resolve(JSON.parse(xhr.response));
      } else {
        reject({
          status: this.status,
          statusText: xhr.statusText
        });
      }
    };
    xhr.onerror = function () {
      reject({
        status: this.status,
        statusText: xhr.statusText
      });
    };
    xhr.send();
  });
}

playerManager.setMessageInterceptor(
    cast.framework.messages.MessageType.LOAD,
    request => {
      return new Promise((resolve, reject) => {
        // Fetch content repository by requested contentId
        makeRequest('GET', 'https://storage.googleapis.com/cpe-sample-media/content.json').then(function (data) {
          let item = data[request.media.contentId];
          if(!item) {
            // Content could not be found in repository
            reject();
          } else {
            // Add metadata
            let metadata = new
               cast.framework.messages.GenericMediaMetadata();
            metadata.title = item.title;
            metadata.subtitle = item.author;

            request.media.metadata = metadata;

            // Resolve request
            resolve(request);
          }
        });
      });
    });

En la siguiente sección, se describe cómo configurar la propiedad media de la solicitud de carga para el contenido DASH.

Cómo usar el contenido DASH de la API de muestra

Ahora que preparamos el interceptor de carga, especificaremos el tipo de contenido para el receptor. Esta información le proporcionará a la app receptora la URL de la lista de reproducción principal y el tipo de MIME de transmisión. Agrega el siguiente código al archivo js/receiver.js en el Promise() del interceptor LOAD:

...
playerManager.setMessageInterceptor(
    cast.framework.messages.MessageType.LOAD,
    request => {
      return new Promise((resolve, reject) => {
          ...
          } else {
            // Adjusting request to make requested content playable
            request.media.contentUrl = item.stream.dash;
            request.media.contentType = 'application/dash+xml';
            ...
          }
        });
      });
    });

Una vez que completes este paso, puedes proceder a realizar una prueba para intentar cargar con contenido DASH. Si quieres probar la carga con contenido HLS, consulta el siguiente paso.

Usa el contenido HLS de la API de muestra

La API de muestra incluye contenido HLS y DASH. Además de configurar el contentType como lo hicimos en el paso anterior, la solicitud de carga necesitará algunas propiedades adicionales para usar las URLs de HLS de la API de muestra. Cuando el receptor está configurado para reproducir transmisiones HLS, el tipo de contenedor predeterminado que se espera es la transmisión de transporte (TS). Como resultado, la app receptora intentará abrir las transmisiones de MP4 de muestra en formato TS solo si se modifica la propiedad contentUrl. En la solicitud de carga, se debe modificar el objeto MediaInformation con propiedades adicionales para que la app receptora sepa que el contenido es de tipo MP4 y no TS. Agrega el siguiente código a tu archivo js/receiver.js en el interceptor de carga para modificar las propiedades contentUrl y contentType. Además, agrega las propiedades HlsSegmentFormat y HlsVideoSegmentFormat.

...
playerManager.setMessageInterceptor(
    cast.framework.messages.MessageType.LOAD,
    request => {
      return new Promise((resolve, reject) => {
          ...
          } else {
            // Adjusting request to make requested content playable
            request.media.contentUrl = item.stream.hls;
            request.media.contentType = 'application/x-mpegurl';
            request.media.hlsSegmentFormat = cast.framework.messages.HlsSegmentFormat.FMP4;
            request.media.hlsVideoSegmentFormat = cast.framework.messages.HlsVideoSegmentFormat.FMP4;
            ...
          }
        });
      });
    });

Pruébalo

Una vez más, abre la herramienta de comando y control (CaC) y establece el ID de app como el ID de app de tu receptor. Selecciona tu dispositivo con el botón para transmitir.

Navega a la pestaña "Load Media". Esta vez, borra el texto del campo "Content URL" junto al botón "Load by Content", lo que obligará a nuestra aplicación a enviar una solicitud LOAD que contenga solo la referencia contentId a nuestro contenido multimedia.

Imagen de la pestaña &quot;Load Media&quot; de la herramienta de comando y control (CaC)

Si todo funcionó bien con tus modificaciones en la app receptora, el interceptor se debería encargar de transformar el objeto MediaInfo en algo que el SDK pueda reproducir en la pantalla.

Haz clic en el botón "Load by Content" para ver si el contenido multimedia se reproduce correctamente. Si lo deseas, puedes cambiar el ID de contenido por otro ID en el archivo content.json.

10. Optimización para pantallas inteligentes

Las pantallas inteligentes son dispositivos con funcionalidad táctil que permiten que las aplicaciones receptoras admitan controles táctiles.

En esta sección, se explica cómo optimizar tu aplicación receptora cuando se inicia en pantallas inteligentes y cómo personalizar los controles del reproductor.

Accede a los controles de la IU

Se puede acceder al objeto de controles de la IU para pantallas inteligentes mediante cast.framework.ui.Controls.GetInstance(). Agrega el siguiente código a tu archivo js/receiver.js arriba de context.start():

...

// Optimizing for smart displays
const touchControls = cast.framework.ui.Controls.getInstance();

context.start();

Si no usas el elemento <cast-media-player>, deberás configurar touchScreenOptimizedApp en CastReceiverOptions. En este codelab, usamos el elemento <cast-media-player>.

context.start({ touchScreenOptimizedApp: true });

Los botones de control predeterminados se asignan a cada ranura en función de MetadataType y MediaStatus.supportedMediaCommands.

Controles de video

En el caso de MetadataType.MOVIE, MetadataType.TV_SHOW y MetadataType.GENERIC, el objeto de controles de la IU para pantallas inteligentes se mostrará como en el siguiente ejemplo.

Imagen de un video que se reproduce con controles de la IU superpuestos

  1. --playback-logo-image
  2. MediaMetadata.subtitle
  3. MediaMetadata.title
  4. MediaStatus.currentTime
  5. MediaInformation.duration
  6. ControlsSlot.SLOT_SECONDARY_1: ControlsButton.QUEUE_PREV
  7. ControlsSlot.SLOT_PRIMARY_1: ControlsButton.SEEK_BACKWARD_30
  8. PLAY/PAUSE
  9. ControlsSlot.SLOT_PRIMARY_2: ControlsButton.SEEK_FORWARD_30
  10. ControlsSlot.SLOT_SECONDARY_2: ControlsButton.QUEUE_NEXT

Controles de audio

En el caso de MetadataType.MUSIC_TRACK, el objeto de controles de la IU para pantallas inteligentes se mostrará de la siguiente manera:

Imagen de música que se reproduce con controles de la IU superpuestos

  1. --playback-logo-image
  2. MusicTrackMediaMetadata.albumName
  3. MusicTrackMediaMetadata.title
  4. MusicTrackMediaMetadata.albumArtist
  5. MusicTrackMediaMetadata.images[0]
  6. MediaStatus.currentTime
  7. MediaInformation.duration
  8. ControlsSlot.SLOT_SECONDARY_1: ControlsButton.NO_BUTTON
  9. ControlsSlot.SLOT_PRIMARY_1: ControlsButton.QUEUE_PREV
  10. PLAY/PAUSE
  11. ControlsSlot.SLOT_PRIMARY_2: ControlsButton.QUEUE_NEXT
  12. ControlsSlot.SLOT_SECONDARY_2: ControlsButton.NO_BUTTON

Actualiza los comandos de contenido multimedia compatibles

El objeto de controles de la IU también determina si se muestra o no un ControlsButton, en función de MediaStatus.supportedMediaCommands.

Cuando el valor de supportedMediaCommands sea igual a ALL_BASIC_MEDIA, se mostrará el diseño de control predeterminado de la siguiente manera:

Imagen de los controles del reproductor multimedia: barra de progreso, botón &quot;Reproducir&quot;, botones &quot;Avanzar&quot; y &quot;Retroceder&quot; habilitados

Cuando el valor de supportedMediaCommands sea igual a ALL_BASIC_MEDIA | QUEUE_PREV | QUEUE_NEXT, se mostrará el diseño de control predeterminado de la siguiente manera:

Imagen de los controles del reproductor multimedia: barra de progreso, botón “Reproducir”, botones “Avanzar” y “Saltar hacia atrás”, y los botones “Cola anterior” y “En fila siguiente” habilitados

Cuando el valor de supportedMediaCommands sea igual a PAUSE | QUEUE_PREV | QUEUE_NEXT, se mostrará el diseño de control predeterminado de la siguiente manera:

Imagen de los controles del reproductor multimedia: barra de progreso, botón “Reproducir” y los botones “Cola anterior” y “A continuación” habilitados

Cuando haya pistas de texto disponibles, el botón de subtítulos siempre aparecerá en SLOT_1.

Imagen de los controles del reproductor multimedia: barra de progreso, botón &quot;Reproducir&quot;, botones &quot;Saltar hacia adelante&quot; y &quot;Saltar hacia atrás&quot;, botones &quot;Cola anterior&quot; y &quot;En fila a continuación&quot;, y botones &quot;Subtítulos&quot; habilitados

Para cambiar dinámicamente el valor de supportedMediaCommands después de iniciar el contexto de un receptor, puedes llamar a PlayerManager.setSupportedMediaCommands para anular el valor. Además, puedes agregar un comando nuevo con addSupportedMediaCommands o quitar uno existente con removeSupportedMediaCommands.

Personaliza los botones de control

Puedes personalizar los controles con PlayerDataBinder. Agrega el siguiente código a tu archivo js/receiver.js debajo de touchControls para establecer la primera ranura de tus controles:

...

// Optimizing for smart displays
const touchControls = cast.framework.ui.Controls.getInstance();
const playerData = new cast.framework.ui.PlayerData();
const playerDataBinder = new cast.framework.ui.PlayerDataBinder(playerData);

playerDataBinder.addEventListener(
  cast.framework.ui.PlayerDataEventType.MEDIA_CHANGED,
  (e) => {
    if (!e.value) return;

    // Clear default buttons and re-assign
    touchControls.clearDefaultSlotAssignments();
    touchControls.assignButton(
      cast.framework.ui.ControlsSlot.SLOT_PRIMARY_1,
      cast.framework.ui.ControlsButton.SEEK_BACKWARD_30
    );
  });

context.start();

11. Cómo implementar la navegación multimedia en pantallas inteligentes

La exploración multimedia es una función del receptor de CAF que permite a los usuarios explorar contenido adicional en dispositivos táctiles. A fin de implementar esto, usarás PlayerDataBinder para configurar la IU de BrowseContent. Luego, puedes propagarlo con BrowseItems según el contenido que desees mostrar.

BrowseContent

A continuación, se muestra un ejemplo de la IU de BrowseContent y sus propiedades:

Imagen de la IU de ExploreContent que muestra dos miniaturas de video y una parte de una tercera

  1. BrowseContent.title
  2. BrowseContent.items

Relación de aspecto

Usa targetAspectRatio property a fin de seleccionar la mejor relación de aspecto para tus recursos de imagen. El SDK de receptor de CAF admite tres relaciones de aspecto: SQUARE_1_TO_1, PORTRAIT_2_TO_3 y LANDSCAPE_16_TO_9.

BrowseItem

Usa BrowseItem para mostrar el título, los subtítulos, la duración y la imagen de cada elemento:

Imagen de la IU de ExploreContent que muestra dos miniaturas de video y una parte de una tercera

  1. BrowseItem.image
  2. BrowseItem.duration
  3. BrowseItem.title
  4. BrowseItem.subtitle

Cómo configurar los datos de exploración multimedia

Puedes proporcionar una lista de contenido multimedia para la navegación llamando a setBrowseContent. Agrega el siguiente código a tu archivo js/receiver.js debajo de tu playerDataBinder y al objeto de escucha de eventos MEDIA_CHANGED para configurar los elementos de navegación con el título "A continuación".

// Optimizing for smart displays
const touchControls = cast.framework.ui.Controls.getInstance();
const playerData = new cast.framework.ui.PlayerData();
const playerDataBinder = new cast.framework.ui.PlayerDataBinder(playerData);

...

let browseItems = getBrowseItems();

function getBrowseItems() {
  let browseItems = [];
  makeRequest('GET', 'https://storage.googleapis.com/cpe-sample-media/content.json')
  .then(function (data) {
    for (let key in data) {
      let item = new cast.framework.ui.BrowseItem();
      item.entity = key;
      item.title = data[key].title;
      item.subtitle = data[key].description;
      item.image = new cast.framework.messages.Image(data[key].poster);
      item.imageType = cast.framework.ui.BrowseImageType.MOVIE;
      browseItems.push(item);
    }
  });
  return browseItems;
}

let browseContent = new cast.framework.ui.BrowseContent();
browseContent.title = 'Up Next';
browseContent.items = browseItems;
browseContent.targetAspectRatio = cast.framework.ui.BrowseImageAspectRatio.LANDSCAPE_16_TO_9;

playerDataBinder.addEventListener(
  cast.framework.ui.PlayerDataEventType.MEDIA_CHANGED,
  (e) => {
    if (!e.value) return;

    ....

    // Media browse
    touchControls.setBrowseContent(browseContent);
  });

Si haces clic en un elemento de navegación multimedia, se activará el interceptor LOAD. Agrega el siguiente código a tu interceptor LOAD para asignar request.media.contentId a request.media.entity desde el elemento de navegación multimedia:

playerManager.setMessageInterceptor(
    cast.framework.messages.MessageType.LOAD,
    request => {
      ...

      // Map contentId to entity
      if (request.media && request.media.entity) {
        request.media.contentId = request.media.entity;
      }

      return new Promise((resolve, reject) => {
            ...
        });
    });

También puedes configurar el objeto BrowseContent en null para quitar la IU de exploración multimedia.

12. Depura las apps receptoras

El SDK de app receptora de transmisión ofrece otra opción para que los desarrolladores depuren fácilmente apps receptoras mediante la API CastDebugLogger y una herramienta de comando y control (CaC) complementaria para capturar registros.

Inicialización

Para incorporar la API, agrega la secuencia de comandos fuente CastDebugLogger al archivo index.html. La fuente debe declararse en la etiqueta <head> después de la declaración del SDK de la app receptora de transmisión.

<head>
  ...
  <script src="//www.gstatic.com/cast/sdk/libs/caf_receiver/v3/cast_receiver_framework.js"></script>
  <!-- Cast Debug Logger -->
  <script src="//www.gstatic.com/cast/sdk/libs/devtools/debug_layer/caf_receiver_logger.js"></script>
</head>

En js/receiver.js, en la parte superior del archivo y debajo de playerManager, agrega el siguiente código para recuperar la instancia CastDebugLogger y habilitar el registrador:

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

// Debug Logger
const castDebugLogger = cast.debug.CastDebugLogger.getInstance();
const LOG_TAG = 'MyAPP.LOG';

// Enable debug logger and show a 'DEBUG MODE' overlay at top left corner.
context.addEventListener(cast.framework.system.EventType.READY, () => {
  if (!castDebugLogger.debugOverlayElement_) {
      castDebugLogger.setEnabled(true);
  }
});

Cuando el registrador de depuración está habilitado, se muestra una superposición que muestra DEBUG MODE en la app receptora.

Imagen de un video que se reproduce con el mensaje “MODO DE DEPURACIÓN” que aparece sobre un fondo rojo en la esquina superior izquierda del marco

Eventos del reproductor de registros

Con CastDebugLogger, puedes registrar fácilmente eventos del reproductor que activa el SDK del receptor de CAF y usar diferentes niveles de registrador para registrar los datos de eventos. La configuración loggerLevelByEvents usa cast.framework.events.EventType y cast.framework.events.category para especificar qué eventos se registrarán.

Agrega el siguiente código debajo de la declaración castDebugLogger para registrar cuando se active un evento CORE del reproductor o se transmita un cambio mediaStatus:

// Debug Logger
const castDebugLogger = cast.debug.CastDebugLogger.getInstance();

// Enable debug logger and show a 'DEBUG MODE' overlay at top left corner.
context.addEventListener(cast.framework.system.EventType.READY, () => {
  if (!castDebugLogger.debugOverlayElement_) {
      castDebugLogger.setEnabled(true);
  }
});

// Set verbosity level for Core events.
castDebugLogger.loggerLevelByEvents = {
  'cast.framework.events.category.CORE': cast.framework.LoggerLevel.INFO,
  'cast.framework.events.EventType.MEDIA_STATUS': cast.framework.LoggerLevel.DEBUG
}

Mensajes de registro y etiquetas personalizadas

La API de CastDebugLogger te permite crear mensajes de registro que aparecen en la superposición de depuración de la app receptora con diferentes colores. Los siguientes métodos de registro están disponibles, ordenados de mayor a menor prioridad:

  • castDebugLogger.error(custom_tag, message);
  • castDebugLogger.warn(custom_tag, message);
  • castDebugLogger.info(custom_tag, message);
  • castDebugLogger.debug(custom_tag, message);

Para cada método de registro, el primer parámetro es una etiqueta personalizada. Puede ser cualquier cadena de identificación que consideres significativa. CastDebugLogger usa etiquetas para filtrar los registros. El uso de las etiquetas se explica en detalle más adelante. El segundo parámetro es el mensaje de registro.

Para mostrar los registros en acción, agrega registros a tu interceptor LOAD.

playerManager.setMessageInterceptor(
  cast.framework.messages.MessageType.LOAD,
  request => {
    castDebugLogger.info(LOG_TAG, 'Intercepting LOAD request');

    // Map contentId to entity
    if (request.media && request.media.entity) {
      request.media.contentId = request.media.entity;
    }

    return new Promise((resolve, reject) => {
      // Fetch content repository by requested contentId
      makeRequest('GET', 'https://storage.googleapis.com/cpe-sample-media/content.json')
        .then(function (data) {
          let item = data[request.media.contentId];
          if(!item) {
            // Content could not be found in repository
            castDebugLogger.error(LOG_TAG, 'Content not found');
            reject();
          } else {
            // Adjusting request to make requested content playable
            request.media.contentUrl = item.stream.dash;
            request.media.contentType = 'application/dash+xml';
            castDebugLogger.warn(LOG_TAG, 'Playable URL:', request.media.contentUrl);

            // Add metadata
            let metadata = new cast.framework.messages.MovieMediaMetadata();
            metadata.metadataType = cast.framework.messages.MetadataType.MOVIE;
            metadata.title = item.title;
            metadata.subtitle = item.author;

            request.media.metadata = metadata;

            // Resolve request
            resolve(request);
          }
      });
    });
  });

Para controlar qué mensajes aparecen en la superposición de depuración, configura el nivel de registro en loggerLevelByTags para cada etiqueta personalizada. Por ejemplo, si habilitas una etiqueta personalizada con el nivel de registro cast.framework.LoggerLevel.DEBUG, se mostrarán todos los mensajes agregados con mensajes de registro de error, advertencia, información y depuración. Habilitar una etiqueta personalizada con el nivel WARNING solo mostrará mensajes de error y advertencias.

La configuración de loggerLevelByTags es opcional. Si no se configuró una etiqueta personalizada para su nivel de registrador, se mostrarán todos los mensajes del registro en la superposición de depuración.

Agrega el siguiente código debajo del registro de eventos CORE:

// Set verbosity level for Core events.
castDebugLogger.loggerLevelByEvents = {
  'cast.framework.events.category.CORE': cast.framework.LoggerLevel.INFO,
  'cast.framework.events.EventType.MEDIA_STATUS': cast.framework.LoggerLevel.DEBUG
}

// Set verbosity level for custom tags.
castDebugLogger.loggerLevelByTags = {
    [LOG_TAG]: cast.framework.LoggerLevel.DEBUG,
};

Superposición para depurar

El Registrador de depuración de transmisión proporciona una superposición de depuración en el receptor para mostrar tus mensajes de registro personalizados en el dispositivo de transmisión. Usa showDebugLogs para activar o desactivar la superposición de depuración y clearDebugLogs para borrar los mensajes del registro de la superposición.

Agrega el siguiente código para obtener una vista previa de la superposición de depuración en la app receptora.

context.addEventListener(cast.framework.system.EventType.READY, () => {
  if (!castDebugLogger.debugOverlayElement_) {
      // Enable debug logger and show a 'DEBUG MODE' overlay at top left corner.
      castDebugLogger.setEnabled(true);

      // Show debug overlay
      castDebugLogger.showDebugLogs(true);

      // Clear log messages on debug overlay
      castDebugLogger.clearDebugLogs();
  }
});

Imagen que muestra la superposición de depuración, una lista de mensajes del registro de depuración con un fondo translúcido en la parte superior de un fotograma de video

13. Felicitaciones

Ahora sabes cómo crear una aplicación receptora web personalizada con el SDK de la app receptora web de transmisión.

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