fix(mpv): memory leak, stuck loading icon, anr, deprecated methods (#273)
* fix: memory leak and stuck loading icon Also replace deprecated audio focus methods * fix: use global scope for posting playback stopped This fixes ANRs that people are having when leaving the player
This commit is contained in:
parent
dff297513a
commit
7b5745acf1
2 changed files with 23 additions and 20 deletions
|
@ -3,6 +3,7 @@ package dev.jdtech.jellyfin.mpv
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.res.AssetManager
|
import android.content.res.AssetManager
|
||||||
|
import android.media.AudioFocusRequest
|
||||||
import android.media.AudioManager
|
import android.media.AudioManager
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import android.os.Looper
|
import android.os.Looper
|
||||||
|
@ -49,14 +50,14 @@ import timber.log.Timber
|
||||||
@Suppress("SpellCheckingInspection")
|
@Suppress("SpellCheckingInspection")
|
||||||
class MPVPlayer(
|
class MPVPlayer(
|
||||||
context: Context,
|
context: Context,
|
||||||
requestAudioFocus: Boolean,
|
private val requestAudioFocus: Boolean,
|
||||||
private val appPreferences: AppPreferences
|
private val appPreferences: AppPreferences
|
||||||
) : BasePlayer(), MPVLib.EventObserver, AudioManager.OnAudioFocusChangeListener {
|
) : BasePlayer(), MPVLib.EventObserver, AudioManager.OnAudioFocusChangeListener {
|
||||||
|
|
||||||
private val audioManager: AudioManager by lazy { context.getSystemService()!! }
|
private val audioManager: AudioManager by lazy { context.getSystemService()!! }
|
||||||
private var audioFocusCallback: () -> Unit = {}
|
private var audioFocusCallback: () -> Unit = {}
|
||||||
private var currentIndex = 0
|
private var currentIndex = 0
|
||||||
private var audioFocusRequest = AudioManager.AUDIOFOCUS_REQUEST_FAILED
|
private lateinit var audioFocusRequest: AudioFocusRequest
|
||||||
private val handler = Handler(context.mainLooper)
|
private val handler = Handler(context.mainLooper)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
@ -132,13 +133,16 @@ class MPVPlayer(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (requestAudioFocus) {
|
if (requestAudioFocus) {
|
||||||
@Suppress("DEPRECATION")
|
val audioAttributes = android.media.AudioAttributes.Builder()
|
||||||
audioFocusRequest = audioManager.requestAudioFocus(
|
.setUsage(android.media.AudioAttributes.USAGE_MEDIA)
|
||||||
/* l = */ this,
|
.setContentType(android.media.AudioAttributes.CONTENT_TYPE_MOVIE)
|
||||||
/* streamType = */ AudioManager.STREAM_MUSIC,
|
.build()
|
||||||
/* durationHint = */ AudioManager.AUDIOFOCUS_GAIN
|
audioFocusRequest = AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN)
|
||||||
)
|
.setAudioAttributes(audioAttributes)
|
||||||
if (audioFocusRequest != AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
|
.setOnAudioFocusChangeListener(this)
|
||||||
|
.build()
|
||||||
|
val res = audioManager.requestAudioFocus(audioFocusRequest)
|
||||||
|
if (res != AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
|
||||||
MPVLib.setPropertyBoolean("pause", true)
|
MPVLib.setPropertyBoolean("pause", true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -312,9 +316,7 @@ class MPVPlayer(
|
||||||
videoListener.onRenderedFirstFrame()
|
videoListener.onRenderedFirstFrame()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (playbackState == Player.STATE_BUFFERING && bufferedPosition > currentPosition) {
|
setPlayerStateAndNotifyIfChanged(playbackState = Player.STATE_READY)
|
||||||
setPlayerStateAndNotifyIfChanged(playbackState = Player.STATE_READY)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> Unit
|
else -> Unit
|
||||||
|
@ -344,9 +346,8 @@ class MPVPlayer(
|
||||||
playerStateChanged = true
|
playerStateChanged = true
|
||||||
}
|
}
|
||||||
if (playerStateChanged) {
|
if (playerStateChanged) {
|
||||||
listeners.queueEvent( /* eventFlag = */ C.INDEX_UNSET) { listener ->
|
listeners.queueEvent(C.INDEX_UNSET) { listener ->
|
||||||
@Suppress("DEPRECATION")
|
listener.onPlaybackStateChanged(playbackState)
|
||||||
listener.onPlayerStateChanged(playWhenReady, playbackState)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (wasPlaying != isPlaying) {
|
if (wasPlaying != isPlaying) {
|
||||||
|
@ -899,11 +900,11 @@ class MPVPlayer(
|
||||||
* player must not be used after calling this method.
|
* player must not be used after calling this method.
|
||||||
*/
|
*/
|
||||||
override fun release() {
|
override fun release() {
|
||||||
if (audioFocusRequest == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
|
if (requestAudioFocus) {
|
||||||
@Suppress("DEPRECATION")
|
audioManager.abandonAudioFocusRequest(audioFocusRequest)
|
||||||
audioManager.abandonAudioFocus(this)
|
|
||||||
}
|
}
|
||||||
resetInternalState()
|
resetInternalState()
|
||||||
|
MPVLib.removeObserver(this)
|
||||||
MPVLib.destroy()
|
MPVLib.destroy()
|
||||||
currentIndex = 0
|
currentIndex = 0
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,9 +24,10 @@ import dev.jdtech.jellyfin.mpv.MPVPlayer
|
||||||
import dev.jdtech.jellyfin.mpv.TrackType
|
import dev.jdtech.jellyfin.mpv.TrackType
|
||||||
import dev.jdtech.jellyfin.repository.JellyfinRepository
|
import dev.jdtech.jellyfin.repository.JellyfinRepository
|
||||||
import dev.jdtech.jellyfin.utils.postDownloadPlaybackProgress
|
import dev.jdtech.jellyfin.utils.postDownloadPlaybackProgress
|
||||||
|
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.GlobalScope
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.runBlocking
|
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
|
@ -163,9 +164,10 @@ constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(DelicateCoroutinesApi::class)
|
||||||
private fun releasePlayer() {
|
private fun releasePlayer() {
|
||||||
player.let { player ->
|
player.let { player ->
|
||||||
runBlocking {
|
GlobalScope.launch {
|
||||||
try {
|
try {
|
||||||
jellyfinRepository.postPlaybackStop(
|
jellyfinRepository.postPlaybackStop(
|
||||||
UUID.fromString(player.currentMediaItem?.mediaId),
|
UUID.fromString(player.currentMediaItem?.mediaId),
|
||||||
|
|
Loading…
Reference in a new issue