Stack di rete

ExoPlayer è di uso comune 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), la selezione di uno stack di rete è semplice come l'aggiornamento di tutte le istanze DataSource.Factory inserite dalla tua app in modo che siano istanze di HttpDataSource.Factory corrispondenti allo stack di rete che vuoi utilizzare. Se la tua app deve riprodurre anche contenuti non http(s), ad esempio file locali, utilizza DefaultDataSource.Factory:

Kotlin

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

Java

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

In questo esempio, PreferredHttpDataSource.Factory è la factory corrispondente allo stack di rete che preferisci. Il livello DefaultDataSource.Factory aggiunge il supporto per le origini non HTTP(S), come i file locali.

L'esempio seguente mostra come creare un oggetto 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 S extensions 7). Nella maggior parte dei casi, utilizza internamente lo stack di rete Cronet, supportando i protocolli HTTP, HTTP/2 e HTTP/3 su QUIC.

ExoPlayer supporta HttpEngine con HttpEngineDataSource.Factory. Puoi inserire questa factory 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 per le app per Android come libreria. Cronet sfrutta diverse tecnologie che riducono la latenza e aumentano il throughput delle richieste di rete necessarie per il funzionamento della tua app, incluse quelle effettuate da ExoPlayer. Supporta in modo nativo i protocolli HTTP, HTTP/2 e HTTP/3 su QUIC. Cronet è utilizzato da alcune delle più grandi app di streaming al mondo, tra cui YouTube.

ExoPlayer supporta Cronet tramite la sua libreria Cronet. Per istruzioni dettagliate su come utilizzare la libreria, consulta il relativo README.md. 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 tornare allo stack di rete integrato di Android (DefaultHttpDataSource) se Google Play Services non è disponibile.
  2. Cronet incorporato: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. Cronet di riserva: l'implementazione di riserva di Cronet implementa l'API di Cronet come wrapper attorno allo 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 sua libreria OkHttp. Per istruzioni dettagliate su come utilizzare la libreria, consulta il relativo README.md. 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 alla tua 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'esatta implementazione 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 aggrega lo 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
Nessuno 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 di app
Cronet (di riserva) 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)
Nessuno L'implementazione varia in base al dispositivo

I protocolli HTTP/2 e HTTP/3 su QUIC possono migliorare significativamente le prestazioni dello streaming multimediale. In particolare, durante lo streaming di contenuti multimediali adattivi distribuiti tramite una rete di distribuzione di contenuti (CDN), 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 importante rispetto all'utilizzo dello stack di rete integrato di Android, a condizione che anche i server su cui sono ospitati i contenuti supportino questi protocolli.

Se consideri lo streaming multimediale in modo isolato, ti consigliamo di utilizzare HttpEngine o Cronet forniti da Google Play Services, con il fallback a DefaultHttpDataSource se Google Play Services non è disponibile. Questo suggerimento rappresenta un buon compromesso tra l'abilitazione 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 suggerimento. Nei casi in cui è probabile che Google Play Services non sia disponibile su una parte significativa dei dispositivi su cui verrà eseguita 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 di contenuti multimediali è solo una parte secondaria della funzionalità della tua app.

Oltre ai contenuti multimediali, in genere è consigliabile scegliere un unico stack di rete per tutte le operazioni di rete eseguite dalla tua 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é molto probabilmente la tua app dovrà eseguire operazioni di rete non correlate alla riproduzione di contenuti multimediali, la scelta dello stack di rete deve in ultima analisi tenere conto dei nostri consigli riportati sopra per lo streaming di contenuti multimediali in isolamento, dei requisiti di eventuali altri componenti che eseguono 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 sul disco per evitare di caricare ripetutamente gli stessi byte dalla rete. Questa opzione è utile quando si torna indietro nei contenuti multimediali correnti o si ripete lo stesso elemento.

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