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 Custom Web Receiver.

  1. Un elemento cast-media-player que representa la IU del reproductor integrada que se proporciona con Web Receiver.
  2. Es un diseño personalizado similar a CSS para el elemento cast-media-player que permite diseñar varios elementos de la IU, como background-image, splash-image y font-family.
  3. Un elemento de secuencia de comandos para cargar el framework de Web Receiver.
  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 del Web Receiver.
  8. Son opciones para establecer comandos que admite la app de Web Receiver.
  9. Una llamada de JavaScript para iniciar la aplicación de Web Receiver.

Configuración y opciones de la aplicación

Configura la aplicación

CastReceiverContext es la clase más externa expuesta al desarrollador y administra la carga de las bibliotecas subyacentes, además de controlar la inicialización del SDK de Web Receiver. El SDK proporciona APIs que permiten a los desarrolladores de aplicaciones configurar el SDK a través de CastReceiverOptions. Estas configuraciones se evalúan una vez por cada inicio de la aplicación y se pasan al SDK cuando se establece 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 del remitente sigue activa. Cuando el Web Receiver no se pudo 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 Web Receiver cierre la sesión del depurador remoto de Chrome cuando no haya emisores conectados en un 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 forma de configurar variables de reproducción, como información de DRM, configuraciones de reintentos y 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 reproductores se crean cada vez que se pasa una carga nueva al SDK de Web Receiver. Las modificaciones en PlaybackConfig después de que se crea el 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 se inicializa el CastReceiverContext.
  • PlayerManager.getPlaybackConfig() para obtener la configuración actual.
  • PlayerManager.setPlaybackConfig() para anular la configuración actual Este parámetro de configuración se aplica a todas las cargas posteriores o hasta que se vuelva a anular.
  • PlayerManager.setMediaPlaybackInfoHandler() para aplicar parámetros de configuración adicionales solo para el elemento multimedia que se carga sobre los parámetros de configuración actuales. Se llama al controlador justo antes de la creación del reproductor. Los cambios que se realicen aquí no son permanentes y no se incluyen en las consultas a getPlaybackConfig(). Cuando se carga el siguiente elemento multimedia, se vuelve a llamar a este controlador.

En el siguiente ejemplo, se muestra cómo establecer PlaybackConfig cuando se inicializa CastReceiverContext. La configuración anula las solicitudes salientes para obtener manifiestos. El controlador especifica que las solicitudes de Access-Control 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 PlaybackConfig con el getter y el setter proporcionados en PlayerManager. El parámetro de configuración establece que el reproductor reanude la reproducción del 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 medios. 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 deberían activar el objeto de escucha. En cast.framework.events.category, puedes encontrar arrays preconfigurados de cast.framework.events.EventType que son útiles para la depuración. El parámetro del evento proporciona información adicional sobre el evento.

Por ejemplo, si quieres saber cuándo se transmite un cambio de 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 Web Receiver 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 devolver la solicitud modificada o una promesa que se resuelva con el valor de la solicitud modificada. Si se devuelve null, se evitará que se llame al controlador de mensajes predeterminado. Consulta Cómo cargar contenido multimedia para obtener más detalles.

Por ejemplo, si deseas cambiar los datos de la solicitud de carga, puedes usar la siguiente lógica para interceptarla y modificarla:

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 de Web Receiver debe devolver 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

Estas son algunas diferencias clave entre la interceptació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.
  • Un objeto de escucha de eventos se usa mejor para activar Analytics o una función personalizada.
playerManager.addEventListener(cast.framework.events.category.CORE,
    event => {
        console.log(event);
    });
  • La interceptación de mensajes te permite escuchar un mensaje, interceptarlo y modificar los datos de la solicitud.
  • La interceptación de mensajes se usa mejor para controlar la lógica personalizada con respecto a 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 para usar en tu implementación tanto para las apps emisoras como para las receptoras. La propiedad es una URL de vínculo directo que puede ser una playlist o contenido multimedia. Tu aplicación debe analizar esta URL y completar al menos uno de los otros dos campos.
  • 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 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 está cargando. Si usas esta propiedad como identificador, tu aplicación debe propagar una URL reproducible en contentUrl.

