プレーヤー インターフェース

プレーヤーは、メディア アイテムの再生を容易にするアプリのコンポーネントです。Media3 の Player インターフェースは、一般的にプレーヤーによって処理される機能の概要を設定します。これには、次のものがあります。

  • 再生、一時停止、シークなどの再生操作に影響する
  • 現在再生中のメディアのプロパティ(再生位置など)をクエリする
  • メディア アイテムの再生リスト/キューの管理
  • 再生プロパティの設定(シャッフル、繰り返し、速度、音量など)
  • 画面への動画のレンダリング

Media3 には、Player インターフェースの実装(ExoPlayer)も用意されています。

コンポーネント間の共通インターフェース

Media3 のいくつかのコンポーネントは、Player インターフェースを実装しています。たとえば、次のようなコンポーネントがあります。

コンポーネント 説明と動作に関するメモ
ExoPlayer メディア プレーヤー API と Player インターフェースのデフォルト実装。
MediaController MediaSession とやり取りして再生コマンドを送信します。PlayerMediaSession が、プレーヤーの UI が存在する Activity または Fragment とは別の Service にある場合は、MediaControllerPlayerView UI のプレーヤーとして割り当てることができます。再生とプレイリストのメソッド呼び出しは、MediaSession を介して Player に送信されます。
MediaBrowser MediaController が提供する機能に加えて、MediaLibrarySession とやり取りして、利用可能なメディア コンテンツをブラウジングします。
ForwardingPlayer メソッド呼び出しを別の Player に転送する Player 実装。このクラスを使用すると、それぞれのメソッドをオーバーライドして、特定のオペレーションを抑制または変更できます。
SimpleBasePlayer 実装するメソッドの数を最小限に抑える Player 実装。カスタム プレーヤーを使用して MediaSession に接続する場合に便利です。
CastPlayer Cast レシーバー アプリと通信する Player の実装。動作は、基盤となる Cast セッションによって異なります。

MediaSessionPlayer インターフェースを実装していませんが、作成するときに Player が必要です。その目的は、他のプロセスまたはスレッドから Player にアクセスできるようにすることです。

Media3 の再生アーキテクチャ

Player にアクセスできる場合は、そのメソッドを直接呼び出して再生コマンドを実行する必要があります。MediaSession を実装すると、再生をアドバタイズし、外部ソースに再生コントロールを付与できます。これらの外部ソースは MediaController を実装します。これにより、メディア セッションへの接続と再生コマンド リクエストの発行が容易になります。

バックグラウンドでメディアを再生する場合は、メディア セッションとプレーヤーを、フォアグラウンド サービスとして実行される MediaSessionService または MediaLibraryService 内に配置する必要があります。そうすることで、再生コントロールの UI を含むアプリ内のアクティビティからプレーヤーを分離できます。この場合、メディア コントローラを使用する必要が生じることがあります。

Media3 再生コンポーネントがメディアアプリのアーキテクチャにどのように適合するかを示した図。
図 1: Player インターフェースは Media3 のアーキテクチャで重要な役割を果たします。

プレーヤーの状態

Player インターフェースを実装するメディア プレーヤーの状態は、主に次の 4 つのカテゴリの情報で構成されます。

  1. 再生状態
  2. メディア アイテムの再生リスト
    • 再生用の MediaItem インスタンスのシーケンス。
    • getCurrentTimeline() で取得
    • Player インスタンスは、MediaItem追加削除などの再生リスト操作メソッドと、getCurrentMediaItem() などのコンビニエンス メソッドを提供できます。
  3. 再生/一時停止のプロパティ(次に例を示します)。
    • playWhenReady: ユーザーがメディアを可能な限り再生するか、一時停止したままにするかを示す
    • 再生の抑制理由: 再生が抑制される理由(playWhenReadytrue の場合でも該当する場合)。
    • isPlaying: プレーヤーが現在再生中かどうか。再生状態が STATE_READYplayWhenReadytrue、再生が抑制されていない場合のみ true になります。
  4. 再生位置(次に例を示します)。

また、Player インターフェースでは、利用可能なトラックメディア メタデータ再生速度音量などの再生の補助プロパティにアクセスできます。

変更をリッスンする

Player.Listener を使用して、Player の変更をリッスンします。リスナーの作成方法と使用方法について詳しくは、Player イベントに関する ExoPlayer のドキュメントをご覧ください。

リスナー インターフェースには、通常の再生の進行状況を追跡するコールバックは含まれていません。進行状況バー UI を設定するなど、再生の進行状況を継続的にモニタリングするには、適切な間隔で現在の位置をクエリする必要があります。

Kotlin

val handler = Handler(Looper.getMainLooper())
fun checkPlaybackPosition(delayMs: Long): Boolean =
  handler.postDelayed(
    {
      val currentPosition = player.currentPosition
      // Update UI based on currentPosition
      checkPlaybackPosition(delayMs)
    },
    delayMs)

Java

Handler handler = new Handler(Looper.getMainLooper());
boolean checkPlaybackPosition(long delayMs) {
    return handler.postDelayed(() -> {
        long currentPosition = player.getCurrentPosition();
        // Update UI based on currentPosition
        checkPlaybackPosition(delayMs);
    }, delayMs);
}

再生を操作する

Player インターフェースには、状態を操作して再生を制御するためのさまざまな方法が用意されています。

カスタム Player の実装

カスタム プレーヤーを作成するには、Media3 に含まれる SimpleBasePlayer を拡張します。このクラスは、実装する必要があるメソッドの数を最小限に抑えるために、Player インターフェースの基本実装を提供します。

まず、getState() メソッドをオーバーライドします。このメソッドは、呼び出されたときに現在のプレーヤーの状態(以下を含む)を入力する必要があります。

  • 使用可能なコマンドのセット
  • 再生プロパティ(再生状態が STATE_READY のときにプレーヤーを再生するかどうか、現在再生中のメディア アイテムのインデックス、現在のアイテム内の再生位置など)

Kotlin

class CustomPlayer : SimpleBasePlayer(looper) {
  override fun getState(): State {
    return State.Builder()
      .setAvailableCommands(...) // Set which playback commands the player can handle
      // Configure additional playback properties
      .setPlayWhenReady(true, PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST)
      .setCurrentMediaItemIndex(0)
      .setContentPositionMs(0)
      .build()
  }
}

Java

public class CustomPlayer extends SimpleBasePlayer {
  public CustomPlayer(Looper looper) {
    super(looper);
  }

  @Override
  protected State getState() {
    return new State.Builder()
      .setAvailableCommands(...) // Set which playback commands the player can handle
      // Configure additional playback properties
      .setPlayWhenReady(true, PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST)
      .setCurrentMediaItemIndex(0)
      .setContentPositionMs(0)
      .build();
  }
}

SimpleBasePlayer は、状態値の有効な組み合わせで State が作成されるようにします。また、リスナーを処理し、リスナーに状態の変化を通知します。状態の更新を手動でトリガーする必要がある場合は、invalidateState() を呼び出します。

getState() メソッド以外に、プレーヤーが使用可能と宣言したコマンドに使用されるメソッドのみを実装する必要があります。実装する機能に対応するオーバーライド可能なハンドラ メソッドを見つけます。たとえば、handleSeek() メソッドをオーバーライドして、COMMAND_SEEK_IN_CURRENT_MEDIA_ITEMCOMMAND_SEEK_TO_NEXT_MEDIA_ITEM などのオペレーションをサポートします。