Cómo agregar funciones principales a tu receptor web personalizado

En esta página, se incluyen fragmentos de código y descripciones de las funciones disponibles para una app de receptor web personalizado.

  1. Un elemento cast-media-player que representa la IU del reproductor integrada que se proporciona con Web Receiver
  2. Estilos personalizados similares a los de CSS para el elemento cast-media-player a fin de aplicar diseño a varios elementos de la IU, como background-image, splash-image y font-family
  3. Un elemento de secuencia de comandos para cargar el framework del receptor web.
  4. Código JavaScript para interceptar mensajes y controlar eventos.
  5. Fila para la reproducción automática.
  6. Opciones para configurar la reproducción
  7. Opciones para establecer el contexto de Web Receiver.
  8. Opciones para establecer comandos que son compatibles con la app de receptor web
  9. Una llamada de JavaScript para iniciar la aplicación receptora web.

Configuración y opciones de la aplicación

Configura la aplicación

La clase CastReceiverContext es la más externa que se expone al desarrollador y administra la carga de las bibliotecas subyacentes y controla la inicialización del SDK de Web Receiver. El SDK proporciona APIs que permiten a los desarrolladores de aplicaciones configurar el SDK mediante CastReceiverOptions. Estas configuraciones se evalúan una vez por inicio de aplicación y se pasan al SDK cuando se configura el parámetro opcional en la llamada a start.

En el siguiente ejemplo, se muestra cómo anular el comportamiento predeterminado para detectar si una conexión de remitente aún está conectada de forma activa. Cuando el receptor web no se ha podido comunicar con un remitente durante maxInactivity segundos, se envía un evento SENDER_DISCONNECTED. La siguiente configuración anula este tiempo de espera. Esto puede ser útil cuando se depuran problemas, ya que evita que la app del Receptor web cierre la sesión de Depurador remoto de Chrome cuando no hay remitentes conectados en estado IDLE.

const context = cast.framework.CastReceiverContext.getInstance();
const options = new cast.framework.CastReceiverOptions();
options.maxInactivity = 3600; // Development only
context.start(options);

Configura el reproductor

Cuando se carga contenido, el SDK de Web Receiver proporciona una manera de configurar variables de reproducción, como la información de DRM, las configuraciones de reintento y los controladores de solicitudes con cast.framework.PlaybackConfig. PlayerManager controla esta información y se evalúa en el momento en que se crean los jugadores. Los jugadores se crean cada vez que se pasa una carga nueva al SDK de Web Receiver. Las modificaciones en el PlaybackConfig después de la creación del reproductor se evalúan en la siguiente carga de contenido. El SDK proporciona los siguientes métodos para modificar el objeto PlaybackConfig.

  • CastReceiverOptions.playbackConfig para anular las opciones de configuración predeterminadas cuando inicializas CastReceiverContext
  • PlayerManager.getPlaybackConfig() para obtener la configuración actual
  • PlayerManager.setPlaybackConfig() para anular la configuración actual Esta configuración se aplica a todas las cargas posteriores o hasta que se vuelva a anular.
  • PlayerManager.setMediaPlaybackInfoHandler() para aplicar configuraciones adicionales solo al elemento multimedia que se carga sobre las configuraciones actuales. Se llama al controlador justo antes de la creación del jugador. Los cambios que se realicen aquí no son permanentes y no se incluyen en las consultas a getPlaybackConfig(). Cuando se cargue el siguiente elemento multimedia, se volverá a llamar a este controlador.

En el siguiente ejemplo, se muestra cómo configurar PlaybackConfig cuando inicializas CastReceiverContext. La configuración anula las solicitudes salientes para obtener manifiestos. El controlador especifica que las solicitudes de control de acceso de CORS se deben realizar con credenciales como cookies o encabezados de autorización.

const playbackConfig = new cast.framework.PlaybackConfig();
playbackConfig.manifestRequestHandler = requestInfo => {
  requestInfo.withCredentials = true;
};
context.start({playbackConfig: playbackConfig});

En el siguiente ejemplo, se muestra cómo anular el PlaybackConfig con el método get y el método set que se proporcionan en PlayerManager. Este parámetro configura el reproductor para que reanude la reproducción de contenido después de que se cargue 1 segmento.

const playerManager =
    cast.framework.CastReceiverContext.getInstance().getPlayerManager();
const playbackConfig = (Object.assign(
            new cast.framework.PlaybackConfig(), playerManager.getPlaybackConfig()));
