Usa el SDK de DAI de IMA en Chromecast

Reproduce transmisiones en vivo registradas con la API de Video Stitcher de Google Cloud

En esta guía, se muestra cómo usar el SDK de IMA DAI para receptores web de CAF para solicitar y reproducir una transmisión en vivo de un evento registrado con la API de Video Stitcher de Google Cloud, y cómo insertar una pausa publicitaria durante la reproducción.

Esta guía amplía el ejemplo básico de DAI de servicio completo y agrega compatibilidad con las transmisiones registradas con la API de Video Stitcher de Google Cloud.

Asegúrate de que los receptores web de CAF admitan tu formato de transmisión antes de continuar.

Para obtener información sobre la integración con otras plataformas o el uso de los SDKs de IMA del cliente, consulta SDKs de Interactive Media Ads.

Fondo

Antes de usar esta guía, familiarízate con el protocolo del receptor web de Chromecast Application Framework.

En esta guía, se supone un nivel básico de familiaridad con los conceptos del receptor de CAF, como los interceptores de mensajes, MediaInformation objetos y el uso de la herramienta Cast Command and Control para emular un remitente de CAF.

Componentes y arquitectura de la app

La implementación de la reproducción de transmisiones en vivo con la API de Video Stitcher de Google Cloud con el SDK de IMA CAF DAI incluye dos componentes principales, como se muestra en esta guía:

  • VideoStitcherLiveStreamRequest: Es un objeto que define una solicitud de transmisión a los servidores de Google. La solicitud especifica una instancia de la API de Cloud Video Stitcher, un ID de configuración de transmisión en vivo y otros parámetros opcionales.
  • StreamManager: Es un objeto que controla la comunicación entre la transmisión de video por Internet y el SDK de IMA DAI, como el envío de pings de seguimiento y el reenvío de eventos de transmisión al publicador.

Requisitos previos

Necesitas las siguientes variables para el SDK de IMA:

  • ID de configuración de transmisión en vivo: Es el ID de configuración de transmisión en vivo que especificaste cuando creaste la configuración de transmisión en vivo de la API de Video Stitcher.

    LIVE_CONFIG_ID

  • Ubicación: Es la región de Google Cloud en la que se creó tu configuración de transmisión en vivo.

    LOCATION

  • Número de proyecto: Es el número de proyecto de Google Cloud que usa la API de Video Stitcher.

    PROJECT_NUMBER

  • Token de OAuth: Es el token de OAuth de corta duración de una cuenta de servicio con el rol de usuario de Video Stitcher. Obtén más información para crear credenciales de corta duración para cuentas de servicio.

    OAUTH_TOKEN

  • Código de red: Es el código de red de Google Ad Manager para solicitar anuncios.

    NETWORK_CODE

  • Clave de contenido personalizado: Es la clave de contenido personalizado de Google Ad Manager que se genera durante el proceso de creación de una configuración para un evento de transmisión en vivo con la API de Video Stitcher.

    CUSTOM_ASSET_KEY

Necesitas lo siguiente para un receptor de Cast personalizado:

  • Una cuenta de Play Console de Cast con dispositivos de prueba en una lista de entidades permitidas

  • Una app de receptor web alojada que esté registrada en Play Console de Cast y que se pueda modificar para alojar el código que proporciona esta guía

  • Una app de envío configurada para usar tu app de receptor web. Para los fines de este ejemplo, esta guía usa la herramienta Cast Command and Control como remitente

Prepara un remitente para pasar datos de transmisión al receptor

Primero, configura tu app de envío para que realice una solicitud de carga a tu receptor web, que contenga los siguientes campos en el MediaInformation objeto de tu plataforma.

Campo Contenido
contentId Un identificador único para este elemento multimedia, como se define en la documentación de referencia de Cast. Este ID no se debe volver a usar para varios elementos en la misma cola de contenido multimedia.

CONTENT_ID

contentUrl Es la URL de transmisión de copia de seguridad opcional para reproducir si no se carga la transmisión de DAI.

BACKUP_STREAM_URL