La sugerencia es usar entity para almacenar los parámetros reales de ID o clave, y usar contentUrl para la URL del contenido multimedia. En el siguiente fragmento, se muestra un ejemplo en el que entity está presente en la solicitud de 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 sobre el dispositivo Cast conectado y el dispositivo de audio o video que se le adjunta. El método getDeviceCapabilities proporciona información de asistencia para el Asistente de Google, Bluetooth y los dispositivos de audio y pantalla conectados.

Este método devuelve un objeto que puedes consultar pasando uno de los enums especificados para obtener la capacidad del dispositivo para ese enum. Los enums se definen en cast.framework.system.DeviceCapabilities.

En este ejemplo, se verifica si el dispositivo Web Receiver puede reproducir HDR y Dolby Vision (DV) con las claves 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 Web Receiver a través de aplicaciones de remitente (Web, Android y iOS), comandos por voz en dispositivos compatibles con Asistente, controles táctiles en pantallas inteligentes y controles remotos en dispositivos Android TV. El SDK de Cast proporciona varias APIs para permitir que la app del Web Receiver controle estas interacciones, actualice la IU de la aplicación a través de estados de acción del usuario y, de manera opcional, envíe los cambios para actualizar cualquier servicio de backend.

Comandos de contenido multimedia compatibles

Los estados de los controles de la IU se controlan con MediaStatus.supportedMediaCommands para los controles expandidos del remitente de iOS y Android, las apps de receptor y de control remoto que se ejecutan en dispositivos táctiles, y las apps de receptor en dispositivos Android TV. Cuando se habilita un Command bit a bit en la propiedad, se habilitan los botones relacionados con esa acción. Si no se establece el valor, el botón se inhabilita. Estos valores se pueden cambiar en el Web Receiver de las siguientes maneras:

  1. Usa PlayerManager.setSupportedMediaCommands para establecer el Commands específico.
  2. Cómo agregar un comando nuevo con addSupportedMediaCommands
  3. Quita 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 transmite el estado, las apps de remitente conectadas actualizarán los botones de su IU según corresponda.

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

Cómo administrar los estados de acción del usuario

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 está reproduciendo. El SDK controla automáticamente las solicitudes que controlan la reproducción. Las solicitudes que modifican propiedades del 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, se debe hacer lo siguiente:

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

El siguiente fragmento intercepta la solicitud LOAD y completa 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 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;
    });
});

El siguiente fragmento 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 del MediaInformation. Actualizar el UserActionState del MediaInformation cambia el estado del botón asociado a la acción solicitada. Este cambio se refleja en la IU de los controles de la 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 los emisores 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, se admiten los siguientes comandos de medios en 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 Pausa el contenido que se está reproduciendo.
Anterior Ir al elemento multimedia anterior de la fila de reproducción
Siguiente Ir al siguiente elemento multimedia de la fila
Detener Detiene el contenido multimedia que se está reproduciendo.
No repetir Inhabilita la repetición de elementos multimedia en la fila una vez que se termine de reproducir el último elemento de la fila.
Repetir una Repite el contenido multimedia que se está reproduciendo de forma indefinida.
Repetir todo Repetir todos los elementos de la fila una vez que se reproduzca el último elemento
Repetir todo y aleatorio Una vez que se reproduzca el último elemento de la fila, mezcla la fila y repite todos los elementos.
Shuffle Mezcla los elementos multimedia en tu fila de reproducción.
Subtítulos ACTIVADOS / DESACTIVADOS Habilita o inhabilita los subtítulos opcionales para tu contenido multimedia. La opción para habilitar o inhabilitar también está disponible por idioma.
Búsqueda por tiempo absoluto Salta al tiempo absoluto especificado.
Buscar en tiempo relativo a la hora actual Avanza o retrocede la reproducción según el período 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 multimedia que se reprodujo si no se está reproduciendo nada.
Cómo establecer la velocidad de reproducción Variar la velocidad de reproducción de contenido multimedia Esto se debería controlar de forma predeterminada. Puedes usar el interceptor de mensajes SET_PLAYBACK_RATE para anular las solicitudes de tarifas entrantes.

Comandos de contenido multimedia compatibles con la 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 admitidos que planeas admitir. Luego, debes aplicar esos comandos habilitando la propiedad CastReceiverOptions.enforceSupportedCommands. La IU en los remitentes del SDK de Cast y los dispositivos táctiles cambiará para reflejar estos parámetros de configuración. Si la marca no está habilitada, se ejecutarán los comandos por voz entrantes.

