Inserção de anúncios

O ExoPlayer pode ser usado para inserção de anúncios do lado do cliente e do lado do servidor.

Inserção de anúncios do lado do cliente

Na inserção de anúncios do lado do cliente, o player alterna entre o carregamento de mídia de URLs diferentes ao fazer a transição entre a reprodução de conteúdo e anúncios. As informações sobre anúncios são carregadas separadamente da mídia, como de uma tag de anúncio XML VAST ou VMAP. Isso pode incluir posições de indicação de anúncio em relação ao início do conteúdo, os URIs de mídia do anúncio real e metadados, como se um determinado anúncio é pulável.

Ao usar o AdsMediaSource do ExoPlayer para inserção de anúncios do lado do cliente, o player tem informações sobre os anúncios que serão mostrados. Essa mudança gera vários benefícios:

  • O player pode expor metadados e funcionalidades relacionados a anúncios usando a API.
  • Os componentes de interface do ExoPlayer podem mostrar marcadores para posições de anúncios automaticamente e mudar o comportamento deles dependendo se o anúncio está sendo reproduzido.
  • Internamente, o player pode manter um buffer consistente nas transições entre anúncios e conteúdo.

Nessa configuração, o player cuida da alternância entre anúncios e conteúdo, o que significa que os apps não precisam controlar vários players separados em segundo plano e em primeiro plano para anúncios e conteúdo.

Ao preparar vídeos de conteúdo e tags de anúncio para uso com a inserção de anúncios do lado do cliente, o ideal é que os anúncios sejam posicionados em amostras de sincronização (keyframes) no vídeo de conteúdo para que o player possa retomar a reprodução do conteúdo sem problemas.

Suporte a anúncios declarativos

Um URI de tag de anúncio pode ser especificado ao criar um 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 ativar a compatibilidade do player com itens de mídia que especificam tags de anúncio, é necessário criar e injetar um DefaultMediaSourceFactory configurado com um AdsLoader.Provider e um AdViewProvider ao criar o player:

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();

Internamente, DefaultMediaSourceFactory vai envolver a origem de mídia de conteúdo em um AdsMediaSource. O AdsMediaSource vai receber um AdsLoader do AdsLoader.Provider e usá-lo para inserir anúncios conforme definido pela tag de anúncio do item de mídia.

O PlayerView do ExoPlayer implementa AdViewProvider. A biblioteca IMA do ExoPlayer fornece um AdsLoader, conforme descrito mais adiante.

Playlists com anúncios

Ao reproduzir uma playlist com vários itens de mídia, o comportamento padrão é solicitar a tag de anúncio e armazenar o estado de reprodução do anúncio uma vez para cada combinação de código da mídia, URI de conteúdo e URI de tag de anúncio. Isso significa que os usuários vão ver anúncios para cada item de mídia com anúncios que tenha um código da mídia ou URI de conteúdo diferente, mesmo que os URIs da tag de anúncio sejam iguais. Se um item de mídia for repetido, o usuário vai ver os anúncios correspondentes apenas uma vez. O estado de reprodução do anúncio armazena se os anúncios foram reproduzidos, para que sejam pulados após a primeira ocorrência.

É possível personalizar esse comportamento transmitindo um identificador de anúncios opaco ao qual o estado de reprodução do anúncio de um determinado item de mídia está vinculado, com base na igualdade de objetos. Veja um exemplo em que o estado de reprodução do anúncio está vinculado apenas ao URI da tag de anúncio, em vez da combinação do código da mídia e do URI da tag de anúncio, transmitindo o URI da tag de anúncio como o identificador de anúncios. O efeito é que os anúncios serão carregados apenas uma vez, e o usuário não verá anúncios no segundo item ao reproduzir a playlist do início ao fim.

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

Inserção de anúncios do lado do cliente guiada pelo servidor

O ExoPlayer vem com o HlsInterstitialsAdsLoader, que permite que os anúncios definidos na playlist HLS sejam inseridos automaticamente no lado do cliente. Consulte a seção sobre HlsInterstitialsAdsLoader na página do HLS.

Biblioteca IMA do ExoPlayer

A biblioteca do IMA do ExoPlayer fornece ImaAdsLoader para integrar a inserção de anúncios do lado do cliente ao seu app. Ela envolve a funcionalidade do SDK do IMA do lado do cliente para oferecer suporte à inserção de anúncios VAST/VMAP. Para instruções sobre como usar a biblioteca, incluindo como lidar com a reprodução em segundo plano e a retomada, consulte o README.

O aplicativo de demonstração usa a biblioteca do IMA e inclui várias tags de anúncio de amostra VAST/VMAP na lista de amostras.

Considerações sobre a interface

O PlayerView oculta os controles de transporte durante a reprodução de anúncios por padrão, mas os apps podem alternar esse comportamento chamando setControllerHideDuringAds. O SDK do IMA vai mostrar outras visualizações sobre o player enquanto um anúncio estiver sendo reproduzido (por exemplo, um link "Mais informações" e um botão de pular, se aplicável).

