メディアのダウンロード

ExoPlayer は、オフライン再生用にメディアをダウンロードする機能を提供します。ほとんどの ダウンロードは、アプリがインストールされていても 説明します。これらのユースケースでは、アプリで DownloadService をサブクラス化し、 ダウンロードを追加、削除、制御するコマンドをサービスに送信します。「 次の図は、関連する主なクラスを示しています。

メディアをダウンロードするためのクラス。矢印の方向はデータの流れを示しています。

  • DownloadService: DownloadManager をラップしてコマンドを転送します。「 サービスにより、アプリが実行中の場合でも DownloadManager の実行を継続できる できます。
  • DownloadManager: 複数のダウンロード、読み込み(および保存)を管理します DownloadIndex からの状態(および状態)、ダウンロードの開始と停止は ネットワーク接続などの要件に 専念できますダウンロード マネージャーは通常、ダウンロードしたデータを HttpDataSource を実行して、Cache に書き込みます。
  • DownloadIndex: ダウンロードの状態を保持します。

DownloadService の作成

DownloadService を作成するには、サブクラス化して実装します。 抽象メソッドの例:

  • getDownloadManager(): 使用する DownloadManager を返します。
  • getScheduler(): オプションの Scheduler を返します。これにより、 サービスに送信されます。 ExoPlayer は次の実装を提供します。 <ph type="x-smartling-placeholder">
      </ph>
    • PlatformScheduler: JobScheduler を使用します(最小 API は 21)。詳しくは、 PlatformScheduler の javadocs でアプリの権限の要件を確認してください。
    • WorkManagerScheduler: WorkManager を使用します。
  • getForegroundNotification(): アプリケーションの起動時に表示される通知を返します。 フォアグラウンドで実行されている場合です。次を使用: DownloadNotificationHelper.buildProgressNotification - 作成 表示されます。

最後に、AndroidManifest.xml ファイルでサービスを定義します。

<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC"/>
<application>
  <service android:name="com.myapp.MyDownloadService"
      android:exported="false"
      android:foregroundServiceType="dataSync">
    <!-- This is needed for Scheduler -->
    <intent-filter>
      <action android:name="androidx.media3.exoplayer.downloadService.action.RESTART"/>
      <category android:name="android.intent.category.DEFAULT"/>
    </intent-filter>
  </service>
</application>

ExoPlayer の DemoDownloadServiceAndroidManifest.xml を参照 デモアプリをご覧ください

DownloadManager を作成する

次のコード スニペットは、DownloadManager をインスタンス化する方法を示しています。 これは、DownloadServicegetDownloadManager() で返すことができます。

Kotlin

// Note: This should be a singleton in your app.
val databaseProvider = StandaloneDatabaseProvider(context)

// A download cache should not evict media, so should use a NoopCacheEvictor.
val downloadCache = SimpleCache(downloadDirectory, NoOpCacheEvictor(), databaseProvider)

// Create a factory for reading the data from the network.
val dataSourceFactory = DefaultHttpDataSource.Factory()

// Choose an executor for downloading data. Using Runnable::run will cause each download task to
// download data on its own thread. Passing an executor that uses multiple threads will speed up
// download tasks that can be split into smaller parts for parallel execution. Applications that
// already have an executor for background downloads may wish to reuse their existing executor.
val downloadExecutor = Executor(Runnable::run)

// Create the download manager.
val downloadManager =
  DownloadManager(context, databaseProvider, downloadCache, dataSourceFactory, downloadExecutor)

// Optionally, properties can be assigned to configure the download manager.
downloadManager.requirements = requirements
downloadManager.maxParallelDownloads = 3

Java

// Note: This should be a singleton in your app.
databaseProvider = new StandaloneDatabaseProvider(context);

// A download cache should not evict media, so should use a NoopCacheEvictor.
downloadCache = new SimpleCache(downloadDirectory, new NoOpCacheEvictor(), databaseProvider);

// Create a factory for reading the data from the network.
dataSourceFactory = new DefaultHttpDataSource.Factory();

// Choose an executor for downloading data. Using Runnable::run will cause each download task to
// download data on its own thread. Passing an executor that uses multiple threads will speed up
// download tasks that can be split into smaller parts for parallel execution. Applications that
// already have an executor for background downloads may wish to reuse their existing executor.
Executor downloadExecutor = Runnable::run;

