ExoPlayer se usa comúnmente para transmitir contenido multimedia por Internet. Admite varias pilas de red para realizar sus solicitudes de red subyacentes. La pila de red que elijas puede tener un impacto significativo en el rendimiento de la transmisión.
En esta página, se describe cómo configurar ExoPlayer para usar la pila de red que elijas, se enumeran las opciones disponibles, se brinda orientación para elegir una pila de red para tu app y se explica cómo habilitar el almacenamiento en caché para el contenido multimedia transmitido.
Cómo configurar ExoPlayer para usar una pila de red específica
ExoPlayer carga datos a través de componentes DataSource, que obtiene de instancias DataSource.Factory que se insertan desde el código de la app.
Si tu app solo necesita reproducir contenido http(s), seleccionar una pila de red es tan simple como actualizar cualquier instancia de DataSource.Factory que inyecte tu app para que sean instancias de HttpDataSource.Factory que correspondan a la pila de red que deseas usar. Si tu app también necesita reproducir contenido que no sea http(s), como archivos locales, usa DefaultDataSource.Factory:
Kotlin
DefaultDataSource.Factory( ... /* baseDataSourceFactory= */ PreferredHttpDataSource.Factory(...))
Java
new DefaultDataSource.Factory( ... /* baseDataSourceFactory= */ new PreferredHttpDataSource.Factory(...));
En este ejemplo, PreferredHttpDataSource.Factory es la fábrica que corresponde a tu pila de red preferida. La capa DefaultDataSource.Factory agrega compatibilidad con fuentes que no son http(s), como archivos locales.
En el siguiente ejemplo, se muestra cómo compilar un ExoPlayer que usará la pila de red de Cronet y también admitirá la reproducción de contenido que no sea 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();
Pilas de red compatibles
ExoPlayer proporciona compatibilidad directa con HttpEngine, Cronet, OkHttp y la pila de red predeterminada integrada de Android. ExoPlayer también se puede extender para admitir cualquier otra pila de red que funcione en Android.
HttpEngine
HttpEngine es la pila de red predeterminada recomendada en Android a partir de la API 34 (o las extensiones de S 7). En la mayoría de los casos, usa la pila de red de Cronet de forma interna, lo que admite los protocolos HTTP, HTTP/2 y HTTP/3 a través de QUIC.
ExoPlayer admite HttpEngine con su HttpEngineDataSource.Factory. Puedes insertar esta fábrica de fuentes de datos como se describe en Cómo configurar ExoPlayer para usar una pila de red específica.
Cronet
Cronet es la pila de red de Chromium que está disponible para las apps de Android como una biblioteca. Cronet aprovecha múltiples tecnologías que reducen la latencia y aumentan la capacidad de procesamiento de las solicitudes de red que tu app necesita para funcionar, incluidas las que realiza ExoPlayer. Admite de forma nativa los protocolos HTTP, HTTP/2 y HTTP/3 a través de QUIC. Cronet se usa en algunas de las apps de transmisión más grandes del mundo, incluido YouTube.
ExoPlayer admite Cronet a través de su biblioteca de Cronet.
Consulta el README.md de la biblioteca para obtener instrucciones detalladas sobre cómo usarla. Ten en cuenta que la biblioteca de Cronet puede usar tres implementaciones subyacentes de Cronet:
- Servicios de Google Play: Recomendamos usar esta implementación en la mayoría de los casos y recurrir a la pila de red integrada de Android (
DefaultHttpDataSource) si los Servicios de Google Play no están disponibles. - Cronet integrado: Puede ser una buena opción si un gran porcentaje de tus usuarios se encuentra en mercados en los que los Servicios de Google Play no están disponibles de forma generalizada o si deseas controlar la versión exacta de la implementación de Cronet que se usa. La principal desventaja de Cronet Embedded es que agrega aproximadamente 8 MB a tu app.
- Respaldo de Cronet: La implementación de respaldo de Cronet implementa la API de Cronet como un wrapper alrededor de la pila de red integrada de Android. No se debe usar con ExoPlayer, ya que usar la pila de redes integrada de Android directamente (con
DefaultHttpDataSource) es más eficiente.
OkHttp
OkHttp es otra pila de redes moderna que usan muchas apps populares para Android. Admite HTTP y HTTP/2, pero aún no admite HTTP/3 a través de QUIC.
ExoPlayer admite OkHttp a través de su biblioteca OkHttp.
Consulta el README.md de la biblioteca para obtener instrucciones detalladas sobre cómo usarla. Cuando se usa la biblioteca de OkHttp, la pila de red se incorpora a la app. Esto es similar a Cronet Embedded, pero OkHttp es mucho más pequeño y agrega menos de 1 MB a la app.
Pila de red integrada de Android
ExoPlayer admite el uso de la pila de red integrada de Android con DefaultHttpDataSource y DefaultHttpDataSource.Factory, que forman parte de la biblioteca principal de ExoPlayer.
La implementación exacta de la pila de red depende del software que se ejecuta en el dispositivo subyacente. En la mayoría de los dispositivos, solo se admite HTTP (es decir, no se admiten HTTP/2 ni HTTP/3 a través de QUIC).
Otras pilas de red
Las apps también pueden integrar otras pilas de red con ExoPlayer.
Para ello, implementa un HttpDataSource que encapsule la pila de red, junto con un HttpDataSource.Factory correspondiente. Las bibliotecas Cronet y OkHttp de ExoPlayer son buenos ejemplos de cómo hacerlo.
Cuando realices la integración con una pila de red de Java pura, es una buena idea implementar un DataSourceContractTest para verificar que tu implementación de HttpDataSource se comporte correctamente. OkHttpDataSourceContractTest en la biblioteca de OkHttp es un buen ejemplo de cómo hacerlo.
Cómo elegir una pila de red
En la siguiente tabla, se describen las ventajas y desventajas de las pilas de red compatibles con ExoPlayer.
| Pila de red | Protocolos | Impacto en el tamaño del APK | Notas |
|---|---|---|---|
| HttpEngine | HTTP HTTP/2 HTTP/3 a través de QUIC |
Ninguna | Solo disponible en la API 34 o en las extensiones de S 7 |
| Cronet (Servicios de Google Play) | HTTP HTTP/2 HTTP/3 a través de QUIC |
Pequeño (menos de 100 KB) |
Requiere los Servicios de Google Play. La versión de Cronet se actualizó automáticamente |
| Cronet (incorporado) | HTTP HTTP/2 HTTP/3 a través de QUIC |
Grande (alrededor de 8 MB) |
El desarrollador de la app controla la versión de Cronet |
| Cronet (alternativa) | HTTP (varía según el dispositivo) |
Pequeño (menos de 100 KB) |
No se recomienda para ExoPlayer |
| OkHttp | HTTP HTTP/2 |
Pequeño (menos de 1 MB) |
|
| Pila de red integrada | HTTP (varía según el dispositivo) |
Ninguna | La implementación varía según el dispositivo |
Los protocolos HTTP/2 y HTTP/3 a través de QUIC pueden mejorar significativamente el rendimiento de la transmisión de contenido multimedia. En particular, cuando se transmite contenido multimedia adaptable distribuido a través de una red de distribución de contenido (CDN), hay casos en los que el uso de estos protocolos puede permitir que las CDN operen de manera mucho más eficiente. Por este motivo, la compatibilidad de HttpEngine y Cronet con HTTP/2 y HTTP/3 a través de QUIC (y la compatibilidad de OkHttp con HTTP/2) es un beneficio importante en comparación con el uso de la pila de red integrada de Android, siempre que los servidores en los que se aloja el contenido también admitan estos protocolos.
Cuando se considera la transmisión de contenido multimedia de forma aislada, recomendamos usar HttpEngine o Cronet proporcionado por los Servicios de Google Play, con una copia de seguridad en DefaultHttpDataSource si los Servicios de Google Play no están disponibles. Esta recomendación logra un buen equilibrio entre permitir el uso de HTTP/2 y HTTP/3 a través de QUIC en la mayoría de los dispositivos, y evitar un aumento significativo en el tamaño del APK. Existen excepciones a esta recomendación. En los casos en los que es probable que los Servicios de Google Play no estén disponibles en una fracción significativa de los dispositivos que ejecutarán tu app, puede ser más adecuado usar Cronet integrado o OkHttp. El uso de la pila de red integrada puede ser aceptable si el tamaño del APK es una preocupación crítica o si la transmisión de contenido multimedia es solo una parte menor de la funcionalidad de tu app.
Más allá de los medios, suele ser una buena idea elegir una sola pila de red para todas las operaciones de redes que realiza tu app. Esto permite que los recursos (como los sockets) se agrupen y compartan de manera eficiente entre ExoPlayer y otros componentes de la app.
Dado que es muy probable que tu app necesite realizar operaciones de red que no estén relacionadas con la reproducción de contenido multimedia, tu elección de la pila de red debe tener en cuenta, en última instancia, nuestras recomendaciones anteriores para la transmisión de contenido multimedia de forma aislada, los requisitos de cualquier otro componente que realice operaciones de red y su importancia relativa para tu app.
Almacenamiento en caché de contenido multimedia
ExoPlayer admite el almacenamiento en caché de los bytes cargados en el disco para evitar la carga repetida de los mismos bytes desde la red. Esto es útil cuando se busca hacia atrás en el contenido multimedia actual o se repite el mismo elemento.
El almacenamiento en caché requiere una instancia de SimpleCache que apunte a un directorio de caché dedicado y 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();