Piles réseau

ExoPlayer est couramment utilisé pour diffuser des contenus multimédias en streaming sur Internet. Il accepte plusieurs piles réseau pour effectuer ses requêtes réseau sous-jacentes. Le choix de la pile réseau peut avoir un impact significatif sur les performances des flux.

Cette page explique comment configurer ExoPlayer pour utiliser la pile réseau de votre choix, liste les options disponibles, fournit des conseils sur le choix d'une pile réseau pour votre application et explique comment activer la mise en cache pour les contenus multimédias diffusés en streaming.

Configurer ExoPlayer pour utiliser une pile réseau spécifique

ExoPlayer charge les données via les composants DataSource, qu'il obtient à partir d'instances DataSource.Factory injectées à partir du code de l'application.

Si votre application a uniquement besoin de lire du contenu HTTP, sélectionner une pile réseau est aussi simple que de mettre à jour les instances DataSource.Factory injectées par votre application pour en faire des instances de HttpDataSource.Factory correspondant à la pile réseau que vous souhaitez utiliser. Si votre application doit également lire du contenu autre que HTTP, comme des fichiers locaux, utilisez DefaultDataSource.Factory:

Kotlin

DefaultDataSource.Factory(
  ...
  /* baseDataSourceFactory= */ PreferredHttpDataSource.Factory(...))

Java

new DefaultDataSource.Factory(
    ...
    /* baseDataSourceFactory= */ new PreferredHttpDataSource.Factory(...));

Dans cet exemple, PreferredHttpDataSource.Factory est la fabrique correspondant à votre pile réseau préférée. La couche DefaultDataSource.Factory prend en charge les sources autres que HTTP, telles que les fichiers locaux.

L'exemple suivant montre comment créer un ExoPlayer qui utilise la pile réseau Cronet et prend également en charge la lecture de contenu autre que HTTP.

Kotlin

// Given a CronetEngine and Executor, build a CronetDataSource.Factory.
val cronetDataSourceFactory = CronetDataSource.Factory(cronetEngine, executor)

// Wrap the CronetDataSource.Factory in a DefaultDataSource.Factory, which adds
// in support for requesting data from other sources (such as files, resources,
// etc).
val dataSourceFactory =
  DefaultDataSource.Factory(context, /* baseDataSourceFactory= */ cronetDataSourceFactory)

// Inject the DefaultDataSource.Factory when creating the player.
val player =
  ExoPlayer.Builder(context)
    .setMediaSourceFactory(
      DefaultMediaSourceFactory(context).setDataSourceFactory(dataSourceFactory)
    )
    .build()

Java

// Given a CronetEngine and Executor, build a CronetDataSource.Factory.
CronetDataSource.Factory cronetDataSourceFactory =
    new CronetDataSource.Factory(cronetEngine, executor);

// Wrap the CronetDataSource.Factory in a DefaultDataSource.Factory, which adds
// in support for requesting data from other sources (such as files, resources,
// etc).
DefaultDataSource.Factory dataSourceFactory =
    new DefaultDataSource.Factory(
        context, /* baseDataSourceFactory= */ cronetDataSourceFactory);

// Inject the DefaultDataSource.Factory when creating the player.
ExoPlayer player =
    new ExoPlayer.Builder(context)
        .setMediaSourceFactory(
            new DefaultMediaSourceFactory(context).setDataSourceFactory(dataSourceFactory))
        .build();

Piles réseau compatibles

ExoPlayer est directement compatible avec Cronet, OkHttp et la pile réseau intégrée d'Android. ExoPlayer peut également être étendu pour prendre en charge toute autre pile réseau fonctionnant sur Android.

Cronet

Cronet est la pile réseau Chromium mise à la disposition des applications Android en tant que bibliothèque. Cronet tire parti de plusieurs technologies qui réduisent la latence et augmentent le débit des requêtes réseau dont votre application a besoin pour fonctionner, y compris celles effectuées par ExoPlayer. En natif, il est compatible avec les protocoles HTTP, HTTP/2 et HTTP/3 via les protocoles QUIC. Cronet est utilisé par certaines des plus grandes applications de streaming au monde, y compris YouTube.

