はじめに
音楽や動画を扱うアプリではExoPlayerとMedia Sessionを組み合わせることが多いと思います。
そのため、ExoPlayerにはMedia SessionのCallbackと同期してExoPlayerの再生/停止などの制御を行うExoPlayer MediaSession extensionという拡張機能が用意されています。
ExoPlayer MediaSession extension
このコアとなっているのはMediaSessionConnector
というクラスで、このクラスがExoPlayerとMedia Sessionを接続する役割を担っています。
このクラスを使って再生/停止制御をしようと思ったときにハマった部分があったので、その内容を以下に記載します。
r2.9.6までonPlay()/onPause()はExoPlayerの制御を行ってくれなかった
冒頭にも記載した通り、MediaSessionConnector
はMedia SessionのCallbackと同期してExoPlayerの再生/停止などの制御を行うときのコアとなるクラスです。
利用するときの最低限の実装は以下のような感じになります(onGetRoot()
とonLoadChildren()
は省略)。
class SampleMediaBrowserService : MediaBrowserServiceCompat() {
private lateinit var exoPlayer: SimpleExoPlayer
private lateinit var mediaSession: MediaSessionCompat
override onCreate() {
// ExoPlayerの初期化
exoPlayer = SimpleExoPlayer.newSimpleInstance(this)
// MediaSessionの初期化
mediaSession = MediaSessionCompat(this, "media_session").apply {
setFlags(
MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS
or MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS
)
setSessionToken(sessionToken)
isActive = true
...
}
// MediaSessionConnectorの初期化
// 必要に応じて各種Callbackをセットする
// 例:PlaybackPreparer、PlaybackControllerなど
MediaSessionConnector(mediaSession, /* playbackController= */ null).apply {
setPlayer(exoPlayer, /* playbackPreparer= */ null)
...
}
}
...
}
このように設定することでExoPlayerの再生/停止制御を行ってくれるとてっきり思っていたのですが、どうやらそうではなく、`MediaSessionConnector`の処理としてはMedia Session側に処理を委譲しているだけでした。 ソースコード全体は[こちら](https://github.com/google/ExoPlayer/blob/r2.9.6/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.java)から確認できます。
@Override
public void onPlay() {
if (canDispatchToPlaybackController(PlaybackStateCompat.ACTION_PLAY)) {
playbackController.onPlay(player);
}
}
@Override
public void onPause() {
if (canDispatchToPlaybackController(PlaybackStateCompat.ACTION_PAUSE)) {
playbackController.onPause(player);
}
}
そのため、**Media SessionにCallback(PlaybackController)をセットし、その実装の中でExoPlayerに対して自前で再生/停止制御を行ってあげなければなりません**。 (正直「マジかよ…overrideしないといけないメソッド増えてむしろ分かりづらくなるやん…」と思い、一旦は使うのをやめてしまいました。)
r2.10.0からはonPlay()/onPause()はExoPlayerの制御を行ってくれるようになった
ところが、r2.10.0からはMediaSessionConnector
内で再生/停止制御を行ってくれる実装になっていました。ソースコード全体はこちらから確認できます。
@Override
public void onPlay() {
if (canDispatchPlaybackAction(PlaybackStateCompat.ACTION_PLAY)) {
if (player.getPlaybackState() == Player.STATE_IDLE) {
if (playbackPreparer != null) {
playbackPreparer.onPrepare();
}
} else if (player.getPlaybackState() == Player.STATE_ENDED) {
controlDispatcher.dispatchSeekTo(player, player.getCurrentWindowIndex(), C.TIME_UNSET);
}
controlDispatcher.dispatchSetPlayWhenReady(player, /* playWhenReady= */ true);
}
}
@Override
public void onPause() {
if (canDispatchPlaybackAction(PlaybackStateCompat.ACTION_PAUSE)) {
controlDispatcher.dispatchSetPlayWhenReady(player, /* playWhenReady= */ false);
}
}
おわりに
ExoPlayerはバージョンアップの度に結構な破壊的変更が入るので、現在使っているバージョン次第ではさくっとアップデートできる場合とそうでない場合があるとは思いますが、これでやっとExoPlayerに対して自前で再生/停止制御を行わずに済みそうです。