playback: fix position polling bug

Fix a bug where position polling would stop when the audio focus
state changed.
This commit is contained in:
OxygenCobalt 2022-04-28 20:04:10 -06:00
parent bcec9272d3
commit 3d03bf9b7e
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47

View file

@ -47,9 +47,6 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.conflate
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.takeWhile
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.oxycblt.auxio.BuildConfig import org.oxycblt.auxio.BuildConfig
import org.oxycblt.auxio.IntegerTable import org.oxycblt.auxio.IntegerTable
@ -76,8 +73,6 @@ import org.oxycblt.auxio.widgets.WidgetProvider
* *
* TODO: Move all external exposal from passing around PlaybackStateManager to passing around the * TODO: Move all external exposal from passing around PlaybackStateManager to passing around the
* MediaMetadata instance. Generally makes it easier to encapsulate this class. * MediaMetadata instance. Generally makes it easier to encapsulate this class.
*
* TODO: Move restore and file opening to service
*/ */
class PlaybackService : class PlaybackService :
Service(), Player.Listener, PlaybackStateManager.Callback, SettingsManager.Callback { Service(), Player.Listener, PlaybackStateManager.Callback, SettingsManager.Callback {
@ -103,7 +98,8 @@ class PlaybackService :
private var isForeground = false private var isForeground = false
private val serviceJob = Job() private val serviceJob = Job()
private val serviceScope = CoroutineScope(serviceJob + Dispatchers.Main) private val positionScope = CoroutineScope(serviceJob + Dispatchers.Main)
private val saveScope = CoroutineScope(serviceJob + Dispatchers.Main)
// --- SERVICE OVERRIDES --- // --- SERVICE OVERRIDES ---
@ -128,13 +124,13 @@ class PlaybackService :
player = newPlayer() player = newPlayer()
player.addListener(this@PlaybackService) player.addListener(this@PlaybackService)
player.setAudioAttributes(
AudioAttributes.Builder()
.setUsage(C.USAGE_MEDIA)
.setContentType(C.CONTENT_TYPE_MUSIC)
.build(),
true)
positionScope.launch {
while (true) {
playbackManager.setPosition(player.currentPosition)
delay(POS_POLL_INTERVAL)
}
}
// --- SYSTEM SETUP --- // --- SYSTEM SETUP ---
widgets = WidgetController(this) widgets = WidgetController(this)
@ -198,9 +194,7 @@ class PlaybackService :
// The service coroutines last job is to save the state to the DB, before terminating itself // The service coroutines last job is to save the state to the DB, before terminating itself
// FIXME: This is a terrible idea, move this to when the user closes the notification // FIXME: This is a terrible idea, move this to when the user closes the notification
// FIXME: Why not also encourage the user to disable battery optimizations while were saveScope.launch {
// at it? Would help prevent state saving issues to an extent.
serviceScope.launch {
playbackManager.saveStateToDatabase(this@PlaybackService) playbackManager.saveStateToDatabase(this@PlaybackService)
serviceJob.cancel() serviceJob.cancel()
} }
@ -219,7 +213,6 @@ class PlaybackService :
override fun onPlaybackStateChanged(state: Int) { override fun onPlaybackStateChanged(state: Int) {
when (state) { when (state) {
Player.STATE_READY -> startPolling()
Player.STATE_ENDED -> { Player.STATE_ENDED -> {
if (playbackManager.loopMode == LoopMode.TRACK) { if (playbackManager.loopMode == LoopMode.TRACK) {
playbackManager.loop() playbackManager.loop()
@ -236,7 +229,11 @@ class PlaybackService :
playbackManager.next() playbackManager.next()
} }
override fun onPositionDiscontinuity(reason: Int) { override fun onPositionDiscontinuity(
oldPosition: Player.PositionInfo,
newPosition: Player.PositionInfo,
reason: Int
) {
if (reason == Player.DISCONTINUITY_REASON_SEEK) { if (reason == Player.DISCONTINUITY_REASON_SEEK) {
playbackManager.setPosition(player.currentPosition) playbackManager.setPosition(player.currentPosition)
} }
@ -282,13 +279,7 @@ class PlaybackService :
} }
override fun onPlayingUpdate(isPlaying: Boolean) { override fun onPlayingUpdate(isPlaying: Boolean) {
if (isPlaying && !player.isPlaying) { player.playWhenReady = isPlaying
player.play()
startPolling()
} else {
player.pause()
}
notification.setPlaying(isPlaying) notification.setPlaying(isPlaying)
startForegroundOrNotify() startForegroundOrNotify()
} }
@ -371,6 +362,12 @@ class PlaybackService :
return ExoPlayer.Builder(this, audioRenderer) return ExoPlayer.Builder(this, audioRenderer)
.setMediaSourceFactory(DefaultMediaSourceFactory(this, extractorsFactory)) .setMediaSourceFactory(DefaultMediaSourceFactory(this, extractorsFactory))
.setWakeMode(C.WAKE_MODE_LOCAL) .setWakeMode(C.WAKE_MODE_LOCAL)
.setAudioAttributes(
AudioAttributes.Builder()
.setUsage(C.USAGE_MEDIA)
.setContentType(C.CONTENT_TYPE_MUSIC)
.build(),
true)
.build() .build()
} }
@ -390,24 +387,6 @@ class PlaybackService :
widgets.update() widgets.update()
} }
/** Start polling the position on a coroutine. */
private fun startPolling() {
val pollFlow =
flow {
while (true) {
emit(player.currentPosition)
delay(POS_POLL_INTERVAL)
}
}
.conflate()
serviceScope.launch {
pollFlow.takeWhile { player.isPlaying }.collect { pos ->
playbackManager.setPosition(pos)
}
}
}
/** /**
* Bring the service into the foreground and show the notification, or refresh the notification. * Bring the service into the foreground and show the notification, or refresh the notification.
*/ */
@ -519,7 +498,7 @@ class PlaybackService :
} }
companion object { companion object {
private const val POS_POLL_INTERVAL = 500L private const val POS_POLL_INTERVAL = 1000L
const val ACTION_LOOP = BuildConfig.APPLICATION_ID + ".action.LOOP" const val ACTION_LOOP = BuildConfig.APPLICATION_ID + ".action.LOOP"
const val ACTION_SHUFFLE = BuildConfig.APPLICATION_ID + ".action.SHUFFLE" const val ACTION_SHUFFLE = BuildConfig.APPLICATION_ID + ".action.SHUFFLE"