replace first callbacks with mutablestate/shareflow
This commit is contained in:
parent
32075dec73
commit
ea099253a1
|
@ -30,7 +30,14 @@ import androidx.media3.exoplayer.source.MediaSource
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.Job
|
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 kotlinx.coroutines.launch
|
||||||
|
import net.newpipe.newplayer.model.UIModeState
|
||||||
import net.newpipe.newplayer.utils.PlayList
|
import net.newpipe.newplayer.utils.PlayList
|
||||||
import kotlin.Exception
|
import kotlin.Exception
|
||||||
|
|
||||||
|
@ -56,16 +63,13 @@ interface NewPlayer {
|
||||||
var currentPosition: Long
|
var currentPosition: Long
|
||||||
var fastSeekAmountSec: Int
|
var fastSeekAmountSec: Int
|
||||||
var playBackMode: PlayMode
|
var playBackMode: PlayMode
|
||||||
var playMode: PlayMode?
|
var playMode : MutableStateFlow<PlayMode?>
|
||||||
|
|
||||||
var playlist: PlayList
|
var playlist: PlayList
|
||||||
|
|
||||||
// calbacks
|
// callbacks
|
||||||
|
|
||||||
interface Listener {
|
val errorFlow : SharedFlow<Exception>
|
||||||
fun playModeChange(playMode: PlayMode) {}
|
|
||||||
fun onError(exception: Exception) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
// methods
|
// methods
|
||||||
fun prepare()
|
fun prepare()
|
||||||
|
@ -74,7 +78,6 @@ interface NewPlayer {
|
||||||
fun addToPlaylist(item: String)
|
fun addToPlaylist(item: String)
|
||||||
fun playStream(item: String, playMode: PlayMode)
|
fun playStream(item: String, playMode: PlayMode)
|
||||||
fun playStream(item: String, streamVariant: String, playMode: PlayMode)
|
fun playStream(item: String, streamVariant: String, playMode: PlayMode)
|
||||||
fun addCallbackListener(listener: Listener?)
|
|
||||||
|
|
||||||
data class Builder(val app: Application, val repository: MediaRepository) {
|
data class Builder(val app: Application, val repository: MediaRepository) {
|
||||||
private var mediaSourceFactory: MediaSource.Factory? = null
|
private var mediaSourceFactory: MediaSource.Factory? = null
|
||||||
|
@ -111,6 +114,9 @@ class NewPlayerImpl(
|
||||||
override val repository: MediaRepository,
|
override val repository: MediaRepository,
|
||||||
) : NewPlayer {
|
) : NewPlayer {
|
||||||
|
|
||||||
|
var mutableErrorFlow = MutableSharedFlow<Exception>()
|
||||||
|
override val errorFlow = mutableErrorFlow.asSharedFlow()
|
||||||
|
|
||||||
override val bufferedPercentage: Int
|
override val bufferedPercentage: Int
|
||||||
get() = internalPlayer.bufferedPercentage
|
get() = internalPlayer.bufferedPercentage
|
||||||
override var currentPosition: Long
|
override var currentPosition: Long
|
||||||
|
@ -122,16 +128,9 @@ class NewPlayerImpl(
|
||||||
override var fastSeekAmountSec: Int = 10
|
override var fastSeekAmountSec: Int = 10
|
||||||
override var playBackMode: PlayMode = PlayMode.EMBEDDED_VIDEO
|
override var playBackMode: PlayMode = PlayMode.EMBEDDED_VIDEO
|
||||||
|
|
||||||
private var callbackListener: ArrayList<NewPlayer.Listener?> = ArrayList()
|
|
||||||
private var playerScope = CoroutineScope(Dispatchers.Default + Job())
|
private var playerScope = CoroutineScope(Dispatchers.Default + Job())
|
||||||
|
|
||||||
override var playMode: PlayMode? = null
|
override var playMode = MutableStateFlow<PlayMode?>(null)
|
||||||
set(value) {
|
|
||||||
field = value
|
|
||||||
if (field != null) {
|
|
||||||
callbackListener.forEach { it?.playModeChange(field!!) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override var playWhenReady: Boolean
|
override var playWhenReady: Boolean
|
||||||
set(value) {
|
set(value) {
|
||||||
|
@ -154,9 +153,7 @@ class NewPlayerImpl(
|
||||||
if (newUri != null) {
|
if (newUri != null) {
|
||||||
TODO("Implement handing new uri on fixed error")
|
TODO("Implement handing new uri on fixed error")
|
||||||
} else {
|
} else {
|
||||||
callbackListener.forEach {
|
mutableErrorFlow.emit(error)
|
||||||
it?.onError(error)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -204,7 +201,7 @@ class NewPlayerImpl(
|
||||||
if (internalPlayer.playbackState == Player.STATE_IDLE) {
|
if (internalPlayer.playbackState == Player.STATE_IDLE) {
|
||||||
internalPlayer.prepare()
|
internalPlayer.prepare()
|
||||||
}
|
}
|
||||||
this.playMode = playMode
|
this.playMode.update { playMode }
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun toMediaItem(item: String, streamVariant: String): MediaItem {
|
private suspend fun toMediaItem(item: String, streamVariant: String): MediaItem {
|
||||||
|
@ -232,13 +229,7 @@ class NewPlayerImpl(
|
||||||
try {
|
try {
|
||||||
task()
|
task()
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
callbackListener.forEach {
|
mutableErrorFlow.emit(e)
|
||||||
it?.onError(e)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun addCallbackListener(listener: NewPlayer.Listener?) {
|
|
||||||
callbackListener.add(listener)
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -21,7 +21,9 @@
|
||||||
|
|
||||||
package net.newpipe.newplayer.utils
|
package net.newpipe.newplayer.utils
|
||||||
|
|
||||||
|
import androidx.media3.common.MediaMetadata
|
||||||
import androidx.media3.common.Player
|
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
|
// 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.
|
// due to this reason some functions force the user to handle elements out of bounds exceptions.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class PlayListIterator(
|
class PlayListIterator(
|
||||||
val exoPlayer: Player,
|
val exoPlayer: Player,
|
||||||
val fromIndex: Int,
|
val fromIndex: Int,
|
||||||
|
@ -83,6 +87,7 @@ class PlayList(val exoPlayer: Player, val fromIndex: Int = 0, val toIndex: Int =
|
||||||
override val size: Int
|
override val size: Int
|
||||||
get() = minOf(exoPlayer.mediaItemCount, toIndex) - fromIndex
|
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 {
|
override fun contains(element: String): Boolean {
|
||||||
for (i in fromIndex..minOf(exoPlayer.mediaItemCount, toIndex)) {
|
for (i in fromIndex..minOf(exoPlayer.mediaItemCount, toIndex)) {
|
||||||
try {
|
try {
|
||||||
|
@ -95,6 +100,7 @@ class PlayList(val exoPlayer: Player, val fromIndex: Int = 0, val toIndex: Int =
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: This contains a race condition. When the player might change the playlist while this function runns
|
||||||
override fun containsAll(elements: Collection<String>): Boolean {
|
override fun containsAll(elements: Collection<String>): Boolean {
|
||||||
for (element in elements) {
|
for (element in elements) {
|
||||||
if (!this.contains(element)) {
|
if (!this.contains(element)) {
|
||||||
|
@ -106,10 +112,10 @@ class PlayList(val exoPlayer: Player, val fromIndex: Int = 0, val toIndex: Int =
|
||||||
|
|
||||||
@Throws(IndexOutOfBoundsException::class)
|
@Throws(IndexOutOfBoundsException::class)
|
||||||
override fun get(index: Int) =
|
override fun get(index: Int) =
|
||||||
if (index < fromIndex || toIndex < index)
|
if (index < 0 || toIndex < index + fromIndex)
|
||||||
throw IndexOutOfBoundsException("Accessed playlist item outside of permitted Playlist ListWindow: $index")
|
throw IndexOutOfBoundsException("Accessed playlist item outside of permitted Playlist ListWindow: $index with [$fromIndex;$toIndex[")
|
||||||
else
|
else
|
||||||
exoPlayer.getMediaItemAt(index).mediaId
|
exoPlayer.getMediaItemAt(index + fromIndex).mediaId
|
||||||
|
|
||||||
override fun isEmpty() = exoPlayer.mediaItemCount == 0 || fromIndex == toIndex
|
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 {
|
override fun lastIndexOf(element: String): Int {
|
||||||
for (i in minOf(toIndex, exoPlayer.mediaItemCount) downTo fromIndex) {
|
var mediaItemCount = 0
|
||||||
try {
|
var newMediaItemCount = minOf(toIndex, exoPlayer.mediaItemCount)
|
||||||
if (exoPlayer.getMediaItemAt(i).mediaId == element) {
|
|
||||||
return i - fromIndex
|
// this while loop is there to catch raceconditions
|
||||||
}
|
while(mediaItemCount != newMediaItemCount) {
|
||||||
} catch (e: IndexOutOfBoundsException) {
|
mediaItemCount = newMediaItemCount
|
||||||
return -1
|
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
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun indexOf(element: String): Int {
|
override fun indexOf(element: String): Int {
|
||||||
for (i in fromIndex.. minOf(toIndex, exoPlayer.mediaItemCount)) {
|
for (i in fromIndex..minOf(toIndex, exoPlayer.mediaItemCount)) {
|
||||||
try {
|
try {
|
||||||
if (exoPlayer.getMediaItemAt(i).mediaId == element) {
|
if (exoPlayer.getMediaItemAt(i).mediaId == element) {
|
||||||
return i - fromIndex
|
return i - fromIndex
|
||||||
|
|
|
@ -34,6 +34,7 @@ import androidx.media3.common.MediaItem
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import net.newpipe.newplayer.ActivityBrainSlug
|
import net.newpipe.newplayer.ActivityBrainSlug
|
||||||
import net.newpipe.newplayer.NewPlayer
|
import net.newpipe.newplayer.NewPlayer
|
||||||
|
import net.newpipe.newplayer.PlayMode
|
||||||
import net.newpipe.newplayer.VideoPlayerView
|
import net.newpipe.newplayer.VideoPlayerView
|
||||||
import net.newpipe.newplayer.model.VideoPlayerViewModel
|
import net.newpipe.newplayer.model.VideoPlayerViewModel
|
||||||
import net.newpipe.newplayer.model.VideoPlayerViewModelImpl
|
import net.newpipe.newplayer.model.VideoPlayerViewModelImpl
|
||||||
|
@ -63,7 +64,7 @@ class MainActivity : AppCompatActivity() {
|
||||||
|
|
||||||
startStreamButton.setOnClickListener {
|
startStreamButton.setOnClickListener {
|
||||||
newPlayer.playWhenReady = true
|
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
|
videoPlayerViewModel.newPlayer = newPlayer
|
||||||
|
|
Loading…
Reference in New Issue