question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Player is accessed on the wrong thread.

See original GitHub issue

ExoPlayer Version

2.17.1

Devices that reproduce the issue

Vivo V2027 Android 12 (SDK 31) Vivo V2130 Android 12 (SDK 31) Vivo V2132 Android 12 (SDK 31) Vivo X80 Android 12 (SDK 31) Vivo V2146 Android 11 (SDK 30)

Devices that do not reproduce the issue

POCO X3 Android 12 (SDK 31) Samsung A32 Android 11 (SDK 30) Infinix Note 7 Android 10 (SDK 29) Sony Xperia ZX3 Android 10 (SDK 29)

Reproducible in the demo app?

No

Reproduction steps

none

Expected result

don’t crash

Actual result

exception.class.missing._Unknown_: java.lang.IllegalStateException	Player is accessed on the wrong thread.
  at android.app.ActivityThread.handleStopService (ActivityThread.java:5021)
  at android.app.ActivityThread.access$2400 (ActivityThread.java:284)
  at android.app.ActivityThread$H.handleMessage (ActivityThread.java:2327)
  at android.os.Handler.dispatchMessage (Handler.java:106)
  at android.os.Looper.loopOnce (Looper.java:233)
  at android.os.Looper.loop (Looper.java:334)
  at android.app.ActivityThread.main (ActivityThread.java:8399)
  at java.lang.reflect.Method.invoke (Native Method)
  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:582)
  at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1068)
Caused by: java.lang.IllegalStateException: 
  at com.google.android.exoplayer2.ExoPlayerImpl.verifyApplicationThread (ExoPlayerImpl.java)
  at com.google.android.exoplayer2.ExoPlayerImpl.getCurrentTimeline (ExoPlayerImpl.java)
  at com.google.android.exoplayer2.analytics.DefaultAnalyticsCollector.K (DefaultAnalyticsCollector.java:25)
  at com.google.android.exoplayer2.analytics.DefaultAnalyticsCollector.generateEventTime (DefaultAnalyticsCollector.java)
  at com.google.android.exoplayer2.analytics.DefaultAnalyticsCollector.generateReadingMediaPeriodEventTime (DefaultAnalyticsCollector.java)
  at com.google.android.exoplayer2.analytics.DefaultAnalyticsCollector.onSurfaceSizeChanged (DefaultAnalyticsCollector.java)
  at com.google.android.exoplayer2.ExoPlayerImpl.lambda$maybeNotifySurfaceSizeChanged$28 (ExoPlayerImpl.java)
  at com.google.android.exoplayer2.ExoPlayerImpl$$InternalSyntheticLambda$0$2d4737b778d7b8503f2f9305c33da9d50db855343d46ce9f1ebd9b998f070724$0.invoke (ExoPlayerImpl.java)
  at com.google.android.exoplayer2.util.ListenerSet$ListenerHolder.invoke (ListenerSet.java)
  at com.google.android.exoplayer2.util.ListenerSet.lambda$queueEvent$0 (ListenerSet.java)
  at com.google.android.exoplayer2.util.ListenerSet$$InternalSyntheticLambda$1$4aa6d67c50ced20c53fd0cecd314136314e77eb5e787a34f9137864aa48c8e5a$0.run (ListenerSet.java)
  at com.google.android.exoplayer2.util.ListenerSet.flushEvents (ListenerSet.java:66)
  at com.google.android.exoplayer2.util.ListenerSet.sendEvent (ListenerSet.java)
  at com.google.android.exoplayer2.ExoPlayerImpl.maybeNotifySurfaceSizeChanged (ExoPlayerImpl.java)
  at com.google.android.exoplayer2.ExoPlayerImpl.access$1800 (ExoPlayerImpl.java)
  at com.google.android.exoplayer2.ExoPlayerImpl$ComponentListener.surfaceDestroyed (ExoPlayerImpl.java)
  at android.service.wallpaper.WallpaperService$Engine.reportSurfaceDestroyed (WallpaperService.java:1945)
  at android.service.wallpaper.WallpaperService$Engine.detach (WallpaperService.java:1971)
  at android.service.wallpaper.WallpaperService.onDestroy (WallpaperService.java:2400)
  at android.app.ActivityThread.handleStopService (ActivityThread.java:5001)
  at android.app.ActivityThread.access$2400 (ActivityThread.java:284)
  at android.app.ActivityThread$H.handleMessage (ActivityThread.java:2327)
  at android.os.Handler.dispatchMessage (Handler.java:106)
  at android.os.Looper.loopOnce (Looper.java:233)
  at android.os.Looper.loop (Looper.java:334)
  at android.app.ActivityThread.main (ActivityThread.java:8399)
  at java.lang.reflect.Method.invoke (Native Method)
  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:582)
  at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1068)