ExoPlayer est compatible avec Cronet via sa bibliothèque Cronet. Consultez le fichier README.md de la bibliothèque pour obtenir des instructions détaillées sur son utilisation. Notez que la bibliothèque Cronet peut utiliser trois implémentations Cronet sous-jacentes:

  1. Services Google Play:nous vous recommandons d'utiliser cette implémentation dans la plupart des cas et de revenir à la pile réseau intégrée à Android (DefaultHttpDataSource) si les services Google Play ne sont pas disponibles.
  2. Cronet intégré:peut être un bon choix si un grand pourcentage de vos utilisateurs se trouvent sur des marchés où les services Google Play ne sont pas largement disponibles ou si vous souhaitez contrôler la version exacte de l'implémentation Cronet utilisée. Le principal inconvénient de Cronet Embedded est qu'il ajoute environ 8 Mo à votre application.
  3. Cronet de remplacement:l'implémentation de remplacement de Cronet implémente l'API de Cronet en tant que wrapper autour de la pile réseau intégrée à Android. Il ne doit pas être utilisé avec ExoPlayer, car il est plus efficace d'utiliser directement la pile réseau intégrée d'Android (en utilisant DefaultHttpDataSource).

OkHttp

OkHttp est une autre pile réseau moderne largement utilisée par de nombreuses applications Android populaires. Il est compatible avec HTTP et HTTP/2, mais pas encore avec HTTP/3 sur QUIC.

ExoPlayer est compatible avec OkHttp via sa bibliothèque OkHttp. Consultez le fichier README.md de la bibliothèque pour obtenir des instructions détaillées sur son utilisation. Lorsque vous utilisez la bibliothèque OkHttp, la pile réseau est intégrée à l'application. Cette méthode est semblable à Cronet Embedded, mais OkHttp est considérablement plus petite, ajoutant moins de 1 Mo à votre application.

Pile réseau intégrée à Android

ExoPlayer est compatible avec l'utilisation de la pile réseau intégrée d'Android avec DefaultHttpDataSource et DefaultHttpDataSource.Factory, qui font partie de la bibliothèque principale d'ExoPlayer.

L'implémentation exacte de la pile réseau dépend du logiciel exécuté sur l'appareil sous-jacent. Sur la plupart des appareils (depuis 2021), seul HTTP est pris en charge (HTTP/2 et HTTP/3 sur QUIC ne le sont pas).

Autres piles réseau

Les applications peuvent également intégrer d'autres piles réseau avec ExoPlayer. Pour ce faire, implémentez un HttpDataSource qui encapsule la pile réseau avec un HttpDataSource.Factory correspondant. Les bibliothèques Cronet et OkHttp d'ExoPlayer sont de bons exemples de la façon de procéder.

Lors de l'intégration à une pile réseau en Java pur, il est recommandé d'implémenter un DataSourceContractTest pour vérifier que votre implémentation de HttpDataSource se comporte correctement. OkHttpDataSourceContractTest dans la bibliothèque OkHttp est un bon exemple de la façon de procéder.

Choisir une pile réseau

Le tableau suivant présente les avantages et les inconvénients des piles réseau compatibles avec ExoPlayer.

