Piles réseau

ExoPlayer est couramment utilisé pour le streaming multimédia sur Internet. Il est compatible avec 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 de streaming.

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

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

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

Si votre application n'a besoin que de lire du contenu http(s), il vous suffit de mettre à jour toutes les instances DataSource.Factory que votre application injecte pour qu'elles deviennent des instances de HttpDataSource.Factory correspondant à la pile réseau que vous souhaitez utiliser. Si votre application doit également lire du contenu non http(s), 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 correspond à la fabrique associée à votre pile réseau préférée. La couche DefaultDataSource.Factory ajoute la prise en charge des sources non http(s), telles que les fichiers locaux.

L'exemple suivant montre comment créer un ExoPlayer qui utilisera la pile réseau Cronet et prendra également en charge la lecture de contenu non http(s).

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 HttpEngine, Cronet, OkHttp et la pile réseau par défaut intégrée d'Android. ExoPlayer peut également être étendu pour prendre en charge toute autre pile réseau fonctionnant sur Android.

HttpEngine

HttpEngine est la pile réseau par défaut recommandée sur Android à partir de l'API 34 (ou des extensions S 7). Dans la plupart des cas, il utilise en interne la pile réseau Cronet, qui est compatible avec les protocoles HTTP, HTTP/2 et HTTP/3 sur QUIC.

ExoPlayer est compatible avec HttpEngine grâce à son HttpEngineDataSource.Factory. Vous pouvez injecter cette fabrique de sources de données comme décrit dans Configurer ExoPlayer pour utiliser une pile réseau spécifique.

Cronet

Cronet est la pile réseau Chromium mise à la disposition des applications Android en tant que bibliothèque. Cronet exploite plusieurs technologies qui réduisent la latence et augmentent le débit des requêtes réseau nécessaires au fonctionnement de votre application, y compris celles effectuées par ExoPlayer. Il est compatible de manière native avec les protocoles HTTP, HTTP/2 et HTTP/3 sur 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. Pour obtenir des instructions détaillées sur l'utilisation de la bibliothèque, consultez son README.md. 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 d'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. Solution de repli Cronet : l'implémentation de repli de Cronet implémente l'API de Cronet en tant qu'encapsuleur autour de la pile réseau intégrée d'Android. Il ne doit pas être utilisé avec ExoPlayer, car l'utilisation directe de la pile réseau intégrée d'Android (avec DefaultHttpDataSource) est plus efficace.

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. Pour obtenir des instructions détaillées sur l'utilisation de la bibliothèque, consultez son README.md. Lorsque vous utilisez la bibliothèque OkHttp, la pile réseau est intégrée à l'application. Cela ressemble à Cronet Embedded, mais OkHttp est beaucoup plus petit et ajoute moins d'1 Mo à votre application.

Pile réseau intégrée d'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 ExoPlayer principale.

L'implémentation exacte de la pile réseau dépend du logiciel exécuté sur l'appareil sous-jacent. La plupart des appareils ne sont compatibles qu'avec HTTP (c'est-à-dire que HTTP/2 et HTTP/3 sur QUIC ne sont pas compatibles).

Autres piles réseau

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

Lorsque vous intégrez une pile réseau Java pure, il est judicieux d'implémenter un DataSourceContractTest pour vérifier que votre implémentation 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 de la taille de l'APK Notes
HttpEngine HTTP
HTTP/2
HTTP/3 sur QUIC
Aucun Disponible uniquement sur l'API 34 ou les extensions S 7
Cronet (services Google Play) HTTP
HTTP/2
HTTP/3 sur QUIC
Petite
(< 100 Ko)
Nécessite les services Google Play. Version de Cronet mise à jour automatiquement
Cronet (intégré) HTTP
HTTP/2
HTTP/3 sur QUIC
Grande
(~8 Mo)
Version de Cronet contrôlée par le développeur de l'application
Cronet (solution de remplacement) HTTP
(variable selon l'appareil)
Petite
(< 100 Ko)
Non recommandé pour ExoPlayer
OkHttp HTTP
HTTP/2
Petite
(<1 Mo)
Pile réseau intégrée HTTP
(variable selon l'appareil)
Aucun L'implémentation varie selon l'appareil

Les protocoles HTTP/2 et HTTP/3 sur QUIC peuvent améliorer considérablement les performances de streaming multimédia. En particulier, lors de la diffusion de contenus multimédias adaptatifs distribués à l'aide d'un réseau de diffusion de contenu (CDN), l'utilisation de ces protocoles peut permettre aux CDN de fonctionner beaucoup plus efficacement. Pour cette raison, la compatibilité de HttpEngine et Cronet avec HTTP/2 et HTTP/3 sur QUIC (et la compatibilité d'OkHttp avec HTTP/2) constitue 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 le streaming multimédia de manière isolée, nous vous recommandons d'utiliser HttpEngine ou Cronet fourni par les services Google Play, en revenant à DefaultHttpDataSource si les services Google Play ne sont pas disponibles. Cette recommandation établit un bon équilibre entre l'activation de l'utilisation de HTTP/2 et HTTP/3 sur QUIC sur la plupart des appareils, et la prévention d'une augmentation significative de la taille de l'APK. Il existe des exceptions à cette recommandation. Dans les cas où les services Google Play sont susceptibles de ne pas être disponibles sur une fraction importante des appareils sur lesquels votre application sera exécutée, 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 une préoccupation majeure ou si le streaming multimédia ne représente qu'une petite partie des fonctionnalités de votre application.

Au-delà des médias, il est généralement judicieux de choisir une seule pile réseau pour l'ensemble des opérations réseau effectuées par votre application. Cela permet de regrouper et de partager efficacement les ressources (telles que les sockets) entre ExoPlayer et les autres composants de l'application.

Étant donné que votre application devra très probablement effectuer des opérations réseau non liées à la lecture de contenus multimédias, votre choix de pile réseau doit tenir compte de nos recommandations ci-dessus pour le streaming multimédia isolé, des exigences de tout autre composant effectuant des opérations réseau et de leur importance relative pour votre application.

Mettre en cache des contenus multimédias

ExoPlayer est compatible avec la mise en cache des octets chargés sur le disque pour éviter de charger plusieurs fois les mêmes octets à partir du réseau. Cette option est utile lorsque vous souhaitez revenir en arrière dans le contenu multimédia actuel ou répéter 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();