Por ejemplo, si permites PAUSE desde tus aplicaciones de envío y dispositivos táctiles, también debes configurar tu receptor para que refleje esos parámetros de configuración. Cuando se configura, se descartarán todos los comandos de voz entrantes si no se incluyen en la lista de comandos admitidos.

En el siguiente ejemplo, proporcionamos el CastReceiverOptions cuando iniciamos el CastReceiverContext. Agregamos compatibilidad con el comando PAUSE y forzamos al reproductor a admitir solo ese comando. Ahora, si un comando por voz solicita otra operación, como SEEK, se rechazará. Se le notificará al usuario que el comando aún no se admite.

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

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

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

En el caso de los comandos de medios que tu aplicación no admite, devuelve 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;
  });

Pasa a segundo plano desde 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 el habla del usuario o responderle, se envía un mensaje FocusState de NOT_IN_FOCUS a la aplicación de Web Receiver cuando comienza la actividad. Cuando finaliza la actividad, se envía otro mensaje con IN_FOCUS. Según tu aplicación y el contenido multimedia que se esté reproduciendo, es posible que quieras pausar el contenido multimedia cuando el FocusState esté NOT_IN_FOCUS interceptando el tipo de mensaje FOCUS_STATE.

Por ejemplo, es una buena experiencia del usuario pausar la reproducción de audiolibros si Asistente está respondiendo a una consulta 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 usa el mismo idioma en el que se pronunció 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 se establece en true para el comando "Ok Google, activa los subtítulos", ya que el idioma se infirió a partir del idioma en el que se pronunció el comando. Si se solicita el idioma de forma explícita, como en "OK Google, activa los subtítulos en inglés", isSuggestedLanguage se establece en false.

Metadatos y casting de voz

Si bien el receptor web controla los comandos por voz de forma predeterminada, debes asegurarte de que los metadatos de tu contenido sean completos y precisos. Esto garantiza que Asistente controle correctamente los comandos por voz y que los metadatos se muestren correctamente en los nuevos tipos de interfaces, como la app de Google Home y las pantallas inteligentes, como Google Home Hub.

Transferencia de transmisión

La conservació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 con comandos por voz, la app de Google Home o pantallas inteligentes. El contenido multimedia deja de reproducirse en un dispositivo (la fuente) y continúa en otro (el destino). Cualquier dispositivo Cast con el firmware más reciente puede servir como fuente o destino 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 del contenido multimedia.
    2. La aplicación de Web Receiver recibe un comando para guardar el estado actual de los medios.
    3. Se cierra la aplicación de Web Receiver.
  2. En el dispositivo de destino, haz lo siguiente:
    1. Se carga la aplicación de Web Receiver.
    2. La aplicación de Web Receiver recibe un comando para restablecer el estado de los medios guardados.
    3. Se reanuda la reproducción del contenido multimedia.

Los elementos del estado de los medios incluyen lo siguiente:

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

Cómo habilitar la transferencia de transmisión

Para implementar la transferencia de transmisiones en tu Web Receiver, haz lo siguiente:

  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 Cómo conservar el estado de la sesión. Solo anula estos métodos si se deben almacenar datos personalizados como parte de la instantánea de la sesión. De lo contrario, la implementación predeterminada para conservar los estados de sesión admitirá la transferencia de transmisiones.

Cómo conservar el estado de la sesión

El SDK de Web Receiver proporciona una implementación predeterminada para que las apps de Web Receiver conserven los estados de la sesión tomando una instantánea del estado actual de los medios, convirtiendo el estado en una solicitud de carga y reanudando la sesión con la solicitud de carga.

Si es necesario, se puede anular la solicitud de carga que genera el receptor web en el interceptor de mensajes SESSION_STATE. Si deseas agregar datos personalizados a la solicitud de carga, te sugerimos que los incluyas 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 de contenido

El receptor web admite la carga previa de elementos multimedia después del elemento de reproducción actual en la fila.

