androidx / media

Jetpack Media3 support libraries for media use cases, including ExoPlayer, an extensible media player for Android
https://developer.android.com/media/media3
Apache License 2.0
1.59k stars 377 forks source link

Error in RuntimeException while executing runnable PlayerServiceActivity$$ExternalSyntheticLambda0@a30fc82 with executor MoreExecutors.directExecutor() #1597

Open AnshumanHexabrain opened 1 month ago

AnshumanHexabrain commented 1 month ago

Hello there, First off, I want to say a big thank you for the amazing work on Media3! 🎉 The integration process was really smooth, and I'm super impressed.

I have a query regarding crash issue in MediaLibraryService

I have a implemented MediaLibraryService for mobile and android auto and getting an crash while opening the activity like

RuntimeException while executing runnable AudioWithSyncServiceActivity$$ExternalSyntheticLambda0@a30fc82 with executor MoreExecutors.directExecutor() java.util.concurrent.ExecutionException: java.lang.SecurityException: Session rejected the connection request. at com.google.common.util.concurrent.AbstractFuture.getDoneValue(AbstractFuture.java:594) at com.google.common.util.concurrent.AbstractFuture.get(AbstractFuture.java:553)

As I have added below code for my activity and service

Activity ` private lateinit var controllerFuture: ListenableFuture private val controller: MediaController? get() = if (controllerFuture.isDone && !controllerFuture.isCancelled) controllerFuture.get() else null

    controllerFuture =
            MediaController.Builder(
                this,
                SessionToken(this, ComponentName(this, PlayerServiceWithSync::class.java)),
            )
                .buildAsync()
        controllerFuture.addListener({ setController() }, MoreExecutors.directExecutor())

        private fun setController() {
    val controller = this.controller ?: return

    playerView.player = controller
    playerView.useController = true

    lifecycleScope.launch {
        delay(500)
        EventBus.getDefault().post(MessageEvent(controller))
    }

    override fun onBackPressed() {
    releaseService()
    super.onBackPressed()
}

private fun releaseService(){
    Log.d(TAG, "Release service called")
    playerView.player?.release()
    playerView.player = null
    releaseController()
    val stopIntent = Intent(this, PlayerServiceWithSync::class.java)
    stopIntent.action = "STOP_SERVICE"
    startService(stopIntent)
}

private fun releaseController() {
    if (::controllerFuture.isInitialized){
        MediaController.releaseFuture(controllerFuture)
    }
}

}

onService class

OnCreate

val activityClass = msActivity?.get()
            if (activityClass != null){
                val intent = Intent(this@PlayerServiceWithSync, activityClass!!::class.java)
                val pendingFlags = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
                    PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
                } else {
                    PendingIntent.FLAG_UPDATE_CURRENT
                }
                val pendingIntent = PendingIntent.getActivity(
                    this@PlayerServiceWithSync, 0, intent, pendingFlags
                )

                mediaLibrarySession = if (pendingIntent != null){
                    MediaLibrarySession.Builder(this, getMsPlayer()?.msPlayer!!, callback)
                        .setSessionActivity(pendingIntent)
                        .setCustomLayout(createCustomLayout())
                        .build()
                } else {
                    MediaLibrarySession.Builder(this, getMsPlayer()?.msPlayer!!, callback)
                        .setCustomLayout(createCustomLayout())
                        .build()
                }
            } else {
                MediaLibrarySession.Builder(this, getMsPlayer()?.msPlayer!!, callback)
                    .setCustomLayout(createCustomLayout())
                    .build()
            }

@Subscribe(threadMode = ThreadMode.MAIN)
    fun onMessageEvent(event: MessageEvent) {

        val player = if (msPlayer?.get() != null){
            msPlayer?.get()
        } else {
            val config = PlayerConfig()

            val msPlayer = WeakReference(Player(
                msContext?.get() ?: this,
                msConfig ?: config,
                msContainer?.get(),
                msPlayerView?.get()?: PlayerView(this),
                msMiniPlayerConfig ?: MiniPlayerConfig()
            ))
            msPlayer.get()
        }

//        msConfig?.let { msPlayer?.get()?.updateMsConfig(config = it) }
        player?.setPlayer(event.controller)
//        playerLitener()
    }
as I am using media3 1.4.0
microkatz commented 1 month ago

@AnshumanHexabrain

I think there is some confusion in your code logic. It appears that you are creating the controller and then sending it via MessageEvent to your session service code of which you are then setting the controller as the player? The session code should have its own ExoPlayer instance that will be running the media playback. It should not be the controller.

Perhaps it would help to review the developer documentation we have, https://developer.android.com/media/implement/playback-app.

All you should need to do is set the correct token on the building of your MediaController. You shouldn't need to pass the controller to the session code.

Here is some other resources and code that may be helpful.

Hopefully that helps! Please write back if you have additional questions.