contentType Es el tipo MIME opcional de la URL de transmisión de copia de seguridad para reproducir si no se carga la transmisión de DAI.

BACKUP_STREAM_MIMETYPE

streamType El literal de cadena o la constante que se usa para este valor varía según la plataforma del remitente.

LIVE

customData

El campo customData contiene un almacén de pares clave-valor de campos obligatorios adicionales. En este caso, customData contiene los datos de transmisión de DAI que recopilaste.

Campo Contenido
liveConfigID LIVE_CONFIG_ID
region LOCATION
projectNumber PROJECT_NUMBER
oAuthToken OAUTH_TOKEN
networkCode NETWORK_CODE
customAssetKey CUSTOM_ASSET_KEY

Aquí encontrarás algunos ejemplos de código que te ayudarán a comenzar:

Web

Para configurar estos valores en un remitente web de Cast, primero crea un MediaInfo objeto con los datos requeridos y, luego, realiza una solicitud de carga al receptor web.

// Create mediaInfo object
const mediaInfo = new chrome.cast.media.MediaInfo("CONTENT_ID");
mediaInfo.contentUrl = "BACKUP_STREAM_URL";
mediaInfo.contentType = "BACKUP_STREAM_MIMETYPE";
mediaInfo.streamType = chrome.cast.media.StreamType.LIVE;
mediaInfo.customData = {
liveConfigID: "LIVE_CONFIG_ID",
region: "LOCATION",
projectNumber: "PROJECT_NUMBER",
oAuthToken: "OAUTH_TOKEN",
networkCode: "NETWORK_CODE",
customAssetKey: "CUSTOM_ASSET_KEY"
};

// Make load request to cast web receiver
const castSession = cast.framework.CastContext.getInstance().getCurrentSession();
const request = new chrome.cast.media.LoadRequest(mediaInfo);
castSession.loadMedia(request).then(
  () => { console.log('Load succeed'); },
  (errorCode) => { console.log('Error code: ' + errorCode); });

Android

Para configurar estos valores en un remitente web de Cast, primero crea un MediaInfo objeto con los datos requeridos y, luego, realiza una solicitud de carga al receptor web.

JSONObject customData = new JSONObject()
  .put("liveConfigID", "LIVE_CONFIG_ID")
  .put("region", "LOCATION")
  .put("projectNumber", "PROJECT_NUMBER")
  .put("oAuthToken", "OAUTH_TOKEN")
  .put("networkCode", "NETWORK_CODE")
  .put("customAssetKey", "CUSTOM_ASSET_KEY");

MediaInfo mediaInfo = MediaInfo.Builder("CONTENT_ID")
  .setContentUrl("BACKUP_STREAM_URL")
  .setContentType("BACKUP_STREAM_MIMETYPE")
  .setStreamType(MediaInfo.STREAM_TYPE_LIVE)
  .setCustomData(customData)
  .build();

RemoteMediaClient remoteMediaClient = mCastSession.getRemoteMediaClient();
remoteMediaClient.load(new MediaLoadRequestData.Builder().setMediaInfo(mediaInfo).build());

iOS (Obj-C)

Para configurar estos valores en un remitente web de Cast, primero crea un GCKMediaInformation objeto con los datos requeridos y, luego, realiza una solicitud de carga al receptor web.

NSURL url = [NSURL URLWithString:@"BACKUP_STREAM_URL"];
NSDictionary *customData = @{
  @"liveConfigID": @"LIVE_CONFIG_ID",
  @"region": @"LOCATION",
  @"projectNumber": @"PROJECT_NUMBER",
  @"oAuthToken": @"OAUTH_TOKEN",
  @"networkCode": @"NETWORK_CODE",
  @"customAssetKey": @"CUSTOM_ASSET_KEY"
};

GCKMediaInformationBuilder *mediaInfoBuilder =
  [[GCKMediaInformationBuilder alloc] initWithContentID: @"CONTENT_ID"];
