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) 來源 (例如本機檔案) 的支援。
以下範例說明如何建構 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 直接支援 HttpEngine、Cronet、OkHttp 和 Android 的內建預設網路堆疊。ExoPlayer 也可擴充,支援 Android 上的任何其他網路堆疊。
HttpEngine
HttpEngine
是 Android API 34 (或 S 擴充功能 7) 的建議預設網路堆疊。在大多數情況下,內部會使用 Cronet 網路堆疊,支援透過 QUIC 通訊協定的 HTTP、HTTP/2 和 HTTP/3。
ExoPlayer 支援 HttpEngine,並提供 HttpEngineDataSource.Factory。您可以按照「設定 ExoPlayer 以使用特定網路堆疊」一文所述,注入這個資料來源工廠。
Cronet
Cronet 是 Chromium 網路堆疊,可做為供 Android 應用程式使用的程式庫。Cronet 利用多項技術縮短延遲時間,並提高應用程式運作所需的網路要求總處理量,包括 ExoPlayer 發出的要求。原生支援 HTTP、HTTP/2 和 HTTP/3 over QUIC 通訊協定。全球許多大型串流應用程式 (包括 YouTube) 都使用 Cronet。
ExoPlayer 透過 Cronet 程式庫支援 Cronet。如需詳細的使用說明,請參閱程式庫的 README.md。請注意,Cronet 程式庫可使用三種基礎 Cronet 實作方式:
- Google Play 服務:我們建議在大多數情況下使用這項實作方式,並在 Google Play 服務無法使用時,改用 Android 內建的網路堆疊 (
DefaultHttpDataSource)。 - Cronet 內嵌:如果您的使用者有很大一部分位於 Google Play 服務不普及的市場,或是您想控管所用 Cronet 實作的確切版本,這或許是不錯的選擇。Cronet Embedded 的主要缺點是會為應用程式增加約 8 MB 的大小。
- Cronet 回溯: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 支援搭配 DefaultHttpDataSource 和 DefaultHttpDataSource.Factory 使用 Android 內建的網路堆疊,這兩者都屬於核心 ExoPlayer 程式庫。
確切的網路堆疊實作方式取決於基礎裝置上執行的軟體。大多數裝置僅支援 HTTP (也就是不支援透過 QUIC 的 HTTP/2 和 HTTP/3)。
其他網路堆疊
應用程式也可以將其他網路堆疊與 ExoPlayer 整合。如要執行這項操作,請實作 HttpDataSource,將網路堆疊連同對應的 HttpDataSource.Factory 包裝在一起。ExoPlayer 的 Cronet 和 OkHttp 程式庫就是這方面的絕佳範例。
整合純 Java 網路堆疊時,建議您實作 DataSourceContractTest,檢查 HttpDataSource 實作項目是否運作正常。OkHttp 程式庫中的 OkHttpDataSourceContractTest 就是這類做法的絕佳範例。
選擇網路堆疊
下表列出 ExoPlayer 支援的網路堆疊優缺點。
| 網路堆疊 | 通訊協定 | APK 大小影響 | 附註 |
|---|---|---|---|
| HttpEngine | HTTP HTTP/2 HTTP/3 (透過 QUIC) |
無 | 僅適用於 API 34 或 S Extensions 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 更有效率地運作。因此,與使用 Android 內建網路堆疊相比,HttpEngine 和 Cronet 支援透過 QUIC 傳輸 HTTP/2 和 HTTP/3 (以及 OkHttp 支援 HTTP/2) 是一大優勢,前提是託管內容的伺服器也支援這些通訊協定。
如果只考慮媒體串流,建議使用 Google Play 服務提供的 HttpEngine 或 Cronet,並在 Google Play 服務無法使用時改用 DefaultHttpDataSource。這項建議可讓大多數裝置透過 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();