O SDK do IMA pode informar se os anúncios estão ocultos por visualizações fornecidas pelo aplicativo renderizadas sobre o player. Os apps que precisam sobrepor visualizações essenciais para controlar a reprodução precisam registrá-las no SDK do IMA para que sejam omitidas dos cálculos de visibilidade. Ao usar PlayerView como AdViewProvider, ele vai registrar automaticamente as sobreposições de controle. Os apps que usam uma interface personalizada do player precisam registrar as visualizações de sobreposição retornando-as de AdViewProvider.getAdOverlayInfos.

Para mais informações sobre as visualizações de sobreposição, consulte Open Measurement no SDK do IMA.

Anúncios complementares

Algumas tags de anúncio contêm anúncios complementares adicionais que podem ser mostrados em "espaços" na interface de um app. Esses slots podem ser transmitidos usando ImaAdsLoader.Builder.setCompanionAdSlots(slots). Para mais informações, consulte Como adicionar anúncios complementares.

Anúncios independentes

O SDK do IMA foi projetado para inserir anúncios em conteúdo de mídia, não para reproduzir anúncios independentes por conta própria. Portanto, a reprodução de anúncios independentes não é compatível com a biblioteca do IMA. Recomendamos usar o SDK do Google Mobile Ads para esse caso de uso.

Usar um SDK de anúncios de terceiros

Se você precisar carregar anúncios usando um SDK de anúncios de terceiros, verifique se ele já oferece uma integração com o ExoPlayer. Caso contrário, a abordagem recomendada é implementar um AdsLoader personalizado que envolva o SDK de anúncios de terceiros, já que ele oferece os benefícios de AdsMediaSource descritos anteriormente. ImaAdsLoader funciona como um exemplo de implementação.

Como alternativa, use o suporte a playlists do ExoPlayer para criar uma sequência de anúncios e clipes de conteúdo:

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

Inserção de anúncios do lado do servidor

Na inserção de anúncios do lado do servidor (também chamada de inserção de anúncios dinâmicos ou DAI), o stream de mídia contém anúncios e conteúdo. Um manifesto DASH pode apontar para segmentos de conteúdo e de anúncio, possivelmente em períodos separados. Para HLS, consulte a documentação da Apple sobre como incorporar anúncios em uma playlist.

Ao usar a inserção de anúncios do lado do servidor, o cliente pode precisar resolver o URL de mídia dinamicamente para receber o stream integrado, mostrar sobreposições de anúncios na interface ou informar eventos a um SDK de anúncios ou servidor de anúncios.

O DefaultMediaSourceFactory do ExoPlayer pode delegar todas essas tarefas a uma MediaSource de inserção de anúncios do lado do servidor para URIs que usam o 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 IMA do ExoPlayer

A biblioteca IMA do ExoPlayer fornece ImaServerSideAdInsertionMediaSource para integrar os streams de anúncios inseridos do lado do servidor do IMA ao seu app. Ela une a funcionalidade do SDK de DAI do IMA para Android e integra totalmente os metadados de anúncios fornecidos ao player. Por exemplo, isso permite usar métodos como Player.isPlayingAd(), ouvir transições de anúncios de conteúdo e permitir que o player processe a lógica de reprodução de anúncios, como pular anúncios já reproduzidos.

Para usar essa classe, é necessário configurar o ImaServerSideAdInsertionMediaSource.AdsLoader e o ImaServerSideAdInsertionMediaSource.Factory e conectá-los ao player:

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

Carregue sua chave de recurso do IMA ou o ID da origem do conteúdo e o ID do vídeo criando um URL com 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 fim, libere o carregador de anúncios quando ele não estiver mais em uso:

Kotlin

adsLoader.release()

Java

adsLoader.release();

Considerações sobre a interface

As mesmas considerações de interface da inserção de anúncios do lado do cliente também se aplicam à inserção de anúncios do lado do servidor.

Anúncios complementares

Algumas tags de anúncio contêm anúncios complementares adicionais que podem ser mostrados em "espaços" na interface de um app. Esses slots podem ser transmitidos usando ImaServerSideAdInsertionMediaSource.AdsLoader.Builder.setCompanionAdSlots(slots). Para mais informações, consulte Como adicionar anúncios complementares.

Usar um SDK de anúncios de terceiros

Se você precisar carregar anúncios usando um SDK de anúncios de terceiros, verifique se ele já oferece uma integração com o ExoPlayer. Caso contrário, é recomendável fornecer um MediaSource personalizado que aceite URIs com o esquema ssai:// semelhante a ImaServerSideAdInsertionMediaSource.

A lógica real de criação da estrutura do anúncio pode ser delegada ao ServerSideAdInsertionMediaSource de uso geral, que envolve um stream MediaSource e permite que o usuário defina e atualize o AdPlaybackState que representa os metadados do anúncio.

Muitas vezes, os streams de anúncios inseridos do lado do servidor contêm eventos programados para notificar o player sobre os metadados do anúncio. Consulte os formatos compatíveis para saber quais formatos de metadados programados são aceitos pelo ExoPlayer. As implementações personalizadas do SDK de anúncios MediaSource podem detectar eventos de metadados programados do player usando Player.Listener.onMetadata.