// Create the download manager.
downloadManager =
    new DownloadManager(
        context, databaseProvider, downloadCache, dataSourceFactory, downloadExecutor);

// Optionally, setters can be called to configure the download manager.
downloadManager.setRequirements(requirements);
downloadManager.setMaxParallelDownloads(3);

具体的な例については、デモアプリの DemoUtil をご覧ください。

ダウンロードの追加

ダウンロードを追加するには、DownloadRequest を作成して DownloadService。アダプティブ ストリームの場合は、DownloadHelper を使用して DownloadRequest をビルドします。次の 次の例は、ダウンロード リクエストを作成する方法を示しています。

Kotlin

val downloadRequest = DownloadRequest.Builder(contentId, contentUri).build()

Java

DownloadRequest downloadRequest = new DownloadRequest.Builder(contentId, contentUri).build();

この例では、contentId はコンテンツの一意の識別子です。単純なケースでは 多くの場合、contentUricontentId として使用できますが、アプリは無料で使用できます ユースケースに最適な ID スキームを 選択できますDownloadRequest.Builder には次も存在します いくつかのオプションセッターがあります。たとえば、setKeySetIdsetData は、次の目的で使用できます。 アプリがダウンロードと関連付ける DRM とカスタムデータを設定する できます。コンテンツの MIME タイプは setMimeType を使用して指定できます。 contentUri からコンテンツ タイプを推測できない場合のヒントとして使用します。

作成したら、リクエストを DownloadService に送信して、 ダウンロード:

Kotlin

DownloadService.sendAddDownload(
  context,
  MyDownloadService::class.java,
  downloadRequest,
  /* foreground= */ false
)

Java

DownloadService.sendAddDownload(
    context, MyDownloadService.class, downloadRequest, /* foreground= */ false);

この例では、MyDownloadService がアプリの DownloadService サブクラスであり、 foreground パラメータはサービスを 使用します。アプリがすでにフォアグラウンドにある場合、foreground このパラメータは通常 false に設定する必要があります。これは、DownloadService によって 処理する必要があると判断した場合、自身をフォアグラウンドに表示します。

ダウンロードを削除しています

ダウンロードを削除するには、DownloadService に delete コマンドを送信します。 ここで、contentId には削除するダウンロードを指定します。

Kotlin

DownloadService.sendRemoveDownload(
  context,
  MyDownloadService::class.java,
  contentId,
  /* foreground= */ false
)

Java

DownloadService.sendRemoveDownload(
    context, MyDownloadService.class, contentId, /* foreground= */ false);

次のキーでダウンロードしたデータをすべて削除することもできます。 DownloadService.sendRemoveAllDownloads

ダウンロードの開始と停止

ダウンロードは、次の 4 つの条件が満たされた場合にのみ進行します。

  • ダウンロードに停止理由がない。
  • ダウンロードは一時停止されません。
  • ダウンロードを続行するための要件を満たしています。要件では、 許可するネットワーク タイプとデバイスを制限する制約を設定できます。 アイドル状態または充電器に接続している。
  • 並列ダウンロードの最大数を超えていません。

これらすべての条件は、コマンドを DownloadService

ダウンロードの停止理由の設定とクリア

1 つまたは複数のダウンロードを停止する理由を設定できます。

Kotlin

// Set the stop reason for a single download.
DownloadService.sendSetStopReason(
  context,
  MyDownloadService::class.java,
  contentId,
  stopReason,
  /* foreground= */ false
)

// Clear the stop reason for a single download.
DownloadService.sendSetStopReason(
  context,
  MyDownloadService::class.java,
  contentId,
  Download.STOP_REASON_NONE,
  /* foreground= */ false
)

Java

// Set the stop reason for a single download.
DownloadService.sendSetStopReason(
    context, MyDownloadService.class, contentId, stopReason, /* foreground= */ false);

// Clear the stop reason for a single download.
DownloadService.sendSetStopReason(
    context,
    MyDownloadService.class,
    contentId,
    Download.STOP_REASON_NONE,
    /* foreground= */ false);

stopReason にはゼロ以外の任意の値を指定できます(Download.STOP_REASON_NONE = 0 は ダウンロードが停止しないことを示す特別な値)。次があるアプリ: 複数の理由でダウンロードを停止する場合は、 その理由を確認できますすべての停止理由を設定およびクリアする ダウンロードは、Google Play Console の 1 回のダウンロード。ただし、contentIdnull に設定する必要があります。

