Jetpack Media3 は、動画ファイルと音声ファイルの再生に関する基本機能を概説する Player インターフェースを定義します。ExoPlayer は、Media3 におけるこのインターフェースのデフォルト実装です。ExoPlayer は、ほとんどの再生ユースケースに対応する包括的な機能セットを提供し、追加のユースケースに対応できるようにカスタマイズできるため、ExoPlayer の使用をおすすめします。また、ExoPlayer はデバイスと OS の断片化を抽象化するため、コードは Android エコシステム全体で一貫して動作します。ExoPlayer には次のものが含まれます。
- 再生リストのサポート
- さまざまなプログレッシブ ストリーミング形式とアダプティブ ストリーミング 形式のサポート
- クライアントサイドとサーバーサイドの両方の広告挿入のサポート
- DRM で保護された再生のサポート
このページでは、再生アプリの構築における重要な手順について説明します。詳細については、Media3 ExoPlayer の完全なガイドをご覧ください。
スタートガイド
まず、Jetpack Media3 の ExoPlayer、UI、Common モジュールへの依存関係を追加します。
implementation "androidx.media3:media3-exoplayer:1.10.0" implementation "androidx.media3:media3-ui:1.10.0" implementation "androidx.media3:media3-common:1.10.0"
ユースケースによっては、DASH 形式でストリームを再生するための exoplayer-dash など、Media3 の追加モジュールが必要になる場合もあります。
1.10.0 は、ライブラリの任意のバージョンに置き換えてください。最新バージョンについては、リリースノート
をご覧ください。
メディア プレーヤーを作成する
Media3 では、付属の実装である Player
インターフェース、ExoPlayer を使用することも、独自のカスタム実装を構築することもできます。
ExoPlayer を作成する
ExoPlayer インスタンスを作成する最も簡単な方法は次のとおりです。
Kotlin
val player = ExoPlayer.Builder(context).build()
Java
ExoPlayer player = new ExoPlayer.Builder(context).build();
メディア プレーヤーは、それが存在する Activity、Fragment、Service の onCreate() ライフサイクル メソッドで作成できます。
Builder には、
次のようなさまざまなカスタマイズ オプションがあります。
setAudioAttributes()を使用して、音声フォーカスの処理を構成するsetHandleAudioBecomingNoisy()を使用して、オーディオ出力デバイスが切断されたときの再生動作を構成するsetTrackSelector()を使用して、トラック選択を構成する
Media3 には、アプリのレイアウト ファイルに含めることができる PlayerView UI コンポーネントが用意されています。このコンポーネントは、再生コントロール用の PlayerControlView、字幕表示用の SubtitleView、動画レンダリング用の Surface をカプセル化します。
プレーヤーを準備する
`setMediaItem()` や `addMediaItem()` などのメソッドを使用して、再生する メディア アイテム を再生リストに追加します。次に、prepare() を呼び出してメディアの読み込みを開始し、必要なリソースを取得します。
アプリがフォアグラウンドになる前に、これらの手順を実行しないでください。プレーヤーが Activity または Fragment にある場合は、API レベル 24 以降では onStart() ライフサイクル メソッドで、API レベル 23 以前では onResume() ライフサイクル メソッドでプレーヤーを準備します。Service にあるプレーヤーの場合は、onCreate() で準備できます。ライフサイクル メソッドの実装方法の
例については、ExoPlayer Codelab をご覧ください。
プレーヤーを制御する
プレーヤーの準備が完了したら、次のようなプレーヤーのメソッドを呼び出して再生を制御できます。
play()とpause()を使用して、再生を開始または一時停止するseekTo()を使用して、現在のメディア アイテム内の位置にシークするseekToNextMediaItem()とseekToPreviousMediaItem()を使用して、再生リストを移動する
PlayerView や PlayerControlView などの UI コンポーネントは、プレーヤーにバインドされると適切に更新されます。
プレーヤーを解放する
再生には、動画
デコーダなど、供給が限られたリソースが必要になる場合があります。そのため、プレーヤーが不要になったら、プレーヤーで release()
を呼び出してリソースを解放することが重要です。
プレーヤーが Activity または Fragment にある場合は、API レベル 24 以降では onStop() ライフサイクル メソッドで、API レベル 23 以前では onPause() メソッドでプレーヤーを解放します。Service にあるプレーヤーの場合は、onDestroy() で解放できます。ライフサイクル メソッドの実装方法の
例については、ExoPlayer Codelab をご覧ください。
メディア セッションで再生を管理する
Android では、メディア セッションは、プロセス境界を越えてメディア プレーヤーを操作するための標準化された方法を提供します。メディア セッションをプレーヤーに接続すると、メディアの再生を外部に公開し、外部ソースから再生コマンドを受信できます。たとえば、モバイル デバイスや大画面デバイスのシステム メディア コントロールと統合できます。
メディア セッションを使用するには、Media3 Session モジュールへの依存関係を追加します。
implementation "androidx.media3:media3-session:1.10.0"
メディア セッションを作成する
プレーヤーを初期化したら、次のように MediaSession を作成できます。
Kotlin
val player = ExoPlayer.Builder(context).build() val mediaSession = MediaSession.Builder(context, player).build()
Java
ExoPlayer player = new ExoPlayer.Builder(context).build(); MediaSession mediaSession = new MediaSession.Builder(context, player).build();
Media3 は、Player の状態を MediaSession の状態と自動的に同期します。これは、Player実装(
ExoPlayer、CastPlayer、カスタム実装など)で動作します。
他のクライアントに制御を許可する
クライアント アプリは、メディア コントローラ
を実装してメディア セッションの再生を制御できます。これらのリクエストを受信するには、
コールバック オブジェクトを
ビルド時に設定します。MediaSession
コントローラがメディア セッションに接続しようとすると、
onConnect()
メソッドが呼び出されます。提供されている ControllerInfo
を使用して、リクエストを受け入れる
か拒否する
かを決定できます。この例については、Media3 Session デモアプリをご覧ください。
接続すると、コントローラはセッションに再生コマンドを送信できます。セッションは、これらのコマンドをプレーヤーに委任します。Player インターフェースで定義された再生コマンドと再生リスト コマンドは、セッションによって自動的に処理されます。
他のコールバック メソッドを使用すると、たとえば、
カスタム再生コマンド
のリクエストや再生リストの変更などを処理できます。これらのコールバックにも同様に ControllerInfo オブジェクトが含まれているため、リクエストごとにアクセス制御を決定できます。
バックグラウンドでメディアを再生する
アプリがフォアグラウンドにないときにメディアの再生を続行するには(ユーザーがアプリを開いていない場合でも、音楽、オーディオブック、ポッドキャストを再生するなど)、Player と MediaSession を
フォアグラウンド サービスにカプセル化する必要があります。Media3 には、この目的のために MediaSessionService インターフェースが用意されています。
MediaSessionService を実装する
MediaSessionService を拡張するクラスを作成し、onCreate() ライフサイクル メソッドで
MediaSession をインスタンス化します。
Kotlin
class PlaybackService : MediaSessionService() { private var mediaSession: MediaSession? = null // Create your Player and MediaSession in the onCreate lifecycle event override fun onCreate() { super.onCreate() val player = ExoPlayer.Builder(this).build() mediaSession = MediaSession.Builder(this, player).build() } // Remember to release the player and media session in onDestroy override fun onDestroy() { mediaSession?.run { player.release() release() mediaSession = null } super.onDestroy() } }
Java
public class PlaybackService extends MediaSessionService { private MediaSession mediaSession = null; @Override public void onCreate() { super.onCreate(); ExoPlayer player = new ExoPlayer.Builder(this).build(); mediaSession = new MediaSession.Builder(this, player).build(); } @Override public void onDestroy() { mediaSession.getPlayer().release(); mediaSession.release(); mediaSession = null; super.onDestroy(); } }
マニフェストで、Service クラスを MediaSessionService インテント
フィルタとともに追加し、フォアグラウンド
サービスを実行するための FOREGROUND_SERVICE 権限をリクエストします。
<service
android:name=".PlaybackService"
android:foregroundServiceType="mediaPlayback"
android:exported="true">
<intent-filter>
<action android:name="androidx.media3.session.MediaSessionService"/>
</intent-filter>
</service>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
最後に、作成したクラスで onGetSession() メソッドをオーバーライドして、メディア セッションへのクライアント アクセスを制御します。接続リクエストを受け入れる場合は MediaSession を返し、リクエストを拒否する場合は null を返します。
Kotlin
// This example always accepts the connection request override fun onGetSession( controllerInfo: MediaSession.ControllerInfo ): MediaSession? = mediaSession
Java
@Override public MediaSession onGetSession(MediaSession.ControllerInfo controllerInfo) { // This example always accepts the connection request return mediaSession; }
UI に接続する
メディア セッションがプレーヤー UI が存在する Activity または Fragment とは別の Service にある場合は、MediaController を使用してそれらをリンクできます。UI を含む Activity または Fragment の onStart() メソッドで、MediaSession の SessionToken を作成し、SessionToken を使用して MediaController をビルドします。MediaController のビルドは非同期で行われます。
Kotlin
override fun onStart() { val sessionToken = SessionToken(this, ComponentName(this, PlaybackService::class.java)) val controllerFuture = MediaController.Builder(this, sessionToken).buildAsync() controllerFuture.addListener( { // Call controllerFuture.get() to retrieve the MediaController. // MediaController implements the Player interface, so it can be // attached to the PlayerView UI component. playerView.setPlayer(controllerFuture.get()) }, MoreExecutors.directExecutor() ) }
Java
@Override public void onStart() { SessionToken sessionToken = new SessionToken(this, new ComponentName(this, PlaybackService.class)); ListenableFuture<MediaController> controllerFuture = new MediaController.Builder(this, sessionToken).buildAsync(); controllerFuture.addListener(() -> { // Call controllerFuture.get() to retrieve the MediaController. // MediaController implements the Player interface, so it can be // attached to the PlayerView UI component. playerView.setPlayer(controllerFuture.get()); }, MoreExecutors.directExecutor()) }
MediaController は Player インターフェースを実装しているため、play() や pause() などの同じメソッドを使用して再生を制御できます。他の
コンポーネントと同様に、MediaController が不要になったら、onStop() ライフサイクル メソッドなど、Activity の
MediaController.releaseFuture() を呼び出して解放してください。
通知を公開する
フォアグラウンド サービスは、アクティブなときに通知を公開する必要があります。A
MediaSessionService は、MediaNotification の形式で
notification を
自動的に作成します。MediaStyleカスタム通知を提供するには、
MediaNotification.Provider
をDefaultMediaNotificationProvider.Builder
を使用して作成するか、プロバイダ インターフェースのカスタム実装を作成します。プロバイダを MediaSession に追加します
setMediaNotificationProvider。
コンテンツ ライブラリを宣伝する
MediaLibraryService は、クライアント
アプリがアプリで提供されるメディア コンテンツを閲覧できるようにすることで、MediaSessionService を基盤として構築されます。クライアント アプリは、MediaLibraryService とやり取り
するために
MediaBrowser を実装します。
MediaLibraryService の実装は
MediaSessionService の実装と似ていますが、onGetSession() では MediaSession ではなく
MediaLibrarySession を返す必要があります。MediaSession.Callback と比較して、MediaLibrarySession.Callback には、ブラウザ クライアントがライブラリ サービスで提供されるコンテンツを移動できるようにする追加のメソッドが含まれています。
MediaSessionService と同様に、マニフェストで MediaLibraryService を宣言し、フォアグラウンド サービスを実行するための FOREGROUND_SERVICE 権限をリクエストします。
<service
android:name=".PlaybackService"
android:foregroundServiceType="mediaPlayback"
android:exported="true">
<intent-filter>
<action android:name="androidx.media3.session.MediaLibraryService"/>
<action android:name="android.media.browse.MediaBrowserService"/>
</intent-filter>
</service>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
上記の例には、MediaLibraryService と、下位互換性のためにレガシー MediaBrowserService の両方のインテント フィルタが含まれています。追加のインテント フィルタにより、MediaBrowserCompat API を使用するクライアント アプリは Service を認識できます。
MediaLibrarySession を使用すると、単一のルート MediaItem を持つツリー構造でコンテンツ ライブラリを提供できます。ツリー内の各 MediaItem には、任意の数の子 MediaItem ノードを含めることができます。クライアント アプリのリクエストに基づいて、別のルートまたは別のツリーを提供できます。たとえば、おすすめのメディア アイテムのリストを探しているクライアントに返すツリーには、ルート MediaItem と 1 レベルの子 MediaItem ノードのみが含まれる場合があります。一方、別のクライアント アプリに返すツリーは、より完全なコンテンツ ライブラリを表す場合があります。
MediaLibrarySession を作成する
MediaLibrarySession
は MediaSession API を拡張して、コンテンツ閲覧 API を追加します。
MediaSession コールバックと比較して、
MediaLibrarySession コールバック
には次のようなメソッドが追加されています。
onGetLibraryRoot(): クライアントがコンテンツ ツリーのルートMediaItemをリクエストした場合onGetChildren(): クライアントがコンテンツ ツリー内のMediaItemの子をリクエストした場合onGetSearchResult(): クライアントが特定のクエリのコンテンツ ツリーから検索結果をリクエストした場合
関連するコールバック メソッドには、クライアント アプリが関心のあるコンテンツ ツリーのタイプに関する追加のシグナルを含む LibraryParams
オブジェクトが含まれます。