Code

open class MovieLiveWallpaperService : WallpaperService() {
    private var contexts: Activity? = null

    enum class Mode {
        FIT_CENTER,
        FIT_START,
        FIT_END,
        FIT_XY,
        CENTER_CROP
    }

    private val mode: Mode
        get() = AppSharedPreferences
            .getStringDefValue(this,"scale_type", Mode.CENTER_CROP.name).let(
                Mode::valueOf)

    fun setToWallPaper(activity: Activity) {
        Utility.sendEvent("Live_Engine")
        contexts = activity
        try {
            val intent = Intent(WallpaperManager.ACTION_CHANGE_LIVE_WALLPAPER)
            intent.putExtra(
                WallpaperManager.EXTRA_LIVE_WALLPAPER_COMPONENT, ComponentName(
                    activity,
                    MovieLiveWallpaperService::class.java
                )
            )
            activity.startActivity(intent)
        } catch (ignore: ActivityNotFoundException) {
        }
    }

    override fun onCreateEngine(): Engine = GlEngine()

    protected fun initExoMediaPlayer(): ExoPlayer {
        val player = this.let { ExoPlayer.Builder(it).build() }
        player.videoScalingMode = C.VIDEO_SCALING_MODE_SCALE_TO_FIT
        player.playWhenReady = true
        player.repeatMode = Player.REPEAT_MODE_ONE
        player.volume = 0f
        if (mode == Mode.CENTER_CROP) {
            player.videoScalingMode = C.VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING
        } else {
            player.videoScalingMode = C.VIDEO_SCALING_MODE_SCALE_TO_FIT
        }
        if (mode == Mode.FIT_CENTER) {
            player.addListener(object : Player.Listener {
                override fun onPlayerError(error: PlaybackException) {
                    super.onPlayerError(error)
                    contexts?.let {
                        Toast.makeText(
                            it,
                            "${error.message} Something Went Wrong!",
                            Toast.LENGTH_SHORT
                        ).show()
                    }
                }
            })

        }
        return player
    }

    inner class GlEngine : WallpaperService.Engine() {

        private var exoMediaPlayer = initExoMediaPlayer()

        override fun onVisibilityChanged(visible: Boolean) {
            exoMediaPlayer.playWhenReady = visible
            if (visible) onResume()
            else onPause()
        }

        @Synchronized
        override fun onSurfaceCreated(holder: SurfaceHolder) {
            kotlin.runCatching {
                if (mode == Mode.FIT_CENTER) {
                    exoMediaPlayer.setVideoSurface(holder.surface)
                } else {
                    exoMediaPlayer.setVideoSurfaceHolder(holder)
                }
                val videoUri = this@MovieLiveWallpaperService.let {
                    AppSharedPreferences.getString(
                        it,
                        "absolutePath"
                    )
                }
                val isLocalVideo =
                    AppSharedPreferences.getBool(this@MovieLiveWallpaperService, "isLocalVideo")
                when {
                    isLocalVideo -> exoMediaPlayer.setMediaSource(
                        buildMediaSourceForLocal(
                            Uri.parse(
                                videoUri
                            )
                        )
                    )
                    !isLocalVideo -> exoMediaPlayer.setMediaSource(
                        buildMediaSource(
                            Uri.parse(
                                videoUri
                            )
                        )
                    )
                }

                exoMediaPlayer.prepare()
                exoMediaPlayer.play()
            }
        }

        private fun buildMediaSource(uri: Uri): MediaSource {
            val userAgent = "exoplayer-liveWallpaper"
            val media_item: MediaItem = MediaItem.fromUri(uri)
            val cache_datasource_factory = CacheDataSource.Factory()
                .setCache(EngineVideoCache.getInstance(this@MovieLiveWallpaperService))
                .setUpstreamDataSourceFactory(
                    DefaultHttpDataSource.Factory()
                        .setUserAgent(userAgent)
                )
            return ProgressiveMediaSource.Factory(cache_datasource_factory)
                .createMediaSource(media_item)
        }

        private fun buildMediaSourceForLocal(uri: Uri): MediaSource {
            val media_item: MediaItem = MediaItem.fromUri(uri)
            val dataSource = CacheDataSource.Factory()
                    .setCache(EngineVideoCache.getInstance(this@MovieLiveWallpaperService))
                    .setUpstreamDataSourceFactory(DefaultDataSource.Factory(this@MovieLiveWallpaperService))
            return  ProgressiveMediaSource.Factory(dataSource)
                .createMediaSource(media_item)
        }

        override fun onSurfaceChanged(
            holder: SurfaceHolder?,
            format: Int,
            width: Int,
            height: Int
        ) {
        }

        @Synchronized
        override fun onSurfaceDestroyed(holder: SurfaceHolder?) {
        }

        override fun onDestroy() {
            kotlin.runCatching {
                super.onDestroy()
                exoMediaPlayer.stop()
                exoMediaPlayer.release()
            }
        }

        private fun onPause() {
            kotlin.runCatching {
                exoMediaPlayer.pause()
            }
        }

        private fun onResume() {
            kotlin.runCatching {
                exoMediaPlayer.play()
            }
        }
    }
}