playbackConfig.autoResumeNumberOfSegments = 1;
playerManager.setPlaybackConfig(playbackConfig);

En el siguiente ejemplo, se muestra cómo anular PlaybackConfig para una solicitud de carga específica con el controlador de información de reproducción de contenido multimedia. El controlador llama a un método getLicenseUrlForMedia implementado por la aplicación para obtener el licenseUrl del contentId del elemento actual.

playerManager.setMediaPlaybackInfoHandler((loadRequestData, playbackConfig) => {
  const mediaInformation = loadRequestData.media;
  playbackConfig.licenseUrl = getLicenseUrlForMedia(mediaInformation.contentId);

  return playbackConfig;
});

Objeto de escucha de eventos

El SDK de Web Receiver permite que tu app de Web Receiver controle los eventos del reproductor. El objeto de escucha de eventos toma un parámetro cast.framework.events.EventType (o un array de estos parámetros) que especifica los eventos que deben activar el objeto de escucha. Los arrays preconfigurados de cast.framework.events.EventType que son útiles para la depuración se pueden encontrar en cast.framework.events.category. El parámetro del evento proporciona información adicional sobre el evento.

Por ejemplo, si deseas saber cuándo se transmite un cambio mediaStatus, puedes usar la siguiente lógica para controlar el evento:

const playerManager =
    cast.framework.CastReceiverContext.getInstance().getPlayerManager();
playerManager.addEventListener(
    cast.framework.events.EventType.MEDIA_STATUS, (event) => {
      // Write your own event handling code, for example
      // using the event.mediaStatus value
});

Intercepción de mensajes

El SDK de Web Receiver permite que tu app de receptor web intercepte mensajes y ejecute código personalizado en ellos. El interceptor de mensajes toma un parámetro cast.framework.messages.MessageType que especifica qué tipo de mensaje se debe interceptar.

El interceptor debe mostrar la solicitud modificada o una promesa que se resuelve con el valor de la solicitud modificado. Si se muestra null, no se llamará al controlador de mensajes predeterminado. Consulta Cómo cargar contenido multimedia para obtener más detalles.

Por ejemplo, si quieres cambiar los datos de la solicitud de carga, puedes usar la siguiente lógica para interceptarlos y modificarlos:

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

playerManager.setMessageInterceptor(
    cast.framework.messages.MessageType.LOAD, loadRequestData => {
      const error = new cast.framework.messages.ErrorData(
                      cast.framework.messages.ErrorType.LOAD_FAILED);
      if (!loadRequestData.media) {
        error.reason = cast.framework.messages.ErrorReason.INVALID_PARAM;
        return error;
      }

      if (!loadRequestData.media.entity) {
        return loadRequestData;
      }

      return thirdparty.fetchAssetAndAuth(loadRequestData.media.entity,
                                          loadRequestData.credentials)
        .then(asset => {
          if (!asset) {
            throw cast.framework.messages.ErrorReason.INVALID_REQUEST;
          }

          loadRequestData.media.contentUrl = asset.url;
          loadRequestData.media.metadata = asset.metadata;
          loadRequestData.media.tracks = asset.tracks;
          return loadRequestData;
        }).catch(reason => {
          error.reason = reason; // cast.framework.messages.ErrorReason
          return error;
        });
    });

context.start();

Manejo de errores

Cuando se producen errores en el interceptor de mensajes, tu app del receptor web debe mostrar un cast.framework.messages.ErrorType y un cast.framework.messages.ErrorReason adecuados.

playerManager.setMessageInterceptor(
    cast.framework.messages.MessageType.LOAD, loadRequestData => {
      const error = new cast.framework.messages.ErrorData(
                      cast.framework.messages.ErrorType.LOAD_CANCELLED);
      if (!loadRequestData.media) {
        error.reason = cast.framework.messages.ErrorReason.INVALID_PARAM;
        return error;
      }

      ...

      return fetchAssetAndAuth(loadRequestData.media.entity,
                               loadRequestData.credentials)
        .then(asset => {
          ...
          return loadRequestData;
        }).catch(reason => {
          error.reason = reason; // cast.framework.messages.ErrorReason
          return error;
        });
    });

Intercepción de mensajes frente a objeto de escucha de eventos

A continuación, se indican algunas diferencias clave entre la intercepción de mensajes y el objeto de escucha de eventos:

  • Un objeto de escucha de eventos no te permite modificar los datos de la solicitud.
  • Es mejor usar un objeto de escucha de eventos para activar estadísticas o una función personalizada.
