Description
ExoPlayer Version
2.18.1
Devices that reproduce the issue
Devices: Moto, Samsung, Pixel
Android Versions: 12, 13
Devices that do not reproduce the issue
Has not been observed on any android versions under 12
Reproducible in the demo app?
Trying, haven't been able to reproduce
Reproduction steps
I've been able to reproduce it locally by triggering rapid volume changes when exiting playback. I've done it both via spamming ADB commands and also holding the physical volume slider on the phone.
Looking across multiple instances of it occurring, it seems to happen to a non-insignificant number of users after the playback activity / fragments trigger their destroyed lifecycle methods.
It's worth noting that our playback activity is locked to landscape, so users often get configuration changes when exiting it (many users lock their phones in portrait). Reproducing this using the volume method as described above is rather flakey - but as of right now I haven't been able to reproduce while keeping the phone in landscape across both activities.
java.lang.IllegalStateException
at com.google.android.exoplayer2.util.Assertions.checkState
at com.google.android.exoplayer2.util.FlagSet$Builder.build(SourceFile:150)
at com.google.android.exoplayer2.util.ListenerSet$ListenerHolder.release
at com.google.android.exoplayer2.util.ListenerSet.release(SourceFile:236)
at com.google.android.exoplayer2.analytics.DefaultAnalyticsCollector.releaseInternal
at com.google.android.exoplayer2.StreamVolumeManager$VolumeChangeReceiver$$InternalSyntheticLambda$3$f8a604daa12c21ed8502402f441ed63734c776977dc7c4af3d0e402bf56df29e$0.run$bridge(SourceFile:0)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loopOnce(Looper.java:226)
at android.os.Looper.loop(Looper.java:313)
at android.app.ActivityThread.main(ActivityThread.java:8751)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:571)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1135)
Expected result
ExoPlayer would not throw an IllegalStateException after the activity has been destroyed.
Actual result
ExoPlayer occasionally enters a state where an exception is thrown.
Media
N/A
Bug Report
- You will email the zip file produced by
adb bugreport
to dev.exoplayer@gmail.com after filing this issue.
Activity
tonihei commentedon Nov 10, 2022
Do you create or use the player on a background thread that isn't the application main thread by any chance? Or is there anything else noteworthy about how you release the player?
It certainly looks like a bug that this particular IllegalStateException is thrown and I'm trying to understand under which circumstances it can happen.
malbanese commentedon Nov 10, 2022
@tonihei We're not creating the player from a background thread, to be 100% sure I reproduced it while asserting that it was the main thread. As far as releasing the player, it does happen inside of a fragment's onDestroy method, but when double checking - there's nothing noteworthy happening at the same time.
I verified that our release method does only get called a single time, and to be extra sure it wasn't some strange interaction with our own
AnalyticsListener
, I also reproduced it without adding it as well.I've been able to band-aid fix it by cloning the
DefaultAnalyticsListener
and catching the exception inside the class'sreleaseInternal
method - but its a non-ideal fix, since something strange is obviously happening.tonihei commentedon Nov 15, 2022
I tried to reproduce this in the ExoPlayer demo app by manually changing the volume and by programmatically inundating the listener with continuous artificial volume change events. This didn't trigger the problem, so I believe there is something in your setup that make this happen. Can you try to reproduce in the demo app to see what you changes to make this problem appear?
I also tried to analyze the method calls to understand how this exception can possibly happen and found some possibilities that are not directly related to the volume changes. It seems the exception can happen if you overwrite a
Player.Listener
orAnalyticsListener
and from within one of the callbacks callplayer.release()/removeListener()/removeAnalyticsListener()
(orAnalyticsCollector.release()
). Even then, the problem only occurs if this callback is followed by another automatic release or listener removal AND there was a pending event to be notified (this could be the volume change).Could you check your listener implementations to see if/when you call any of these methods? We should also look into fixing this problem, but would be good to understand where it comes from exactly.
tonihei commentedon Nov 15, 2022
Update: I can reproduce in a unit test that removes a listener from within the
onEvents
callback (you can probably use any other callback triggered at the same time, likeAnalyticsCollector.onReleased
). I assume this is what's happening in your app as well. We'll provide a fix for this!malbanese commentedon Nov 15, 2022
Aha, thanks for the thorough explanation on how it might be happening! I can definitely double check the cases you've outlined, just for some peace of mind.
8 remaining items