Pile réseau Protocoles Impact sur la taille de l'APK Notes
Cronet (services Google Play) HTTP
HTTP/2
HTTP/3 sur QUIC
Petite
(< 100 Ko)
Nécessite les services Google Play. Mise à jour automatique de la version Cronet
Cronet (intégré) HTTP
HTTP/2
HTTP/3 sur QUIC
Grand
(~8 Mo)
Version Cronet contrôlée par le développeur de l'application
Cronet (valeur de remplacement) HTTP
(selon l'appareil)
Petite
(< 100 Ko)
Non recommandé pour ExoPlayer
OkHttp HTTP
HTTP/2
Petit
(< 1 Mo)
Nécessite un environnement d'exécution Kotlin
Pile réseau intégrée HTTP
(selon l'appareil)
Aucune L'implémentation varie selon l'appareil

Les protocoles HTTP/2 et HTTP/3 sur QUIC peuvent améliorer considérablement les performances du streaming multimédia. En particulier, lors de la diffusion de contenus multimédias adaptatifs distribués à l'aide d'un réseau de distribution de contenu (CDN), l'utilisation de ces protocoles permet parfois aux CDN de fonctionner beaucoup plus efficacement. Pour cette raison, la compatibilité de Cronet avec HTTP/2 et HTTP/3 via QUIC (et la compatibilité d'OkHttp avec HTTP/2) est un avantage majeur par rapport à l'utilisation de la pile réseau intégrée d'Android, à condition que les serveurs sur lesquels le contenu est hébergé soient également compatibles avec ces protocoles.

Lorsque vous envisagez de diffuser des contenus multimédias de manière isolée, nous vous recommandons d'utiliser Cronet fourni par les services Google Play, en revenant à DefaultHttpDataSource si les services Google Play ne sont pas disponibles. Cette recommandation offre un bon compromis entre l'activation de HTTP/2 et du HTTP/3 sur la plupart des appareils via QUIC, tout en évitant une augmentation significative de la taille de l'APK. Il existe des exceptions à cette recommandation. Dans les cas où les services Google Play risquent d'être indisponibles sur une part significative des appareils qui exécutent votre application, il peut être plus approprié d'utiliser Cronet Embedded ou OkHttp. L'utilisation de la pile réseau intégrée peut être acceptable si la taille de l'APK est un problème critique ou si le streaming multimédia ne constitue qu'une partie mineure des fonctionnalités de votre application.

Au-delà des contenus multimédias, il est généralement judicieux de choisir une seule pile réseau pour toute la mise en réseau effectuée par votre application. Cela permet de mettre efficacement en commun et à partager des ressources (telles que les sockets) entre ExoPlayer et les autres composants de l'application.

Étant donné que votre application devra probablement être mise en réseau sans être liée à la lecture de contenus multimédias, votre choix de pile réseau doit au final tenir compte de nos recommandations ci-dessus pour le streaming multimédia de manière isolée, des exigences de tous les autres composants qui assurent la mise en réseau et de leur importance relative pour votre application.

Mise en cache du contenu multimédia

ExoPlayer prend en charge la mise en cache des octets chargés sur le disque pour empêcher le chargement répété des mêmes octets depuis le réseau. Cela est utile lorsque vous revenez en arrière dans le contenu multimédia actuel ou lorsque vous répétez le même élément.

La mise en cache nécessite une instance SimpleCache pointant vers un répertoire de cache dédié et un CacheDataSource.Factory:

Kotlin

// Note: This should be a singleton in your app.
val databaseProvider = StandaloneDatabaseProvider(context)

// An on-the-fly cache should evict media when reaching a maximum disk space limit.
val cache =
    SimpleCache(
        downloadDirectory, LeastRecentlyUsedCacheEvictor(maxBytes), databaseProvider)

// Configure the DataSource.Factory with the cache and factory for the desired HTTP stack.
val cacheDataSourceFactory =
    CacheDataSource.Factory()
        .setCache(cache)
        .setUpstreamDataSourceFactory(httpDataSourceFactory)

// Inject the DefaultDataSource.Factory when creating the player.
val player =
    ExoPlayer.Builder(context)
        .setMediaSourceFactory(
            DefaultMediaSourceFactory(context).setDataSourceFactory(cacheDataSourceFactory))
        .build()

Java

// Note: This should be a singleton in your app.
DatabaseProvider databaseProvider = new StandaloneDatabaseProvider(context);

// An on-the-fly cache should evict media when reaching a maximum disk space limit.
Cache cache =
    new SimpleCache(
        downloadDirectory, new LeastRecentlyUsedCacheEvictor(maxBytes), databaseProvider);

// Configure the DataSource.Factory with the cache and factory for the desired HTTP stack.
DataSource.Factory cacheDataSourceFactory =
    new CacheDataSource.Factory()
        .setCache(cache)
        .setUpstreamDataSourceFactory(httpDataSourceFactory);

// Inject the DefaultDataSource.Factory when creating the player.
ExoPlayer player =
    new ExoPlayer.Builder(context)
        .setMediaSourceFactory(
            new DefaultMediaSourceFactory(context).setDataSourceFactory(cacheDataSourceFactory))
        .build();