playerManager.addEventListener(cast.framework.events.category.CORE,
    event => {
        console.log(event);
    });
  • La intercepción de mensajes te permite escuchar, interceptar y modificar los datos de la solicitud.
  • La interceptación de mensajes se usa mejor para controlar la lógica personalizada en relación con los datos de la solicitud.

Carga de contenido multimedia

MediaInformation proporciona numerosas propiedades para cargar contenido multimedia en el mensaje cast.framework.messages.MessageType.LOAD, incluidos entity, contentUrl y contentId.

  • entity es la propiedad sugerida que puedes usar en tu implementación para las apps de remitente y receptor. La propiedad es una URL de vínculo directo que puede ser una playlist o contenido multimedia. La aplicación debe analizar esta URL y propagar al menos uno de los otros dos campos.
  • El objeto contentUrl corresponde a la URL reproducible que el reproductor usará para cargar el contenido. Por ejemplo, esta URL podría dirigir a un manifiesto de DASH.
  • El objeto contentId puede ser una URL de contenido reproducible (similar a la de la propiedad contentUrl) o un identificador único del contenido o la playlist que se cargan. Si usas esta propiedad como identificador, tu aplicación debe propagar una URL reproducible en el contentUrl.

Se sugiere usar entity para almacenar el ID real o los parámetros clave, y contentUrl para la URL del contenido multimedia. En el siguiente fragmento, se muestra un ejemplo de esto, en el que el entity está presente en la solicitud LOAD y se recupera el contentUrl reproducible:

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

      if (!loadRequestData.media.entity) {
        // Copy the value from contentId for legacy reasons if needed
        loadRequestData.media.entity = loadRequestData.media.contentId;
      }

      return thirdparty.fetchAssetAndAuth(loadRequestData.media.entity,
                                          loadRequestData.credentials)
        .then(asset => {
          loadRequestData.media.contentUrl = asset.url;
          ...
          return loadRequestData;
        });
    });

Funciones del dispositivo

El método getDeviceCapabilities proporciona información del dispositivo en el dispositivo de transmisión conectado y el dispositivo de audio o video conectado a él. El método getDeviceCapabilities proporciona información de compatibilidad para Asistente de Google, Bluetooth y los dispositivos de pantalla y audio conectados.

Este método muestra un objeto que puedes consultar pasando una de las enumeraciones especificadas para obtener la capacidad del dispositivo de esa enumeración. Las enumeraciones se definen en cast.framework.system.DeviceCapabilities.

En este ejemplo, se verifica si el dispositivo receptor web es capaz de reproducir HDR y DolbyVision (DV) con las teclas IS_HDR_SUPPORTED y IS_DV_SUPPORTED, respectivamente.

const context = cast.framework.CastReceiverContext.getInstance();
context.addEventListener(cast.framework.system.EventType.READY, () => {
  const deviceCapabilities = context.getDeviceCapabilities();
  if (deviceCapabilities &&
      deviceCapabilities[cast.framework.system.DeviceCapabilities.IS_HDR_SUPPORTED]) {
    // Write your own event handling code, for example
    // using the deviceCapabilities[cast.framework.system.DeviceCapabilities.IS_HDR_SUPPORTED] value
  }
  if (deviceCapabilities &&
      deviceCapabilities[cast.framework.system.DeviceCapabilities.IS_DV_SUPPORTED]) {
    // Write your own event handling code, for example
    // using the deviceCapabilities[cast.framework.system.DeviceCapabilities.IS_DV_SUPPORTED] value
  }
});
context.start();

Cómo controlar la interacción del usuario

Un usuario puede interactuar con tu aplicación de receptor web a través de aplicaciones emisoras (Web, iOS y Android), comandos por voz en dispositivos compatibles con el Asistente, controles de tacto en pantallas inteligentes y controles remotos en dispositivos Android TV. El SDK de Cast proporciona varias APIs para permitir que la app receptora web controle estas interacciones, actualice la IU de la aplicación mediante estados de acciones del usuario y, opcionalmente, envíe los cambios para actualizar cualquier servicio de backend.

Comandos multimedia compatibles

