From 7b5745acf113a951700be8ff21316a6175d2bf25 Mon Sep 17 00:00:00 2001 From: Jarne Demeulemeester <32322857+jarnedemeulemeester@users.noreply.github.com> Date: Sun, 5 Feb 2023 01:15:43 +0100 Subject: [PATCH] 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 --- .../java/dev/jdtech/jellyfin/mpv/MPVPlayer.kt | 37 ++++++++++--------- .../viewmodels/PlayerActivityViewModel.kt | 6 ++- 2 files changed, 23 insertions(+), 20 deletions(-) diff --git a/player/video/src/main/java/dev/jdtech/jellyfin/mpv/MPVPlayer.kt b/player/video/src/main/java/dev/jdtech/jellyfin/mpv/MPVPlayer.kt index 753d7216..9a9ec664 100644 --- a/player/video/src/main/java/dev/jdtech/jellyfin/mpv/MPVPlayer.kt +++ b/player/video/src/main/java/dev/jdtech/jellyfin/mpv/MPVPlayer.kt @@ -3,6 +3,7 @@ package dev.jdtech.jellyfin.mpv import android.app.Application import android.content.Context import android.content.res.AssetManager +import android.media.AudioFocusRequest import android.media.AudioManager import android.os.Handler import android.os.Looper @@ -49,14 +50,14 @@ import timber.log.Timber @Suppress("SpellCheckingInspection") class MPVPlayer( context: Context, - requestAudioFocus: Boolean, + private val requestAudioFocus: Boolean, private val appPreferences: AppPreferences ) : BasePlayer(), MPVLib.EventObserver, AudioManager.OnAudioFocusChangeListener { private val audioManager: AudioManager by lazy { context.getSystemService()!! } private var audioFocusCallback: () -> Unit = {} private var currentIndex = 0 - private var audioFocusRequest = AudioManager.AUDIOFOCUS_REQUEST_FAILED + private lateinit var audioFocusRequest: AudioFocusRequest private val handler = Handler(context.mainLooper) init { @@ -132,13 +133,16 @@ class MPVPlayer( } if (requestAudioFocus) { - @Suppress("DEPRECATION") - audioFocusRequest = audioManager.requestAudioFocus( - /* l = */ this, - /* streamType = */ AudioManager.STREAM_MUSIC, - /* durationHint = */ AudioManager.AUDIOFOCUS_GAIN - ) - if (audioFocusRequest != AudioManager.AUDIOFOCUS_REQUEST_GRANTED) { + val audioAttributes = android.media.AudioAttributes.Builder() + .setUsage(android.media.AudioAttributes.USAGE_MEDIA) + .setContentType(android.media.AudioAttributes.CONTENT_TYPE_MOVIE) + .build() + audioFocusRequest = AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN) + .setAudioAttributes(audioAttributes) + .setOnAudioFocusChangeListener(this) + .build() + val res = audioManager.requestAudioFocus(audioFocusRequest) + if (res != AudioManager.AUDIOFOCUS_REQUEST_GRANTED) { MPVLib.setPropertyBoolean("pause", true) } } @@ -312,9 +316,7 @@ class MPVPlayer( videoListener.onRenderedFirstFrame() } } else { - if (playbackState == Player.STATE_BUFFERING && bufferedPosition > currentPosition) { - setPlayerStateAndNotifyIfChanged(playbackState = Player.STATE_READY) - } + setPlayerStateAndNotifyIfChanged(playbackState = Player.STATE_READY) } } else -> Unit @@ -344,9 +346,8 @@ class MPVPlayer( playerStateChanged = true } if (playerStateChanged) { - listeners.queueEvent( /* eventFlag = */ C.INDEX_UNSET) { listener -> - @Suppress("DEPRECATION") - listener.onPlayerStateChanged(playWhenReady, playbackState) + listeners.queueEvent(C.INDEX_UNSET) { listener -> + listener.onPlaybackStateChanged(playbackState) } } if (wasPlaying != isPlaying) { @@ -899,11 +900,11 @@ class MPVPlayer( * player must not be used after calling this method. */ override fun release() { - if (audioFocusRequest == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) { - @Suppress("DEPRECATION") - audioManager.abandonAudioFocus(this) + if (requestAudioFocus) { + audioManager.abandonAudioFocusRequest(audioFocusRequest) } resetInternalState() + MPVLib.removeObserver(this) MPVLib.destroy() currentIndex = 0 } diff --git a/player/video/src/main/java/dev/jdtech/jellyfin/viewmodels/PlayerActivityViewModel.kt b/player/video/src/main/java/dev/jdtech/jellyfin/viewmodels/PlayerActivityViewModel.kt index bd66aa62..f74ab963 100644 --- a/player/video/src/main/java/dev/jdtech/jellyfin/viewmodels/PlayerActivityViewModel.kt +++ b/player/video/src/main/java/dev/jdtech/jellyfin/viewmodels/PlayerActivityViewModel.kt @@ -24,9 +24,10 @@ import dev.jdtech.jellyfin.mpv.MPVPlayer import dev.jdtech.jellyfin.mpv.TrackType import dev.jdtech.jellyfin.repository.JellyfinRepository import dev.jdtech.jellyfin.utils.postDownloadPlaybackProgress +import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch -import kotlinx.coroutines.runBlocking import kotlinx.coroutines.withContext import timber.log.Timber import java.util.UUID @@ -163,9 +164,10 @@ constructor( } } + @OptIn(DelicateCoroutinesApi::class) private fun releasePlayer() { player.let { player -> - runBlocking { + GlobalScope.launch { try { jellyfinRepository.postPlaybackStop( UUID.fromString(player.currentMediaItem?.mediaId),