Сетевые стеки

ExoPlayer обычно используется для потоковой передачи мультимедиа через Интернет. Он поддерживает несколько сетевых стеков для выполнения базовых сетевых запросов. Выбор сетевого стека может оказать существенное влияние на производительность потоковой передачи.

На этой странице описано, как настроить ExoPlayer для использования выбранного вами сетевого стека, перечислены доступные параметры, приведены некоторые рекомендации по выбору сетевого стека для вашего приложения и объясняется, как включить кэширование для потокового мультимедиа.

Настройка ExoPlayer для использования определенного сетевого стека

ExoPlayer загружает данные через компоненты DataSource , которые он получает из экземпляров DataSource.Factory , внедряемых из кода приложения.

Если вашему приложению необходимо воспроизводить только содержимое http(s), выбрать сетевой стек так же просто, как обновить любые экземпляры DataSource.Factory , которые ваше приложение внедряет, чтобы они стали экземплярами HttpDataSource.Factory , соответствующими сетевому стеку, который вы хотите использовать. Если вашему приложению также необходимо воспроизводить контент, отличный от http(s), например локальные файлы, используйте DefaultDataSource.Factory :

Котлин

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

Джава

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()

Джава

// 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:

  1. Сервисы Google Play: мы рекомендуем использовать эту реализацию в большинстве случаев и вернуться к встроенному сетевому стеку Android ( DefaultHttpDataSource ), если Сервисы Google Play недоступны.
  2. Cronet Embedded: может быть хорошим выбором, если большой процент ваших пользователей находится на рынках, где сервисы Google Play не широко доступны, или если вы хотите контролировать точную версию используемой реализации Cronet. Основным недостатком Cronet Embedded является то, что он добавляет к вашему приложению примерно 8 МБ.
  3. Cronet Fallback: Резервная реализация Cronet реализует API Cronet как оболочку встроенного сетевого стека Android. Его не следует использовать с ExoPlayer, поскольку прямое использование встроенного сетевого стека Android (с помощью DefaultHttpDataSource ) более эффективно.

ОкHttp

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 . Библиотеки ExoPlayer Cronet и OkHttp являются хорошими примерами того, как это сделать.

При интеграции с сетевым стеком чистого Java рекомендуется реализовать DataSourceContractTest , чтобы проверить правильность работы вашей реализации HttpDataSource . OkHttpDataSourceContractTest в библиотеке OkHttp — хороший пример того, как это сделать.

Выбор сетевого стека

В следующей таблице представлены плюсы и минусы сетевых стеков, поддерживаемых ExoPlayer.

Сетевой стек Протоколы Влияние размера APK Примечания
HttpEngine HTTP
HTTP/2
HTTP/3 через QUIC
Никто Доступно только для API 34 или S Extensions 7.
Кронет (Сервисы Google Play) HTTP
HTTP/2
HTTP/3 через QUIC
Маленький
(<100 КБ)
Требуются сервисы Google Play. Версия Cronet обновляется автоматически
Кронет (встроенный) HTTP
HTTP/2
HTTP/3 через QUIC
Большой
(~8 МБ)
Версия Cronet контролируется разработчиком приложения
Кронет (резервный вариант) HTTP
(зависит от устройства)
Маленький
(<100 КБ)
Не рекомендуется для ExoPlayer
ОкHttp HTTP
HTTP/2
Маленький
(<1 МБ)
Встроенный сетевой стек HTTP
(зависит от устройства)
Никто Реализация зависит от устройства

Протоколы HTTP/2 и HTTP/3 через QUIC могут значительно улучшить производительность потоковой передачи мультимедиа. В частности, при потоковой передаче адаптивного мультимедиа, распространяемого с помощью сети распространения контента (CDN), бывают случаи, когда использование этих протоколов может позволить CDN работать гораздо более эффективно. По этой причине поддержка HttpEngine и Cronet как HTTP/2, так и HTTP/3 через QUIC (а также поддержка HTTP/2 в OkHttp) является основным преимуществом по сравнению с использованием встроенного сетевого стека Android при условии, что серверы, на которых размещается контент, хостинг также поддерживает эти протоколы.

При рассмотрении изолированной потоковой передачи мультимедиа мы рекомендуем использовать HttpEngine или Cronet, предоставляемые службами Google Play, с возвратом к DefaultHttpDataSource , если службы Google Play недоступны. Эта рекомендация обеспечивает хороший баланс между возможностью использования HTTP/2 и HTTP/3 поверх QUIC на большинстве устройств и избежанием значительного увеличения размера APK. Из этой рекомендации есть исключения. В случаях, когда Сервисы Google Play могут быть недоступны на значительной части устройств, на которых будет работать ваше приложение, использование 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()

Джава

// 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();