diff --git a/android/src/main/java/dev/zoriya/omni/EventMap.kt b/android/src/main/java/dev/zoriya/omni/EventMap.kt index ba79318..daed677 100644 --- a/android/src/main/java/dev/zoriya/omni/EventMap.kt +++ b/android/src/main/java/dev/zoriya/omni/EventMap.kt @@ -2,7 +2,17 @@ package dev.zoriya.omni import android.os.SystemClock import androidx.media3.common.C +import androidx.media3.common.C.TRACK_TYPE_AUDIO +import androidx.media3.common.C.TRACK_TYPE_TEXT +import androidx.media3.common.C.TRACK_TYPE_VIDEO +import androidx.media3.common.PlaybackException +import androidx.media3.common.PlaybackParameters import androidx.media3.common.Player +import androidx.media3.common.Player.STATE_BUFFERING +import androidx.media3.common.Player.STATE_ENDED +import androidx.media3.common.Player.STATE_IDLE +import androidx.media3.common.Player.STATE_READY +import androidx.media3.common.Tracks import com.margelo.nitro.omni.BoolProperty import com.margelo.nitro.omni.HybridOmniEventMapSpec import com.margelo.nitro.omni.NumberProperty @@ -11,8 +21,8 @@ import com.margelo.nitro.omni.Rendition import com.margelo.nitro.omni.Track class EventMap(private val player: Player) : HybridOmniEventMapSpec(), Player.Listener { - val onPrevListeners = mutableSetOf<() -> Unit>() - val onNextListeners = mutableSetOf<() -> Unit>() + private val onPrevListeners = mutableSetOf<() -> Unit>() + private val onNextListeners = mutableSetOf<() -> Unit>() private val onEndListeners = mutableSetOf<() -> Unit>() private val onErrorListeners = mutableSetOf<(type: String, message: String) -> Unit>() private val onAudioFocusChangeListeners = mutableSetOf<(status: String) -> Unit>() @@ -27,17 +37,6 @@ class EventMap(private val player: Player) : HybridOmniEventMapSpec(), Player.Li init { player.addListener(this) - emitCoreState(forceCurrentTime = true) - } - - private fun computePlayerStatus(): PlayerStatus { - val loading = player.isLoading - val idle = player.playbackState == Player.STATE_IDLE || player.playbackState == Player.STATE_ENDED - return when { - loading -> PlayerStatus.LOADING - idle -> PlayerStatus.IDLE - else -> PlayerStatus.READYTOPLAY - } } private fun selectedTrack(trackType: Int): Track? { @@ -58,61 +57,56 @@ class EventMap(private val player: Player) : HybridOmniEventMapSpec(), Player.Li return null } - override fun onEvents(player: Player, events: Player.Events) { - if ( - events.contains(Player.EVENT_PLAYBACK_STATE_CHANGED) || - events.contains(Player.EVENT_IS_LOADING_CHANGED) - ) { - val status = computePlayerStatus() - playerStatusListeners.forEach { it(status) } - if (player.playbackState == Player.STATE_ENDED) { + override fun onPlaybackStateChanged(playbackState: Int) { + val state = when (player.playbackState) { + STATE_IDLE -> PlayerStatus.IDLE + STATE_BUFFERING -> PlayerStatus.LOADING + STATE_READY -> PlayerStatus.READYTOPLAY + STATE_ENDED -> { onEndListeners.forEach { it() } + PlayerStatus.IDLE } + else -> PlayerStatus.IDLE } + playerStatusListeners.forEach { it(state) } + } - if ( - events.contains(Player.EVENT_PLAY_WHEN_READY_CHANGED) || - events.contains(Player.EVENT_IS_PLAYING_CHANGED) - ) { - val isPlaying = player.isPlaying - onAudioFocusChangeListeners.forEach { it(if (isPlaying) "playing" else "paused") } - stateBoolListeners[BoolProperty.ISPLAYING]?.forEach { it(isPlaying) } - } + override fun onPlayWhenReadyChanged(playWhenReady: Boolean, reason: Int) { + onIsPlayingChanged(playWhenReady) + } - if (events.contains(Player.EVENT_VOLUME_CHANGED)) { - val volume = player.volume.toDouble().coerceIn(0.0, 1.0) - stateListeners[NumberProperty.VOLUME]?.forEach { it(volume) } - stateBoolListeners[BoolProperty.MUTED]?.forEach { it(volume <= 0.0) } - } + override fun onIsPlayingChanged(isPlaying: Boolean) { + stateBoolListeners[BoolProperty.ISPLAYING]?.forEach { it(isPlaying) } + } - if (events.contains(Player.EVENT_PLAYBACK_PARAMETERS_CHANGED)) { - stateListeners[NumberProperty.PLAYBACKRATE]?.forEach { - it(player.playbackParameters.speed.toDouble()) - } - } + override fun onVolumeChanged(volume: Float) { + stateListeners[NumberProperty.VOLUME]?.forEach { it(volume.toDouble()) } + stateBoolListeners[BoolProperty.MUTED]?.forEach { it(volume <= 0.0) } + } - if ( - events.contains(Player.EVENT_POSITION_DISCONTINUITY) || - events.contains(Player.EVENT_PLAYBACK_STATE_CHANGED) || - events.contains(Player.EVENT_IS_LOADING_CHANGED) - ) { - emitCoreState(forceCurrentTime = true) - } else { - emitCoreState(forceCurrentTime = false) - } - - if (events.contains(Player.EVENT_TRACKS_CHANGED)) { - selectedTrack(C.TRACK_TYPE_VIDEO)?.let { track -> - onVideoTrackChangeListeners.forEach { it(track) } - } - selectedTrack(C.TRACK_TYPE_AUDIO)?.let { track -> - onAudioTrackChangeListeners.forEach { it(track) } - } - onSubtitleChangeListeners.forEach { it(selectedTrack(C.TRACK_TYPE_TEXT)) } + override fun onPlaybackParametersChanged(playbackParameters: PlaybackParameters) { + stateListeners[NumberProperty.PLAYBACKRATE]?.forEach { + it(playbackParameters.speed.toDouble()) } } - override fun onPlayerError(error: androidx.media3.common.PlaybackException) { + override fun onTracksChanged(tracks: Tracks) { + selectedTrack(TRACK_TYPE_VIDEO)?.let { track -> + onVideoTrackChangeListeners.forEach { it(track) } + } + selectedTrack(TRACK_TYPE_AUDIO)?.let { track -> + onAudioTrackChangeListeners.forEach { it(track) } + } + onSubtitleChangeListeners.forEach { + it( + selectedTrack( + TRACK_TYPE_TEXT + ) + ) + } + } + + override fun onPlayerError(error: PlaybackException) { onErrorListeners.forEach { it(error.errorCodeName, error.message ?: "unknown message") } @@ -123,7 +117,7 @@ class EventMap(private val player: Player) : HybridOmniEventMapSpec(), Player.Li newPosition: Player.PositionInfo, reason: Int ) { - emitCurrentTime(force = true) + emitCoreState(forceCurrentTime = true) } private fun emitCoreState(forceCurrentTime: Boolean) { diff --git a/android/src/main/java/dev/zoriya/omni/MpvPlayer.kt b/android/src/main/java/dev/zoriya/omni/MpvPlayer.kt index 7e3e3ee..5c70178 100644 --- a/android/src/main/java/dev/zoriya/omni/MpvPlayer.kt +++ b/android/src/main/java/dev/zoriya/omni/MpvPlayer.kt @@ -146,7 +146,7 @@ class MpvPlayer(ctx: Context) : BasePlayer(), MPVLib.EventObserver { override fun addMediaItems( p0: Int, - p1: List? + p1: List ) = Unit override fun moveMediaItems(fromIndex: Int, toIndex: Int, newIndex: Int) = Unit @@ -165,18 +165,15 @@ class MpvPlayer(ctx: Context) : BasePlayer(), MPVLib.EventObserver { override fun prepare() = Unit - override fun getPlaybackState(): Int { - val ended = mpv.getPropertyBoolean("eof-reached") ?: false - if (ended) return Player.STATE_ENDED + override fun getPlaybackState(): Int = + when (true) { + mpv.getPropertyBoolean("paused-for-cache") -> STATE_BUFFERING + mpv.getPropertyBoolean("eof-reached") -> STATE_ENDED + mpv.getPropertyBoolean("core-idle") -> STATE_IDLE + else -> STATE_READY + } - val idle = mpv.getPropertyBoolean("core-idle") ?: false - if (idle) return Player.STATE_IDLE - - val loading = mpv.getPropertyBoolean("paused-for-cache") ?: false - return if (loading) Player.STATE_BUFFERING else Player.STATE_READY - } - - override fun getPlaybackSuppressionReason(): Int = Player.PLAYBACK_SUPPRESSION_REASON_NONE + override fun getPlaybackSuppressionReason(): Int = PLAYBACK_SUPPRESSION_REASON_NONE override fun getPlayerError(): PlaybackException? = playerError @@ -188,7 +185,7 @@ class MpvPlayer(ctx: Context) : BasePlayer(), MPVLib.EventObserver { override fun setRepeatMode(repeatMode: Int) = Unit - override fun getRepeatMode(): Int = Player.REPEAT_MODE_OFF + override fun getRepeatMode(): Int = REPEAT_MODE_OFF override fun setShuffleModeEnabled(shuffleModeEnabled: Boolean) = Unit @@ -481,6 +478,16 @@ class MpvPlayer(ctx: Context) : BasePlayer(), MPVLib.EventObserver { override fun event(eventId: Int) { when (eventId) { + MPVLib.MpvEvent.MPV_EVENT_START_FILE -> listeners.forEach { + it.onPlaybackStateChanged(STATE_BUFFERING) + } + + MPVLib.MpvEvent.MPV_EVENT_FILE_LOADED -> + listeners.forEach { + it.onPlaybackStateChanged(STATE_READY) + it.onIsPlayingChanged(playWhenReady) + } + MPVLib.MpvEvent.MPV_EVENT_SEEK, MPVLib.MpvEvent.MPV_EVENT_PLAYBACK_RESTART -> { val positionMs = getCurrentPosition() @@ -500,6 +507,12 @@ class MpvPlayer(ctx: Context) : BasePlayer(), MPVLib.EventObserver { } } + MPVLib.MpvEvent.MPV_EVENT_END_FILE -> listeners.forEach { + it.onPlaybackStateChanged( + STATE_ENDED + ) + } + MPVLib.MpvEvent.MPV_EVENT_QUEUE_OVERFLOW -> { playerError = PlaybackException( "mpv event queue overflow", @@ -508,7 +521,13 @@ class MpvPlayer(ctx: Context) : BasePlayer(), MPVLib.EventObserver { ) listeners.forEach { it.onPlayerErrorChanged(playerError) - it.onPlayerError(playerError) + it.onPlayerError( + playerError ?: PlaybackException( + "unknown", + null, + PlaybackException.ERROR_CODE_UNSPECIFIED + ) + ) } } } @@ -555,8 +574,9 @@ class MpvPlayer(ctx: Context) : BasePlayer(), MPVLib.EventObserver { } "core-idle", "eof-reached" -> - listeners.forEach { it.onPlaybackStateChanged(getPlaybackState()) - it.onIsPlayingChanged(false) } + listeners.forEach { + it.onPlaybackStateChanged(getPlaybackState()) + } "paused-for-cache" -> { listeners.forEach { diff --git a/android/src/main/java/dev/zoriya/omni/OmniPlayer.kt b/android/src/main/java/dev/zoriya/omni/OmniPlayer.kt index c80b208..c9dd302 100644 --- a/android/src/main/java/dev/zoriya/omni/OmniPlayer.kt +++ b/android/src/main/java/dev/zoriya/omni/OmniPlayer.kt @@ -112,11 +112,11 @@ class OmniPlayer : HybridOmniPlayerSpec() { } override fun playPrev() { - eventMap.onPrevListeners.forEach { it() } + player.seekToPreviousMediaItem() } override fun playNext() { - eventMap.onNextListeners.forEach { it() } + player.seekToNextMediaItem() } override fun selectVideo(video: Track) { diff --git a/example/App.tsx b/example/App.tsx index c0cd788..fe958b4 100644 --- a/example/App.tsx +++ b/example/App.tsx @@ -200,7 +200,6 @@ function PlayerExample({ refreshTracks(); }; - return ( react-native-omni @@ -393,7 +392,8 @@ function PlayerExample({ rendition.selected && styles.selectedTrackButtonText, ]} > - {rendition.width}x{rendition.height} ({Math.round(rendition.bitrate / 1000)} kbps) + {rendition.width}x{rendition.height} ( + {Math.round(rendition.bitrate / 1000)} kbps) )) @@ -405,6 +405,7 @@ function PlayerExample({ style={styles.logCard} contentContainerStyle={styles.logContent} > + Logs {logs.length === 0 ? ( Event log will appear here. ) : (