网络堆栈

ExoPlayer 通常用于通过互联网流式传输媒体。它支持 多个网络堆栈来发出底层网络请求具体选择哪种方式,完全由你决定 可能会对流式传输性能产生重大影响。

本页概述了如何配置 ExoPlayer 以使用 列出了可用的选项,并提供了一些有关如何 并说明如何为流式播放启用缓存 媒体。

将 ExoPlayer 配置为使用特定的网络堆栈

ExoPlayer 通过 DataSource 组件加载数据,该组件会从 从应用代码注入的 DataSource.Factory 实例。

如果您的应用只需播放 http(s) 内容,请选择一个网络 就像更新任意 DataSource.Factory 实例一样简单, 应用注入为 HttpDataSource.Factory 的实例 与您要使用的网络堆栈相对应如果您的应用还 需要播放非 http(s) 内容(如本地文件)、 DefaultDataSource.Factory

Kotlin

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

Java

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

在此示例中,PreferredHttpDataSource.Factory 是与您的 首选网络堆栈DefaultDataSource.Factory 层添加了支持 用于非 http(s) 来源,例如本地文件。

以下示例展示了如何构建将使用 Cronet 组件的 ExoPlayer 网络堆栈,还支持播放非 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();

支持的网络堆栈

ExoPlayer 直接支持 HttpEngine、Cronet、OkHttp 和 Android 的 内置默认网络堆栈ExoPlayer 还可以经过扩展,以支持 支持在 Android 上运行的其他网络堆栈

HttpEngine

HttpEngine 是 API 级别 34(或 Android S)在 Android 上建议的默认网络堆栈 扩展程序 7)。在大多数情况下,它在内部使用 Cronet 网络堆栈, 支持基于 QUIC 协议的 HTTP、HTTP/2 和 HTTP/3。

ExoPlayer 通过其 HttpEngineDataSource.Factory 支持 HttpEngine。您可以 按照配置 ExoPlayer 以使用 特定网络堆栈

Cronet

Cronet 是 Chromium 网络堆栈以库的形式提供给 Android 应用。Cronet 通过 充分利用多种技术,缩短延迟时间并增加 您的应用需要工作所需的网络请求的吞吐量,包括那些 由 ExoPlayer 生成。它以原生方式支持基于 QUIC 的 HTTP、HTTP/2 和 HTTP/3 协议全球一些大型在线影音应用都在使用 Cronet, 包括 YouTube。

ExoPlayer 支持 Cronet, Cronet 库。 如需详细了解如何使用,请参阅库的 README.md 。请注意,Cronet 库能够使用三个底层的 Cronet 实现:

  1. Google Play 服务:我们建议在大多数情况下使用此实现, 以及回退到 Android 的内置网络堆栈 (DefaultHttpDataSource) 如果 Google Play 服务不可用。
  2. Cronet Embedded:如果您的大部分用户都使用这项服务,这是一个不错的选择 位于未广泛提供 Google Play 服务的市场,或者 想要控制正在使用的 Cronet 实现的确切版本。通过 Cronet Embedded 的主要缺点是,它会将大约 8MB 的内容 。
  3. Cronet 回退:Cronet 的回退实现会实现 Cronet 的 API,可用作 Android 内置网络堆栈的封装容器。它应该 不可用于 ExoPlayer,因为使用的是 Android 的内置网络堆栈 (使用 DefaultHttpDataSource)的效率更高。

OkHttp

OkHttp 是另一种新型网络堆栈, 被许多热门的 Android 应用广泛使用。它支持 HTTP 和 HTTP/2,但尚不支持基于 QUIC 的 HTTP/3。

ExoPlayer 通过其 API 调用来支持 OkHttp, OkHttp 库。 如需详细了解如何使用,请参阅库的 README.md 。使用 OkHttp 库时,网络堆栈会嵌入到 应用。与 Cronet Embedded 类似,但 OkHttp 显著 从而为应用增加不到 1MB 的大小。

Android 的内置网络堆栈

ExoPlayer 支持使用 Android 的内置网络堆栈 DefaultHttpDataSourceDefaultHttpDataSource.Factory,属于 核心 ExoPlayer 库。

网络堆栈的确切实现取决于 底层设备大多数设备只支持 HTTP 不支持 HTTP/2 和 HTTP/3 over QUIC)。

其他网络堆栈

应用还可以将其他网络堆栈与 ExoPlayer 集成。 为此,请实现一个封装网络堆栈的 HttpDataSource, 以及相应的 HttpDataSource.Factory。ExoPlayer 的 Cronet 和 OkHttp 库就是关于如何执行此操作的范例。

与纯 Java 网络堆栈集成时,最好实现 DataSourceContractTest,以检查您的 HttpDataSource 实现是否正常 正常运行。OkHttp 库中的 OkHttpDataSourceContractTest 是 这是一个不错的例子。

选择网络堆栈

下表概述了 Google Cloud 中 ExoPlayer。

网络堆栈 协议 APK 大小影响 备注
HttpEngine HTTP
HTTP/2
HTTP/3(基于 QUIC)
仅适用于 API 34 或 S 扩展 7
Cronet(Google Play 服务) HTTP
HTTP/2
HTTP/3(基于 QUIC)

(<100KB)
需要 Google Play 服务。Cronet 版本已自动更新
Cronet(嵌入式) HTTP
HTTP/2
HTTP/3(基于 QUIC)

(约 8MB)
由应用开发者控制的 Cronet 版本
Cronet(后备) HTTP
(因设备而异)

(<100KB)
不推荐用于 ExoPlayer
OkHttp HTTP
HTTP/2

(小于 1MB)
内置网络堆栈 HTTP
(因设备而异)
实现因设备而异

基于 QUIC 协议的 HTTP/2 和 HTTP/3 可以显著改善媒体 流式传输性能特别是,当流式传输 使用内容分发网络 (CDN) 分发,则在某些情况下, 使用这些协议可让 CDN 更高效地运行 因此,HttpEngine 和 Cronet 同时支持 HTTP/2 和 HTTP/3 与 QUIC(以及 OkHttp 对 HTTP/2 的支持)相比, 但前提是要用 Android 的内置网络堆栈 也支持这些协议。

在单独考虑媒体流式传输时,我们建议使用 HttpEngine 或 Google Play 服务提供的 Cronet 回退到 DefaultHttpDataSource 如果 Google Play 服务不可用。此建议不错 在大多数设备上通过 QUIC 使用 HTTP/2 和 HTTP/3,以及 避免 APK 大小显著增加。不过,也有例外情况 建议。针对可能无法使用 Google Play 服务的情况 在很大一部分设备上运行您的应用时 使用 Cronet Embedded 或 OkHttp 可能更加合适。使用内置 如果 APK 大小非常严重,或者如果媒体 流式传输只是应用功能的一小部分。

除了媒体之外,通常最好选择单个网络堆栈 为您的应用执行的所有网络配置数据。这样,资源便可 (例如套接字)在 ExoPlayer 和其他 应用组件。

因为您的应用很可能需要执行与网络无关的连接 到媒体播放,您对网络堆栈的选择最终应考虑我们的 单独进行媒体流式传输时,所有媒体流的 执行网络连接的其他组件,以及它们对您的应用的 应用。

缓存媒体

ExoPlayer 支持将加载的字节缓存到磁盘,以防止重复加载 来自网络的相同字节在当前所设的下段快退时, 或重复播放同一项内容。

缓存需要指向专用缓存的 SimpleCache 实例 目录和 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();