Add playback updates to PlaybackService

Add the ability for PlaybackService to move to the next song when the current one ends, update the duration, and also be played/paused.
This commit is contained in:
OxygenCobalt 2020-10-26 11:04:22 -06:00
parent 42325c456e
commit 1afaae7b0a
5 changed files with 63 additions and 7 deletions

View file

@ -13,8 +13,8 @@ import org.oxycblt.auxio.R
import org.oxycblt.auxio.databinding.FragmentAlbumDetailBinding
import org.oxycblt.auxio.detail.adapters.DetailSongAdapter
import org.oxycblt.auxio.music.MusicStore
import org.oxycblt.auxio.playback.state.PlaybackMode
import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.playback.state.PlaybackMode
import org.oxycblt.auxio.theme.applyDivider
import org.oxycblt.auxio.theme.disable

View file

@ -25,8 +25,8 @@ import org.oxycblt.auxio.music.BaseModel
import org.oxycblt.auxio.music.Genre
import org.oxycblt.auxio.music.MusicStore
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.playback.state.PlaybackMode
import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.playback.state.PlaybackMode
import org.oxycblt.auxio.theme.applyColor
import org.oxycblt.auxio.theme.applyDivider
import org.oxycblt.auxio.theme.resolveAttr

View file

@ -8,6 +8,15 @@ import android.os.IBinder
import com.google.android.exoplayer2.MediaItem
import com.google.android.exoplayer2.Player
import com.google.android.exoplayer2.SimpleExoPlayer
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.conflate
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.takeWhile
import kotlinx.coroutines.launch
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.music.toURI
import org.oxycblt.auxio.playback.state.PlaybackStateCallback
@ -26,6 +35,11 @@ class PlaybackService : Service(), Player.EventListener, PlaybackStateCallback {
private val mBinder = LocalBinder()
private val playbackManager = PlaybackStateManager.getInstance()
private val serviceJob = Job()
private val serviceScope = CoroutineScope(
serviceJob + Dispatchers.Main
)
override fun onBind(intent: Intent): IBinder {
return mBinder
}
@ -41,17 +55,59 @@ class PlaybackService : Service(), Player.EventListener, PlaybackStateCallback {
player.release()
playbackManager.removeCallback(this)
serviceJob.cancel()
}
override fun onSongUpdate(song: Song?) {
song?.let {
val item = MediaItem.fromUri(it.id.toURI())
song?.let { song ->
val item = MediaItem.fromUri(song.id.toURI())
player.setMediaItem(item)
player.prepare()
player.play()
}
}
override fun onPlayingUpdate(isPlaying: Boolean) {
if (isPlaying) {
player.play()
startPollingPosition()
} else {
player.pause()
}
}
fun doSeek(position: Long) {
player.seekTo(position * 1000)
}
// Awful Hack to get position polling to work, as exoplayer does not provide any
// onPositionChanged callback for some inane reason.
// FIXME: Consider using exoplayer UI elements here, don't be surprised if this causes problems.
private fun pollCurrentPosition() = flow {
while (player.currentPosition <= player.duration) {
emit(player.currentPosition)
delay(500)
}
}.conflate()
private fun startPollingPosition() {
serviceScope.launch {
pollCurrentPosition().takeWhile { true }.collect {
playbackManager.setPosition(it / 1000)
}
}
}
override fun onPlaybackStateChanged(state: Int) {
if (state == Player.STATE_ENDED) {
playbackManager.skipNext()
} else if (state == Player.STATE_READY) {
startPollingPosition()
}
}
inner class LocalBinder : Binder() {
fun getService() = this@PlaybackService
}

View file

@ -82,9 +82,7 @@ class PlaybackViewModel(private val context: Context) : ViewModel(), PlaybackSta
playbackIntent = Intent(context, PlaybackService::class.java).also {
context.bindService(it, connection, Context.BIND_AUTO_CREATE)
}
}
init {
playbackManager.addCallback(this)
}
@ -132,6 +130,8 @@ class PlaybackViewModel(private val context: Context) : ViewModel(), PlaybackSta
fun updatePositionWithProgress(progress: Int) {
playbackManager.setPosition(progress.toLong())
playbackService.doSeek(progress.toLong())
}
// --- QUEUE FUNCTIONS ---

View file

@ -10,8 +10,8 @@ import androidx.fragment.app.activityViewModels
import org.oxycblt.auxio.R
import org.oxycblt.auxio.databinding.FragmentSongsBinding
import org.oxycblt.auxio.music.MusicStore
import org.oxycblt.auxio.playback.state.PlaybackMode
import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.playback.state.PlaybackMode
import org.oxycblt.auxio.theme.applyDivider
class SongsFragment : Fragment() {