メディアアプリに接続する方法は 2 つあります。
MediaControllerMediaBrowser
MediaController
メディア コントローラはメディア セッションとやり取りして、メディアアプリの再生をクエリして制御します。Media3 では、MediaController API が Player インターフェースを実装します。メディア コントローラを使用するクライアント アプリの例は次のとおりです。
- Android システムのメディア コントロール
- Android Wear OS コンパニオン アプリ
- Android Auto と Automotive OS
- Google アシスタントなどの音声アシスタント
- メディア コントローラ テストアプリ
メディア コントローラは、メディアアプリ内でも役立ちます。たとえば、プレーヤーとメディア セッションが UI を含む Activity または Fragment とは別の Service に存在する場合などです。
MediaController を作成
MediaController を作成するには、まず対応する MediaSession の SessionToken を作成します。Activity または Fragment の onStart() メソッドが適しています。
Kotlin
val sessionToken =
SessionToken(context, ComponentName(context, PlaybackService::class.java))
Java
SessionToken sessionToken =
new SessionToken(context, new ComponentName(context, PlaybackService.class));
この SessionToken を使用して MediaController をビルドすると、コントローラが指定されたセッションに接続されます。これは非同期で行われるため、結果をリッスンし、利用可能になったら使用する必要があります。
Kotlin
val controllerFuture =
MediaController.Builder(context, sessionToken).buildAsync()
controllerFuture.addListener({
// MediaController is available here with controllerFuture.get()
}, MoreExecutors.directExecutor())
Java
ListenableFuture<MediaController> controllerFuture =
new MediaController.Builder(context, sessionToken).buildAsync();
controllerFuture.addListener(() -> {
// MediaController is available here with controllerFuture.get()
}, MoreExecutors.directExecutor());
MediaController を使用する
MediaController は Player インターフェースを実装しているため、インターフェースで定義されたコマンドを使用して、接続された MediaSession の再生を制御できます。つまり、MediaController で play() を呼び出すと、接続された MediaSession にコマンドが送信され、その後、コマンドが基盤となる Player に委任されます。
コントローラに Player.Listener を追加して、Player 状態の変化をリッスンできます。Player.Listener の使用について詳しくは、プレーヤー イベント ガイドをご覧ください。
MediaController.Listener インターフェースは、接続された MediaSession からのイベントとカスタム コマンドの追加のコールバックを定義します。たとえば、セッションがカスタム コマンドを送信した場合は onCustomCommand()、セッションが使用可能なセッション コマンドを変更した場合は onAvailableSessionCommandsChanged()、コントローラがセッションから切断された場合は onDisconnected() です。
Builder を使用してコントローラをビルドするときに、MediaController.Listener を設定できます。
Kotlin
MediaController.Builder(context, sessionToken)
.setListener(
object : MediaController.Listener {
override fun onCustomCommand(
controller: MediaController,
command: SessionCommand,
args: Bundle,
): ListenableFuture<SessionResult> {
// Handle custom command.
return Futures.immediateFuture(SessionResult(SessionResult.RESULT_SUCCESS))
}
override fun onDisconnected(controller: MediaController) {
// Handle disconnection.
}
}
)
.buildAsync()
Java
new MediaController.Builder(context, sessionToken)
.setListener(
new MediaController.Listener() {
@Override
public ListenableFuture<SessionResult> onCustomCommand(
MediaController controller, SessionCommand command, Bundle args) {
// Handle custom command.
return Futures.immediateFuture(new SessionResult(SessionResult.RESULT_SUCCESS));
}
@Override
public void onDisconnected(MediaController controller) {
// Handle disconnection.
}
})
.buildAsync();
他のコンポーネントと同様に、Activity や Fragment の onStop() メソッドなど、MediaController が不要になったらリリースすることを忘れないでください。
Kotlin
MediaController.releaseFuture(controllerFuture)
Java
MediaController.releaseFuture(controllerFuture);
コントローラをリリースしても、セッションに送信された保留中のコマンドはすべて配信されます。これらのコマンドが処理されるか、タイムアウト期間が経過するかのいずれか早い方のタイミングで、セッション サービスからバインドが解除されます。
MediaBrowser
MediaBrowser は MediaController が提供する機能の上に構築され、メディアアプリの MediaLibraryService が提供するメディア ライブラリのブラウジングも可能にします。
MediaBrowser を作成
Kotlin
val browserFuture = MediaBrowser.Builder(context, sessionToken).buildAsync()
browserFuture.addListener({
// MediaBrowser is available here with browserFuture.get()
}, MoreExecutors.directExecutor())
Java
ListenableFuture<MediaBrowser> browserFuture =
new MediaBrowser.Builder(context, sessionToken).buildAsync();
browserFuture.addListener(() -> {
// MediaBrowser is available here with browserFuture.get()
}, MoreExecutors.directExecutor());
MediaBrowser を使用する
メディアアプリのコンテンツ ライブラリの閲覧を開始するには、まず getLibraryRoot() でルートノードを取得します。
Kotlin
// Get the library root to start browsing the library tree.
val rootFuture = mediaBrowser.getLibraryRoot(/* params= */ null)
rootFuture.addListener({
// Root node MediaItem is available here with rootFuture.get().value
}, MoreExecutors.directExecutor())
Java
// Get the library root to start browsing the library tree.
ListenableFuture<LibraryResult<MediaItem>> rootFuture =
mediaBrowser.getLibraryRoot(/* params= */ null);
rootFuture.addListener(() -> {
// Root node MediaItem is available here with rootFuture.get().value
}, MoreExecutors.directExecutor());
ライブラリ内の MediaItem の子を getChildren() で取得することで、メディア ライブラリ内を移動できます。たとえば、ルートノード MediaItem の子を取得するには、次のようにします。
Kotlin
// Get the library root to start browsing the library tree.
val childrenFuture =
mediaBrowser.getChildren(rootMediaItem.mediaId, 0, Int.MAX_VALUE, null)
childrenFuture.addListener({
// List of children MediaItem nodes is available here with
// childrenFuture.get().value
}, MoreExecutors.directExecutor())
Java
ListenableFuture<LibraryResult<ImmutableList<MediaItem>>> childrenFuture =
mediaBrowser.getChildren(rootMediaItem.mediaId, 0, Integer.MAX_VALUE, null);
childrenFuture.addListener(() -> {
// List of children MediaItem nodes is available here with
// childrenFuture.get().value
}, MoreExecutors.directExecutor());
別のメディアアプリの再生コントロールを表示する
別のメディアアプリのボタンを含む UI コントロールを表示する場合は、そのアプリの宣言されたメディアボタンの優先設定に従うことが重要です。
アプリの優先設定と UI の制約や要件を解決する最善の方法は、CommandButton.DisplayConstraints を使用することです。UI で実行できる操作の制限を定義できます。また、resolve メソッドは、アイコン、位置、意図したアクションとともに表示するボタンの明確なリストを提供します。