Stack di rete

ExoPlayer viene comunemente utilizzato per lo streaming di contenuti multimediali su internet. Supporta più stack di rete per effettuare le richieste di rete sottostanti. La scelta dello stack di rete può avere un impatto significativo sulle prestazioni di streaming.

Questa pagina descrive come configurare ExoPlayer per utilizzare lo stack di rete che preferisci, elenca le opzioni disponibili, fornisce alcune indicazioni su come scegliere uno stack di rete per la tua app e spiega come attivare la memorizzazione nella cache per i contenuti multimediali in streaming.

Configurazione di ExoPlayer per l'utilizzo di uno stack di rete specifico

ExoPlayer carica i dati tramite i componenti DataSource, che ottiene dalle istanze DataSource.Factory inserite dal codice dell'app.

Se la tua app deve riprodurre solo contenuti http(s), selezionare uno stack di rete è semplice come aggiornare qualsiasi istanza DataSource.Factory che la tua app inserisce in modo che siano istanze di HttpDataSource.Factory che corrisponde allo stack di rete che vuoi utilizzare. Se la tua app deve riprodurre anche contenuti non http(s), come file locali, utilizza DefaultDataSource.Factory:

Kotlin

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

Java

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

In questo esempio, PreferredHttpDataSource.Factory è la fabbrica corrispondente allo stack di rete preferito. Il livello DefaultDataSource.Factory aggiunge il supporto per origini non http(s) come i file locali.

L'esempio seguente mostra come creare un ExoPlayer che utilizzerà lo stack di rete Cronet e supporterà anche la riproduzione di contenuti 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();

Stack di rete supportati

ExoPlayer fornisce supporto diretto per HttpEngine, Cronet, OkHttp e lo stack di rete predefinito integrato di Android. ExoPlayer può anche essere esteso per supportare qualsiasi altro stack di rete che funziona su Android.

HttpEngine

HttpEngine è lo stack di rete predefinito consigliato su Android a partire dall'API 34 (o dalle estensioni S 7). Nella maggior parte dei casi, utilizza internamente lo stack di rete Cronet, che supporta i protocolli HTTP, HTTP/2 e HTTP/3 su QUIC.

ExoPlayer supporta HttpEngine con il suo HttpEngineDataSource.Factory. Puoi inserire questa fabbrica di origini dati come descritto in Configurazione di ExoPlayer per l'utilizzo di uno stack di rete specifico.

Cronet

Cronet è lo stack di rete Chromium reso disponibile alle app Android come libreria. Cronet sfrutta diverse tecnologie che riducono la latenza e aumentano il throughput delle richieste di rete necessarie per il funzionamento dell'app, incluse quelle effettuate da ExoPlayer. Supporta in modo nativo i protocolli HTTP, HTTP/2 e HTTP/3 su QUIC. Cronet viene utilizzato da alcune delle più grandi app di streaming al mondo, tra cui YouTube.

ExoPlayer supporta Cronet tramite la relativa libreria Cronet. Per istruzioni dettagliate su come utilizzarla, consulta README.md della libreria. Tieni presente che la libreria Cronet è in grado di utilizzare tre implementazioni Cronet sottostanti:

  1. Google Play Services:consigliamo di utilizzare questa implementazione nella maggior parte dei casi e di ripiegare sullo stack di rete integrato di Android (DefaultHttpDataSource) se Google Play Services non è disponibile.
  2. Cronet Embedded: potrebbe essere una buona scelta se una percentuale elevata dei tuoi utenti si trova in mercati in cui Google Play Services non è ampiamente disponibile o se vuoi controllare la versione esatta dell'implementazione di Cronet in uso. Lo svantaggio principale di Cronet Embedded è che aggiunge circa 8 MB alla tua app.
  3. Fallback di Cronet:l'implementazione di fallback di Cronet implementa l'API di Cronet come wrapper dello stack di rete integrato di Android. Non deve essere utilizzato con ExoPlayer, poiché l'utilizzo diretto dello stack di rete integrato di Android (tramite DefaultHttpDataSource) è più efficiente.

OkHttp

OkHttp è un altro stack di rete moderno ampiamente utilizzato da molte app per Android popolari. Supporta HTTP e HTTP/2, ma non ancora HTTP/3 su QUIC.

ExoPlayer supporta OkHttp tramite la relativa libreria OkHttp. Per istruzioni dettagliate su come utilizzarla, consulta README.md della libreria. Quando utilizzi la libreria OkHttp, lo stack di rete è incorporato nell'app. È simile a Cronet Embedded, ma OkHttp è molto più piccolo e aggiunge meno di 1 MB all'app.

Stack di rete integrato di Android

