ExoPlayer se puede usar para la inserción de anuncios del cliente y del servidor.
Inserción de anuncios del cliente
En la inserción de anuncios del cliente, el reproductor alterna entre cargar contenido multimedia de diferentes URLs a medida que pasa de reproducir contenido a anuncios. La información sobre los anuncios se carga por separado del contenido multimedia, como desde una etiqueta de anuncio XML VAST o VMAP. Esto puede incluir posiciones de indicadores de anuncios en relación con el inicio del contenido, los URIs de medios de anuncios reales y metadatos, como si se puede omitir un anuncio determinado.
Cuando se usa AdsMediaSource de ExoPlayer para la inserción de anuncios del cliente, el reproductor tiene información sobre los anuncios que se reproducirán. Esto tiene varios beneficios, como los siguientes:
- El reproductor puede exponer metadatos y funciones relacionados con los anuncios a través de su API.
- Los componentes de la IU de ExoPlayer pueden mostrar marcadores para las posiciones de los anuncios automáticamente y cambiar su comportamiento según si se está reproduciendo el anuncio.
- De forma interna, el reproductor puede mantener un búfer coherente en las transiciones entre los anuncios y el contenido.
En esta configuración, el reproductor se encarga de alternar entre los anuncios y el contenido, lo que significa que las apps no necesitan controlar varios reproductores independientes en segundo plano y en primer plano para los anuncios y el contenido.
Cuando prepares videos de contenido y etiquetas de anuncios para usarlos con la inserción de anuncios del cliente, lo ideal es que los anuncios se coloquen en muestras de sincronización (fotogramas clave) en el video de contenido para que el reproductor pueda reanudar la reproducción del contenido sin problemas.
Compatibilidad con anuncios declarativos
Se puede especificar un URI de etiqueta de anuncio cuando se compila un MediaItem:
Kotlin
val mediaItem = MediaItem.Builder() .setUri(videoUri) .setAdsConfiguration(MediaItem.AdsConfiguration.Builder(adTagUri).build()) .build()
Java
MediaItem mediaItem = new MediaItem.Builder() .setUri(videoUri) .setAdsConfiguration(new MediaItem.AdsConfiguration.Builder(adTagUri).build()) .build();
Para habilitar la compatibilidad del reproductor con los elementos multimedia que especifican etiquetas de anuncios, es necesario compilar e insertar un DefaultMediaSourceFactory configurado con un AdsLoader.Provider y un AdViewProvider cuando se crea el reproductor:
Kotlin
val mediaSourceFactory: MediaSource.Factory = DefaultMediaSourceFactory(context) .setLocalAdInsertionComponents(adsLoaderProvider, playerView) val player = ExoPlayer.Builder(context).setMediaSourceFactory(mediaSourceFactory).build()
Java
MediaSource.Factory mediaSourceFactory = new DefaultMediaSourceFactory(context) .setLocalAdInsertionComponents(adsLoaderProvider, /* adViewProvider= */ playerView); ExoPlayer player = new ExoPlayer.Builder(context).setMediaSourceFactory(mediaSourceFactory).build();
De forma interna, DefaultMediaSourceFactory unirá la fuente de contenido multimedia en un AdsMediaSource. El AdsMediaSource obtendrá un AdsLoader del AdsLoader.Provider y lo usará para insertar anuncios según lo defina la etiqueta de anuncio del elemento multimedia.
PlayerView de ExoPlayer implementa AdViewProvider. La biblioteca de IMA de ExoPlayer proporciona un AdsLoader, como se describe más adelante.
Playlists con anuncios
Cuando se reproduce una lista de reproducción con varios elementos multimedia, el comportamiento predeterminado es solicitar la etiqueta de anuncio y almacenar el estado de reproducción del anuncio una vez para cada combinación de ID de contenido multimedia, URI de contenido y URI de etiqueta de anuncio. Esto significa que los usuarios verán anuncios para cada elemento multimedia con anuncios que tenga un ID de contenido multimedia o un URI de contenido distinto, incluso si los URI de la etiqueta de anuncio coinciden. Si se repite un elemento multimedia, el usuario verá los anuncios correspondientes solo una vez (el estado de reproducción del anuncio almacena si se reprodujeron los anuncios, por lo que se omiten después de su primera reproducción).
Es posible personalizar este comportamiento pasando un identificador de anuncios opaco con el que se vincula el estado de reproducción de anuncios para un elemento multimedia determinado, según la igualdad de objetos. Aquí tienes un ejemplo en el que el estado de reproducción del anuncio se vincula solo al URI de la etiqueta de anuncio, en lugar de a la combinación del ID de contenido multimedia y el URI de la etiqueta de anuncio, pasando el URI de la etiqueta de anuncio como identificador de anuncios. El efecto es que los anuncios se cargarán solo una vez y el usuario no verá anuncios en el segundo elemento cuando reproduzca la playlist de principio a fin.
Kotlin
// Build the media items, passing the same ads identifier for both items, // which means they share ad playback state so ads play only once. val firstItem = MediaItem.Builder() .setUri(firstVideoUri) .setAdsConfiguration( MediaItem.AdsConfiguration.Builder(adTagUri).setAdsId(adTagUri).build() ) .build() val secondItem = MediaItem.Builder() .setUri(secondVideoUri) .setAdsConfiguration( MediaItem.AdsConfiguration.Builder(adTagUri).setAdsId(adTagUri).build() ) .build() player.addMediaItem(firstItem) player.addMediaItem(secondItem)
Java
// Build the media items, passing the same ads identifier for both items, // which means they share ad playback state so ads play only once. MediaItem firstItem = new MediaItem.Builder() .setUri(firstVideoUri) .setAdsConfiguration( new MediaItem.AdsConfiguration.Builder(adTagUri).setAdsId(adTagUri).build()) .build(); MediaItem secondItem = new MediaItem.Builder() .setUri(secondVideoUri) .setAdsConfiguration( new MediaItem.AdsConfiguration.Builder(adTagUri).setAdsId(adTagUri).build()) .build(); player.addMediaItem(firstItem); player.addMediaItem(secondItem);
Inserción de anuncios del cliente guiada por el servidor
ExoPlayer incluye HlsInterstitialsAdsLoader, que admite anuncios definidos en la playlist de HLS para que se inserten automáticamente del lado del cliente. Consulta la
sección sobre HlsInterstitialsAdsLoader en la página de HLS.
Biblioteca de IMA de ExoPlayer
La biblioteca de IMA de ExoPlayer proporciona ImaAdsLoader para integrar la inserción de anuncios del cliente en tu app. Une la funcionalidad del SDK de IMA del cliente para admitir la inserción de anuncios de VAST/VMAP. Para obtener instrucciones sobre cómo usar la biblioteca, incluido cómo controlar la reproducción en segundo plano y la reanudación, consulta el archivo README.
La aplicación de demostración usa la biblioteca de IMA y, en la lista de ejemplo, incluye varias etiquetas de anuncios de VAST o VMAP de muestra.
Consideraciones sobre la IU
De forma predeterminada, PlayerView oculta sus controles de transporte durante la reproducción de anuncios, pero las apps pueden activar o desactivar este comportamiento llamando a setControllerHideDuringAds. El SDK de IMA mostrará vistas adicionales sobre el reproductor mientras se reproduce un anuncio (por ejemplo, un vínculo de "más información" y un botón para omitir, si corresponde).
El SDK de IMA puede informar si las vistas proporcionadas por la aplicación que se renderizan sobre el reproductor ocultan los anuncios. Las apps que necesitan superponer vistas que son esenciales para controlar la reproducción deben registrarlas con el SDK de IMA para que se puedan omitir de los cálculos de visibilidad. Cuando uses PlayerView como AdViewProvider, se registrarán automáticamente sus superposiciones de control. Las apps que usan una IU de reproductor personalizada deben registrar las vistas de superposición devolviéndolas desde AdViewProvider.getAdOverlayInfos.
Para obtener más información sobre las vistas de superposición, consulta Open Measurement en el SDK de IMA.
Anuncios complementarios
Algunas etiquetas de anuncios contienen anuncios complementarios adicionales que se pueden mostrar en "espacios" de la IU de una app. Estos espacios se pueden pasar con ImaAdsLoader.Builder.setCompanionAdSlots(slots). Para obtener más información, consulta Cómo agregar anuncios complementarios.
Anuncios independientes
El SDK de IMA está diseñado para insertar anuncios en contenido multimedia, no para reproducir anuncios independientes por sí mismos. Por lo tanto, la biblioteca de IMA no admite la reproducción de anuncios independientes. En su lugar, te recomendamos que uses el SDK de anuncios de Google para dispositivos móviles para este caso de uso.
Usa un SDK de anuncios de terceros
Si necesitas cargar anuncios con un SDK de anuncios de terceros, vale la pena verificar si ya proporciona una integración de ExoPlayer. De lo contrario, se recomienda implementar un AdsLoader personalizado que una el SDK de anuncios de terceros, ya que proporciona los beneficios de AdsMediaSource descritos anteriormente.
ImaAdsLoader actúa como una implementación de ejemplo.
Como alternativa, puedes usar la compatibilidad con playlists de ExoPlayer para crear una secuencia de anuncios y clips de contenido:
Kotlin
// A pre-roll ad. val preRollAd = MediaItem.fromUri(preRollAdUri) // The start of the content. val contentStart = MediaItem.Builder() .setUri(contentUri) .setClippingConfiguration( MediaItem.ClippingConfiguration.Builder().setEndPositionMs(120000).build() ) .build() // A mid-roll ad. val midRollAd = MediaItem.fromUri(midRollAdUri) // The rest of the content val contentEnd = MediaItem.Builder() .setUri(contentUri) .setClippingConfiguration( MediaItem.ClippingConfiguration.Builder().setStartPositionMs(120000).build() ) .build() // Build the playlist. player.addMediaItem(preRollAd) player.addMediaItem(contentStart) player.addMediaItem(midRollAd) player.addMediaItem(contentEnd)
Java
// A pre-roll ad. MediaItem preRollAd = MediaItem.fromUri(preRollAdUri); // The start of the content. MediaItem contentStart = new MediaItem.Builder() .setUri(contentUri) .setClippingConfiguration( new MediaItem.ClippingConfiguration.Builder().setEndPositionMs(120_000).build()) .build(); // A mid-roll ad. MediaItem midRollAd = MediaItem.fromUri(midRollAdUri); // The rest of the content MediaItem contentEnd = new MediaItem.Builder() .setUri(contentUri) .setClippingConfiguration( new MediaItem.ClippingConfiguration.Builder().setStartPositionMs(120_000).build()) .build(); // Build the playlist. player.addMediaItem(preRollAd); player.addMediaItem(contentStart); player.addMediaItem(midRollAd); player.addMediaItem(contentEnd);
Inserción de anuncios del servidor
En la inserción de anuncios del servidor (también llamada inserción de anuncios dinámicos o DAI), la transmisión de contenido multimedia incluye anuncios y contenido. Un manifiesto de DASH puede apuntar a segmentos de contenido y de anuncios, posiblemente en períodos separados. Para HLS, consulta la documentación de Apple sobre cómo incorporar anuncios en una playlist.
Cuando se usa la inserción de anuncios del servidor, es posible que el cliente deba resolver la URL de contenido multimedia de forma dinámica para obtener la transmisión unida, mostrar superposiciones de anuncios en la IU o informar eventos a un SDK de anuncios o a un servidor de anuncios.
El DefaultMediaSourceFactory de ExoPlayer puede delegar todas estas tareas a un MediaSource de inserción de anuncios del servidor para los URI que usan el esquema ssai://:
Kotlin
val player = ExoPlayer.Builder(context) .setMediaSourceFactory( DefaultMediaSourceFactory(context).setServerSideAdInsertionMediaSourceFactory(ssaiFactory) ) .build()
Java
Player player = new ExoPlayer.Builder(context) .setMediaSourceFactory( new DefaultMediaSourceFactory(context) .setServerSideAdInsertionMediaSourceFactory(ssaiFactory)) .build();
Biblioteca de IMA de ExoPlayer
La biblioteca de IMA de ExoPlayer proporciona ImaServerSideAdInsertionMediaSource para integrarse con las transmisiones de anuncios insertados del servidor de IMA en tu app. Une la funcionalidad del SDK de IMA para DAI para Android y, además, integra por completo los metadatos de anuncios proporcionados en el reproductor. Por ejemplo, esto te permite usar métodos como Player.isPlayingAd(), escuchar las transiciones de contenido a anuncio y permitir que el reproductor controle la lógica de reproducción de anuncios, como omitir los anuncios que ya se reprodujeron.
Para usar esta clase, debes configurar ImaServerSideAdInsertionMediaSource.AdsLoader y ImaServerSideAdInsertionMediaSource.Factory, y conectarlos al reproductor:
Kotlin
// MediaSource.Factory to load the actual media stream. val defaultMediaSourceFactory = DefaultMediaSourceFactory(context) // AdsLoader that can be reused for multiple playbacks. val adsLoader = ImaServerSideAdInsertionMediaSource.AdsLoader.Builder(context, adViewProvider).build() // MediaSource.Factory to create the ad sources for the current player. val adsMediaSourceFactory = ImaServerSideAdInsertionMediaSource.Factory(adsLoader, defaultMediaSourceFactory) // Configure DefaultMediaSourceFactory to create both IMA DAI sources and // regular media sources. If you just play IMA DAI streams, you can also use // adsMediaSourceFactory directly. defaultMediaSourceFactory.setServerSideAdInsertionMediaSourceFactory(adsMediaSourceFactory) // Set the MediaSource.Factory on the Player. val player = ExoPlayer.Builder(context).setMediaSourceFactory(defaultMediaSourceFactory).build() // Set the player on the AdsLoader adsLoader.setPlayer(player)
Java
// MediaSource.Factory to load the actual media stream. DefaultMediaSourceFactory defaultMediaSourceFactory = new DefaultMediaSourceFactory(context); // AdsLoader that can be reused for multiple playbacks. ImaServerSideAdInsertionMediaSource.AdsLoader adsLoader = new ImaServerSideAdInsertionMediaSource.AdsLoader.Builder(context, adViewProvider).build(); // MediaSource.Factory to create the ad sources for the current player. ImaServerSideAdInsertionMediaSource.Factory adsMediaSourceFactory = new ImaServerSideAdInsertionMediaSource.Factory(adsLoader, defaultMediaSourceFactory); // Configure DefaultMediaSourceFactory to create both IMA DAI sources and // regular media sources. If you just play IMA DAI streams, you can also use // adsMediaSourceFactory directly. defaultMediaSourceFactory.setServerSideAdInsertionMediaSourceFactory(adsMediaSourceFactory); // Set the MediaSource.Factory on the Player. Player player = new ExoPlayer.Builder(context).setMediaSourceFactory(defaultMediaSourceFactory).build(); // Set the player on the AdsLoader adsLoader.setPlayer(player);
Carga tu clave de recurso de IMA o el ID de la fuente del contenido y el ID de video creando una URL con ImaServerSideAdInsertionUriBuilder:
Kotlin
val ssaiUri = ImaServerSideAdInsertionUriBuilder() .setAssetKey(assetKey) .setFormat(C.CONTENT_TYPE_HLS) .build() player.setMediaItem(MediaItem.fromUri(ssaiUri))
Java
Uri ssaiUri = new ImaServerSideAdInsertionUriBuilder() .setAssetKey(assetKey) .setFormat(C.CONTENT_TYPE_HLS) .build(); player.setMediaItem(MediaItem.fromUri(ssaiUri));
Por último, libera el cargador de anuncios cuando ya no se use:
Kotlin
adsLoader.release()
Java
adsLoader.release();
Consideraciones sobre la IU
Las mismas consideraciones de la IU que para la inserción de anuncios del cliente también se aplican a la inserción de anuncios del servidor.
Anuncios complementarios
Algunas etiquetas de anuncios contienen anuncios complementarios adicionales que se pueden mostrar en "espacios" de la IU de una app. Estos espacios se pueden pasar con ImaServerSideAdInsertionMediaSource.AdsLoader.Builder.setCompanionAdSlots(slots).
Para obtener más información, consulta Cómo agregar anuncios complementarios.
Usa un SDK de anuncios de terceros
Si necesitas cargar anuncios con un SDK de anuncios de terceros, vale la pena verificar si ya proporciona una integración de ExoPlayer. De lo contrario, se recomienda proporcionar un MediaSource personalizado que acepte URIs con el esquema ssai:// similar a ImaServerSideAdInsertionMediaSource.
La lógica real de crear la estructura del anuncio se puede delegar al ServerSideAdInsertionMediaSource de uso general, que une un flujo MediaSource y permite que el usuario establezca y actualice el AdPlaybackState que representa los metadatos del anuncio.
A menudo, las transmisiones de anuncios insertados del servidor contienen eventos cronometrados para notificar al reproductor
sobre los metadatos de los anuncios. Consulta los formatos compatibles para obtener información sobre los formatos de metadatos cronometrados que admite ExoPlayer. Las implementaciones del SDK de anuncios personalizados de MediaSource pueden escuchar eventos de metadatos cronometrados del reproductor con Player.Listener.onMetadata.