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. A te la scelta dello stack di rete può avere un impatto significativo sulle prestazioni dei flussi di dati.

Questa pagina illustra come configurare ExoPlayer in modo che utilizzi lo stack di rete scelto, 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.

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

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

Se la tua app deve riprodurre solo contenuti http(s), selezionare uno stack di rete è semplice come aggiornare le eventuali istanze DataSource.Factory iniettate dall'app in modo che siano istanze di HttpDataSource.Factory corrispondente allo stack di rete che vuoi utilizzare. Se la tua app deve riprodurre contenuti non HTTP, ad esempio 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 factory corrispondente allo stack di rete preferito. Il livello DefaultDataSource.Factory aggiunge il supporto per le origini non http(s), ad esempio i file locali.

L'esempio seguente mostra come creare un ExoPlayer che utilizzi lo stack di rete Cronet e supporti 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 stack di rete predefinito integrato. ExoPlayer può essere esteso anche per supportare qualsiasi altro stack di rete compatibile con Android.

HttpEngine

HttpEngine è lo stack di rete predefinito consigliato su Android dall'API 34 (o estensioni 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 il suo HttpEngineDataSource.Factory. Puoi inserire il fabbrica dell'origine dati come descritto in Configurare ExoPlayer per l'utilizzo di un'immagine stack di rete specifico.

Cronet

Cronet è il Stack di rete di Chromium reso disponibile per le app per Android come raccolta. Cronet prende sfruttare molteplici tecnologie che riducono la latenza delle richieste di rete necessarie per il funzionamento dell'app, incluse quelle creato 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, incluso YouTube.

ExoPlayer supporta Cronet tramite la sua libreria Cronet. Per istruzioni dettagliate su come utilizzare, consulta le README.md della libreria li annotino. Tieni presente che la libreria Cronet è in grado di utilizzare tre implementazioni di Cronet di base:

  1. Google Play Services: consigliamo di utilizzare questa implementazione nella maggior parte di Android, facendo ricorso allo stack di rete integrato di Android (DefaultHttpDataSource) se Google Play Services non è disponibile.
  2. Cronet incorporato: può 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. La lo svantaggio principale di Cronet Embedded è che aggiunge circa 8 MB a la tua app.
  3. Cronet Fallback: 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 moderno stack di rete che è ampiamente usato da molte app Android popolari. Supporta HTTP e HTTP/2, ma non supporta ancora HTTP/3 tramite QUIC.

ExoPlayer supporta OkHttp tramite la sua Libreria OkHttp. Consulta la pagina README.md della libreria per istruzioni dettagliate su come utilizzarla. 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.

Lo stack di rete integrato di Android

ExoPlayer supporta l'uso dello stack di rete integrato di Android con DefaultHttpDataSource e DefaultHttpDataSource.Factory, che fanno parte di la libreria di base ExoPlayer.

L'esatta implementazione dello stack di rete dipende dal software in esecuzione il 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 inoltre integrare altri stack di rete con ExoPlayer. Per farlo, implementa un HttpDataSource che avvolga lo stack di rete insieme a un HttpDataSource.Factory corrispondente. Cronet di ExoPlayer e Le librerie OkHttp sono buoni esempi di come eseguire questa operazione.

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

Scegliere uno stack di rete

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

Stack di rete Protocolli Impatto sulle dimensioni degli 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 tramite QUIC
Piccolo
(<100 kB)
Richiede Google Play Services. La versione di Cronet è stata aggiornata automaticamente
Cronet (incorporato) HTTP
HTTP/2
HTTP/3 tramite QUIC
Grande
(circa 8 MB)
Versione di Cronet controllata dallo sviluppatore dell'app
Cronet (di riserva) HTTP
(varia in base al dispositivo)
Piccolo
(<100 KB)
Sconsigliato 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 i contenuti multimediali le prestazioni dei flussi di dati. In particolare, quando riproduci in streaming contenuti multimediali adattivi distribuiti tramite una rete di distribuzione dei contenuti (CDN), esistono casi quale uso di questi protocolli può consentire alle reti CDN di funzionare in modo molto più efficiente. Per questo motivo, il supporto di HttpEngine e Cronet sia per HTTP/2 che per 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 i server su cui sono ospitati i contenuti supportino anche questi protocolli.

Quando si considera lo streaming di contenuti multimediali in modo isolato, consigliamo di utilizzare HttpEngine o Cronet fornito da Google Play Services di riserva DefaultHttpDataSource se Google Play Services non è disponibile. Questo consiglio ha un impatto positivo equilibrio tra l'abilitazione dell'uso di HTTP/2 e HTTP/3 tramite QUIC sulla maggior parte dei dispositivi e evitando un aumento significativo delle dimensioni degli APK. Esistono eccezioni a questo consiglio. 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 può 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.

Al di là dei soli contenuti multimediali, in genere è una buona idea scegliere un unico stack di rete per tutte le risorse di networking eseguite dalla tua app. Ciò permette alle risorse (come i socket) per essere in pool e condivisi in modo efficiente tra ExoPlayer e altri componenti dell'app.

Poiché è molto probabile che la tua app debba eseguire operazioni di rete non correlate alla riproduzione dei contenuti multimediali, la scelta dello stack di rete deve 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 per tornare indietro nel media corrente o ripetere lo stesso elemento.

La memorizzazione nella cache richiede un'istanza SimpleCache che punti 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();