mediaInfoBuilder.contentURL = url;
mediaInfoBuilder.contentType = @"BACKUP_STREAM_MIMETYPE";
mediaInfoBuilder.streamType = GCKMediaStreamTypeLive;
mediaInfoBuilder.customData = customData;
self.mediaInformation = [mediaInfoBuilder build];

GCKRequest *request = [self.sessionManager.currentSession.remoteMediaClient loadMedia:self.mediaInformation];
if (request != nil) {
  request.delegate = self;
}

iOS (Swift)

Para configurar estos valores en un remitente web de Cast, primero crea un GCKMediaInformation objeto con los datos requeridos y, luego, realiza una solicitud de carga al receptor web.

let url = URL.init(string: "BACKUP_STREAM_URL")
guard let mediaURL = url else {
  print("invalid mediaURL")
  return
}

let customData = [
  "liveConfigID": "LIVE_CONFIG_ID",
  "region": "LOCATION",
  "projectNumber": "PROJECT_NUMBER",
  "oAuthToken": "OAUTH_TOKEN",
  "networkCode": "NETWORK_CODE",
  "customAssetKey": "CUSTOM_ASSET_KEY"
]

let mediaInfoBuilder = GCKMediaInformationBuilder.init(contentId: "CONTENT_ID")
mediaInfoBuilder.contentURL = mediaUrl
mediaInfoBuilder.contentType = "BACKUP_STREAM_MIMETYPE"
mediaInfoBuilder.streamType = GCKMediaStreamType.Live
mediaInfoBuilder.customData = customData
mediaInformation = mediaInfoBuilder.build()

guard let mediaInfo = mediaInformation else {
  print("invalid mediaInformation")
  return
}

if let request = sessionManager.currentSession?.remoteMediaClient?.loadMedia(mediaInfo) {
  request.delegate = self
}

Herramienta CAC

Para configurar estos valores en la herramienta Cast Command and Control , haz clic en la pestaña Load Media y establece el tipo de solicitud de carga personalizada en LOAD. Luego, reemplaza los datos de JSON en el área de texto con este JSON:

{
  "media": {
    "contentId": "CONTENT_ID",
    "contentUrl": "BACKUP_STREAM_URL",
    "contentType": "BACKUP_STREAM_MIMETYPE",
    "streamType": "LIVE",
    "customData": {
      "liveConfigID": "LIVE_CONFIG_ID",
      "region": "LOCATION",
      "projectNumber": "PROJECT_NUMBER",
      "oAuthToken": "OAUTH_TOKEN",
      "networkCode": "NETWORK_CODE",
      "customAssetKey": "CUSTOM_ASSET_KEY"
    }
  }
}

Esta solicitud de carga personalizada se puede enviar al receptor para probar el resto de los pasos.

Crea un receptor web de CAF personalizado

Crea un receptor web personalizado, como se muestra en la Guía del receptor web personalizado del SDK de CAF.

El código de tu receptor debería verse de la siguiente manera:

<html>
<head>
  <script
      src="//www.gstatic.com/cast/sdk/libs/caf_receiver/v3/cast_receiver_framework.js">
  </script>
</head>
<body>
  <cast-media-player></cast-media-player>
  <script>
    const castContext = cast.framework.CastReceiverContext.getInstance()
    castContext.start();
  </script>
</body>
</html>

Importa el SDK de IMA DAI y obtén el administrador de reproductores

Agrega una etiqueta de secuencia de comandos para importar el SDK de IMA DAI para CAF a tu receptor web, justo después de que la secuencia de comandos cargue CAF. Luego, en la etiqueta de secuencia de comandos que sigue, almacena el contexto del receptor y el administrador de reproductores como constantes antes de iniciar el receptor.

<html>
<head>
  <script
      src="//www.gstatic.com/cast/sdk/libs/caf_receiver/v3/cast_receiver_framework.js"></script>
  <script src="//imasdk.googleapis.com/js/sdkloader/cast_dai.js"></script>
</head>
<body>
  <cast-media-player></cast-media-player>
  <script>
    const castContext = cast.framework.CastReceiverContext.getInstance();
    const playerManager = castContext.getPlayerManager();

    castContext.start();
  </script>