Los estados de los controles de la IU se controlan mediante MediaStatus.supportedMediaCommands para los controladores expandidos de envío de iOS y Android, las apps de receptor y control remoto que se ejecutan en dispositivos táctiles, y las apps de receptores en dispositivos Android TV. Cuando se habilita un Command particular a nivel de bits en la propiedad, se habilitan los botones que están relacionados con esa acción. Si no se establece el valor, el botón estará inhabilitado. Estos valores se pueden cambiar en Web Receiver de la siguiente manera:

  1. Usa PlayerManager.setSupportedMediaCommands para establecer la Commands específica.
  2. Agregar un comando nuevo con addSupportedMediaCommands
  3. Quitar un comando existente con removeSupportedMediaCommands
playerManager.setSupportedMediaCommands(cast.framework.messages.Command.SEEK |
  cast.framework.messages.Command.PAUSE);

Cuando el receptor prepare el MediaStatus actualizado, incluirá los cambios en la propiedad supportedMediaCommands. Cuando se transmita el estado, las apps emisoras conectadas actualizarán los botones de su IU según corresponda.

Para obtener más información sobre los comandos de contenido multimedia y los dispositivos táctiles compatibles, consulta la guía de Accessing UI controls.

Cómo administrar los estados de acción de los usuarios

Cuando los usuarios interactúan con la IU o envían comandos por voz, pueden controlar la reproducción del contenido y las propiedades relacionadas con el elemento que se reproduce. El SDK maneja automáticamente las solicitudes que controlan la reproducción. Las solicitudes que modifican propiedades para el elemento que se está reproduciendo, como un comando LIKE, requieren que la aplicación receptora las controle. El SDK proporciona una serie de APIs para controlar estos tipos de solicitudes. Para admitir estas solicitudes, debes hacer lo siguiente:

  • Configura MediaInformation userActionStates con las preferencias del usuario cuando cargues un elemento multimedia.
  • Intercepta los mensajes de USER_ACTION y determina la acción solicitada.
  • Actualiza el UserActionState de MediaInformation para actualizar la IU.

Con el siguiente fragmento, se intercepta la solicitud LOAD y se propaga el MediaInformation de LoadRequestData. En este caso, al usuario le gusta el contenido que se está cargando.

playerManager.setMessageInterceptor(
    cast.framework.messages.MessageType.LOAD, (loadRequestData) => {
      const userActionLike = new cast.framework.messages.UserActionState(
          cast.framework.messages.UserAction.LIKE);
      loadRequestData.media.userActionStates = [userActionLike];

      return loadRequestData;
    });

El siguiente fragmento intercepta el mensaje USER_ACTION y controla la llamada al backend con el cambio solicitado. Luego, realiza una llamada para actualizar el UserActionState en el receptor.

playerManager.setMessageInterceptor(cast.framework.messages.MessageType.USER_ACTION,
  (userActionRequestData) => {
    // Obtain the media information of the current content to associate the action to.
    let mediaInfo = playerManager.getMediaInformation();

    // If there is no media info return an error and ignore the request.
    if (!mediaInfo) {
        console.error('Not playing media, user action is not supported');
        return new cast.framework.messages.ErrorData(messages.ErrorType.BAD_REQUEST);
    }

    // Reach out to backend services to store user action modifications. See sample below.
    return sendUserAction(userActionRequestData, mediaInfo)

    // Upon response from the backend, update the client's UserActionState.
    .then(backendResponse => updateUserActionStates(backendResponse))

    // If any errors occurred in the backend return them to the cast receiver.
    .catch((error) => {
      console.error(error);
      return error;
    });
});

En el siguiente fragmento, se simula una llamada a un servicio de backend. La función verifica el UserActionRequestData para ver el tipo de cambio que solicitó el usuario y solo realiza una llamada de red si el backend admite la acción.

function sendUserAction(userActionRequestData, mediaInfo) {
  return new Promise((resolve, reject) => {
    switch (userActionRequestData.userAction) {
      // Handle user action changes supported by the backend.
      case cast.framework.messages.UserAction.LIKE:
      case cast.framework.messages.UserAction.DISLIKE:
      case cast.framework.messages.UserAction.FOLLOW:
      case cast.framework.messages.UserAction.UNFOLLOW:
      case cast.framework.messages.UserAction.FLAG:
      case cast.framework.messages.UserAction.SKIP_AD:
        let backendResponse = {userActionRequestData: userActionRequestData, mediaInfo: mediaInfo};
        setTimeout(() => {resolve(backendResponse)}, 1000);
        break;
      // Reject all other user action changes.
      default:
        reject(
          new cast.framework.messages.ErrorData(cast.framework.messages.ErrorType.INVALID_REQUEST));
    }
  });
}

