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.7.1" implementation "androidx.media3:media3-ui:1.7.1" implementation "androidx.media3:media3-common:1.7.1"
ユースケースによっては、DASH 形式でストリームを再生するために exoplayer-dash
などの Media3 の追加モジュールが必要になることもあります。
1.7.1
は、使用するライブラリのバージョンに置き換えてください。最新バージョンについては、リリースノートをご覧ください。
メディア プレーヤーの作成
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()
で準備できます。
プレーヤーを操作する
プレーヤーの準備が整ったら、プレーヤーで次のようなメソッドを呼び出して再生を制御できます。
play()
とpause()
で再生を開始、一時停止します。seekTo()
: 現在のメディア アイテム内の位置までシークするseekToNextMediaItem()
とseekToPreviousMediaItem()
で再生リスト内を移動する
PlayerView
や PlayerControlView
などの UI コンポーネントは、プレーヤーにバインドされると、それに応じて更新されます。
プレーヤーをリリースする
再生には、動画デコーダなど、供給が限られているリソースが必要になることがあります。そのため、プレーヤーが不要になったら、プレーヤーで release()
を呼び出してリソースを解放することが重要です。
プレーヤーが Activity
または Fragment
にある場合は、API レベル 24 以上では onStop()
ライフサイクル メソッドで、API レベル 23 以下では onPause()
メソッドでプレーヤーをリリースします。Service
にいるプレーヤーは、onDestroy()
でリリースできます。
メディア セッションを使用した再生の管理
Android では、メディア セッションはプロセス境界を越えてメディア プレーヤーを操作するための標準化された方法を提供します。メディア セッションをプレーヤーに接続すると、メディアの再生を外部に通知したり、外部ソースから再生コマンドを受け取ったりできます。たとえば、モバイル デバイスや大画面デバイスのシステム メディア コントロールと統合できます。
メディア セッションを使用するには、Media3 Session モジュールへの依存関係を追加します。
implementation "androidx.media3:media3-session:1.7.1"
メディア セッションを作成する
次のように、プレーヤーを初期化した後に 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
の状態と自動的に同期します。これは、ExoPlayer
、CastPlayer
、カスタム実装など、任意の Player
実装で機能します。
他のクライアントに制御を許可する
クライアント アプリは、メディア コントローラを実装して、メディア セッションの再生を制御できます。これらのリクエストを受信するには、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(); } }
マニフェストで、MediaSessionService
インテント フィルタを含む Service
クラスを宣言し、フォアグラウンド サービスを実行するための 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
が不要になったら(Activity
の onStop()
ライフサイクル メソッドなど)、MediaController.releaseFuture()
を呼び出してリリースしてください。
通知の公開
フォアグラウンド サービスは、アクティブな間は通知を公開する必要があります。MediaSessionService
は、MediaNotification
の形式で MediaStyle
通知を自動的に作成します。カスタム通知を提供するには、DefaultMediaNotificationProvider.Builder
を使用して MediaNotification.Provider
を作成するか、プロバイダ インターフェースのカスタム実装を作成します。setMediaNotificationProvider
を使用して、プロバイダを MediaSession
に追加します。
コンテンツ ライブラリの宣伝
MediaLibraryService
は MediaSessionService
をベースに、クライアント アプリがアプリから提供されるメディア コンテンツをブラウズできるようにします。クライアント アプリは MediaBrowser
を実装して MediaLibraryService
とやり取りします。
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
オブジェクトが含まれます。