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 la carga de contenido multimedia de diferentes URLs a medida que realiza la transición entre la reproducción de contenido y los anuncios. La información sobre los anuncios se carga por separado del contenido multimedia, como desde una etiqueta de anuncio VAST o VMAP XML. Esto puede incluir posiciones de indicaciones de anuncios en relación con el comienzo del contenido, los URIs de contenido multimedia del anuncio reales y los metadatos, como si un anuncio determinado se puede omitir.
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 mediante 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 el anuncio se está reproduciendo.
- De forma interna, el reproductor puede mantener un búfer coherente en las transiciones entre anuncios y contenido.
En esta configuración, el reproductor se encarga de alternar entre anuncios y 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 ubiquen en muestras de sincronización (fotogramas clave) en el video de contenido, de modo 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 elementos multimedia que especifiquen 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
de AdsLoader.Provider
y lo usará para insertar anuncios según lo definido por la etiqueta de anuncio del elemento multimedia.
PlayerView
de ExoPlayer implementa AdViewProvider
. La biblioteca de IMA de ExoPlayer proporciona un AdsLoader
fácil de usar, como se describe a continuación.
Playlists con anuncios
Cuando se reproduce una playlist con varios elementos multimedia, el comportamiento predeterminado es solicitar la etiqueta de anuncio y almacenar el estado de reproducción del anuncio una vez por cada combinación de ID de contenido, URI de contenido y URI de etiqueta de anuncio. Esto significa que los usuarios verán anuncios para cada elemento multimedia con anuncios que tengan 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 de anuncios almacena si se reprodujeron los anuncios, por lo que se omiten después de su primera aparición).
Es posible personalizar este comportamiento pasando un identificador de anuncios opacos con el que se vincula el estado de reproducción de anuncios de un elemento multimedia determinado, en función de la igualdad de objetos. Este es un ejemplo en el que el estado de reproducción del anuncio está vinculado solo al URI de la etiqueta de anuncio, en lugar de 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);
Biblioteca de IMA de ExoPlayer
La biblioteca de IMA de ExoPlayer proporciona ImaAdsLoader
, lo que facilita la integración de 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 VAST/VMAP. Para obtener instrucciones sobre cómo usar la biblioteca, incluido cómo controlar el segundo plano y reanudar la reproducción, consulta el archivo README.
La aplicación de demostración usa la biblioteca de IMA y también incluye varias etiquetas de anuncios de VAST/VMAP de muestra en la lista 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 en la parte superior del reproductor mientras se reproduce un anuncio (por ejemplo, un vínculo "más información" y un botón para omitir, si corresponde).
El SDK de IMA puede informar si los anuncios están ocultos por vistas proporcionadas por la aplicación que se renderizan sobre el reproductor. 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
, registrará automáticamente sus superposiciones de controles. Las apps que usan una IU de reproductor personalizada deben mostrar las vistas superpuestas desde AdViewProvider.getAdOverlayInfos
para registrarlas.
Para obtener más información sobre las vistas superpuestas, consulta Open Measurement en el SDK de IMA.
Anuncios complementarios
Algunas etiquetas de anuncios contienen anuncios complementarios adicionales que se pueden mostrar en "espacios" en la IU de una app. Estas ranuras se pueden pasar a través de 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 el contenido multimedia, no para reproducir anuncios independientes por sí solos. Por lo tanto, la biblioteca de IMA no admite la reproducción de anuncios independientes. Recomendamos usar el SDK de anuncios de Google para dispositivos móviles en su lugar para este caso de uso.
Usa un SDK de anuncios de terceros
Si necesitas cargar anuncios a través de un SDK de anuncios de terceros, te recomendamos que verifiques si ya proporciona una integración de ExoPlayer. De lo contrario, el enfoque recomendado es 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(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(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 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 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), el flujo de contenido multimedia incluye anuncios y contenido. Un manifiesto DASH puede apuntar a segmentos de contenido y de anuncios, posiblemente en períodos separados. En el caso de 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 combinada, mostrar superposiciones de anuncios en la IU o informar eventos a un SDK de anuncios o un servidor de anuncios.
DefaultMediaSourceFactory
de ExoPlayer puede delegar todas estas tareas a una 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
, lo que facilita la integración con los flujos de anuncios insertados del servidor de IMA en tu app. Une la funcionalidad del SDK de DAI de IMA para Android y, además, integra completamente los metadatos de anuncios proporcionados en el reproductor. Por ejemplo, esto te permite usar métodos como Player.isPlayingAd()
, escuchar transiciones de contenido a anuncios 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);
Para cargar tu clave de activo de IMA, o el ID de fuente de contenido y el ID de video, compila 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, suelta 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" en la IU de una app. Estos espacios se pueden pasar a través de ImaServerSideAdInsertionMediaSource.AdsLoader.Builder.setCompanionAdSlots(slots)
.
Para obtener más información, consulta Cómo agregar anuncios complementarios.
Cómo usar un SDK de anuncios de terceros
Si necesitas cargar anuncios con un SDK de anuncios de terceros, verifica 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 le permite al usuario configurar y actualizar el AdPlaybackState
que representa los metadatos del anuncio.
A menudo, las transmisiones de anuncios insertadas del servidor contienen eventos cronometrados para notificar al reproductor sobre los metadatos del anuncio. Consulta los formatos compatibles para obtener información sobre los formatos de metadatos sincronizados que admite ExoPlayer. Las implementaciones de MediaSource
del SDK de anuncios personalizados pueden detectar eventos de metadatos cronometrados del reproductor con Player.Listener.onMetadata
.