El siguiente fragmento toma el UserActionRequestData y agrega o quita el UserActionState de MediaInformation. La actualización del UserActionState de MediaInformation cambia el estado del botón asociado con la acción solicitada. Este cambio se refleja en la IU de controles de pantalla inteligente, la app de control remoto y la IU de Android TV. También se transmite a través de mensajes MediaStatus salientes para actualizar la IU del controlador expandido para remitentes de iOS y Android.

function updateUserActionStates(backendResponse) {
  // Unwrap the backend response.
  let mediaInfo = backendResponse.mediaInfo;
  let userActionRequestData = backendResponse.userActionRequestData;

  // If the current item playing has changed, don't update the UserActionState for the current item.
  if (playerManager.getMediaInformation().entity !== mediaInfo.entity) {
    return;
  }

  // Check for existing userActionStates in the MediaInformation.
  // If none, initialize a new array to populate states with.
  let userActionStates = mediaInfo.userActionStates || [];

  // Locate the index of the UserActionState that will be updated in the userActionStates array.
  let index = userActionStates.findIndex((currUserActionState) => {
    return currUserActionState.userAction == userActionRequestData.userAction;
  });

  if (userActionRequestData.clear) {
    // Remove the user action state from the array if cleared.
    if (index >= 0) {
      userActionStates.splice(index, 1);
    }
    else {
      console.warn("Could not find UserActionState to remove in MediaInformation");
    }
  } else {
    // Add the UserActionState to the array if enabled.
    userActionStates.push(
      new cast.framework.messages.UserActionState(userActionRequestData.userAction));
  }

  // Update the UserActionState array and set the new MediaInformation
  mediaInfo.userActionStates = userActionStates;
  playerManager.setMediaInformation(mediaInfo, true);
  return;
}

Comandos por voz

Actualmente, los siguientes comandos multimedia son compatibles con el SDK de Web Receiver para dispositivos compatibles con el Asistente. Las implementaciones predeterminadas de estos comandos se encuentran en cast.framework.PlayerManager.

Comando Descripción
Reproducir Reproducir o reanudar la reproducción desde el estado de pausa
Pausar Pausar el contenido que se está reproduciendo
Anterior Pasa al elemento multimedia anterior de la fila.
Siguiente Pasa al siguiente elemento multimedia de la fila.
Detener Detén el contenido multimedia que se está reproduciendo.
No repetir ninguna Inhabilita la repetición de elementos multimedia en la fila una vez que el último elemento termina de reproducirse.
Repetir una vez Repetir indefinidamente el contenido multimedia que se está reproduciendo
Repetir todo Repetir todos los elementos de la cola una vez que se reproduzca el último elemento.
Repetir todo y reproducir aleatoriamente Cuando el último elemento de la cola haya terminado de reproducirse, reproduce en modo aleatorio la lista y repite todos los elementos de la cola.
Reproducción aleatoria Reproduce aleatoriamente los elementos multimedia de la fila de contenido multimedia.
Subtítulos activados o desactivados Habilita o inhabilita los subtítulos para tu contenido multimedia. Las opciones para habilitar o inhabilitar las funciones también están disponibles por idioma.
Búsqueda de tiempo absoluta Salta a la hora absoluta especificada.
Buscar a la hora en relación con la hora actual Adelanta o retrocede el período de tiempo especificado en relación con el tiempo de reproducción actual.
Volver a jugar Reinicia el contenido multimedia que se está reproduciendo o reproduce el último elemento que se reprodujo si no se está reproduciendo nada.
Cómo configurar la velocidad de reproducción Variar la velocidad de reproducción de contenido multimedia Esto debería controlarse de forma predeterminada. Puedes usar el interceptor de mensajes SET_PLAYBACK_RATE para anular las solicitudes de frecuencia entrantes.

Comandos multimedia compatibles con voz

Para evitar que un comando por voz active un comando multimedia en un dispositivo compatible con el Asistente, primero debes configurar los comandos multimedia compatibles que planeas admitir. Luego, debes habilitar la propiedad CastReceiverOptions.enforceSupportedCommands para aplicar esos comandos. La IU de los remitentes del SDK de Cast y de los dispositivos compatibles con los controles táctiles cambiará para reflejar estas configuraciones. Si la marca no está habilitada, se ejecutarán los comandos por voz entrantes.

Por ejemplo, si permites PAUSE desde tus aplicaciones emisoras y dispositivos táctiles, también debes configurar el receptor para que refleje esa configuración. Cuando se configura, los comandos por voz entrantes se descartarán si no se incluyen en la lista de comandos compatibles.

