O ExoPlayer é usado com frequência para streaming de mídia pela Internet. Ele oferece suporte múltiplas pilhas de rede para fazer as solicitações de rede subjacentes. Sua escolha de pilha de rede pode ter um impacto significativo no desempenho do streaming.
Esta página descreve como configurar o ExoPlayer para usar sua pilha de rede de escolha, lista as opções disponíveis, fornece orientações sobre como escolher uma pilha de rede para seu aplicativo e explica como ativar o armazenamento em cache para mídia.
Como configurar o ExoPlayer para usar uma pilha de rede específica
O ExoPlayer carrega dados usando componentes DataSource
, que são obtidos de
instâncias DataSource.Factory
injetadas pelo código do app.
Se o app só precisa reproduzir conteúdo http(s), selecionar uma pilha de rede
é tão simples quanto atualizar qualquer instância DataSource.Factory
que o
app injeta para ser uma instância do HttpDataSource.Factory
que corresponde à pilha de rede que você quer usar. Se o app também
precisa reproduzir conteúdo que não é http(s), como arquivos locais, use
DefaultDataSource.Factory
:
Kotlin
DefaultDataSource.Factory( ... /* baseDataSourceFactory= */ PreferredHttpDataSource.Factory(...))
Java
new DefaultDataSource.Factory( ... /* baseDataSourceFactory= */ new PreferredHttpDataSource.Factory(...));
Neste exemplo, PreferredHttpDataSource.Factory
é a fábrica correspondente à sua
pilha de rede preferida. A camada DefaultDataSource.Factory
adiciona suporte
para fontes não HTTP(s), como arquivos locais.
O exemplo abaixo mostra como criar uma ExoPlayer
que usará a Cronet
pilha de rede e também suporta a reprodução de conteúdo não 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();
Pilhas de rede compatíveis
O ExoPlayer oferece suporte direto para HttpEngine, Cronet, OkHttp e a pilha de rede padrão integrada do Android. O ExoPlayer também pode ser estendido para oferecer suporte a qualquer outra pilha de rede que funcione no Android.
HttpEngine
A HttpEngine é a pilha de rede padrão recomendada no Android a partir da API 34 (ou extensões S7). Na maioria dos casos, ele usa a pilha de rede da Cronet internamente, com suporte a HTTP, HTTP/2 e HTTP/3 sobre protocolos QUIC.
O ExoPlayer oferece suporte ao HttpEngine com a HttpEngineDataSource.Factory
dele. Você pode
injetar essa fábrica de fonte de dados, conforme descrito em Como configurar o ExoPlayer para usar um
pilha de rede específica.
Cronet
A Cronet é a pilha de rede do Chromium disponibilizada para apps Android como uma biblioteca. A Cronet usa várias tecnologias para reduzir a latência e aumentar a capacidade de processamento das solicitações de rede necessárias para o app funcionar, incluindo as feitas pelo ExoPlayer. Ele oferece suporte nativo aos protocolos HTTP, HTTP/2 e HTTP/3 sobre QUIC. O Cronet é usado por alguns dos maiores apps de streaming do mundo, incluindo o YouTube.
O ExoPlayer oferece suporte à Cronet pela
Biblioteca Cronet.
Consulte o README.md
da biblioteca para ver instruções detalhadas sobre como usá-la. A biblioteca da Cronet pode usar três elementos
implementações:
- Google Play Services: recomendamos usar essa implementação na maioria
dos casos e retornar à pilha de rede integrada do Android
(
DefaultHttpDataSource
) se o Google Play Services não estiver disponível. - Cronet incorporada:pode ser uma boa opção se uma grande porcentagem dos seus usuários estão em mercados onde o Google Play Services não está amplamente disponível ou se você querem controlar a versão exata da implementação da Cronet que está sendo usada. O A principal desvantagem do Cronet Embedded é que ele adiciona aproximadamente 8 MB seu app.
- Cronet Fallback:a implementação de substituto da Cronet implementa
A API da Cronet como um wrapper na pilha de rede integrada do Android. Ele não
deve ser usado com o ExoPlayer, já que usar a pilha de rede integrada do Android
diretamente (usando
DefaultHttpDataSource
) é mais eficiente.
OkHttp
A OkHttp é outra pilha de rede moderna que é amplamente usado por muitos apps Android conhecidos. Ele oferece suporte a HTTP e HTTP/2, mas ainda não é compatível com HTTP/3 sobre QUIC.
O ExoPlayer oferece suporte ao OkHttp pela
biblioteca OkHttp.
Consulte o README.md
da biblioteca para ver instruções detalhadas sobre como usá-la. Ao usar a biblioteca OkHttp, a pilha de rede é incorporada ao
app. É semelhante à Cronet Embedded, mas o OkHttp é significativamente
menor, adicionando menos de 1 MB ao seu aplicativo.
Pilha de rede integrada do Android
O ExoPlayer oferece suporte à pilha de rede integrada do Android com
DefaultHttpDataSource
e DefaultHttpDataSource.Factory
, que fazem parte
biblioteca principal do ExoPlayer.
A implementação exata da pilha de rede depende do software em execução no do dispositivo. Na maioria dos dispositivos, só há suporte para HTTP (ou seja, HTTP/2 e HTTP/3 sobre QUIC não são aceitos).
Outras pilhas de rede
Os apps também podem integrar outras pilhas de rede com o ExoPlayer.
Para fazer isso, implemente um HttpDataSource
que envolva a pilha de rede.
com um HttpDataSource.Factory
correspondente. As bibliotecas Cronet e
OkHttp do ExoPlayer são bons exemplos de como fazer isso.
Ao fazer a integração com uma pilha de rede Java pura, é uma boa ideia implementar uma
DataSourceContractTest
para verificar se a implementação de HttpDataSource
se comporta corretamente. Na biblioteca OkHttp, o OkHttpDataSourceContractTest
é uma
um bom exemplo de como fazer isso.
Como escolher uma pilha de rede
A tabela a seguir descreve os prós e contras das pilhas de rede com suporte o ExoPlayer.
Pilha de rede | Protocolos | Impacto no tamanho do APK | Observações |
---|---|---|---|
Mecanismo HTTP | HTTP HTTP/2 HTTP/3 por QUIC |
Nenhum | Disponível apenas na API 34 ou nas extensões S7 |
Cronet (Google Play Services) | HTTP HTTP/2 HTTP/3 por QUIC |
Pequeno (<100KB) |
É necessário ter o Google Play Services. Versão da Cronet atualizada automaticamente |
Cronet (incorporada) | HTTP HTTP/2 HTTP/3 por QUIC |
Grande (aproximadamente 8 MB) |
Versão do Cronet controlada pelo desenvolvedor do app |
Cronet (substituto) | HTTP (varia de acordo com o dispositivo) |
Pequeno (<100 KB) |
Não recomendado para ExoPlayer |
OkHttp | HTTP HTTP/2 |
Pequeno (<1 MB) |
|
Pilha de rede integrada | HTTP (varia de acordo com o dispositivo) |
Nenhum | A implementação varia de acordo com o dispositivo |
Os protocolos HTTP/2 e HTTP/3 sobre QUIC podem melhorar significativamente o desempenho do streaming de mídia. Especificamente, quando o streaming de mídia adaptativa é distribuído usando uma rede de distribuição de conteúdo (CDN), há casos em que o uso desses protocolos permite que as CDNs operem de maneira muito mais eficiente. Por esse motivo, o suporte do HttpEngine e do Cronet para HTTP/2 e HTTP/3 com QUIC (e o suporte do OkHttp para HTTP/2) é um benefício importante em comparação com o uso da pilha de rede integrada do Android, desde que os servidores em que o conteúdo é hospedado também ofereçam suporte a esses protocolos.
Ao considerar o streaming de mídia isoladamente, recomendamos o uso do HttpEngine ou
do Cronet fornecido pelo Google Play Services, que retorna para DefaultHttpDataSource
se o Google Play Services estiver indisponível. Essa recomendação é uma boa
equilibrar a ativação do uso de HTTP/2 e HTTP/3 com o QUIC na maioria dos dispositivos
evitando um aumento significativo no tamanho do APK. Há exceções
recomendação. Nos casos em que o Google Play Services provavelmente não estará disponível
em uma parte significativa dos dispositivos que vão executar seu app,
o uso do Cronet Embedded ou do OkHttp pode ser mais apropriado. O uso da pilha de rede
integrada pode ser aceitável se o tamanho do APK for uma preocupação crítica ou se o streaming
de mídia for apenas uma parte menor da funcionalidade do app.
Além da mídia, normalmente é bom escolher uma pilha de rede para toda a rede realizada pelo seu app. Isso permite que os recursos (como soquetes) para agrupar e compartilhar com eficiência entre o ExoPlayer e outros componentes do app.
Como o app provavelmente precisará realizar conexões de rede não relacionadas à reprodução de mídia, sua escolha de pilha de rede precisa considerar nossas recomendações acima para streaming de mídia isoladamente, os requisitos de qualquer outro componente que realize conexões de rede e a importância relativa deles para o app.
Armazenamento em cache de mídia
O ExoPlayer oferece suporte ao armazenamento em cache de bytes carregados no disco para evitar o carregamento repetido dos mesmos bytes da rede. Isso é útil ao procurar na mídia atual ou repetir o mesmo item.
O armazenamento em cache requer uma instância SimpleCache
que aponte para um diretório de cache
dedicado e um 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();