Bug Report

  • You will email the zip file produced by adb bugreport to dev.exoplayer@gmail.com after filing this issue.

Issue Analytics

  • State:open
  • Created a year ago
  • Comments:9 (3 by maintainers)

github_iconTop GitHub Comments

1reaction
sixonescommented, Aug 25, 2022

@marcbaechinger This is very much an ExoPlayer issue rather than an app issue, ExoPlayer subscribes to the events from the SurfaceHolder inside of ExoPlayerImpl and the SurfaceHolder subscribes to the SurfaceView, the events that are triggered from the SurfaceView / SurfaceHolder are always on the main thread (as it’s an Android view). If ExoPlayer is running on a different thread / looper, when the analytics collector then tries to find the media period event time, the generateReadingMediaPeriodEventTime method tries to access the player timeline, which checks the thread and throws an IllegalStateException.

It’s a fairly simple work around in ExoPlayerImpl by setting up a handler on the applicationLooper and running listeners.sendEvent on that handler inside of maybeNotifySurfaceSizeChanged. To fix it outside of ExoPlayer requires creating a custom SurfaceHolder class that listens to the callbacks and forwards them on the correct thread back to ExoPlayer.

java.lang.IllegalStateException: Player is accessed on the wrong thread.
Current thread: 'main'
Expected thread: 'ExoPlayer'
See https://exoplayer.dev/issues/player-accessed-on-wrong-thread
  at com.google.android.exoplayer2.ExoPlayerImpl.verifyApplicationThread(ExoPlayerImpl.java:2600)
  at com.google.android.exoplayer2.ExoPlayerImpl.getCurrentTimeline(ExoPlayerImpl.java:1194)
  at com.google.android.exoplayer2.analytics.DefaultAnalyticsCollector.generateEventTime(DefaultAnalyticsCollector.java:909)
  at com.google.android.exoplayer2.analytics.DefaultAnalyticsCollector.generateEventTime(DefaultAnalyticsCollector.java:965)
  at com.google.android.exoplayer2.analytics.DefaultAnalyticsCollector.generateReadingMediaPeriodEventTime(DefaultAnalyticsCollector.java:973)
  at com.google.android.exoplayer2.analytics.DefaultAnalyticsCollector.onSurfaceSizeChanged(DefaultAnalyticsCollector.java:374)
  at com.google.android.exoplayer2.ExoPlayerImpl.lambda$maybeNotifySurfaceSizeChanged$27(ExoPlayerImpl.java:2529)
  at com.google.android.exoplayer2.ExoPlayerImpl$$ExternalSyntheticLambda23.invoke(Unknown Source:6)
  at com.google.android.exoplayer2.util.ListenerSet$ListenerHolder.invoke(ListenerSet.java:281)
  at com.google.android.exoplayer2.util.ListenerSet.lambda$queueEvent$0(ListenerSet.java:190)
  at com.google.android.exoplayer2.util.ListenerSet$$ExternalSyntheticLambda1.run(Unknown Source:6)
  at com.google.android.exoplayer2.util.ListenerSet.flushEvents(ListenerSet.java:211)
  at com.google.android.exoplayer2.util.ListenerSet.sendEvent(ListenerSet.java:226)
  at com.google.android.exoplayer2.ExoPlayerImpl.maybeNotifySurfaceSizeChanged(ExoPlayerImpl.java:2528)
  at com.google.android.exoplayer2.ExoPlayerImpl.access$1900(ExoPlayerImpl.java:104)
  at com.google.android.exoplayer2.ExoPlayerImpl$ComponentListener.surfaceChanged(ExoPlayerImpl.java:2894)
  at android.view.SurfaceView.updateSurface(SurfaceView.java:1177)
  at android.view.SurfaceView.lambda$new$0$SurfaceView(SurfaceView.java:173)
  at android.view.-$$Lambda$SurfaceView$w68OV7dB_zKVNsA-r0IrAUtyWas.onPreDraw(Unknown Source:2)
  at android.view.ViewTreeObserver.dispatchOnPreDraw(ViewTreeObserver.java:1093)
  at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:3203)
  at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:2018)
  at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:8467)
  at android.view.Choreographer$CallbackRecord.run(Choreographer.java:972)
  at android.view.Choreographer.doCallbacks(Choreographer.java:796)
  at android.view.Choreographer.doFrame(Choreographer.java:731)
  at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:957)
  at android.os.Handler.handleCallback(Handler.java:938)
  at android.os.Handler.dispatchMessage(Handler.java:99)
  at android.os.Looper.loop(Looper.java:223)
  at android.app.ActivityThread.main(ActivityThread.java:7668)
  at java.lang.reflect.Method.invoke(Native Method)
  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