En el siguiente ejemplo, proporcionamos el CastReceiverOptions cuando se inicia CastReceiverContext. Agregamos compatibilidad con el comando PAUSE y forzamos al jugador para que solo admita ese comando. Ahora, si un comando por voz solicita otra operación, como SEEK, se rechazará. Se notificará al usuario que el comando aún no es compatible.

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

context.start({
  enforceSupportedCommands: true,
  supportedCommands: cast.framework.messages.Command.PAUSE
});

Puedes aplicar una lógica separada para cada comando que desees restringir. Quita la marca enforceSupportedCommands y, para cada comando que desees restringir, puedes interceptar el mensaje entrante. Aquí interceptamos la solicitud que proporciona el SDK para que los comandos de SEEK emitidos a los dispositivos compatibles con el Asistente no activen una búsqueda en tu aplicación de receptor web.

En el caso de los comandos multimedia que no admite tu aplicación, muestra un motivo de error adecuado, como NOT_SUPPORTED.

playerManager.setMessageInterceptor(cast.framework.messages.MessageType.SEEK,
  seekData => {
    // Block seeking if the SEEK supported media command is disabled
    if (!(playerManager.getSupportedMediaCommands() & cast.framework.messages.Command.SEEK)) {
      let e = new cast.framework.messages.ErrorData(cast.framework.messages.ErrorType
      .INVALID_REQUEST);
      e.reason = cast.framework.messages.ErrorReason.NOT_SUPPORTED;
      return e;
    }

    return seekData;
  });

Reproducción en segundo plano a partir de la actividad de voz

Si la plataforma de Cast pone en segundo plano el sonido de tu aplicación debido a la actividad de Asistente, como escuchar la voz del usuario o responder, se envía un mensaje FocusState de NOT_IN_FOCUS a la aplicación receptora web cuando se inicia la actividad. Se envía otro mensaje con IN_FOCUS cuando finaliza la actividad. Según tu aplicación y el contenido multimedia que se esté reproduciendo, es posible que quieras pausar el contenido multimedia cuando FocusState sea NOT_IN_FOCUS mediante la interceptación del tipo de mensaje FOCUS_STATE.

Por ejemplo, pausar la reproducción de audiolibros si Asistente responde a una consulta del usuario ofrece una buena experiencia del usuario.

playerManager.setMessageInterceptor(cast.framework.messages.MessageType.FOCUS_STATE,
  focusStateRequestData => {
    // Pause content when the app is out of focus. Resume when focus is restored.
    if (focusStateRequestData.state == cast.framework.messages.FocusState.NOT_IN_FOCUS) {
      playerManager.pause();
    } else {
      playerManager.play();
    }

    return focusStateRequestData;
  });

Idioma de subtítulos especificado por voz

Cuando un usuario no indica explícitamente el idioma de los subtítulos, se utiliza el mismo idioma en el que se habló el comando. En estos casos, el parámetro isSuggestedLanguage del mensaje entrante indica si el usuario sugirió o solicitó explícitamente el idioma asociado.

Por ejemplo, isSuggestedLanguage está configurado como true para el comando "Hey Google, activa los subtítulos", porque el idioma se infirió por el idioma en el que se habló el comando. Si el idioma se solicita explícitamente, como en "Hey Google, activa los subtítulos en inglés", isSuggestedLanguage se establece en false.

Metadatos y transmisión de voz

Si bien el receptor web controla los comandos por voz de forma predeterminada, debes asegurarte de que los metadatos de tu contenido estén completos y sean precisos. Esto garantiza que Asistente maneje correctamente los comandos por voz y que los metadatos aparezcan de manera adecuada en los nuevos tipos de interfaces, como la app de Google Home y pantallas inteligentes, como Google Home Hub.

Transferencia de transmisión

La preservación del estado de la sesión es la base de la transferencia de transmisión, en la que los usuarios pueden mover transmisiones de audio y video existentes entre dispositivos mediante comandos por voz, la app de Google Home o pantallas inteligentes. El contenido multimedia se detiene en un dispositivo (la fuente) y continúa en otro (el destino). Cualquier dispositivo de transmisión con el firmware más reciente puede funcionar como fuentes o destinos en una transferencia de transmisión.

