1
0
mirror of https://github.com/TeamNewPipe/NewPipe synced 2025-07-25 05:12:58 +00:00

PlayerService: remove !! where possible

It’s a bit unwieldy in places, but should improve the safety of the
code in the face of possible race conditions.
This commit is contained in:
Profpatsch 2025-05-13 17:00:46 +02:00
parent be373dca8d
commit 36115c3164

View File

@ -82,35 +82,35 @@ class PlayerService : MediaBrowserServiceCompat() {
mediaBrowserImpl = MediaBrowserImpl( mediaBrowserImpl = MediaBrowserImpl(
this, this,
Consumer { parentId: String? -> Consumer { parentId: String ->
this.notifyChildrenChanged( this.notifyChildrenChanged(
parentId!! parentId
) )
} }
) )
// see https://developer.android.com/training/cars/media#browser_workflow // see https://developer.android.com/training/cars/media#browser_workflow
mediaSession = MediaSessionCompat(this, "MediaSessionPlayerServ") val session = MediaSessionCompat(this, "MediaSessionPlayerServ")
setSessionToken(mediaSession!!.sessionToken) mediaSession = session
sessionConnector = MediaSessionConnector(mediaSession!!) setSessionToken(session.sessionToken)
sessionConnector!!.setMetadataDeduplicationEnabled(true) val connector = MediaSessionConnector(session)
sessionConnector = connector
connector.setMetadataDeduplicationEnabled(true)
mediaBrowserPlaybackPreparer = MediaBrowserPlaybackPreparer( mediaBrowserPlaybackPreparer = MediaBrowserPlaybackPreparer(
this, this,
BiConsumer { message: String?, code: Int? -> BiConsumer { message: String, code: Int ->
sessionConnector!!.setCustomErrorMessage( connector.setCustomErrorMessage(
message, message,
code!! code
) )
}, },
Runnable { sessionConnector!!.setCustomErrorMessage(null) }, Runnable { connector.setCustomErrorMessage(null) },
Consumer { playWhenReady: Boolean? -> Consumer { playWhenReady: Boolean? ->
if (player != null) { player?.onPrepare()
player!!.onPrepare()
}
} }
) )
sessionConnector!!.setPlaybackPreparer(mediaBrowserPlaybackPreparer) connector.setPlaybackPreparer(mediaBrowserPlaybackPreparer)
// Note: you might be tempted to create the player instance and call startForeground here, // Note: you might be tempted to create the player instance and call startForeground here,
// but be aware that the Android system might start the service just to perform media // but be aware that the Android system might start the service just to perform media
@ -153,16 +153,18 @@ class PlayerService : MediaBrowserServiceCompat() {
player!!.UIs().get(NotificationPlayerUi::class.java) player!!.UIs().get(NotificationPlayerUi::class.java)
?.createNotificationAndStartForeground() ?.createNotificationAndStartForeground()
if (playerWasNull && onPlayerStartedOrStopped != null) { val startedOrStopped = onPlayerStartedOrStopped
if (playerWasNull && startedOrStopped != null) {
// notify that a new player was created (but do it after creating the foreground // notify that a new player was created (but do it after creating the foreground
// notification just to make sure we don't incur, due to slowness, in // notification just to make sure we don't incur, due to slowness, in
// "Context.startForegroundService() did not then call Service.startForeground()") // "Context.startForegroundService() did not then call Service.startForeground()")
onPlayerStartedOrStopped!!.accept(player) startedOrStopped.accept(player)
} }
} }
val p = player
if (Intent.ACTION_MEDIA_BUTTON == intent.action && if (Intent.ACTION_MEDIA_BUTTON == intent.action &&
(player == null || player!!.playQueue == null) (p == null || p.playQueue == null)
) { ) {
/* /*
No need to process media button's actions if the player is not working, otherwise No need to process media button's actions if the player is not working, otherwise
@ -174,7 +176,6 @@ class PlayerService : MediaBrowserServiceCompat() {
return START_NOT_STICKY return START_NOT_STICKY
} }
val p = player
if (p != null) { if (p != null) {
p.handleIntent(intent) p.handleIntent(intent)
p.UIs().get(MediaSessionPlayerUi::class.java) p.UIs().get(MediaSessionPlayerUi::class.java)
@ -189,17 +190,19 @@ class PlayerService : MediaBrowserServiceCompat() {
Log.d(TAG, "stopForImmediateReusing() called") Log.d(TAG, "stopForImmediateReusing() called")
} }
if (player != null && !player!!.exoPlayerIsNull()) { val p = player
if (p != null && !p.exoPlayerIsNull()) {
// Releases wifi & cpu, disables keepScreenOn, etc. // Releases wifi & cpu, disables keepScreenOn, etc.
// We can't just pause the player here because it will make transition // We can't just pause the player here because it will make transition
// from one stream to a new stream not smooth // from one stream to a new stream not smooth
player!!.smoothStopForImmediateReusing() p.smoothStopForImmediateReusing()
} }
} }
override fun onTaskRemoved(rootIntent: Intent?) { override fun onTaskRemoved(rootIntent: Intent?) {
super.onTaskRemoved(rootIntent) super.onTaskRemoved(rootIntent)
if (player != null && !player!!.videoPlayerSelected()) { val p = player
if (p != null && !p.videoPlayerSelected()) {
return return
} }
onDestroy() onDestroy()
@ -215,23 +218,22 @@ class PlayerService : MediaBrowserServiceCompat() {
cleanup() cleanup()
mediaBrowserPlaybackPreparer!!.dispose() mediaBrowserPlaybackPreparer?.dispose()
mediaSession!!.release() mediaSession?.release()
mediaBrowserImpl!!.dispose() mediaBrowserImpl?.dispose()
} }
private fun cleanup() { private fun cleanup() {
if (player != null) { val p = player
if (onPlayerStartedOrStopped != null) { if (p != null) {
// notify that the player is being destroyed // notify that the player is being destroyed
onPlayerStartedOrStopped!!.accept(null) onPlayerStartedOrStopped?.accept(null)
} p.saveAndShutdown()
player!!.saveAndShutdown()
player = null player = null
} }
// Should already be handled by MediaSessionPlayerUi, but just to be sure. // Should already be handled by MediaSessionPlayerUi, but just to be sure.
mediaSession!!.setActive(false) mediaSession?.setActive(false)
// Should already be handled by NotificationUtil.cancelNotificationAndStopForeground() in // Should already be handled by NotificationUtil.cancelNotificationAndStopForeground() in
// NotificationPlayerUi, but let's make sure that the foreground service is stopped. // NotificationPlayerUi, but let's make sure that the foreground service is stopped.
@ -311,10 +313,7 @@ class PlayerService : MediaBrowserServiceCompat() {
*/ */
fun setPlayerListener(listener: Consumer<Player?>?) { fun setPlayerListener(listener: Consumer<Player?>?) {
this.onPlayerStartedOrStopped = listener this.onPlayerStartedOrStopped = listener
if (listener != null) { listener?.accept(player)
// if there is no player, then `null` will be sent here, to ensure the state is synced
listener.accept(player)
}
} }
//endregion //endregion
@ -332,7 +331,7 @@ class PlayerService : MediaBrowserServiceCompat() {
parentId: String, parentId: String,
result: Result<List<MediaBrowserCompat.MediaItem>> result: Result<List<MediaBrowserCompat.MediaItem>>
) { ) {
mediaBrowserImpl!!.onLoadChildren(parentId, result) mediaBrowserImpl?.onLoadChildren(parentId, result)
} }
override fun onSearch( override fun onSearch(
@ -340,7 +339,7 @@ class PlayerService : MediaBrowserServiceCompat() {
extras: Bundle?, extras: Bundle?,
result: Result<List<MediaBrowserCompat.MediaItem>> result: Result<List<MediaBrowserCompat.MediaItem>>
) { ) {
mediaBrowserImpl!!.onSearch(query, result) mediaBrowserImpl?.onSearch(query, result)
} //endregion } //endregion
companion object { companion object {