Insertion d'annonces

ExoPlayer peut être utilisé pour l'insertion d'annonces côté client et côté serveur.

Insertion d'annonces côté client

Dans l'insertion d'annonces côté client, le lecteur bascule entre le chargement de contenu multimédia à partir de différentes URL lorsqu'il passe de la lecture du contenu aux annonces. Les informations sur les annonces sont chargées séparément du support, par exemple à partir d'un tag d'emplacement publicitaire XML VAST ou VMAP. Cela peut inclure les positions du repère de l'annonce par rapport au début du contenu, les URI réels de l'annonce et des métadonnées, par exemple si une annonce donnée est désactivable ou non.

Lorsque vous utilisez le AdsMediaSource d'ExoPlayer pour insérer des annonces côté client, le lecteur dispose d'informations sur les annonces à lire. Cela présente plusieurs avantages :

  • Le lecteur peut présenter des métadonnées et des fonctionnalités liées aux annonces à l'aide de son API.
  • Les composants d'UI d'ExoPlayer peuvent afficher automatiquement des repères pour la position des annonces et modifier leur comportement selon que l'annonce est diffusée ou non.
  • En interne, le lecteur peut conserver un tampon cohérent entre les transitions entre les annonces et le contenu.

Dans cette configuration, le lecteur bascule entre les annonces et le contenu, ce qui signifie que les applications n'ont pas besoin de contrôler plusieurs lecteurs d'arrière-plan/de premier plan distincts pour les annonces et le contenu.

Lors de la préparation des vidéos de contenu et des tags d'emplacement publicitaire à utiliser avec l'insertion d'annonces côté client, les annonces doivent idéalement être positionnées au niveau des échantillons de synchronisation (images clés) dans la vidéo de contenu afin que le lecteur puisse reprendre la lecture du contenu sans difficulté.

Compatibilité avec les annonces déclaratives

Vous pouvez spécifier un URI de tag d'emplacement publicitaire lors de la création d'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();

Pour activer la compatibilité du lecteur avec les éléments multimédias qui spécifient des tags d'emplacement publicitaire, vous devez créer et injecter un DefaultMediaSourceFactory configuré avec AdsLoader.Provider et AdViewProvider lors de la création du lecteur:

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

En interne, DefaultMediaSourceFactory encapsule la source multimédia de contenu dans un AdsMediaSource. AdsMediaSource obtient un AdsLoader à partir de AdsLoader.Provider et l'utilise pour insérer des annonces comme défini par le tag d'emplacement publicitaire de l'élément multimédia.

Le PlayerView d'ExoPlayer implémente AdViewProvider. La bibliothèque IMA d'ExoPlayer fournit un AdsLoader facile à utiliser, comme décrit ci-dessous.

Playlists avec annonces

Lors de la lecture d'une playlist avec plusieurs éléments multimédias, le comportement par défaut consiste à demander le tag d'emplacement publicitaire et à stocker l'état de lecture de l'annonce une fois pour chaque combinaison d'ID multimédia, d'URI de contenu et d'URI de tag d'emplacement publicitaire. Cela signifie que les utilisateurs verront des annonces pour chaque élément multimédia avec des annonces ayant un ID média ou un URI de contenu distincts, même si les URI des tags d'emplacement publicitaire correspondent. Si un élément multimédia est répété, l'utilisateur ne verra les annonces correspondantes qu'une seule fois (l'état de lecture des annonces stocke si des annonces ont été lues, elles seront donc ignorées après leur première occurrence).

Il est possible de personnaliser ce comportement en transmettant un identifiant d'annonce opaque auquel l'état de lecture d'un élément multimédia donné est associé, en fonction de l'égalité des objets. Dans l'exemple ci-dessous, l'état de lecture d'une annonce n'est associé qu'à l'URI du tag d'emplacement publicitaire, et non à la combinaison de l'ID média et de l'URI du tag d'emplacement publicitaire, en transmettant l'URI du tag d'emplacement publicitaire en tant qu'identifiant de l'annonce. Il en résulte que les annonces ne se chargent qu'une seule fois et que l'utilisateur ne verra aucune annonce sur le deuxième élément lors de la lecture de la playlist du début à la 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);

Bibliothèque IMA d'ExoPlayer

La bibliothèque IMA d'ExoPlayer fournit ImaAdsLoader, ce qui facilite l'intégration d'annonces côté client dans votre application. Elle intègre les fonctionnalités du SDK IMA côté client pour permettre l'insertion d'annonces VAST/VMAP. Pour obtenir des instructions sur l'utilisation de la bibliothèque, y compris sur la gestion de la mise en arrière-plan et de la reprise de la lecture, consultez le fichier README.

L'application de démonstration utilise la bibliothèque IMA et inclut plusieurs exemples de tags d'emplacement publicitaire VAST/VMAP dans la liste d'exemples.

Remarques sur l'interface utilisateur

Par défaut, PlayerView masque les commandes de transport pendant la lecture des annonces, mais les applications peuvent activer ou désactiver ce comportement en appelant setControllerHideDuringAds. Le SDK IMA affiche des vues supplémentaires en haut du lecteur pendant la lecture d'une annonce (par exemple, un lien "plus d'infos" et un bouton "Ignorer", le cas échéant).

