Usar el SDK de IMA DAI en Chromecast

Reproducir emisiones en directo registradas con la API Google Cloud Video Stitcher

En esta guía se muestra cómo usar el SDK de IMA DAI para Web Receivers de CAF para solicitar y reproducir una emisión en directo de un evento registrado con la API Video Stitcher de Google Cloud e insertar un bloque de anuncios durante la reproducción.

En esta guía se amplía el ejemplo básico de la inserción dinámica de anuncios de servicio completo, añadiendo compatibilidad con las emisiones registradas en la API Google Cloud Video Stitcher.

Antes de continuar, asegúrate de que tu formato de streaming sea compatible con los web receivers de CAF.

Para obtener información sobre cómo integrar otras plataformas o usar los SDKs de IMA del lado del cliente, consulte SDKs de anuncios multimedia interactivos.

Fondo

Antes de usar esta guía, familiarízate con el protocolo Web Receiver del framework de aplicaciones de Chromecast.

En esta guía se da por hecho que tienes un nivel básico de familiarización con los conceptos del receptor de CAF, como los interceptores de mensajes, los objetos MediaInformation y el uso de la herramienta de control y comandos de Cast para emular un remitente de CAF.

Componentes y arquitectura de la aplicación

Para implementar la reproducción de emisiones en directo con la API Video Stitcher de Google Cloud y el SDK de inserción dinámica de anuncios de CAF de IMA, se necesitan dos componentes principales, tal como se muestra en esta guía:

  • VideoStitcherLiveStreamRequest: objeto que define una solicitud de transmisión a los servidores de Google. La solicitud especifica una instancia de la API Cloud Video Stitcher, un ID de configuración en directo y otros parámetros opcionales.
  • StreamManager: objeto que gestiona la comunicación entre el flujo de vídeo y el SDK de inserción dinámica de anuncios de IMA, como enviar pings de seguimiento y reenviar eventos de flujo al editor.

Requisitos previos

Necesita las siguientes variables para el SDK de IMA:

  • ID de configuración en directo: es el ID de configuración en directo que especificaste al crear tu configuración en directo de la API Video Stitcher.

    LIVE_CONFIG_ID

  • Ubicación: la región de Google Cloud en la que se creó tu Live Config.

    LOCATION

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

    PROJECT_NUMBER

  • Token de OAuth: token de OAuth de corta duración de una cuenta de servicio con el rol de usuario de Video Stitcher. Consulta más información sobre cómo crear credenciales de cuentas de servicio de duración reducida.

    OAUTH_TOKEN

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

    NETWORK_CODE

  • Clave de recurso personalizada: clave de recurso personalizada de Google Ad Manager generada durante el proceso de creación de una configuración para un evento de emisión en directo con la API Video Stitcher.

    CUSTOM_ASSET_KEY

Para crear un receptor Cast personalizado, necesitas lo siguiente:

Preparar un remitente para que transfiera datos de la emisión al receptor

Primero, configura tu aplicación emisora para que haga una solicitud de carga a tu receptor web, que contenga los siguientes campos en el objeto MediaInformation de tu plataforma.

Campo Contenido
contentId Identificador único de este elemento multimedia, tal como se define en la documentación de referencia de Cast. Este ID no se debe reutilizar para varios elementos de la misma cola multimedia.

CONTENT_ID

contentUrl URL de emisión de respaldo opcional que se reproducirá si no se puede cargar la emisión de inserción dinámica de anuncios.

BACKUP_STREAM_URL

contentType Tipo MIME opcional de la URL de la emisión de respaldo que se reproducirá si no se puede cargar la emisión de inserción dinámica de anuncios.

BACKUP_STREAM_MIMETYPE

streamType La cadena literal 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 clave-valor de campos obligatorios adicionales. En este caso, customData contiene los datos de la emisión de inserción dinámica de anuncios que ha recogido.

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

Aquí tienes algunos ejemplos de código para ayudarte a empezar:

Web

Para configurar estos valores en un remitente web de Cast, primero crea un objeto MediaInfo con los datos necesarios y, a continuación, haz 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 objeto MediaInfo con los datos necesarios y, a continuación, haz 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 objeto GCKMediaInformation con los datos necesarios y, a continuación, haz 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 objeto GCKMediaInformation con los datos necesarios y, a continuación, haz 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 de control por voz de Cast, haz clic en la pestaña Cargar contenido multimedia y define el tipo de solicitud de carga personalizada como LOAD. A continuación, sustituye los datos JSON del área de texto por 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.

Crear un receptor web CAF personalizado

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

El código del receptor debería tener el siguiente aspecto:

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

Importar el SDK de IMA DAI y obtener el gestor de reproductores

Añada una etiqueta <script> para importar el SDK de IMA DAI para CAF a su receptor web, justo después de cargar el script de CAF. A continuación, en la etiqueta de secuencia de comandos que sigue, almacena el contexto del receptor y el gestor 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>

Inicializar el gestor de emisiones de IMA

Inicializa el gestor de emisiones 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>

Crear el interceptor de carga de Stream Manager

Antes de que tus elementos multimedia se transfieran a CAF, crea tu solicitud de emisió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();

Crear la solicitud de flujo

Completa la función createStreamRequest para crear una solicitud de emisión en directo de la API Video Stitcher basada en 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;
    };

(Opcional) Añadir opciones de sesión de streaming

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

Por ejemplo, puedes anular las opciones del manifiesto con el siguiente fragmento de código, que solicita dos manifiestos de emisión con representaciones ordenadas de menor a mayor tasa de bits.

...

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

streamManager.requestStream(streamRequest);