ネットワーク スタック

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

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

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

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

アプリで http(s) コンテンツを再生するだけでよい場合、ネットワーク スタックの選択は、アプリが挿入する DataSource.Factory インスタンスを、使用するネットワーク スタックに対応する HttpDataSource.Factory のインスタンスに更新するだけで済みます。アプリでローカル ファイルなどの http(s) 以外のコンテンツも再生する必要がある場合は、DefaultDataSource.Factory を使用します。

Kotlin

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

Java

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

この例では、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 は、HttpEngine、Cronet、OkHttp、Android の組み込みのデフォルト ネットワーク スタックを直接サポートしています。ExoPlayer を拡張して、Android で動作する他のネットワーク スタックをサポートすることもできます。

HttpEngine

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

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

Cronet

Cronet は Android アプリがライブラリとして利用できる Chromium ネットワーク スタックです。Cronet は、アプリの動作に必要なネットワーク リクエスト(ExoPlayer によるリクエストを含む)のレイテンシを抑え、スループットを向上させる複数のテクノロジーを利用します。HTTP、HTTP/2、HTTP/3 over QUIC プロトコルをネイティブでサポートしています。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 の主なデメリットは、アプリのサイズが約 8 MB 増加することです。
  3. Cronet フォールバック: Cronet のフォールバック実装は、Android の組み込みネットワーク スタックのラッパーとして Cronet の API を実装します。Android の組み込みネットワーク スタックを(DefaultHttpDataSource を使用して)直接使用する方が効率的であるため、ExoPlayer では使用しないでください。

OkHttp

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

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

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

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

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

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

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

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

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

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

ネットワーク スタック プロトコル APK サイズへの影響 メモ
HttpEngine HTTP
HTTP/2
HTTP/3 over QUIC
なし API 34 または S Extensions 7 でのみ利用可能
Cronet(Google Play 開発者サービス) HTTP
HTTP/2
HTTP/3 over QUIC
小
(100 KB 未満)
Google Play 開発者サービスが必要です。Cronet のバージョンが自動的に更新される
Cronet(埋め込み) HTTP
HTTP/2
HTTP/3 over QUIC
大
(約 8 MB)
アプリ デベロッパーが管理する Cronet のバージョン
Cronet(代替) HTTP
(デバイスによって異なる)
小
(100 KB 未満)
ExoPlayer には推奨されません
OkHttp HTTP
HTTP/2
小
(1 MB 未満)
組み込みのネットワーク スタック HTTP
(デバイスによって異なる)
なし 実装はデバイスによって異なります。

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

メディア ストリーミングを単独で検討する場合は、Google Play 開発者サービスが提供する HttpEngine または Cronet を使用することをおすすめします。Google Play 開発者サービスが利用できない場合は、DefaultHttpDataSource にフォールバックします。この推奨事項は、ほとんどのデバイスで HTTP/2 と HTTP/3 over QUIC を使用できるようにすることと、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();