MediaSessionManager は端末上で有効な media session を提供するクラスです。通常のアプリであれば、NotificationListenerService と組み合わせて現状どの media session が端末上で動いているかを取得する目的で使います。
端末上で動いている media session を取得する方法は次の2種類です。
MediaSessionManager.OnActiveSessionsChangedListener を使う
MediaSessionManager#getActiveSessions() を使う
どちらも media session に紐づいた MediaController のリストが得られます。
media session は音楽アプリが作成・保持し Android システムに登録するもので、音楽アプリが複数インストールされた端末では当然複数の異なる media session が存在することになります(同一のアプリが複数の media session を持つことも想定されているようですが、ここではひとつの音楽アプリがひとつの media session を持つ前提で考えます)。
MediaController は media session に紐づくので、複数の音楽アプリが動いているときには MediaController も複数存在します。media session 自体は排他的な動きをしない *1 ので、MediaSessionManager は MediaController をリストに詰めて返します。ただし、同じデバイスで複数のアプリが同時に音楽を再生できるわけではなく、ある音楽アプリが再生を開始すると他の音楽アプリは再生を停止します。
それでは、リストで得られる MediaController から現在再生コントロールの権限を握っているものを選び取るにはどうしたらよいでしょうか。
MediaSessionManager のドキュメントでは、MediaController のリストは重要度でソートされリストの先頭が最も重要な MediaController となることが書かれています。
この「重要度」を決めるファクターが何なのか、具体的な言及がないためいざ使おうとすると困るのですが、AOSP のコードを追いかけていくとソート順を決めるファクターに言及があります。
android.googlesource.com
この Javadoc からは PlaybackState#isActive() が true なものが先頭に来ることがわかります。
PlaybackState#isActive() は、現在再生リストの先頭にあり media session にも登録されている media item を読み込み中、再生中だったり、次の曲へ曲送りをしている最中だったりする場合に true になります。
ここで次のような操作をしたときに MediaSessionMangager#OnActiveSessionsChangedListener の動きを観測すると、Javadoc の記述通りの動きをしていることがわかります。ただし再生状態の変化が必ずしも OnActiveSessionsChangedListener を呼ばないことに気をつけます。
- 音楽アプリ A を起動する
- OnActiveSessionsChangedListener で得られるリスト: [音楽アプリ A の MediaController]
- 音楽アプリ A で再生を開始する
- OnActiveSessionsChangedListener は呼ばれない
- 音楽アプリ B を起動する
- OnActiveSessionsChangedListener で得られるリスト: [音楽アプリ A の MediaController, 音楽アプリ B の MediaController]
例えば、次のような操作をしたときも概ね想像通りリストがソートされます。
- 音楽アプリ A を起動する
- OnActiveSessionsChangedListener で得られるリスト: [音楽アプリ A の MediaController]
- 音楽アプリ A で再生を開始する
- OnActiveSessionsChangedListener は呼ばれない
- 音楽アプリ A で再生を停止する
- OnActiveSessionsChangedListener は呼ばれない
- 音楽アプリ B を起動する
- OnActiveSessionsChangedListener で得られるリスト: [音楽アプリ A の MediaController, 音楽アプリ B の MediaController]
- 音楽アプリ B で再生を開始する
- OnActiveSessionsChangedListener で得られるリスト: [音楽アプリ B の MediaController, 音楽アプリ A の MediaController]
ここまでで、 複数の MediaController からひとつ再生コントロールを握っているものを選ぶには OnActiveSessionsChangedListener 等で提供されるすべての MediaController の再生状態を監視し、 PlaybackState#isActive() が true になったものを選択すればよいことがわかります。
さて、先程の手順を少し変え、音楽アプリ A での再生停止をせず直接音楽アプリ B で再生を開始するとどうなるでしょうか。いつも次のような結果になるとは限りませんが、すこし直感に反する動きを見る場合があります。これはそれぞれの音楽アプリで再生・停止を実行するタイミングの微妙なズレで瞬間的に複数のアプリの PlaybackState#isActive() が true になってしまうケースで起こることが考えられます。
- 音楽アプリ A を起動する
- OnActiveSessionsChangedListener で得られるリスト: [音楽アプリ A の MediaController]
- 音楽アプリ B を起動する
- OnActiveSessionsChangedListener で得られるリスト: [音楽アプリ A の MediaController, 音楽アプリ B の MediaController]
- 音楽アプリ A で再生を開始する
- OnActiveSessionsChangedListener は呼ばれない
- 音楽アプリ B で再生を開始する
- OnActiveSessionsChangedListener で得られるリスト: [音楽アプリ A の MediaController, 音楽アプリ B の MediaController]
MediaSessionManager がソート順を決められないため、音楽アプリ B が先頭に来るはずが実際には音楽アプリ A が先頭のままになっています。
ここまでは瞬間的に複数の音楽アプリが再生中であると判定してしまう可能性があることを見てみましたが、実際には単なるタイミングの問題による瞬間的な事象以外にも、複数の音楽アプリが再生中になり得るケースがあります。
少し前に述べた 同じデバイスで複数のアプリが同時に音楽を再生できるわけではなく、ある音楽アプリが再生を開始すると他の音楽アプリは再生を停止する という制約とは相容れないように見えますが、 Cast に代表されるスマートデバイスを考慮に入れるとこのケースも考えなくてはなりません。
Cast 等別のデバイスで音楽を再生するとき
多くの音楽アプリが Cast に対応しており、Nest Hub などで音楽を再生できるような機能をもっています。ある音楽アプリが Cast を使って他のデバイスで音楽を再生したとき、他の音楽アプリは Android スマートフォン上(あるいは Bluetooth 等でペアリングしたヘッドセット)で音楽の再生ができるようになります。
Cast を使用して再生しているアプリも、Android スマートフォン上で再生しているアプリも、どちらも media session を active にしているため、MediaSessionManager が返す MediaController も再生中のものはすべて PlaybackState#isActive() が true になります。
このケースでどちらを選び取るかはアプリの仕様に依るところになりますが、Cast などのデバイスで再生しているのか Android スマートフォン上で再生しているかを見分けるには PlaybackInfo#getPlaybackType() を使います。
PlaybackInfo#getPlaybackType() は LOCAL か REMOTE かどちらかの定数を返してきます。LOCAL は Android スマートフォン上で再生、REMOTE は Cast などのデバイスで再生していることを示します。
ここまで述べてきた MediaController ですが、2026年3月現在、実は大きく 2 種類の MediaController があります。
- Legacy MediaController: android.media.session.MediaController で MediaSessionManager が返すもの
- Jetpack MediaController: androidx.media3.session.MediaController
現状多くの場合 Jeptack MediaController を使うことが推奨されていて、Legacy MediaController から Jetpack MediaController へ変換する便利関数も用意されていますが、少し気をつけなければいけない点があります。
Playback State
Legacy MediaController のいう Playback State は音楽データを処理する仕組みの状態(初期状態、コンテンツの読み込み中、再生可能状態など)とコンテンツの再生状態(再生中、停止中など)の2つの状態を合わせた状態を指します。
一方 Jetpack MediaController のいう Playback State にはコンテンツの再生状態再生状態は含まれず、音楽データを処理する仕組みの状態のみを表すようになっています。
よって Jetpack MediaController で再生状態の確認をする場合は MediaController#isPlaying 等別の関数・コールバックを見ることになります。
Playback Info と Device Info
Legacy MediaController が提供する Playback Info に相当するものは Jetpack MediaController では Device Info です。
どちらも Playback type として LOCAL か REMOTE かを確認する手段を提供していますが、定数の定義が微妙に異なります。
- Playback Info (定数はどちらも int)
- Device Info (定数はどちらも int)
定数の比較を確実にするため、パッケージ名・クラス名を対応する MediaController に合わせて変える必要があります。