ダウンロードの停止理由が 0 以外の場合、 Download.STATE_STOPPED 状態。停止理由は DownloadIndex。アプリケーション プロセスが強制終了されても保持されます。 確認しました。

すべてのダウンロードを一時停止、再開しています

すべてのダウンロードの一時停止と再開は次のように行えます。

Kotlin

// Pause all downloads.
DownloadService.sendPauseDownloads(
  context,
  MyDownloadService::class.java,
  /* foreground= */ false
)

// Resume all downloads.
DownloadService.sendResumeDownloads(
  context,
  MyDownloadService::class.java,
  /* foreground= */ false
)

Java

// Pause all downloads.
DownloadService.sendPauseDownloads(context, MyDownloadService.class, /* foreground= */ false);

// Resume all downloads.
DownloadService.sendResumeDownloads(context, MyDownloadService.class, /* foreground= */ false);

一時停止されたダウンロードは Download.STATE_QUEUED 状態になります。 停止理由を設定するとは異なり、このアプローチでは状態は保持されません。 できます。これは、DownloadManager のランタイム状態にのみ影響します。

ダウンロードを進行させるための要件を設定する

Requirements を使用すると、満たす必要がある制約を指定できます。 ダウンロードを続行します。要件を設定するには DownloadManager を作成するとき(例: DownloadManager.setRequirements()上記の例をご覧ください。コマンドを 1 つずつ送信して動的に変更することもできます。 DownloadService に追加します。

Kotlin

// Set the download requirements.
DownloadService.sendSetRequirements(
  context, MyDownloadService::class.java, requirements, /* foreground= */ false)

Java

// Set the download requirements.
DownloadService.sendSetRequirements(
  context,
  MyDownloadService.class,
  requirements,
  /* foreground= */ false);

要件を満たしていないためにダウンロードを続行できない場合は、 Download.STATE_QUEUED 状態になります。満たされていないクエリをクエリすることもできます。 DownloadManager.getNotMetRequirements() と併用します。

並列ダウンロードの最大数の設定

並列ダウンロードの最大数は、次の呼び出しによって設定できます。 DownloadManager.setMaxParallelDownloads()。これは通常 上記の例のように DownloadManager を作成します。

並列ダウンロードの最大数が原因でダウンロードを続行できない場合 すでに処理中の場合は、Download.STATE_QUEUED 状態になります。

ダウンロードのクエリ

DownloadManagerDownloadIndex に対して、すべての状態を照会できる 完了または失敗したダウンロードが含まれますDownloadIndex DownloadManager.getDownloadIndex() を呼び出して取得できます。このカーソルは、 すべてのダウンロードに対して反復処理を実行します。その後、次の呼び出しによって DownloadIndex.getDownloads()。または 1 回のダウンロードの状態は クエリするには DownloadIndex.getDownload() を呼び出します。

DownloadManager には DownloadManager.getCurrentDownloads() も用意されています。 現在のダウンロードの状態(未完了または失敗)のみを返します。この メソッドは、通知やその他の UI コンポーネントを更新するときに役立ちます。 ダウンロードの進行状況やステータスを確認できます。

ダウンロードの再生

DownloadManager にリスナーを追加すると、 ダウンロードの変更状態:

Kotlin

downloadManager.addListener(
  object : DownloadManager.Listener { // Override methods of interest here.
  }
)

Java

downloadManager.addListener(
    new DownloadManager.Listener() {
      // Override methods of interest here.
    });

詳しくは、デモアプリの DownloadTracker クラスの DownloadManagerListener をご覧ください。 具体的な例を挙げます。

ダウンロードしたコンテンツの再生

ダウンロードしたコンテンツの再生は、オンライン コンテンツの再生と似ていますが、 データは、ネットワーク経由ではなく、ダウンロード Cache から読み取られます。

ダウンロードしたコンテンツを再生するには、同じコマンドを使用して CacheDataSource.Factory を作成します。 ダウンロードに使用された Cache インスタンスを作成し、 プレーヤーのビルド時に DefaultMediaSourceFactory を使用する:

Kotlin

// Create a read-only cache data source factory using the download cache.
val cacheDataSourceFactory: DataSource.Factory =
  CacheDataSource.Factory()
    .setCache(downloadCache)
    .setUpstreamDataSourceFactory(httpDataSourceFactory)
    .setCacheWriteDataSinkFactory(null) // Disable writing.

val player =
  ExoPlayer.Builder(context)
    .setMediaSourceFactory(
      DefaultMediaSourceFactory(context).setDataSourceFactory(cacheDataSourceFactory)
    )
    .build()

Java

// Create a read-only cache data source factory using the download cache.
DataSource.Factory cacheDataSourceFactory =
    new CacheDataSource.Factory()
        .setCache(downloadCache)
        .setUpstreamDataSourceFactory(httpDataSourceFactory)
        .setCacheWriteDataSinkFactory(null); // Disable writing.

ExoPlayer player =
    new ExoPlayer.Builder(context)
        .setMediaSourceFactory(
            new DefaultMediaSourceFactory(context).setDataSourceFactory(cacheDataSourceFactory))
        .build();

同じプレーヤー インスタンスを、ダウンロードされていないコンテンツの再生にも使用する場合 そのような事態を避けるために、CacheDataSource.Factory を読み取り専用に構成する必要があります。 コンテンツをダウンロードすることもできます。

プレーヤーが CacheDataSource.Factory で構成されると、 ダウンロードしたコンテンツにアクセスして再生できる。ダウンロードの再生は 対応する MediaItem をプレーヤーに渡すだけです。MediaItem Download.request.toMediaItem を使用して Download から取得できます。または、 DownloadRequest.toMediaItem を使用して DownloadRequest から直接取得します。

MediaSource の構成

上記の例では、ダウンロード キャッシュをすべての MediaItem 秒。ダウンロードキャッシュを プレーヤーに直接渡すことができる個別の MediaSource インスタンス:

Kotlin

val mediaSource =
  ProgressiveMediaSource.Factory(cacheDataSourceFactory)
    .createMediaSource(MediaItem.fromUri(contentUri))
player.setMediaSource(mediaSource)
player.prepare()

Java

ProgressiveMediaSource mediaSource =
    new ProgressiveMediaSource.Factory(cacheDataSourceFactory)
        .createMediaSource(MediaItem.fromUri(contentUri));
player.setMediaSource(mediaSource);
player.prepare();

アダプティブ ストリームのダウンロードと再生

アダプティブ ストリーム(DASH、SmoothStreaming、HLS など)には通常、 使用できます。同じコンテンツを含む複数のトラックが 画質の違い(SD、HD、4K 動画トラックなど)に対応しています。また、 同じタイプの複数のトラックに、異なるコンテンツ(複数の 音声トラックが異なる場合があります。

ストリーミング再生では、トラック セレクタを使用して、 トラックが再生されます。同様に、ダウンロードの場合、DownloadHelper を使用して以下を行うことができます。 一時保存するトラックを選択できます。DownloadHelper の一般的な使用例 手順は次のとおりです。

  1. いずれかの DownloadHelper.forMediaItem を使用して DownloadHelper を作成する あります。ヘルパーを準備し、コールバックを待ちます。

    Kotlin

    val downloadHelper =
     DownloadHelper.forMediaItem(
       context,
       MediaItem.fromUri(contentUri),
       DefaultRenderersFactory(context),
       dataSourceFactory
     )
    downloadHelper.prepare(callback)
    

    Java

    DownloadHelper downloadHelper =
       DownloadHelper.forMediaItem(
           context,
           MediaItem.fromUri(contentUri),
           new DefaultRenderersFactory(context),
           dataSourceFactory);
    downloadHelper.prepare(callback);
    
  2. 必要に応じて、getMappedTrackInfo を使用して、デフォルトで選択されているトラックを確認します。 および getTrackSelectionsclearTrackSelections を使用して調整します。 replaceTrackSelectionsaddTrackSelection
  3. 呼び出して、選択したトラックの DownloadRequest を作成します。 getDownloadRequest。このリクエストは、DownloadService に渡して ダウンロードを追加します。
  4. release() を使用してヘルパーを解放します。

ダウンロードしたアダプティブ コンテンツを再生するには、プレーヤーを設定し、 前述のように、対応する MediaItem を渡します。

MediaItem をビルドする場合、MediaItem.localConfiguration.streamKeys は次のようにする必要があります。 DownloadRequest 内のものと一致するように設定します。これにより、プレーヤーは ダウンロードしたトラックのサブセットを再生できます。使用 Download.request.toMediaItemDownloadRequest.toMediaItem を使用して、 この処理は MediaItem が行います。