Jetpack Media3 は、動画ファイルと音声ファイルを再生するための基本機能を概説する Player
インターフェースを定義しています。ExoPlayer
は、Media3 のこのインターフェースのデフォルト実装です。ExoPlayer は、ほとんどの再生ユースケースに対応する包括的な機能セットを備えており、追加のユースケースを処理するためにカスタマイズできるため、ExoPlayer を使用することをおすすめします。また、ExoPlayer はデバイスと OS の断片化を抽象化するため、Android エコシステム全体でコードが一貫して機能します。ExoPlayer には以下が含まれます。
- 再生リストのサポート
- さまざまなプログレッシブ ストリーミング形式とアダプティブ ストリーミング フォーマットのサポート
- クライアントサイドとサーバーサイドの両方の広告挿入に対応
- DRM で保護された再生のサポート
このページでは、再生アプリを作成するための主な手順について説明します。詳細については、Media3 ExoPlayer の完全ガイドをご覧ください。
開始する
まず、Jetpack Media3 の ExoPlayer、UI、共通モジュールへの依存関係を追加します。
implementation "androidx.media3:media3-exoplayer:1.3.1" implementation "androidx.media3:media3-ui:1.3.1" implementation "androidx.media3:media3-common:1.3.1"
ユースケースによっては、DASH 形式でストリームを再生するために、exoplayer-dash
などの Media3 の追加モジュールが必要になる場合もあります。
1.3.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.3.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.releaseFuture()
を呼び出して、Activity
の onStop()
ライフサイクル メソッドなど、不要になったら忘れずに MediaController
を解放してください。
通知の公開
フォアグラウンド サービスは、アクティブなときに通知を公開する必要があります。MediaSessionService
は、MediaStyle
通知を MediaNotification
の形式で自動的に作成します。カスタム通知を提供するには、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
を使用すると、1 つのルート MediaItem
を持つツリー構造でコンテンツ ライブラリを提供できます。ツリー内の各 MediaItem
には任意の数の子 MediaItem
ノードを設定できます。クライアント アプリのリクエストに基づいて、異なるルートまたは別のツリーを表示できます。たとえば、クライアントに戻ったときに推奨されるメディア アイテムのリストを探すツリーには、ルート MediaItem
と単一レベルの子 MediaItem
ノードしか含まれていないのに対し、別のクライアント アプリに戻ったツリーは、より完全なコンテンツ ライブラリを表す可能性があります。
MediaLibrarySession
の作成
MediaLibrarySession
は MediaSession
API を拡張して、コンテンツ ブラウジング API を追加します。MediaSession
コールバックと比較すると、MediaLibrarySession
コールバックでは次のようなメソッドが追加されます。
onGetLibraryRoot()
: クライアントがコンテンツ ツリーのルートMediaItem
をリクエストした場合onGetChildren()
: クライアントがコンテンツ ツリー内のMediaItem
の子をリクエストした場合onGetSearchResult()
: クライアントが特定のクエリに対してコンテンツ ツリーの検索結果をリクエストした場合
関連するコールバック メソッドには、クライアント アプリが関心を持つコンテンツ ツリーのタイプに関する追加のシグナルを含む LibraryParams
オブジェクトが含まれます。