0reactions
freeboubcommented, Nov 15, 2022

I confirm @sixones analysis and can confirm this is reproduced on 2.18.1 release. Here is my callstack, but I don’t think it brings additionnal informations. I tryed to disable analyticsCollector with: setAnalyticsCollector(null) or with player.getAnalyticsCollector().setPlayer(null, null); but unfortunately it doesn’t seem possible.

11-15 22:37:14.353  7819  7819 E SurfaceView: Exception configuring surface
11-15 22:37:14.353  7819  7819 E SurfaceView: java.lang.IllegalStateException: Player is accessed on the wrong thread.
11-15 22:37:14.353  7819  7819 E SurfaceView: Current thread: 'main'
11-15 22:37:14.353  7819  7819 E SurfaceView: Expected thread: 'RNVLooper_0'
11-15 22:37:14.353  7819  7819 E SurfaceView: See https://exoplayer.dev/issues/player-accessed-on-wrong-thread
11-15 22:37:14.353  7819  7819 E SurfaceView: 	at com.google.android.exoplayer2.ExoPlayerImpl.verifyApplicationThread(ExoPlayerImpl.java:2597)
11-15 22:37:14.353  7819  7819 E SurfaceView: 	at com.google.android.exoplayer2.ExoPlayerImpl.getCurrentMediaItemIndex(ExoPlayerImpl.java:1010)
11-15 22:37:14.353  7819  7819 E SurfaceView: 	at com.google.android.exoplayer2.analytics.DefaultAnalyticsCollector.generateEventTime(DefaultAnalyticsCollector.java:958)
11-15 22:37:14.353  7819  7819 E SurfaceView: 	at com.google.android.exoplayer2.analytics.DefaultAnalyticsCollector.generateReadingMediaPeriodEventTime(DefaultAnalyticsCollector.java:973)
11-15 22:37:14.353  7819  7819 E SurfaceView: 	at com.google.android.exoplayer2.analytics.DefaultAnalyticsCollector.onSurfaceSizeChanged(DefaultAnalyticsCollector.java:374)
11-15 22:37:14.353  7819  7819 E SurfaceView: 	at com.google.android.exoplayer2.ExoPlayerImpl.lambda$maybeNotifySurfaceSizeChanged$27(ExoPlayerImpl.java:2526)
11-15 22:37:14.353  7819  7819 E SurfaceView: 	at com.google.android.exoplayer2.-$$Lambda$ExoPlayerImpl$LEzBBscn-_l3k3Wp16Yiv1NbVFo.invoke(Unknown Source:6)
11-15 22:37:14.353  7819  7819 E SurfaceView: 	at com.google.android.exoplayer2.util.ListenerSet$ListenerHolder.invoke(ListenerSet.java:281)
11-15 22:37:14.353  7819  7819 E SurfaceView: 	at com.google.android.exoplayer2.util.ListenerSet.lambda$queueEvent$0(ListenerSet.java:190)
11-15 22:37:14.353  7819  7819 E SurfaceView: 	at com.google.android.exoplayer2.util.-$$Lambda$ListenerSet$NbKDn9xtItiyMgYZmjIx_Sv1FFQ.run(Unknown Source:6)
11-15 22:37:14.353  7819  7819 E SurfaceView: 	at com.google.android.exoplayer2.util.ListenerSet.flushEvents(ListenerSet.java:211)
11-15 22:37:14.353  7819  7819 E SurfaceView: 	at com.google.android.exoplayer2.util.ListenerSet.sendEvent(ListenerSet.java:226)
11-15 22:37:14.353  7819  7819 E SurfaceView: 	at com.google.android.exoplayer2.ExoPlayerImpl.maybeNotifySurfaceSizeChanged(ExoPlayerImpl.java:2525)
11-15 22:37:14.353  7819  7819 E SurfaceView: 	at com.google.android.exoplayer2.ExoPlayerImpl.access$1800(ExoPlayerImpl.java:104)
11-15 22:37:14.353  7819  7819 E SurfaceView: 	at com.google.android.exoplayer2.ExoPlayerImpl$ComponentListener.surfaceChanged(ExoPlayerImpl.java:2882)
11-15 22:37:14.353  7819  7819 E SurfaceView: 	at android.view.SurfaceView.updateSurface(SurfaceView.java:770)
11-15 22:37:14.353  7819  7819 E SurfaceView: 	at android.view.SurfaceView$2.onPreDraw(SurfaceView.java:155)
11-15 22:37:14.353  7819  7819 E SurfaceView: 	at android.view.ViewTreeObserver.dispatchOnPreDraw(ViewTreeObserver.java:1088)
11-15 22:37:14.353  7819  7819 E SurfaceView: 	at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2745)
11-15 22:37:14.353  7819  7819 E SurfaceView: 	at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1721)
11-15 22:37:14.353  7819  7819 E SurfaceView: 	at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:7598)
11-15 22:37:14.353  7819  7819 E SurfaceView: 	at android.view.Choreographer$CallbackRecord.run(Choreographer.java:966)
11-15 22:37:14.353  7819  7819 E SurfaceView: 	at android.view.Choreographer.doCallbacks(Choreographer.java:790)
11-15 22:37:14.353  7819  7819 E SurfaceView: 	at android.view.Choreographer.doFrame(Choreographer.java:725)
11-15 22:37:14.353  7819  7819 E SurfaceView: 	at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:951)
11-15 22:37:14.353  7819  7819 E SurfaceView: 	at android.os.Handler.handleCallback(Handler.java:883)
11-15 22:37:14.353  7819  7819 E SurfaceView: 	at android.os.Handler.dispatchMessage(Handler.java:100)
11-15 22:37:14.353  7819  7819 E SurfaceView: 	at android.os.Looper.loop(Looper.java:214)
11-15 22:37:14.353  7819  7819 E SurfaceView: 	at android.app.ActivityThread.main(ActivityThread.java:7356)
11-15 22:37:14.353  7819  7819 E SurfaceView: 	at java.lang.reflect.Method.invoke(Native Method)
11-15 22:37:14.353  7819  7819 E SurfaceView: 	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
11-15 22:37:14.353  7819  7819 E SurfaceView: 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)

Read more comments on GitHub >

github_iconTop Results From Across the Web

Player is accessed on the wrong thread · Issue #8843 - GitHub
One of the purposes of this class is to provide a surface in which a secondary thread can render into the screen. If...
Read more >
Exoplayer throws Player is accessed on the wrong thread ...
In onResume() from MainActivity I set exoPlayer.experimentalSetOffloadSchedulingEnabled(false); which throws "Player is accessed on the wrong ...
Read more >
Troubleshooting - ExoPlayer
What do “Player is accessed on the wrong thread” errors mean? See A note on threading on the getting started page. How can...
Read more >
com.google.android.exoplayer2.SimpleExoPlayer ... - Tabnine
Only * players which are accessed on the main thread are supported ... getApplicationLooper()) { Log.w( TAG, "Player is accessed on the wrong...
Read more >
SimpleExoPlayer: Player is accessed on the wrong thread
While watching videos using NewPipe v0.16.2, logcat being spammed with the following line: W SimpleExoPlayer: Player is accessed on the ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found