ネットワーク スタック

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 レイヤは、Google Cloud HTTP(S) 以外のソース(ローカル ファイルなど)に対してリクエストできます。

次の例は、Cronet ネットワーク スタックを使用し、http(s) 以外のコンテンツの再生もサポートする ExoPlayer を作成する方法を示しています。

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 を拡張して、Google Cloud の 他のネットワーク スタックに実装することもできます。

HTTP エンジン

HttpEngine Android で推奨されるデフォルト ネットワーク スタックの API 34(S 拡張機能 7)ほとんどの場合、内部で Cronet ネットワーク スタックを使用しますが、 QUIC プロトコルを介して HTTP、HTTP/2、HTTP/3 をサポート

ExoPlayer は、HttpEngineDataSource.Factory で HttpEngine をサポートしています。このデータソース ファクトリーは、特定のネットワーク スタックを使用するように ExoPlayer を構成するで説明されているように挿入できます。

Cronet

Cronet は、Android アプリがライブラリとして利用できる Chromium ネットワーク スタックです。Cronet は、ExoPlayer によって作成されたものを含む、アプリの動作に必要なネットワーク リクエストのレイテンシを抑え、スループットを向上させる複数のテクノロジーを利用します。QUIC プロトコル経由の HTTP、HTTP/2、HTTP/3 をネイティブにサポートしています。Cronet は、YouTube をはじめとする世界最大のストリーミング アプリで使用されています。

ExoPlayer は、Cronet ライブラリを介して Cronet をサポートしています。使用方法の詳細については、ライブラリの README.md をご覧ください。Cronet ライブラリは、次の 3 つの基盤となる Cronet 実装を使用できます。

  1. Google Play 開発者サービス: ほとんどの場合、この実装を使用し、Google Play 開発者サービスが使用できない場合は Android の組み込みネットワーク スタック(DefaultHttpDataSource)にフォールバックすることをおすすめします。
  2. Cronet Embedded: ユーザーの割合が高い場合に適しています。 Google Play 開発者サービスが十分に提供されていない市場にある場合、または 使用する Cronet 実装の正確なバージョンを制御する必要がある場合。「 Cronet Embedded の主なデメリットは、 説明します。
  3. Cronet のフォールバック: Cronet の実装のフォールバック実装 Android の組み込みネットワーク スタックのラッパーとしての Cronet の API。本来は 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 は、Android の組み込みネットワーク スタックの使用をサポートしています。 DefaultHttpDataSourceDefaultHttpDataSource.Factory: ExoPlayer のコアライブラリです。

正確なネットワーク スタックの実装は、基盤となるデバイスで実行されているソフトウェアによって異なります。ほとんどのデバイスでは HTTP のみがサポートされています(つまり、 HTTP/2 と HTTP/3 over QUIC はサポートされていません)。

その他のネットワーク スタック

アプリは、他のネットワーク スタックを ExoPlayer と統合することもできます。 これを行うには、ネットワーク スタックをラップする HttpDataSource と、対応する HttpDataSource.Factory を実装します。ExoPlayer の Cronet ライブラリと OkHttp ライブラリは、この方法の良い例です。

純粋な Java ネットワーク スタックと統合する場合は、DataSourceContractTest を実装して、HttpDataSource 実装が正しく動作することを確認することをおすすめします。OkHttp ライブラリの OkHttpDataSourceContractTest は、この方法の良い例です。

ネットワーク スタックの選択

次の表に、ExoPlayer でサポートされているネットワーク スタックの長所と短所を示します。

ネットワーク スタック プロトコル APK サイズへの影響
HTTP エンジン HTTP
HTTP/2
QUIC を介した HTTP/3
なし API 34 または S Extensions 7 でのみ使用可能
Cronet(Google Play 開発者サービス) HTTP
HTTP/2
QUIC 経由の HTTP/3

(100 KB 未満)
Google Play 開発者サービスが必要です。Cronet のバージョンが自動更新されました
Cronet(埋め込み) HTTP
HTTP/2
QUIC 経由の HTTP/3

(~ 8 MB)
アプリ デベロッパーによって管理されている Cronet のバージョン
Cronet(代替) HTTP
(デバイスによって異なる)

(100 KB 未満)
ExoPlayer には非推奨
OkHttp HTTP
HTTP/2

(1 MB 未満)
組み込みネットワーク スタック HTTP
(デバイスによって異なる)
なし 実装はデバイスによって異なります

QUIC プロトコルを介した HTTP/2 と HTTP/3 は、メディアを大幅に改善できます。 パフォーマンスが向上します特に、サイズの大きいアダプティブ メディアをストリーミングする場合は、 コンテンツ配信ネットワーク(CDN)を使用して配信する場合、 どちらのプロトコルを使用することで CDN の運用効率が 大幅に向上します このため、コンテンツがホストされているサーバーがこれらのプロトコルをサポートしている場合、HttpEngine と Cronet が QUIC を介した HTTP/2 と HTTP/3 の両方をサポートしていること(および OkHttp が HTTP/2 をサポートしていること)は、Android の組み込みネットワーク スタックを使用する場合と比較して大きなメリットとなります。

メディア ストリーミングのみを検討する場合は、Google Play 開発者サービスが利用できない場合は DefaultHttpDataSource にフォールバックする Google Play 開発者サービスが提供する HttpEngine または Cronet を使用することをおすすめします。この推奨事項は、ほとんどのデバイスで QUIC を介した HTTP/2 と HTTP/3 の使用を有効にし、APK サイズの大幅な増加を回避するバランスの取れたものです。この推奨事項には例外があります。アプリを実行するデバイスの大部分で Google Play 開発者サービスが使用できない可能性が高い場合は、Cronet Embedded または OkHttp を使用することをおすすめします。組み込みネットワーク スタックの使用は、APK サイズが重要な懸念事項である場合や、メディア ストリーミングがアプリの機能のごく一部である場合に許容されます。

通常、メディアだけでなく、アプリが行うすべてのネットワーキングに単一のネットワーク スタックを選択することをおすすめします。これにより、リソース(ソケットなど)を効率的にプールし、ExoPlayer と他のアプリ コンポーネント間で共有できます。

アプリではメディアの再生に関連しないネットワーク処理を行う必要があるため、ネットワーク スタックを選択する際には、メディア ストリーミングのみに関する上記の推奨事項、ネットワーク処理を行う他のコンポーネントの要件、アプリに対するそれらの相対的な重要性を考慮する必要があります。

メディアのキャッシュ保存

ExoPlayer は、読み込まれたバイトをディスクにキャッシュに保存し、ネットワークから同じバイトを繰り返し読み込まないようにします。これは、現在の日付を 同じ項目の繰り返し再生を行えるようになります

キャッシュには、専用のキャッシュ ディレクトリと CacheDataSource.Factory を指す SimpleCache インスタンスが必要です。

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