</body>
</html>

Inicializa el administrador de transmisiones de IMA

Inicializa el administrador de transmisiones de IMA.

<html>
<head>
  <script type="text/javascript"
      src="//www.gstatic.com/cast/sdk/libs/caf_receiver/v3/cast_receiver_framework.js"></script>
  <script src="//imasdk.googleapis.com/js/sdkloader/cast_dai.js"></script>
</head>
<body>
  <cast-media-player></cast-media-player>
  <script>
    const castContext = cast.framework.CastReceiverContext.getInstance();
    const playerManager = castContext.getPlayerManager();
    const streamManager = new google.ima.cast.dai.api.StreamManager();

    castContext.start();
  </script>
</body>
</html>

Crea el interceptor de carga del administrador de transmisiones

Antes de que tus elementos multimedia se pasen a CAF, crea tu solicitud de transmisión en un interceptor de mensajes LOAD.

    const castContext = cast.framework.CastReceiverContext.getInstance();
    const playerManager = castContext.getPlayerManager();
    const streamManager = new google.ima.cast.dai.api.StreamManager();

    /**
     * Creates a livestream request object for the Video Stitcher API.
     * @param {!LoadRequestData} castRequest The request object from the cast sender
     * @return {StreamRequest} an IMA stream request
     */
    const createStreamRequest = (castRequest) => { /* ... */};

    /**
     * Initates a DAI stream request for the final stream manifest.
     * @param {!LoadRequestData} castRequest The request object from the cast sender
     * @return {Promise<LoadRequestData>} a promise that resolves to an updated castRequest, containing the DAI stream manifest
     */
    const createDAICastRequest = (castRequest) => {
        return streamManager.requestStream(castRequest, createStreamRequest(castRequest))
          .then((castRequestWithStreamData) => {
            console.log('Successfully made DAI stream request.');
            return castRequestWithStreamData;
          })
          .catch((error) => {
            console.log('Failed to make DAI stream request.');
            // CAF will automatically fallback to the content URL
            // that it can read from the castRequest object.
            return castRequest;
          });
    };

    playerManager.setMessageInterceptor(
        cast.framework.messages.MessageType.LOAD, createDAICastRequest);

    castContext.start();

Crea la solicitud de transmisión

Completa la función createStreamRequest para crear una solicitud de transmisión en vivo de la API de Video Stitcher, según la solicitud de carga de CAF.

    /**
     * Creates a livestream request object for the Video Stitcher API.
     * @param {!LoadRequestData} castRequest The request object from the cast sender
     * @return {StreamRequest} an IMA stream request
     */
    const createStreamRequest = (castRequest) => {
      const streamRequest = new google.ima.cast.dai.api.VideoStitcherLiveStreamRequest();
      const customData = castRequest.media.customData;

      streamRequest.liveStreamEventId = customData.liveConfigID;
      streamRequest.region = customData.region;
      streamRequest.projectNumber = customData.projectNumber;
      streamRequest.oAuthToken = customData.oAuthToken;
      streamRequest.networkCode = customData.networkCode;
      streamRequest.customAssetKey = customData.customAssetKey;

      return streamRequest;
    };

Agrega opciones de sesión de transmisión (opcional)

Personaliza tu solicitud de transmisión agregando opciones de sesión para anular la configuración predeterminada de la API de Cloud Video Stitcher con VideoStitcherLiveStreamRequest.videoStitcherSessionOptions. Si proporcionas una opción no reconocida, la API de Cloud Video Stitcher responderá con un error HTTP 400. Consulta la guía de solución de problemas para obtener asistencia.

Por ejemplo, puedes anular las opciones de manifiesto con el siguiente fragmento de código, que solicita dos manifiestos de transmisión con representaciones ordenadas de la tasa de bits más baja a la más alta.

...

// The following session options are examples. Use session options
// that are compatible with your video stream.
streamRequest.videoStitcherSessionOptions = {
  "manifestOptions": {
    "bitrateOrder": "ascending"
  }
};

streamManager.requestStream(streamRequest);