ExoPlayer supporta l'utilizzo dello stack di rete integrato di Android con DefaultHttpDataSource e DefaultHttpDataSource.Factory, che fanno parte della libreria ExoPlayer principale.

L'implementazione esatta dello stack di rete dipende dal software in esecuzione sul dispositivo sottostante. Sulla maggior parte dei dispositivi è supportato solo HTTP (ovvero, HTTP/2 e HTTP/3 su QUIC non sono supportati).

Altri stack di rete

Le app possono anche integrare altri stack di rete con ExoPlayer. Per farlo, implementa un HttpDataSource che esegue il wrapping dello stack di rete, insieme a un HttpDataSource.Factory corrispondente. Le librerie Cronet e OkHttp di ExoPlayer sono buoni esempi di come farlo.

Quando esegui l'integrazione con uno stack di rete Java puro, è consigliabile implementare un DataSourceContractTest per verificare che l'implementazione di HttpDataSource si comporti correttamente. OkHttpDataSourceContractTest nella libreria OkHttp è un buon esempio di come farlo.

Scelta di uno stack di rete

La tabella seguente illustra i pro e i contro degli stack di rete supportati da ExoPlayer.

Stack di rete Protocolli Impatto sulle dimensioni dell'APK Note
HttpEngine HTTP
HTTP/2
HTTP/3 su QUIC
Nessuna Disponibile solo su API 34 o S Extensions 7
Cronet (Google Play Services) HTTP
HTTP/2
HTTP/3 su QUIC
Piccolo
(<100 KB)
Richiede Google Play Services. Versione di Cronet aggiornata automaticamente
Cronet (incorporato) HTTP
HTTP/2
HTTP/3 su QUIC
Grande
(~8 MB)
Versione di Cronet controllata dallo sviluppatore dell'app
Cronet (fallback) HTTP
(varia in base al dispositivo)
Piccolo
(<100 KB)
Non consigliato per ExoPlayer
OkHttp HTTP
HTTP/2
Piccolo
(<1 MB)
Stack di rete integrato HTTP
(varia in base al dispositivo)
Nessuna L'implementazione varia in base al dispositivo

I protocolli HTTP/2 e HTTP/3 su QUIC possono migliorare notevolmente le prestazioni di streaming multimediale. In particolare, durante lo streaming di contenuti multimediali adattivi distribuiti tramite una rete CDN (Content Delivery Network), esistono casi in cui l'utilizzo di questi protocolli può consentire alle CDN di operare in modo molto più efficiente. Per questo motivo, il supporto di HttpEngine e Cronet per HTTP/2 e HTTP/3 su QUIC (e il supporto di OkHttp per HTTP/2) è un vantaggio significativo rispetto all'utilizzo dello stack di rete integrato di Android, a condizione che anche i server su cui è ospitato il contenuto supportino questi protocolli.

Se consideri lo streaming multimediale in isolamento, ti consigliamo di utilizzare HttpEngine o Cronet fornito da Google Play Services, con fallback a DefaultHttpDataSource se Google Play Services non è disponibile. Questo consiglio rappresenta un buon compromesso tra l'attivazione dell'utilizzo di HTTP/2 e HTTP/3 su QUIC sulla maggior parte dei dispositivi e l'evitare un aumento significativo delle dimensioni dell'APK. Esistono eccezioni a questo consiglio. Nei casi in cui è probabile che Google Play Services non sia disponibile su una parte significativa dei dispositivi che eseguiranno la tua app, l'utilizzo di Cronet Embedded o OkHttp potrebbe essere più appropriato. L'utilizzo dello stack di rete integrato potrebbe essere accettabile se le dimensioni dell'APK sono un problema critico o se lo streaming multimediale è solo una parte secondaria delle funzionalità della tua app.

Oltre ai contenuti multimediali, in genere è consigliabile scegliere un'unica pila di rete per tutte le operazioni di rete eseguite dall'app. In questo modo, le risorse (come i socket) possono essere raggruppate e condivise in modo efficiente tra ExoPlayer e altri componenti dell'app.

Poiché la tua app dovrà probabilmente eseguire operazioni di rete non correlate alla riproduzione di contenuti multimediali, la scelta dello stack di rete deve tenere conto delle nostre raccomandazioni riportate sopra per lo streaming multimediale isolato, dei requisiti di qualsiasi altro componente che esegue operazioni di rete e della loro importanza relativa per la tua app.

Memorizzazione nella cache dei contenuti multimediali

ExoPlayer supporta la memorizzazione nella cache dei byte caricati su disco per evitare di caricare ripetutamente gli stessi byte dalla rete. Questa opzione è utile quando cerchi indietro nel file multimediale corrente o ripeti lo stesso elemento.

La memorizzazione nella cache richiede un'istanza SimpleCache che rimandi a una directory della cache dedicata e 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();