playback: reattach settings to player

It's mostly identical to prior, albiet pausing on repeat now leaves the
player position at the end of the song rather than the beginning.
That's the only regression I couldn't figure out how to resolve.
This commit is contained in:
Alexander Capehart 2024-01-13 20:26:02 -07:00
parent bd240f967e
commit b2d71f8903
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
5 changed files with 54 additions and 29 deletions

View file

@ -66,6 +66,8 @@ interface PlaybackSettings : Settings<PlaybackSettings.Listener> {
fun onNotificationActionChanged() {}
/** Called when [barAction] has changed. */
fun onBarActionChanged() {}
/** Called when [pauseOnRepeat] has changed. */
fun onPauseOnRepeatChanged() {}
}
}
@ -187,6 +189,10 @@ class PlaybackSettingsImpl @Inject constructor(@ApplicationContext context: Cont
logD("Dispatching bar action change")
listener.onBarActionChanged()
}
getString(R.string.set_key_repeat_pause) -> {
logD("Dispatching pause on repeat change")
listener.onPauseOnRepeatChanged()
}
}
}

View file

@ -34,8 +34,6 @@ interface PlaybackStateHolder {
fun resolveQueue(): RawQueue
val isShuffled: Boolean
val audioSessionId: Int
fun newPlayback(queue: List<Song>, start: Song?, parent: MusicParent?, shuffled: Boolean)

View file

@ -187,9 +187,9 @@ interface PlaybackStateManager {
* [PlaybackStateHolder].
*
* @param stateHolder The [PlaybackStateHolder] to synchronize with. Must be the current
* [PlaybackStateHolder]. Does nothing if invoked by another [PlaybackStateHolder]
* implementation.
* @param ack The [StateAck] to acknowledge.
* [PlaybackStateHolder]. Does nothing if invoked by another [PlaybackStateHolder]
* implementation.
* @param ack The [StateAck] to acknowledge.
*/
fun ack(stateHolder: PlaybackStateHolder, ack: StateAck)
@ -269,8 +269,8 @@ interface PlaybackStateManager {
fun onQueueChanged(queue: List<Song>, index: Int, change: QueueChange) {}
/**
* Called when the queue has changed in a non-trivial manner (such as re-shuffling), but
* the currently playing [Song] has not.
* Called when the queue has changed in a non-trivial manner (such as re-shuffling), but the
* currently playing [Song] has not.
*
* @param queue The songs of the new queue.
* @param index The new index of the currently playing [Song].
@ -407,6 +407,8 @@ class PlaybackStateManagerImpl @Inject constructor() : PlaybackStateManager {
}
this.stateHolder = stateHolder
// TODO: Re-init player
}
@Synchronized
@ -627,7 +629,7 @@ class PlaybackStateManagerImpl @Inject constructor() : PlaybackStateManager {
)
if (change.type == QueueChange.Type.SONG) {
playing(true)
stateHolder.playing(true)
}
listeners.forEach {
@ -640,7 +642,7 @@ class PlaybackStateManagerImpl @Inject constructor() : PlaybackStateManager {
stateMirror.copy(
queue = rawQueue.resolveSongs(),
index = rawQueue.resolveIndex(),
isShuffled = stateHolder.isShuffled,
isShuffled = rawQueue.isShuffled,
rawQueue = rawQueue)
listeners.forEach {
it.onQueueReordered(
@ -654,7 +656,7 @@ class PlaybackStateManagerImpl @Inject constructor() : PlaybackStateManager {
parent = stateHolder.parent,
queue = rawQueue.resolveSongs(),
index = rawQueue.resolveIndex(),
isShuffled = stateHolder.isShuffled,
isShuffled = rawQueue.isShuffled,
rawQueue = rawQueue)
listeners.forEach {
it.onNewPlayback(

View file

@ -24,7 +24,6 @@ import androidx.media3.common.Player
import androidx.media3.exoplayer.ExoPlayer
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.playback.state.RawQueue
import org.oxycblt.auxio.playback.state.RepeatMode
import org.oxycblt.auxio.util.logD
val ExoPlayer.song
@ -33,19 +32,9 @@ val ExoPlayer.song
fun ExoPlayer.resolveQueue(): RawQueue {
val heap = (0 until mediaItemCount).map { getMediaItemAt(it).song }
val shuffledMapping = if (shuffleModeEnabled) unscrambleQueueIndices() else emptyList()
logD(shuffledMapping)
return RawQueue(heap, shuffledMapping, currentMediaItemIndex)
}
val ExoPlayer.repeat: RepeatMode
get() =
when (repeatMode) {
Player.REPEAT_MODE_OFF -> RepeatMode.NONE
Player.REPEAT_MODE_ONE -> RepeatMode.TRACK
Player.REPEAT_MODE_ALL -> RepeatMode.ALL
else -> throw IllegalStateException("Unknown repeat mode: $repeatMode")
}
fun ExoPlayer.orderedQueue(queue: Collection<Song>, start: Song?) {
clearMediaItems()
shuffleModeEnabled = false

View file

@ -88,6 +88,7 @@ class PlaybackService :
Service(),
Player.Listener,
PlaybackStateHolder,
PlaybackSettings.Listener,
MediaSessionComponent.Listener,
MusicRepository.UpdateListener {
// Player components
@ -156,6 +157,7 @@ class PlaybackService :
playbackManager.registerStateHolder(this)
musicRepository.addUpdateListener(this)
mediaSessionComponent.registerListener(this)
playbackSettings.registerListener(this)
val intentFilter =
IntentFilter().apply {
@ -197,6 +199,7 @@ class PlaybackService :
playbackManager.playing(false)
playbackManager.unregisterStateHolder(this)
musicRepository.removeUpdateListener(this)
playbackSettings.unregisterListener(this)
unregisterReceiver(systemReceiver)
serviceJob.cancel()
@ -217,9 +220,6 @@ class PlaybackService :
// --- PLAYBACKSTATEHOLDER OVERRIDES ---
override val repeatMode
get() = player.repeat
override val progression: Progression
get() =
player.song?.let {
@ -232,10 +232,16 @@ class PlaybackService :
}
?: Progression.nil()
override var parent: MusicParent? = null
override val repeatMode
get() =
when (val repeatMode = player.repeatMode) {
Player.REPEAT_MODE_OFF -> RepeatMode.NONE
Player.REPEAT_MODE_ONE -> RepeatMode.TRACK
Player.REPEAT_MODE_ALL -> RepeatMode.ALL
else -> throw IllegalStateException("Unknown repeat mode: $repeatMode")
}
override val isShuffled
get() = player.shuffleModeEnabled
override var parent: MusicParent? = null
override fun resolveQueue() = player.resolveQueue()
@ -272,6 +278,7 @@ class PlaybackService :
RepeatMode.TRACK -> Player.REPEAT_MODE_ONE
}
playbackManager.ack(this, StateAck.RepeatModeChanged)
updatePauseOnRepeat()
}
override fun seekTo(positionMs: Long) {
@ -284,7 +291,11 @@ class PlaybackService :
}
override fun prev() {
player.seekToPrevious()
if (playbackSettings.rewindWithPrev) {
player.seekToPrevious()
} else {
player.seekToPreviousMediaItem()
}
playbackManager.ack(this, StateAck.IndexMoved)
}
@ -398,6 +409,15 @@ class PlaybackService :
}
}
override fun onPlaybackStateChanged(playbackState: Int) {
super.onPlaybackStateChanged(playbackState)
if (playbackState == Player.STATE_ENDED && player.repeatMode == Player.REPEAT_MODE_OFF) {
goto(0)
player.pause()
}
}
override fun onEvents(player: Player, events: Player.Events) {
super.onEvents(player, events)
@ -418,6 +438,12 @@ class PlaybackService :
playbackManager.next()
}
// --- OTHER OVERRIDES ---
override fun onPauseOnRepeatChanged() {
updatePauseOnRepeat()
}
override fun onMusicChanges(changes: MusicRepository.Changes) {
if (changes.deviceLibrary && musicRepository.deviceLibrary != null) {
// We now have a library, see if we have anything we need to do.
@ -428,6 +454,11 @@ class PlaybackService :
// --- OTHER FUNCTIONS ---
private fun updatePauseOnRepeat() {
player.pauseAtEndOfMediaItems =
playbackManager.repeatMode == RepeatMode.TRACK && playbackSettings.pauseOnRepeat
}
private fun broadcastAudioEffectAction(event: String) {
logD("Broadcasting AudioEffect event: $event")
sendBroadcast(
@ -556,6 +587,5 @@ class PlaybackService :
const val ACTION_PLAY_PAUSE = BuildConfig.APPLICATION_ID + ".action.PLAY_PAUSE"
const val ACTION_SKIP_NEXT = BuildConfig.APPLICATION_ID + ".action.NEXT"
const val ACTION_EXIT = BuildConfig.APPLICATION_ID + ".action.EXIT"
private const val REWIND_THRESHOLD = 3000L
}
}