El flujo de eventos para la transferencia de transmisión es el siguiente:

  1. En el dispositivo de origen:
    1. Se detiene la reproducción de contenido multimedia.
    2. La aplicación Web Receiver recibe un comando para guardar el estado actual de los medios.
    3. La aplicación Web Receiver se cerró.
  2. En el dispositivo de destino:
    1. Se cargó la aplicación Web Receiver.
    2. La aplicación de receptor web recibe un comando para restablecer el estado de contenido multimedia guardado.
    3. Se reanuda la reproducción de contenido multimedia.

Entre los elementos del estado del contenido multimedia, se incluyen los siguientes:

  • Es la posición o marca de tiempo específica de la canción, el video o el elemento multimedia.
  • Se ubica en una fila más amplia (como una playlist o la radio de un artista).
  • El usuario autenticado.
  • Estado de reproducción (por ejemplo, en reproducción o en pausa)

Habilita la transferencia de transmisión

A fin de implementar la transferencia de transmisión para tu receptor web, sigue estos pasos:

  1. Actualiza supportedMediaCommands con el comando STREAM_TRANSFER:
    playerManager.addSupportedMediaCommands(
    cast.framework.messages.Command.STREAM_TRANSFER, true);
  2. De manera opcional, anula los interceptores de mensajes SESSION_STATE y RESUME_SESSION como se describe en Preserva el estado de la sesión. Anótalos solo si los datos personalizados deben almacenarse como parte de la instantánea de la sesión. De lo contrario, la implementación predeterminada para preservar los estados de sesión será compatible con la transferencia de transmisión.

Preserva el estado de la sesión

El SDK de Web Receiver proporciona una implementación predeterminada para las apps de receptor web con el objetivo de preservar los estados de la sesión. Para ello, toma una instantánea del estado del contenido multimedia actual, convierte el estado en una solicitud de carga y reanuda la sesión con esta solicitud.

Si es necesario, la solicitud de carga que genera el receptor web se puede anular en el interceptor de mensajes SESSION_STATE. Si deseas agregar datos personalizados a la solicitud de carga, te sugerimos que los coloques en loadRequestData.customData.

playerManager.setMessageInterceptor(
    cast.framework.messages.MessageType.SESSION_STATE,
    function (sessionState) {
        // Override sessionState.loadRequestData if needed.
        const newCredentials = updateCredentials_(sessionState.loadRequestData.credentials);
        sessionState.loadRequestData.credentials = newCredentials;

        // Add custom data if needed.
        sessionState.loadRequestData.customData = {
            'membership': 'PREMIUM'
        };

        return sessionState;
    });

Los datos personalizados se pueden recuperar de loadRequestData.customData en el interceptor de mensajes RESUME_SESSION.

let cred_ = null;
let membership_ = null;

playerManager.setMessageInterceptor(
    cast.framework.messages.MessageType.RESUME_SESSION,
    function (resumeSessionRequest) {
        let sessionState = resumeSessionRequest.sessionState;

        // Modify sessionState.loadRequestData if needed.
        cred_ = sessionState.loadRequestData.credentials;

        // Retrieve custom data.
        membership_ = sessionState.loadRequestData.customData.membership;

        return resumeSessionRequest;
    });

Precarga del contenido

Web Receiver admite la precarga de elementos multimedia después del elemento de reproducción actual en la cola.

La operación de precarga descarga previamente varios segmentos de los próximos elementos. La especificación se realiza en el valor preloadTime en el objeto QueueItem (el valor predeterminado es 20 segundos si no se proporciona). El tiempo se expresa en segundos, en relación con el final del elemento que se está reproduciendo . Solo los valores positivos son válidos. Por ejemplo, si el valor es de 10 segundos, este elemento se precarga 10 segundos antes de que haya finalizado el elemento anterior. Si el tiempo de precarga es superior al tiempo restante para currentItem, la precarga se realizará lo antes posible. Entonces, si se especifica un valor muy grande de carga previa en elqueueItem, se podría precargar el siguiente cuando se esté reproduciendo el elemento actual. Sin embargo, dejamos la configuración y la elección del desarrollador, ya que este valor puede afectar el ancho de banda y el rendimiento de la transmisión del elemento que se está reproduciendo.

De forma predeterminada, la precarga funcionará para el contenido de transmisión HLS, DASH y Smooth Streaming.

Los archivos de audio y video MP4 normales, como MP3, no se precargarán, ya que los dispositivos de transmisión solo admiten un elemento multimedia y no se pueden usar para precargar mientras un elemento de contenido existente aún se esté reproduciendo.

Mensajes personalizados

El intercambio de mensajes es el método de interacción clave para las aplicaciones receptoras web.

