網路堆疊

ExoPlayer 常用於透過網際網路串流播放媒體。支援使用多個網路堆疊發出基礎網路要求。您選擇的網路堆疊可能會對串流效能產生重大影響。

本頁面概述如何設定 ExoPlayer 以使用您選擇的網路堆疊、列出可用選項,並提供有關如何為應用程式選擇網路堆疊的指南,以及如何啟用串流媒體的快取功能。

設定 ExoPlayer 以使用特定網路堆疊

ExoPlayer 透過 DataSource 元件載入資料,而 ExoPlayer 會從從應用程式程式碼插入的 DataSource.Factory 執行個體取得資料。

如果應用程式只需要播放 http(s) 內容,選取網路堆疊就和將應用程式插入的任何 DataSource.Factory 例項更新為與所需網路堆疊對應的 HttpDataSource.Factory 例項一樣簡單。如果應用程式也需要播放非 HTTP 內容(例如本機檔案),請使用 DefaultDataSource.Factory

Kotlin

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

Java

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

在此範例中,PreferredHttpDataSource.Factory 是與您偏好網路堆疊對應的工廠。DefaultDataSource.Factory 層也支援非 http(s) 來源,例如本機檔案。

下例說明如何建構 ExoPlayer,以便使用 Cronet 網路堆疊及支援播放非 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 直接支援 Cronet、OkHttp 和 Android 的內建網路堆疊。您也能進一步擴充 ExoPlayer,以支援在 Android 上執行的任何其他網路堆疊。

克羅內

Cronet 是 Chromium 網路堆疊,可做為 Android 應用程式的程式庫。Cronet 利用多項技術縮短延遲時間,並提高應用程式運作所需的網路要求總處理量,包括 ExoPlayer 產生的網路要求。此服務原生支援透過 QUIC 通訊協定使用 HTTP、HTTP/2 和 HTTP/3。一些全球最大的串流應用程式 (包括 YouTube) 都使用 Cronet。

ExoPlayer 透過其 Cronet 程式庫支援 Cronet。請參閱程式庫的 README.md,進一步瞭解如何使用程式庫。請注意,Cronet 程式庫可使用三種基礎 Cronet 實作:

  1. Google Play 服務:我們建議在大多數情況下使用這項實作;如果 Google Play 服務無法使用,請改用 Android 的內建網路堆疊 (DefaultHttpDataSource)。
  2. Cronet Embedded:如果貴機構使用者大多位於 Google Play 服務未廣泛使用的市場,或者想要控制使用的確切 Cronet 實作版本,不妨使用這個選項。Cronet Embedded 的一大缺點,是它會在應用程式中增加約 8 MB 的空間。
  3. Cronet Fallback:Cronet 的備用實作方式會實作 Cronet 的 API,做為 Android 內建網路堆疊的包裝函式。不應與 ExoPlayer 搭配使用,因為直接使用 Android 內建網路堆疊 (透過 DefaultHttpDataSource) 會更有效率。

OkHttp

OkHttp 是許多熱門 Android 應用程式廣泛使用的新型網路堆疊。此介面支援 HTTP 和 HTTP/2,但尚未支援透過 QUIC 使用 HTTP/3。

ExoPlayer 透過其 OkHttp 程式庫支援 OkHttp。請參閱程式庫的 README.md,進一步瞭解如何使用程式庫。使用 OkHttp 程式庫時,系統會將網路堆疊嵌入應用程式中。這與 Cronet Embedded 類似,不過 OkHttp 非常小,會在應用程式中增加 1 MB 以下。

Android 內建網路堆疊

ExoPlayer 支援透過 DefaultHttpDataSourceDefaultHttpDataSource.Factory (屬於核心 ExoPlayer 程式庫的一部分) 使用 Android 內建的網路堆疊。

確切的網路堆疊實作取決於基礎裝置上執行的軟體。大多數裝置 (自 2021 年起) 僅支援 HTTP (也就是不支援 HTTP/2 和 QUIC 的 HTTP/3)。

其他網路堆疊

應用程式還可以將其他網路堆疊與 ExoPlayer 整合。為此,請實作 HttpDataSource 來納入網路堆疊,並搭配使用對應的 HttpDataSource.Factory。ExoPlayer 的 Cronet 和 OkHttp 程式庫都是執行相關做法的絕佳範例。

與純 Java 網路堆疊整合時,建議您實作 DataSourceContractTest,檢查 HttpDataSource 實作項目是否正確運作。OkHttp 程式庫中的 OkHttpDataSourceContractTest 是相關操作的優良範例。

選擇網路堆疊

下表概略說明 ExoPlayer 支援的網路堆疊優缺點。

網路堆疊 通訊協定 APK 大小影響 附註
Cronet (Google Play 服務) HTTP
HTTP/2
HTTP/3 透過 QUIC
小型
(小於 100KB)
必須搭配 Google Play 服務才能使用。自動更新 Cronet 版本
Cronet (內嵌) HTTP
HTTP/2
HTTP/3 透過 QUIC

(約 8 MB)
應用程式開發人員控管的 Cronet 版本
Cronet (備用廣告) HTTP
(因裝置而異)
小型
(小於 100KB)
不建議 ExoPlayer
OkHttp HTTP
HTTP/2
小型
(小於 1 MB)
需要 Kotlin 執行階段
內建網路堆疊 HTTP
(因裝置而異)
導入方式因裝置而異

透過 QUIC 通訊協定使用 HTTP/2 和 HTTP/3 可大幅提升媒體串流效能。特別是,當透過內容傳遞網路 (CDN) 放送串流的自動調整媒體時,若使用這些通訊協定,則可讓 CDN 作業更有效率。因此,相較於使用 Android 的內建網路堆疊,Cronet 支援透過 QUIC 進行 HTTP/2 和 HTTP/3 支援 (和 OkHttp 對 HTTP/2 的支援),由於託管內容的伺服器也支援這些通訊協定,因此提供了 Cronet 支援。

單獨考慮進行媒體串流時,建議您使用 Google Play 服務提供的 Cronet。如果 Google Play 服務無法使用,改回使用 DefaultHttpDataSource。在大多數裝置上啟用 HTTP/2 和 HTTP/3 以及 QUIC 之間的建議,兩者之間可達到良好平衡,避免 APK 大小大幅增加。這項建議會有例外狀況。對於將執行應用程式的大部分裝置而言,Google Play 服務可能無法使用,因此建議您使用 Cronet Embedded 或 OkHttp。如果 APK 大小是關鍵考量,或媒體串流只是應用程式功能的一小部分,那麼系統或許可以接受使用內建網路堆疊。

一般來說,除了媒體之外,建議您為應用程式執行的所有網路選擇單一網路堆疊。這樣做可讓 ExoPlayer 與其他應用程式元件之間有效率地集區和共用資源 (例如通訊端)。

由於您的應用程式很可能需要執行與媒體播放無關的網路,因此您選擇的網路堆疊最終應將上述建議的獨立媒體串流納入考量、其他執行網路的元件的需求,以及對應用程式的重要性。

快取媒體

ExoPlayer 支援將已載入的位元組數快取至磁碟,以防止從網路重複載入相同的位元組。如果要在目前的媒體中搜尋或重複相同項目,這個方法就非常實用。

快取需要指向專屬的快取目錄和 CacheDataSource.FactorySimpleCache 執行個體:

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