fix: resolve buffering on foreground return
This commit is contained in:
@@ -24,6 +24,7 @@ class Media3Player(private val context: Context) {
|
||||
var onBufferingListener: ((Boolean) -> Unit)? = null
|
||||
var onPlaybackStateChanged: ((isPlaying: Boolean, position: Long, bufferedPosition: Long, duration: Long) -> Unit)? = null
|
||||
var onErrorListener: ((error: String, isRetriable: Boolean) -> Unit)? = null
|
||||
var onRenderedFirstFrameListener: (() -> Unit)? = null
|
||||
|
||||
init {
|
||||
NetworkUtils.setupAndroid7SSL()
|
||||
@@ -54,6 +55,9 @@ class Media3Player(private val context: Context) {
|
||||
}
|
||||
|
||||
fun attachSurface(surface: Surface?) {
|
||||
if (this.surface === surface) {
|
||||
return
|
||||
}
|
||||
this.surface = surface
|
||||
try {
|
||||
if (surface == null || surface.isValid) {
|
||||
@@ -71,11 +75,18 @@ class Media3Player(private val context: Context) {
|
||||
state.isFixingM3u8 = false
|
||||
actualPlayingUrl = null
|
||||
|
||||
val currentSurface = surface
|
||||
|
||||
exoPlayer?.apply {
|
||||
stop()
|
||||
clearMediaItems()
|
||||
clearVideoSurface()
|
||||
setMediaItem(createMediaItem(url))
|
||||
prepare()
|
||||
|
||||
if (currentSurface != null && currentSurface.isValid) {
|
||||
setVideoSurface(currentSurface)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,6 +138,10 @@ class Media3Player(private val context: Context) {
|
||||
fun start() {
|
||||
state.shouldPlayWhenReady = true
|
||||
exoPlayer?.let {
|
||||
val s = surface
|
||||
if (s != null && s.isValid) {
|
||||
it.setVideoSurface(s)
|
||||
}
|
||||
if (it.playbackState == androidx.media3.common.Player.STATE_IDLE) it.prepare()
|
||||
it.play()
|
||||
}
|
||||
@@ -137,7 +152,14 @@ class Media3Player(private val context: Context) {
|
||||
exoPlayer?.pause()
|
||||
}
|
||||
|
||||
fun stop() = exoPlayer?.stop()
|
||||
fun stop() {
|
||||
exoPlayer?.stop()
|
||||
exoPlayer?.clearVideoSurface()
|
||||
}
|
||||
|
||||
fun clearVideoSurface() {
|
||||
exoPlayer?.clearVideoSurface()
|
||||
}
|
||||
|
||||
fun setHardwareAcceleration(enabled: Boolean) {
|
||||
if (currentHardwareAcceleration != enabled) {
|
||||
|
||||
@@ -107,7 +107,6 @@ class PlaybackService : MediaSessionService() {
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
mediaSession?.player?.stop()
|
||||
mediaSession?.release()
|
||||
mediaSession = null
|
||||
currentPlayer = null
|
||||
|
||||
@@ -140,13 +140,17 @@ fun PlayerSurface(
|
||||
) {
|
||||
val textureViewRef = remember { mutableStateOf<TextureView?>(null) }
|
||||
var surfaceReady by remember { mutableStateOf(true) }
|
||||
var lastChannelUrl by remember { mutableStateOf(currentChannelUrl) }
|
||||
|
||||
LaunchedEffect(currentChannelUrl) {
|
||||
if (currentChannelUrl.isNotEmpty()) {
|
||||
if (currentChannelUrl.isNotEmpty() && currentChannelUrl != lastChannelUrl) {
|
||||
lastChannelUrl = currentChannelUrl
|
||||
surfaceReady = false
|
||||
player?.attachSurface(null)
|
||||
kotlinx.coroutines.delay(50)
|
||||
surfaceReady = true
|
||||
} else if (lastChannelUrl.isEmpty() && currentChannelUrl.isNotEmpty()) {
|
||||
lastChannelUrl = currentChannelUrl
|
||||
}
|
||||
}
|
||||
|
||||
@@ -198,5 +202,7 @@ fun PlayerSurface(
|
||||
modifier = Modifier
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,11 +111,15 @@ private fun PlayerPageContent(
|
||||
viewModel.refreshPreferences()
|
||||
}
|
||||
|
||||
var isPlayerClean by remember { mutableStateOf(false) }
|
||||
|
||||
LaunchedEffect(url) {
|
||||
media3Player.apply {
|
||||
stop()
|
||||
clearVideoSurface()
|
||||
exoPlayer?.clearMediaItems()
|
||||
}
|
||||
isPlayerClean = true
|
||||
viewModel.loadChannels(url, initialChannelUrl, initialChannelId, initialVideoTitle)
|
||||
}
|
||||
|
||||
@@ -217,9 +221,12 @@ private fun PlayerPageContent(
|
||||
|
||||
Lifecycle.Event.ON_STOP -> {
|
||||
val backgroundPlay = com.antoniegil.astronia.util.SettingsManager.getBackgroundPlay(context)
|
||||
val wasPipActive = isInPictureInPictureMode
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
val isPip = activity?.isInPictureInPictureMode == true
|
||||
if (isPip && !backgroundPlay) {
|
||||
isInPictureInPictureMode = isPip
|
||||
|
||||
if ((isPip || wasPipActive) && !backgroundPlay) {
|
||||
media3Player.pause()
|
||||
wasPlayingBeforePause = false
|
||||
return@LifecycleEventObserver
|
||||
@@ -332,30 +339,20 @@ private fun PlayerPageContent(
|
||||
viewModel.toggleControls()
|
||||
}
|
||||
) {
|
||||
LaunchedEffect(media3Player) {
|
||||
media3Player.surface?.let { surface ->
|
||||
if (surface.isValid) {
|
||||
media3Player.attachSurface(surface)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val onSurfaceReady = remember {
|
||||
{
|
||||
if (pendingAutoPlay) {
|
||||
pendingAutoPlay = false
|
||||
media3Player.start()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (uiState.currentChannelUrl.isNotEmpty()) {
|
||||
if (uiState.currentChannelUrl.isNotEmpty() && isPlayerClean) {
|
||||
PlayerSurface(
|
||||
player = media3Player,
|
||||
aspectRatio = uiState.aspectRatio,
|
||||
mirrorFlip = uiState.mirrorFlip,
|
||||
isBackgroundRetained = false,
|
||||
onSurfaceReady = onSurfaceReady,
|
||||
isBackgroundRetained = true,
|
||||
onSurfaceReady = {
|
||||
if (pendingAutoPlay && !media3Player.isPlaying) {
|
||||
pendingAutoPlay = false
|
||||
media3Player.start()
|
||||
} else if (pendingAutoPlay) {
|
||||
pendingAutoPlay = false
|
||||
}
|
||||
},
|
||||
currentChannelUrl = uiState.currentChannelUrl
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user