playback: make mediasession rely on exoplayer
Make PlaybackSessionConnector also take events from ExoPlayer as it used to with MediaSessionConnector. This improves reliability somewhat at the cost of making the code even more hideous.
This commit is contained in:
parent
58eee7a891
commit
9aabfe2294
3 changed files with 36 additions and 11 deletions
|
@ -234,8 +234,8 @@ class PlaybackStateManager private constructor() {
|
||||||
private fun updatePlayback(song: Song, shouldPlay: Boolean = true) {
|
private fun updatePlayback(song: Song, shouldPlay: Boolean = true) {
|
||||||
mIsInUserQueue = false
|
mIsInUserQueue = false
|
||||||
|
|
||||||
mPosition = 0
|
|
||||||
mSong = song
|
mSong = song
|
||||||
|
mPosition = 0
|
||||||
|
|
||||||
setPlaying(shouldPlay)
|
setPlaying(shouldPlay)
|
||||||
}
|
}
|
||||||
|
|
|
@ -112,7 +112,7 @@ class PlaybackService : Service(), Player.Listener, PlaybackStateManager.Callbac
|
||||||
isActive = true
|
isActive = true
|
||||||
}
|
}
|
||||||
|
|
||||||
connector = PlaybackSessionConnector(this, mediaSession)
|
connector = PlaybackSessionConnector(this, player, mediaSession)
|
||||||
|
|
||||||
// Then the notif/headset callbacks
|
// Then the notif/headset callbacks
|
||||||
IntentFilter().apply {
|
IntentFilter().apply {
|
||||||
|
@ -204,6 +204,12 @@ class PlaybackService : Service(), Player.Listener, PlaybackStateManager.Callbac
|
||||||
playbackManager.next()
|
playbackManager.next()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onPositionDiscontinuity(reason: Int) {
|
||||||
|
if (reason == Player.DISCONTINUITY_REASON_SEEK) {
|
||||||
|
playbackManager.setPosition(player.currentPosition)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// --- PLAYBACK STATE CALLBACK OVERRIDES ---
|
// --- PLAYBACK STATE CALLBACK OVERRIDES ---
|
||||||
|
|
||||||
override fun onSongUpdate(song: Song?) {
|
override fun onSongUpdate(song: Song?) {
|
||||||
|
|
|
@ -6,21 +6,28 @@ import android.os.SystemClock
|
||||||
import android.support.v4.media.MediaMetadataCompat
|
import android.support.v4.media.MediaMetadataCompat
|
||||||
import android.support.v4.media.session.MediaSessionCompat
|
import android.support.v4.media.session.MediaSessionCompat
|
||||||
import android.support.v4.media.session.PlaybackStateCompat
|
import android.support.v4.media.session.PlaybackStateCompat
|
||||||
|
import com.google.android.exoplayer2.Player
|
||||||
import org.oxycblt.auxio.coil.loadBitmap
|
import org.oxycblt.auxio.coil.loadBitmap
|
||||||
import org.oxycblt.auxio.music.Song
|
import org.oxycblt.auxio.music.Song
|
||||||
import org.oxycblt.auxio.playback.state.LoopMode
|
import org.oxycblt.auxio.playback.state.LoopMode
|
||||||
import org.oxycblt.auxio.playback.state.PlaybackStateManager
|
import org.oxycblt.auxio.playback.state.PlaybackStateManager
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Nightmarish class that coordinates communication between [MediaSessionCompat], [Player],
|
||||||
|
* and [PlaybackStateManager]
|
||||||
|
*/
|
||||||
class PlaybackSessionConnector(
|
class PlaybackSessionConnector(
|
||||||
private val context: Context,
|
private val context: Context,
|
||||||
|
private val player: Player,
|
||||||
private val mediaSession: MediaSessionCompat
|
private val mediaSession: MediaSessionCompat
|
||||||
) : PlaybackStateManager.Callback, MediaSessionCompat.Callback() {
|
) : PlaybackStateManager.Callback, Player.Listener, MediaSessionCompat.Callback() {
|
||||||
private val playbackManager = PlaybackStateManager.getInstance()
|
private val playbackManager = PlaybackStateManager.getInstance()
|
||||||
private val emptyMetadata = MediaMetadataCompat.Builder().build()
|
private val emptyMetadata = MediaMetadataCompat.Builder().build()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
mediaSession.setCallback(this)
|
mediaSession.setCallback(this)
|
||||||
playbackManager.addCallback(this)
|
playbackManager.addCallback(this)
|
||||||
|
player.addListener(this)
|
||||||
|
|
||||||
onSongUpdate(playbackManager.song)
|
onSongUpdate(playbackManager.song)
|
||||||
onPlayingUpdate(playbackManager.isPlaying)
|
onPlayingUpdate(playbackManager.isPlaying)
|
||||||
|
@ -28,6 +35,7 @@ class PlaybackSessionConnector(
|
||||||
|
|
||||||
fun release() {
|
fun release() {
|
||||||
playbackManager.removeCallback(this)
|
playbackManager.removeCallback(this)
|
||||||
|
player.removeListener(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- MEDIASESSION CALLBACKS ---
|
// --- MEDIASESSION CALLBACKS ---
|
||||||
|
@ -49,7 +57,7 @@ class PlaybackSessionConnector(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSeekTo(position: Long) {
|
override fun onSeekTo(position: Long) {
|
||||||
playbackManager.seekTo(position)
|
player.seekTo(position)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onRewind() {
|
override fun onRewind() {
|
||||||
|
@ -83,8 +91,6 @@ class PlaybackSessionConnector(
|
||||||
// --- PLAYBACKSTATEMANAGER CALLBACKS ---
|
// --- PLAYBACKSTATEMANAGER CALLBACKS ---
|
||||||
|
|
||||||
override fun onSongUpdate(song: Song?) {
|
override fun onSongUpdate(song: Song?) {
|
||||||
invalidateSessionState()
|
|
||||||
|
|
||||||
if (song == null) {
|
if (song == null) {
|
||||||
mediaSession.setMetadata(emptyMetadata)
|
mediaSession.setMetadata(emptyMetadata)
|
||||||
return
|
return
|
||||||
|
@ -110,19 +116,32 @@ class PlaybackSessionConnector(
|
||||||
invalidateSessionState()
|
invalidateSessionState()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSeek(position: Long) {
|
// --
|
||||||
invalidateSessionState()
|
|
||||||
|
override fun onEvents(player: Player, events: Player.Events) {
|
||||||
|
if (events.containsAny(
|
||||||
|
Player.EVENT_POSITION_DISCONTINUITY,
|
||||||
|
Player.EVENT_PLAYBACK_STATE_CHANGED,
|
||||||
|
Player.EVENT_PLAY_WHEN_READY_CHANGED,
|
||||||
|
Player.EVENT_IS_PLAYING_CHANGED,
|
||||||
|
Player.EVENT_REPEAT_MODE_CHANGED,
|
||||||
|
Player.EVENT_PLAYBACK_PARAMETERS_CHANGED
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
invalidateSessionState()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- MISC ---
|
// --- MISC ---
|
||||||
|
|
||||||
private fun invalidateSessionState() {
|
private fun invalidateSessionState() {
|
||||||
// Position updates arrive faster when you upload STATE_PAUSED for some inane reason.
|
// Position updates arrive faster when you upload STATE_PAUSED for some insane reason.
|
||||||
val state = PlaybackStateCompat.Builder()
|
val state = PlaybackStateCompat.Builder()
|
||||||
.setActions(ACTIONS)
|
.setActions(ACTIONS)
|
||||||
|
.setBufferedPosition(player.bufferedPosition)
|
||||||
.setState(
|
.setState(
|
||||||
PlaybackStateCompat.STATE_PAUSED,
|
PlaybackStateCompat.STATE_PAUSED,
|
||||||
playbackManager.position,
|
player.currentPosition,
|
||||||
1.0f,
|
1.0f,
|
||||||
SystemClock.elapsedRealtime()
|
SystemClock.elapsedRealtime()
|
||||||
)
|
)
|
||||||
|
@ -131,7 +150,7 @@ class PlaybackSessionConnector(
|
||||||
|
|
||||||
state.setState(
|
state.setState(
|
||||||
getPlayerState(),
|
getPlayerState(),
|
||||||
playbackManager.position,
|
player.currentPosition,
|
||||||
1.0f,
|
1.0f,
|
||||||
SystemClock.elapsedRealtime()
|
SystemClock.elapsedRealtime()
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in a new issue