diff --git a/android/src/main/java/dev/zoriya/omni/OmniPlayer.kt b/android/src/main/java/dev/zoriya/omni/OmniPlayer.kt index bc584ff..a83b1e0 100644 --- a/android/src/main/java/dev/zoriya/omni/OmniPlayer.kt +++ b/android/src/main/java/dev/zoriya/omni/OmniPlayer.kt @@ -106,21 +106,34 @@ class OmniPlayer( override var showNotification: Boolean? = false set(value) { - if (value == true) { + field = value + syncNotificationService() + } + + private var serviceRunning = false + + private fun syncNotificationService() { + val shouldShow = showNotification == true && source != null + when { + shouldShow && !serviceRunning -> { val otherIsPlaying = notificationPlayer?.let { other -> - runOnMainThreadSync { other.isPlaying } + other !== localPlayer && runOnMainThreadSync { other.isPlaying } } == true if (otherIsPlaying) { throw Error("Two players can't display notifications at the same time.") } notificationPlayer = localPlayer ctx.startForegroundService(Intent(ctx, OmniPlayerService::class.java)) - } else if (field == true && notificationPlayer == localPlayer) { + serviceRunning = true + } + + !shouldShow && serviceRunning -> { ctx.stopService(Intent(ctx, OmniPlayerService::class.java)) - notificationPlayer = null + if (notificationPlayer == localPlayer) notificationPlayer = null + serviceRunning = false } - field = value } + } override val castStatus: CastStatus get() = runOnMainThreadSync { computeCastStatus() } @@ -297,6 +310,7 @@ class OmniPlayer( runOnMainThreadSync { player.clearMediaItems() } + syncNotificationService() return } val handleAudioFocus = @@ -329,6 +343,7 @@ class OmniPlayer( player.setMediaItems(mediaItems, startIndex, startPositionMs.toLong()) player.prepare() } + syncNotificationService() } override fun play() { @@ -504,7 +519,13 @@ class OmniPlayerService : MediaSessionService() { override fun onCreate() { super.onCreate() - player = OmniPlayer.notificationPlayer ?: throw Error("No player available") + val available = OmniPlayer.notificationPlayer + if (available == null) { + startForeground(1, createImmediateNotification()) + stopSelf() + return + } + player = available val launchIntent = packageManager.getLaunchIntentForPackage(packageName)?.apply { addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP) } @@ -540,7 +561,8 @@ class OmniPlayerService : MediaSessionService() { player = current mediaSession.player = current } - return super.onStartCommand(intent, flags, startId) + super.onStartCommand(intent, flags, startId) + return START_NOT_STICKY } private fun createImmediateNotification(): Notification { @@ -581,7 +603,7 @@ class OmniPlayerService : MediaSessionService() { } override fun onDestroy() { - mediaSession.release() + if (::mediaSession.isInitialized) mediaSession.release() super.onDestroy() } } diff --git a/android/src/main/java/dev/zoriya/omni/VlcPlayer.kt b/android/src/main/java/dev/zoriya/omni/VlcPlayer.kt index 0bc8fa9..339ed92 100644 --- a/android/src/main/java/dev/zoriya/omni/VlcPlayer.kt +++ b/android/src/main/java/dev/zoriya/omni/VlcPlayer.kt @@ -742,9 +742,9 @@ class VlcPlayer(ctx: Context) : } } - override fun getCurrentPeriodIndex() = currentMediaItemIndex + override fun getCurrentPeriodIndex() = currentMediaItemIndex.coerceAtLeast(0) - override fun getCurrentMediaItemIndex() = currentMediaItemIndex + override fun getCurrentMediaItemIndex() = currentMediaItemIndex.coerceAtLeast(0) override fun getDuration(): Long = player.length.takeIf { it > 0 } ?: TIME_UNSET diff --git a/example/App.tsx b/example/App.tsx index 2fd838c..d474b54 100644 --- a/example/App.tsx +++ b/example/App.tsx @@ -57,12 +57,16 @@ function PlayerExample({ trackLabel, backend, onSwitchBackend, + hasSource, + onLoad, }: { onPrev: () => void; onNext: () => void; trackLabel: string; backend: AndroidBackend; onSwitchBackend: (backend: AndroidBackend) => void; + hasSource: boolean; + onLoad: () => void; }): React.JSX.Element { const player = usePlayer(); const status = usePlayerState("status"); @@ -233,7 +237,20 @@ function PlayerExample({ return ( react-native-omni - {trackLabel} + + {hasSource ? trackLabel : "No media loaded"} + + + + + + {hasSource ? "Unload media" : "Load media"} + + + ("vlc"); const [pendingBackend, setPendingBackend] = useState( null, @@ -574,7 +594,7 @@ function App(): React.JSX.Element { return ( setHasSource((v) => !v)} /> );