ネットワーク スタック

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

HttpEngine

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

ExoPlayer は HttpEngineDataSource.FactoryHttpEngine をサポートしています。このデータソース ファクトリは、特定のネットワーク スタックを使用するように 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 を実装します。DefaultHttpDataSource を使用して Android の組み込みネットワーク スタックを直接使用する方が効率的であるため、ExoPlayer で使用しないでください。

OkHttp

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

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

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

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

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

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

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

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

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

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

ネットワーク スタック プロトコル APK サイズへの影響 備考
HttpEngine HTTP
HTTP/2
QUIC 経由の HTTP/3
なし API 34 または S 拡張機能 7 でのみ利用可能
Cronet(Google Play 開発者サービス) HTTP
HTTP/2
QUIC 経由の HTTP/3

(100 KB 未満)
Google Play 開発者サービスが必要です。Cronet のバージョンが自動的に更新される
Cronet(埋め込み) HTTP
HTTP/2
QUIC 経由の HTTP/3
Large
(約 8 MB)
アプリ デベロッパーが管理する Cronet バージョン
Cronet(フォールバック) HTTP
(デバイスによって異なります)

(100 KB 未満)
ExoPlayer では推奨されません
OkHttp HTTP
HTTP/2

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

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

メディア ストリーミングを単独で検討する場合は、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();