Jetpack Media3 では、動画や音声ファイルの再生の基本機能についての概要を示す Player
インターフェースが定義されています。ExoPlayer
は、Media3 でこのインターフェースのデフォルト実装です。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 形式でストリームを再生するために、Media3 からの追加モジュール(exoplayer-dash
など)も必要になる場合があります。
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()
などの同じメソッドを使用して再生を制御できます。他のコンポーネントと同様に、Activity
の onStop()
ライフサイクル メソッドなど、不要になったら必ず MediaController.releaseFuture()
を呼び出して MediaController
を解放してください。
通知の公開
フォアグラウンド サービスは、アクティブなときに通知を公開する必要があります。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
と単一レベルの子 MediaItem
ノードのみが含まれるのに対し、別のクライアント アプリに戻ったツリーは、より完全なコンテンツのライブラリを表す場合があります。
MediaLibrarySession
の作成
MediaLibrarySession
は MediaSession
API を拡張して、コンテンツ ブラウジング API を追加します。MediaSession
コールバックとは異なり、MediaLibrarySession
コールバックは次のようなメソッドを追加します。
onGetLibraryRoot()
: クライアントがコンテンツ ツリーのルートMediaItem
をリクエストした場合onGetChildren()
: クライアントがコンテンツ ツリー内のMediaItem
の子をリクエストした場合onGetSearchResult()
: クライアントが特定のクエリに対するコンテンツ ツリーの検索結果をリクエストした場合
関連するコールバック メソッドには、クライアント アプリの対象コンテンツ ツリーのタイプに関する追加のシグナルを含む LibraryParams
オブジェクトが含まれます。