ネットワーク スタック

ExoPlayer は、インターネットを介したメディアのストリーミングによく使用されます。基盤となるネットワーク リクエストを行うために、複数のネットワーク スタックをサポートしています。ネットワーク スタックの選択は、ストリーミングのパフォーマンスに大きな影響を与える可能性があります。

このページでは、選択したネットワーク スタックを使用するように ExoPlayer を設定する方法、利用可能なオプション、アプリのネットワーク スタックの選択方法、ストリーミング メディアのキャッシュを有効にする方法について説明します。

特定のネットワーク スタックを使用するように ExoPlayer を構成する

ExoPlayer は、アプリコードから挿入された DataSource.Factory インスタンスから取得する DataSource コンポーネントを介してデータを読み込みます。

アプリで 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 ネットワーク スタックを使用し、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 は、Cronet、OkHttp、Android の組み込みネットワーク スタックを直接サポートしています。ExoPlayer は、Android で動作する他のネットワーク スタックをサポートするように拡張することもできます。

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 埋め込み: Google Play 開発者サービスが広く利用できない市場にユーザーの大部分がいる場合や、使用する Cronet 実装のバージョンを正確に管理したい場合に適しています。Cronet Embedded の主なデメリットは、アプリが約 8 MB 追加されることです。
  3. Cronet フォールバック: Cronet のフォールバック実装は、Android の組み込みネットワーク スタックのラッパーとして Cronet の API を実装します。DefaultHttpDataSource を使用して Android の組み込みネットワーク スタックを直接使用する方が効率的であるため、ExoPlayer では使用しないでください。

OkHttp

OkHttp も、多くの一般的な Android アプリで広く使用されている最新のネットワーク スタックです。HTTP と HTTP/2 はサポートされていますが、QUIC を介した HTTP/3 はまだサポートされていません。

ExoPlayer は、OkHttp ライブラリを通じて OkHttp をサポートしています。使用方法の詳細については、ライブラリの README.md をご覧ください。OkHttp ライブラリを使用する場合、ネットワーク スタックがアプリ内に埋め込まれます。Cronet Embedded と似ていますが、OkHttp の方がはるかに小さく、アプリに追加するサイズは 1 MB 未満です。

Android の組み込みネットワーク スタック

ExoPlayer は、ExoPlayer のコア ライブラリの一部である DefaultHttpDataSourceDefaultHttpDataSource.Factory による Android の組み込みネットワーク スタックの使用をサポートしています。

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

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

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

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

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

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

ネットワーク スタック プロトコル APK サイズの影響 Notes
Cronet(Google Play 開発者サービス) HTTP
HTTP/2
HTTP/3(QUIC 経由)

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

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

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

(1 MB 未満)
Kotlin ランタイムが必要
組み込みのネットワーク スタック HTTP
(デバイスによって異なる)
なし 実装はデバイスによって異なる

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

メディア ストリーミングを単独で検討する場合は、Google Play 開発者サービスが提供する 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();