La operación de precarga descarga previamente varios segmentos de los elementos próximos. La especificación se realiza en el valor de preloadTime en el objeto QueueItem (el valor predeterminado es de 20 segundos si no se proporciona). El tiempo se expresa en segundos, en relación con el final del elemento que se está reproduciendo actualmente . Solo se permiten valores positivos. Por ejemplo, si el valor es de 10 segundos, este elemento se precargará 10 segundos antes de que finalice el elemento anterior. Si el tiempo de precarga es mayor que el tiempo restante del elemento actual, la precarga se realizará lo antes posible. Por lo tanto, si se especifica un valor de precarga muy grande en el objeto queueItem, se podría lograr el efecto de que, cada vez que se reproduce el elemento actual, ya se esté precargando el siguiente. Sin embargo, dejamos la configuración y la elección de este valor a cargo del desarrollador, ya que puede afectar el ancho de banda y el rendimiento de la transmisión del elemento que se está reproduciendo.

La carga previa funcionará de forma predeterminada para el contenido de HLS, DASH y Smooth Streaming.

Los archivos de audio y video MP4 normales, como los MP3, no se precargan, ya que los dispositivos Cast solo admiten un elemento multimedia y no se pueden usar para precargar mientras se reproduce un elemento de contenido existente.

Mensajes personalizados

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

Un remitente emite mensajes a un Web Receiver con las APIs del remitente para la plataforma en la que se ejecuta el remitente (Android, iOS o 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 adoptan las propiedades del tipo de evento específico.

Una aplicación de Web Receiver puede optar por detectar mensajes en un espacio de nombres especificado. De esta manera, se dice que la aplicación de Web Receiver admite ese protocolo de espacio de nombres. Luego, los emisores conectados que deseen comunicarse en ese espacio de nombres deberán usar el protocolo adecuado.

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".

A continuación, se muestra un fragmento de código para que el receptor web detecte 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 Web Receiver pueden mantener a los remitentes informados sobre el estado del receptor web enviándoles mensajes. Una aplicación de Web Receiver puede enviar mensajes con 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 en el estado de la aplicación. Además de la mensajería punto a punto (con un límite de 64 KB), un Web Receiver también puede transmitir mensajes a todos los remitentes conectados.

Transmite contenido a dispositivos de audio

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

Android TV

En esta sección, se explica cómo el receptor web de Google usa tus entradas como reproducción y la compatibilidad con Android TV.

Cómo integrar tu aplicación con el control remoto

El receptor web de Google que se ejecuta en el dispositivo Android TV traduce la entrada de los controles del dispositivo (es decir, el control remoto manual) como mensajes de reproducción de medios definidos para el espacio de nombres urn:x-cast:com.google.cast.media, como se describe en Mensajes de reproducción de medios. Tu aplicación debe admitir estos mensajes para controlar la reproducción de contenido multimedia y permitir el control básico de la reproducción 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 garantizar que tu aplicación sea compatible con Android TV:

  • Ten en cuenta que la cadena de usuario-agente contiene "Android" y "CrKey"; algunos sitios pueden redireccionar a un sitio solo para dispositivos móviles porque detectan la etiqueta "Android". No supongas que "Android" en la cadena del usuario-agente siempre indica un usuario de dispositivos móviles.
  • La pila de medios de Android puede usar GZIP transparente para recuperar datos. Asegúrate de que tus datos de medios puedan responder a Accept-Encoding: gzip.
  • Los eventos de medios HTML5 de Android TV se pueden activar en momentos diferentes que en Chromecast, lo que puede revelar problemas que estaban ocultos en Chromecast.
  • Cuando actualices el contenido multimedia, usa los eventos relacionados con el contenido multimedia que activan los elementos <audio>/<video>, como timeupdate, pause y waiting. Evita usar eventos relacionados con redes, como progress, suspend y stalled, ya que suelen depender de la plataforma. Consulta Eventos de medios para obtener más información sobre el control de eventos de medios en tu receptor.
  • Cuando configures los certificados HTTPS de tu sitio receptor, asegúrate de incluir los certificados de CA intermedios. Consulta la página de prueba de SSL de Qualsys para verificar si la ruta de certificación de confianza de tu sitio incluye un certificado de CA etiquetado como “descarga adicional”. Si es así, es posible que no se cargue en plataformas basadas en Android.
  • Si bien Chromecast muestra la página del receptor en un plano gráfico de 720p, otras plataformas de Cast, como Android TV, pueden mostrar la página hasta en 1080p. Asegúrate de que tu página del receptor se ajuste correctamente a diferentes resoluciones.