From ea099253a1810b22de1a76409cb518d1c297cefe Mon Sep 17 00:00:00 2001 From: Christian Schabesberger Date: Sat, 24 Aug 2024 14:06:23 +0200 Subject: [PATCH] replace first callbacks with mutablestate/shareflow --- .../java/net/newpipe/newplayer/NewPlayer.kt | 43 ++++++++----------- .../net/newpipe/newplayer/utils/PlayList.kt | 35 ++++++++++----- .../newpipe/newplayer/testapp/MainActivity.kt | 3 +- 3 files changed, 43 insertions(+), 38 deletions(-) diff --git a/new-player/src/main/java/net/newpipe/newplayer/NewPlayer.kt b/new-player/src/main/java/net/newpipe/newplayer/NewPlayer.kt index 1aa0784..115f798 100644 --- a/new-player/src/main/java/net/newpipe/newplayer/NewPlayer.kt +++ b/new-player/src/main/java/net/newpipe/newplayer/NewPlayer.kt @@ -30,7 +30,14 @@ import androidx.media3.exoplayer.source.MediaSource import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharedFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asSharedFlow +import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch +import net.newpipe.newplayer.model.UIModeState import net.newpipe.newplayer.utils.PlayList import kotlin.Exception @@ -56,16 +63,13 @@ interface NewPlayer { var currentPosition: Long var fastSeekAmountSec: Int var playBackMode: PlayMode - var playMode: PlayMode? + var playMode : MutableStateFlow var playlist: PlayList - // calbacks + // callbacks - interface Listener { - fun playModeChange(playMode: PlayMode) {} - fun onError(exception: Exception) {} - } + val errorFlow : SharedFlow // methods fun prepare() @@ -74,7 +78,6 @@ interface NewPlayer { fun addToPlaylist(item: String) fun playStream(item: String, playMode: PlayMode) fun playStream(item: String, streamVariant: String, playMode: PlayMode) - fun addCallbackListener(listener: Listener?) data class Builder(val app: Application, val repository: MediaRepository) { private var mediaSourceFactory: MediaSource.Factory? = null @@ -111,6 +114,9 @@ class NewPlayerImpl( override val repository: MediaRepository, ) : NewPlayer { + var mutableErrorFlow = MutableSharedFlow() + override val errorFlow = mutableErrorFlow.asSharedFlow() + override val bufferedPercentage: Int get() = internalPlayer.bufferedPercentage override var currentPosition: Long @@ -122,16 +128,9 @@ class NewPlayerImpl( override var fastSeekAmountSec: Int = 10 override var playBackMode: PlayMode = PlayMode.EMBEDDED_VIDEO - private var callbackListener: ArrayList = ArrayList() private var playerScope = CoroutineScope(Dispatchers.Default + Job()) - override var playMode: PlayMode? = null - set(value) { - field = value - if (field != null) { - callbackListener.forEach { it?.playModeChange(field!!) } - } - } + override var playMode = MutableStateFlow(null) override var playWhenReady: Boolean set(value) { @@ -154,9 +153,7 @@ class NewPlayerImpl( if (newUri != null) { TODO("Implement handing new uri on fixed error") } else { - callbackListener.forEach { - it?.onError(error) - } + mutableErrorFlow.emit(error) } } } @@ -204,7 +201,7 @@ class NewPlayerImpl( if (internalPlayer.playbackState == Player.STATE_IDLE) { internalPlayer.prepare() } - this.playMode = playMode + this.playMode.update { playMode } } private suspend fun toMediaItem(item: String, streamVariant: String): MediaItem { @@ -232,13 +229,7 @@ class NewPlayerImpl( try { task() } catch (e: Exception) { - callbackListener.forEach { - it?.onError(e) - } + mutableErrorFlow.emit(e) } } - - override fun addCallbackListener(listener: NewPlayer.Listener?) { - callbackListener.add(listener) - } } \ No newline at end of file diff --git a/new-player/src/main/java/net/newpipe/newplayer/utils/PlayList.kt b/new-player/src/main/java/net/newpipe/newplayer/utils/PlayList.kt index ff86c6a..e3199ec 100644 --- a/new-player/src/main/java/net/newpipe/newplayer/utils/PlayList.kt +++ b/new-player/src/main/java/net/newpipe/newplayer/utils/PlayList.kt @@ -21,7 +21,9 @@ package net.newpipe.newplayer.utils +import androidx.media3.common.MediaMetadata import androidx.media3.common.Player +import androidx.media3.common.Player.Listener // TODO: This is cool, but it might still contains all raceconditions since two actors are mutating the @@ -32,6 +34,8 @@ import androidx.media3.common.Player // due to this reason some functions force the user to handle elements out of bounds exceptions. + + class PlayListIterator( val exoPlayer: Player, val fromIndex: Int, @@ -83,6 +87,7 @@ class PlayList(val exoPlayer: Player, val fromIndex: Int = 0, val toIndex: Int = override val size: Int get() = minOf(exoPlayer.mediaItemCount, toIndex) - fromIndex + // TODO: This contains a race condition. When the player might change the playlist while this function runns override fun contains(element: String): Boolean { for (i in fromIndex..minOf(exoPlayer.mediaItemCount, toIndex)) { try { @@ -95,6 +100,7 @@ class PlayList(val exoPlayer: Player, val fromIndex: Int = 0, val toIndex: Int = return false } + // TODO: This contains a race condition. When the player might change the playlist while this function runns override fun containsAll(elements: Collection): Boolean { for (element in elements) { if (!this.contains(element)) { @@ -106,10 +112,10 @@ class PlayList(val exoPlayer: Player, val fromIndex: Int = 0, val toIndex: Int = @Throws(IndexOutOfBoundsException::class) override fun get(index: Int) = - if (index < fromIndex || toIndex < index) - throw IndexOutOfBoundsException("Accessed playlist item outside of permitted Playlist ListWindow: $index") + if (index < 0 || toIndex < index + fromIndex) + throw IndexOutOfBoundsException("Accessed playlist item outside of permitted Playlist ListWindow: $index with [$fromIndex;$toIndex[") else - exoPlayer.getMediaItemAt(index).mediaId + exoPlayer.getMediaItemAt(index + fromIndex).mediaId override fun isEmpty() = exoPlayer.mediaItemCount == 0 || fromIndex == toIndex @@ -127,20 +133,27 @@ class PlayList(val exoPlayer: Player, val fromIndex: Int = 0, val toIndex: Int = ) override fun lastIndexOf(element: String): Int { - for (i in minOf(toIndex, exoPlayer.mediaItemCount) downTo fromIndex) { - try { - if (exoPlayer.getMediaItemAt(i).mediaId == element) { - return i - fromIndex - } - } catch (e: IndexOutOfBoundsException) { - return -1 + var mediaItemCount = 0 + var newMediaItemCount = minOf(toIndex, exoPlayer.mediaItemCount) + + // this while loop is there to catch raceconditions + while(mediaItemCount != newMediaItemCount) { + mediaItemCount = newMediaItemCount + for (i in minOf(toIndex, exoPlayer.mediaItemCount) downTo fromIndex) { + try { + if (exoPlayer.getMediaItemAt(i).mediaId == element) { + return i - fromIndex + } + } catch (_: IndexOutOfBoundsException) {} + } + newMediaItemCount = minOf(toIndex, exoPlayer.mediaItemCount) } return -1 } override fun indexOf(element: String): Int { - for (i in fromIndex.. minOf(toIndex, exoPlayer.mediaItemCount)) { + for (i in fromIndex..minOf(toIndex, exoPlayer.mediaItemCount)) { try { if (exoPlayer.getMediaItemAt(i).mediaId == element) { return i - fromIndex diff --git a/test-app/src/main/java/net/newpipe/newplayer/testapp/MainActivity.kt b/test-app/src/main/java/net/newpipe/newplayer/testapp/MainActivity.kt index f7f9487..f9924f7 100644 --- a/test-app/src/main/java/net/newpipe/newplayer/testapp/MainActivity.kt +++ b/test-app/src/main/java/net/newpipe/newplayer/testapp/MainActivity.kt @@ -34,6 +34,7 @@ import androidx.media3.common.MediaItem import dagger.hilt.android.AndroidEntryPoint import net.newpipe.newplayer.ActivityBrainSlug import net.newpipe.newplayer.NewPlayer +import net.newpipe.newplayer.PlayMode import net.newpipe.newplayer.VideoPlayerView import net.newpipe.newplayer.model.VideoPlayerViewModel import net.newpipe.newplayer.model.VideoPlayerViewModelImpl @@ -63,7 +64,7 @@ class MainActivity : AppCompatActivity() { startStreamButton.setOnClickListener { newPlayer.playWhenReady = true - newPlayer.setStream(MediaItem.fromUri(getString(R.string.ccc_6502_video))) + newPlayer.playStream(getString(R.string.ccc_6502_video), PlayMode.EMBEDDED_VIDEO) } videoPlayerViewModel.newPlayer = newPlayer