ExoPlayer широко используется для потоковой передачи мультимедиа через интернет. Он поддерживает несколько сетевых стеков для выполнения базовых сетевых запросов. Выбор сетевого стека может существенно повлиять на производительность потоковой передачи.
На этой странице описано, как настроить ExoPlayer для использования выбранного вами сетевого стека, перечислены доступные параметры, даны рекомендации по выбору сетевого стека для вашего приложения, а также объясняется, как включить кэширование для потокового мультимедиа.
Настройка ExoPlayer для использования определенного сетевого стека.
ExoPlayer загружает данные через компоненты DataSource , которые он получает из экземпляров DataSource.Factory , внедряемых из кода приложения.
Если вашему приложению нужно воспроизводить только HTTP(S) контент, выбор сетевого стека осуществляется очень просто: достаточно обновить все экземпляры DataSource.Factory , которые внедряет ваше приложение, на экземпляры HttpDataSource.Factory , соответствующие используемому вами сетевому стеку. Если вашему приложению также нужно воспроизводить контент, не относящийся к HTTP(S), например, локальные файлы, используйте DefaultDataSource.Factory :
Котлин
DefaultDataSource.Factory( ... /* baseDataSourceFactory= */ PreferredHttpDataSource.Factory(...))
Java
new DefaultDataSource.Factory( ... /* baseDataSourceFactory= */ new PreferredHttpDataSource.Factory(...));
В этом примере PreferredHttpDataSource.Factory — это фабрика, соответствующая вашему предпочтительному сетевому стеку. Слой DefaultDataSource.Factory добавляет поддержку источников, не использующих HTTP(s), таких как локальные файлы.
В следующем примере показано, как создать ExoPlayer , который будет использовать сетевой стек Cronet и поддерживать воспроизведение контента, не использующего протокол HTTP(S).
Котлин
// 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();
Поддерживаемые сетевые стеки
ExoPlayer обеспечивает прямую поддержку HttpEngine, Cronet, OkHttp и встроенного в Android сетевого стека по умолчанию. ExoPlayer также может быть расширен для поддержки любого другого сетевого стека, работающего на Android.
HttpEngine
HttpEngine — это рекомендуемый сетевой стек по умолчанию для Android, начиная с API 34 (или расширений S 7). В большинстве случаев он использует внутренний сетевой стек Cronet, поддерживающий протоколы HTTP, HTTP/2 и HTTP/3 поверх QUIC.
ExoPlayer поддерживает HttpEngine с помощью HttpEngineDataSource.Factory . Вы можете внедрить эту фабрику источников данных, как описано в разделе «Настройка ExoPlayer для использования определенного сетевого стека» .
Кронет
Cronet — это сетевой стек Chromium, доступный для Android-приложений в виде библиотеки. Cronet использует множество технологий, которые уменьшают задержку и увеличивают пропускную способность сетевых запросов, необходимых для работы вашего приложения, включая запросы от ExoPlayer. Он изначально поддерживает протоколы HTTP, HTTP/2 и HTTP/3 поверх QUIC. Cronet используется некоторыми из крупнейших в мире потоковых приложений, включая YouTube.
ExoPlayer поддерживает Cronet через свою библиотеку Cronet . Подробные инструкции по её использованию см. в README.md библиотеки. Обратите внимание, что библиотека Cronet может использовать три базовые реализации Cronet:
- Сервисы Google Play: В большинстве случаев мы рекомендуем использовать эту реализацию, а если сервисы Google Play недоступны, использовать встроенный в Android сетевой стек (
DefaultHttpDataSource). - Cronet Embedded: Может быть хорошим выбором, если значительная часть ваших пользователей находится на рынках, где сервисы Google Play не широко распространены, или если вы хотите контролировать точную версию используемой реализации Cronet. Главный недостаток Cronet Embedded заключается в том, что он добавляет примерно 8 МБ к размеру вашего приложения.
- Резервная реализация Cronet: резервная реализация Cronet использует API Cronet в качестве обертки над встроенным сетевым стеком Android. Ее не следует использовать с ExoPlayer, поскольку использование встроенного сетевого стека Android напрямую (с помощью
DefaultHttpDataSource) более эффективно.
OkHttp
OkHttp — это ещё один современный сетевой стек, широко используемый многими популярными приложениями для Android. Он поддерживает HTTP и HTTP/2, но пока не поддерживает HTTP/3 через QUIC.
ExoPlayer поддерживает OkHttp через свою библиотеку OkHttp . Подробные инструкции по её использованию см. в README.md библиотеки. При использовании библиотеки OkHttp сетевой стек встраивается в приложение. Это похоже на Cronet Embedded, однако OkHttp значительно меньше по размеру, добавляя к вашему приложению менее 1 МБ.
Встроенный сетевой стек Android
ExoPlayer поддерживает использование встроенного в Android сетевого стека с помощью DefaultHttpDataSource и DefaultHttpDataSource.Factory , которые являются частью основной библиотеки ExoPlayer.
Точная реализация сетевого стека зависит от программного обеспечения, работающего на используемом устройстве. На большинстве устройств поддерживается только HTTP (то есть HTTP/2 и HTTP/3 через QUIC не поддерживаются).
Другие сетевые стеки
Приложения также могут интегрировать другие сетевые стеки с ExoPlayer. Для этого необходимо реализовать HttpDataSource , который является оберткой для сетевого стека, вместе с соответствующим HttpDataSource.Factory . Библиотеки Cronet и OkHttp из ExoPlayer являются хорошими примерами того, как это можно сделать.
При интеграции с сетевым стеком на чистом Java рекомендуется реализовать DataSourceContractTest для проверки корректности работы вашей реализации HttpDataSource . OkHttpDataSourceContractTest из библиотеки OkHttp — хороший пример того, как это сделать.
Выбор сетевого стека
В таблице ниже приведены преимущества и недостатки сетевых стеков, поддерживаемых ExoPlayer.
| Сетевой стек | Протоколы | влияние размера APK | Примечания |
|---|---|---|---|
| HttpEngine | HTTP HTTP/2 HTTP/3 поверх QUIC | Никто | Доступно только для API 34 или расширений S 7. |
| Cronet (сервисы Google Play) | HTTP HTTP/2 HTTP/3 поверх QUIC | Маленький (<100 КБ) | Требуется Google Play Services. Версия Cronet обновляется автоматически. |
| Cronet (встроенный) | HTTP HTTP/2 HTTP/3 поверх QUIC | Большой (~8 МБ) | Версия Cronet контролируется разработчиком приложения. |
| Кронет (запасной вариант) | HTTP (зависит от устройства) | Маленький (<100 КБ) | Не рекомендуется для ExoPlayer |
| OkHttp | HTTP HTTP/2 | Маленький (<1 МБ) | |
| Встроенный сетевой стек | HTTP (зависит от устройства) | Никто | Реализация зависит от устройства. |
Протоколы HTTP/2 и HTTP/3 поверх QUIC могут значительно повысить производительность потоковой передачи мультимедиа. В частности, при потоковой передаче адаптивного мультимедиа, распространяемого через сеть доставки контента (CDN), использование этих протоколов позволяет CDN работать гораздо эффективнее. По этой причине поддержка протоколов HTTP/2 и HTTP/3 поверх QUIC в HttpEngine и Cronet (а также поддержка HTTP/2 в OkHttp) является существенным преимуществом по сравнению с использованием встроенного в Android сетевого стека, при условии, что серверы, на которых размещается контент, также поддерживают эти протоколы.
При рассмотрении потоковой передачи мультимедиа отдельно, мы рекомендуем использовать HttpEngine или Cronet, предоставляемые Google Play Services, с последующим переключением на DefaultHttpDataSource , если Google Play Services недоступны. Эта рекомендация обеспечивает хороший баланс между возможностью использования HTTP/2 и HTTP/3 через QUIC на большинстве устройств и предотвращением значительного увеличения размера APK-файла. Однако существуют исключения из этого правила. В случаях, когда Google Play Services, вероятно, будут недоступны на значительной части устройств, на которых будет работать ваше приложение, использование Cronet Embedded или OkHttp может быть более целесообразным. Использование встроенного сетевого стека может быть приемлемым, если размер APK-файла является критически важным фактором или если потоковая передача мультимедиа составляет лишь незначительную часть функциональности вашего приложения.
Помимо передачи медиафайлов, обычно целесообразно использовать единый сетевой стек для всех сетевых операций, выполняемых вашим приложением. Это позволяет эффективно объединять и совместно использовать ресурсы (например, сокеты) между ExoPlayer и другими компонентами приложения.
Поскольку вашему приложению, скорее всего, потребуется выполнять сетевые операции, не связанные с воспроизведением мультимедиа, при выборе сетевого стека следует учитывать наши рекомендации выше относительно потоковой передачи мультимедиа в отрыве от контекста, требования к любым другим компонентам, выполняющим сетевые операции, и их относительную важность для вашего приложения.
Кэширование медиафайлов
ExoPlayer поддерживает кэширование загруженных байтов на диск, чтобы предотвратить повторную загрузку одних и тех же байтов из сети. Это полезно при перемотке назад по текущему медиафайлу или при повторном воспроизведении одного и того же элемента.
Для кэширования требуется экземпляр SimpleCache , указывающий на выделенный каталог кэша, и объект CacheDataSource.Factory :
Котлин
// 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();