fix(player): playback position reset on process death and playback continues playing when the device is locked

Closes #389 #390
This commit is contained in:
Jarne Demeulemeester 2023-07-09 15:15:15 +02:00
parent 58cbd9cf9d
commit 7a3b67f64b
No known key found for this signature in database
GPG key ID: 1E5C6AFBD622E9F5
4 changed files with 22 additions and 8 deletions

View file

@ -24,6 +24,7 @@
<activity
android:name=".PlayerActivity"
android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"
android:screenOrientation="sensorLandscape" />
<activity

View file

@ -30,6 +30,7 @@ abstract class BasePlayerActivity : AppCompatActivity() {
override fun onPause() {
super.onPause()
viewModel.playWhenReady = viewModel.player.playWhenReady == true
viewModel.player.playWhenReady = false
}

View file

@ -27,7 +27,6 @@ import dev.jdtech.jellyfin.mpv.TrackType
import dev.jdtech.jellyfin.utils.PlayerGestureHelper
import dev.jdtech.jellyfin.utils.PreviewScrubListener
import dev.jdtech.jellyfin.viewmodels.PlayerActivityViewModel
import timber.log.Timber
import javax.inject.Inject
import dev.jdtech.jellyfin.player.video.R as PlayerVideoR
@ -46,7 +45,6 @@ class PlayerActivity : BasePlayerActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Timber.d("Creating player activity")
binding = ActivityPlayerBinding.inflate(layoutInflater)
setContentView(binding.root)

View file

@ -5,6 +5,7 @@ import android.os.Handler
import android.os.Looper
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.media3.common.AudioAttributes
@ -44,6 +45,7 @@ constructor(
private val application: Application,
private val jellyfinRepository: JellyfinRepository,
private val appPreferences: AppPreferences,
private val savedStateHandle: SavedStateHandle,
) : ViewModel(), Player.Listener {
val player: Player
@ -71,8 +73,8 @@ constructor(
val trackSelector = DefaultTrackSelector(application)
var playWhenReady = true
private var currentMediaItemIndex = 0
private var playbackPosition: Long = 0
private var currentMediaItemIndex = savedStateHandle["mediaItemIndex"] ?: 0
private var playbackPosition: Long = savedStateHandle["position"] ?: 0
var playbackSpeed: Float = 1f
var disableSubtitle: Boolean = false
@ -116,6 +118,10 @@ constructor(
fun initializePlayer(
items: Array<PlayerItem>,
) {
// Skip initialization when there are already items
if (this.items.isNotEmpty()) {
return
}
this.items = items
player.addListener(this)
@ -156,10 +162,16 @@ constructor(
Timber.e(e)
}
val startPosition = if (playbackPosition == 0L) {
items.getOrNull(currentMediaItemIndex)?.playbackPosition ?: C.TIME_UNSET
} else {
playbackPosition
}
player.setMediaItems(
mediaItems,
currentMediaItemIndex,
items.getOrNull(currentMediaItemIndex)?.playbackPosition ?: C.TIME_UNSET,
startPosition,
)
if (appPreferences.playerMpv) { // For some reason, adding a 1ms delay between these two lines fixes a crash when playing with mpv from downloads
withContext(Dispatchers.IO) {
@ -191,9 +203,9 @@ constructor(
}
_currentTrickPlay.value = null
playWhenReady = player.playWhenReady
playbackPosition = position
currentMediaItemIndex = player.currentMediaItemIndex
playWhenReady = false
playbackPosition = 0L
currentMediaItemIndex = 0
player.removeListener(this)
player.release()
}
@ -201,6 +213,7 @@ constructor(
private fun pollPosition(player: Player) {
val playbackProgressRunnable = object : Runnable {
override fun run() {
savedStateHandle["position"] = player.currentPosition
viewModelScope.launch {
if (player.currentMediaItem != null && player.currentMediaItem!!.mediaId.isNotEmpty()) {
val itemId = UUID.fromString(player.currentMediaItem!!.mediaId)
@ -240,6 +253,7 @@ constructor(
override fun onMediaItemTransition(mediaItem: MediaItem?, reason: Int) {
Timber.d("Playing MediaItem: ${mediaItem?.mediaId}")
savedStateHandle["mediaItemIndex"] = player.currentMediaItemIndex
viewModelScope.launch {
try {
items.first { it.itemId.toString() == player.currentMediaItem?.mediaId }