Un remitente envía mensajes a un receptor web con las APIs de remitente de la plataforma que ejecuta (Android, iOS y la Web). El objeto de evento (que es la manifestación de un mensaje) que se pasa a los objetos de escucha de eventos tiene un elemento de datos (event.data) en el que los datos toman las propiedades del tipo de evento específico.

Una aplicación receptora web puede optar por escuchar los mensajes en un espacio de nombres especificado. Por lo tanto, se dice que la aplicación receptora web es compatible con ese protocolo de espacio de nombres. Luego, depende de cualquier remitente conectado que desee comunicarse en ese espacio de nombres para usar el protocolo apropiado.

Todos los espacios de nombres se definen con una cadena y deben comenzar con "urn:x-cast:" seguido de cualquier cadena. Por ejemplo, "urn:x-cast:com.example.cast.mynamespace".

Este es un fragmento de código para que el receptor web escuche mensajes personalizados de remitentes conectados:

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

const CUSTOM_CHANNEL = 'urn:x-cast:com.example.cast.mynamespace';
context.addCustomMessageListener(CUSTOM_CHANNEL, function(customEvent) {
  // handle customEvent.
});

context.start();

Del mismo modo, las aplicaciones de Receptor web pueden enviar mensajes a remitentes conectados para mantener informados a los remitentes sobre el estado del receptor web. Una aplicación receptora web puede enviar mensajes mediante sendCustomMessage(namespace, senderId, message) en CastReceiverContext. Un receptor web puede enviar mensajes a un remitente individual, ya sea en respuesta a un mensaje recibido o debido a un cambio de estado de la aplicación. Más allá de los mensajes punto a punto (con un límite de 64 KB), un receptor web también puede transmitir mensajes a todos los remitentes conectados.

Transmitir para dispositivos de audio

Consulta la guía de Google Cast para dispositivos de audio para obtener compatibilidad con la reproducción de solo audio.

Android TV

En esta sección, se explica cómo Google Web Receiver usa tus entradas como reproducción y la compatibilidad con Android TV.

Integrar tu aplicación con el control remoto

El Google Web Receiver que se ejecuta en el dispositivo Android TV traduce la entrada de las entradas de control del dispositivo (es decir, el control remoto de mano) como mensajes de reproducción de contenido multimedia definidos para el espacio de nombres urn:x-cast:com.google.cast.media, según se describe en Mensajes de reproducción de contenido multimedia. La aplicación debe admitir estos mensajes para controlar la reproducción de contenido multimedia de la aplicación a fin de permitir el control de reproducción básico desde las entradas de control de Android TV.

Lineamientos para la compatibilidad con Android TV

A continuación, se incluyen algunas recomendaciones y errores comunes que debes evitar para asegurarte de que tu aplicación sea compatible con Android TV:

  • Ten en cuenta que la cadena usuario-agente contiene "Android" y "CrKey". Es posible que algunos sitios redireccionen a sitios solo para dispositivos móviles porque detectan la etiqueta "Android". No des por sentado que "Android" en la cadena usuario-agente siempre indica un usuario de dispositivo móvil.
  • La pila de medios de Android puede usar GZIP transparente para recuperar datos. Asegúrate de que los datos multimedia puedan responder a Accept-Encoding: gzip.
  • Es posible que los eventos multimedia HTML5 de Android TV se activen en tiempos diferentes a los de Chromecast. Esto podría revelar problemas ocultos en Chromecast.
  • Cuando actualices el contenido multimedia, usa eventos relacionados con contenido multimedia activados por elementos <audio>/<video>, como timeupdate, pause y waiting. Evita usar eventos relacionados con las herramientas de redes, como progress, suspend y stalled, ya que estos dependen de la plataforma. Consulta Eventos multimedia para obtener más información sobre cómo controlar los eventos multimedia en tu receptor.
  • Cuando configures los certificados HTTPS del sitio del receptor, asegúrate de incluir certificados de la AC intermedios. Consulta la página de prueba de SSL de Qualsys para verificar lo siguiente: Si la ruta de certificación de confianza de tu sitio incluye un certificado de la AC etiquetado como "descarga adicional", es posible que no se cargue en plataformas basadas en Android.
  • Mientras que Chromecast muestra la página del receptor en un plano de gráficos de 720p, otras plataformas de transmisión, como Android TV, pueden mostrar la página en hasta 1080p. Asegúrate de que la página del receptor se ajuste correctamente a diferentes resoluciones.