Le SDK IMA peut indiquer si les annonces sont masquées par les vues fournies par l'application qui s'affichent au-dessus du lecteur. Les applications qui doivent superposer des vues essentielles pour le contrôle de la lecture doivent les enregistrer avec le SDK IMA pour pouvoir les omettre dans les calculs de visibilité. Lorsque vous utilisez PlayerView comme AdViewProvider, il enregistre automatiquement ses superpositions de commandes. Les applications qui utilisent une UI de lecteur personnalisée doivent enregistrer les vues en superposition en les renvoyant à partir de AdViewProvider.getAdOverlayInfos.

Pour en savoir plus sur les vues en superposition, consultez Open Measurement dans le SDK IMA.

Annonces associées

Certains tags d'emplacement publicitaire contiennent des annonces associées supplémentaires qui peuvent s'afficher dans des "espaces publicitaires" au sein d'une interface utilisateur d'application. Ces emplacements peuvent être transmis via ImaAdsLoader.Builder.setCompanionAdSlots(slots). Pour plus d'informations, consultez la section Ajouter des annonces associées.

Annonces autonomes

Le SDK IMA est conçu pour insérer des annonces dans du contenu multimédia, et non pour diffuser des annonces autonomes. La lecture d'annonces autonomes n'est donc pas compatible avec la bibliothèque IMA. Nous vous recommandons plutôt d'utiliser le SDK Google Mobile Ads pour ce cas d'utilisation.

Utiliser un SDK publicitaire tiers

Si vous devez charger des annonces via un SDK publicitaire tiers, vérifiez s'il propose déjà une intégration ExoPlayer. Si ce n'est pas le cas, nous vous recommandons d'implémenter un AdsLoader personnalisé qui encapsule le SDK publicitaire tiers, car il offre les avantages de AdsMediaSource décrits ci-dessus. ImaAdsLoader sert d'exemple d'implémentation.

Vous pouvez également utiliser la compatibilité des playlists d'ExoPlayer pour créer une séquence d'annonces et d'extraits de contenu:

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

Insertion d'annonces côté serveur

Dans l'insertion d'annonces côté serveur (également appelée insertion dynamique d'annonce), le flux multimédia contient à la fois des annonces et du contenu. Un fichier manifeste DASH peut renvoyer à la fois vers des segments de contenu et d'annonces, éventuellement dans des périodes distinctes. Pour le protocole HLS, consultez la documentation d'Apple sur l'intégration d'annonces dans une playlist.

Lorsque vous utilisez l'insertion d'annonces côté serveur, le client peut avoir besoin de résoudre l'URL multimédia de manière dynamique pour obtenir le flux assemblé, d'afficher des superpositions d'annonces dans l'interface utilisateur ou de signaler des événements à un SDK publicitaire ou à un ad server.

Le DefaultMediaSourceFactory d'ExoPlayer peut déléguer toutes ces tâches à un MediaSource d'insertion d'annonces côté serveur pour les URI utilisant le schéma 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();

Bibliothèque IMA d'ExoPlayer

La bibliothèque IMA d'ExoPlayer fournit ImaServerSideAdInsertionMediaSource, ce qui facilite l'intégration dans votre application aux flux d'annonces insérés côté serveur d'IMA. Elle englobe les fonctionnalités du SDK IMA DAI pour Android et intègre entièrement les métadonnées d'annonces fournies dans le lecteur. Par exemple, cela vous permet d'utiliser des méthodes telles que Player.isPlayingAd(), d'écouter les transitions de contenu/annonce et de laisser le lecteur gérer la logique de lecture des annonces, comme ignorer les annonces déjà lues.

Pour utiliser cette classe, vous devez configurer ImaServerSideAdInsertionMediaSource.AdsLoader et ImaServerSideAdInsertionMediaSource.Factory, puis les connecter au lecteur:

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

Chargez votre clé d'élément IMA (ou ID de source de contenu et votre ID vidéo) en créant une URL avec 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));

Enfin, libérez le chargeur d'annonces lorsqu'il n'est plus utilisé:

Kotlin

adsLoader.release()

Java

adsLoader.release();

Remarques sur l'interface utilisateur

Les mêmes considérations relatives à l'interface utilisateur que pour l'insertion d'annonces côté client s'appliquent également à l'insertion d'annonces côté serveur.

Annonces associées

Certains tags d'emplacement publicitaire contiennent des annonces associées supplémentaires qui peuvent s'afficher dans des "espaces publicitaires" au sein d'une interface utilisateur d'application. Ces emplacements peuvent être transmis via ImaServerSideAdInsertionMediaSource.AdsLoader.Builder.setCompanionAdSlots(slots). Pour plus d'informations, consultez la section Ajouter des annonces associées.

Utiliser un SDK publicitaire tiers

Si vous devez charger des annonces à l'aide d'un SDK publicitaire tiers, vérifiez s'il propose déjà une intégration ExoPlayer. Si ce n'est pas le cas, il est recommandé de fournir un MediaSource personnalisé qui accepte les URI avec un schéma ssai:// semblable à ImaServerSideAdInsertionMediaSource.

La logique de création de la structure d'annonce peut être déléguée à l'ServerSideAdInsertionMediaSource à usage général, qui encapsule un flux MediaSource et permet à l'utilisateur de définir et de mettre à jour l'AdPlaybackState représentant les métadonnées de l'annonce.

Souvent, les flux d'annonces insérés côté serveur contiennent des événements programmés pour informer le lecteur des métadonnées des annonces. Veuillez consulter les formats compatibles pour en savoir plus sur les formats de métadonnées minutées compatibles avec ExoPlayer. Les implémentations MediaSource du SDK publicitaire personnalisé peuvent écouter les événements de métadonnées minutés du lecteur à l'aide de Player.Listener.onMetadata.