Skip to content

ExoPlayer can report isLoading=true in STATE_ENDED, crashing ForwardingSimpleBasePlayer / CastPlayer #3467

Open

Description

@albinus-sc

Version

Media3 1.11.1

More version details

Also seen on 1.10.1

We use CastPlayer.Builder().setLocalPlayer(exoPlayer), so the local ExoPlayer is wrapped in a ForwardingSimpleBasePlayer.

Devices that reproduce the issue

Various devices and Android versions in production. 9 within 30 minutes, across three app versions from users who were casting a live HLS stream. It seems the HLS stream was being restarted in this period, causing the crash.

Devices that do not reproduce the issue

No response

Reproducible in the demo app?

Not tested

Reproduction steps

We have not been able to reproduce it locally. The users were most likely listening to a live HLS audio stream when it crashed.

Expected result

ExoPlayer never reports isLoading() == true while getPlaybackState() is STATE_IDLE or STATE_ENDED, as required by SimpleBasePlayer.State.

Actual result

Fatal Exception: java.lang.IllegalArgumentException: isLoading only allowed when not in STATE_IDLE or STATE_ENDED
       at com.google.common.base.Preconditions.checkArgument(Preconditions.java:143)
       at androidx.media3.common.SimpleBasePlayer$State.<init>(SimpleBasePlayer.java:1073)
       at androidx.media3.common.SimpleBasePlayer$State.<init>(SimpleBasePlayer.java:101)
       at androidx.media3.common.SimpleBasePlayer$State$Builder.build(SimpleBasePlayer.java:844)
       at androidx.media3.common.ForwardingSimpleBasePlayer.getState(ForwardingSimpleBasePlayer.java:188)
       at androidx.media3.cast.CastPlayerImpl.getState(CastPlayerImpl.java:87)
       at androidx.media3.common.SimpleBasePlayer.invalidateState(SimpleBasePlayer.java:3178)
       at androidx.media3.common.ForwardingSimpleBasePlayer$PlayerListener.onEvents(ForwardingSimpleBasePlayer.java:532)
       at androidx.media3.exoplayer.ExoPlayerImpl.lambda$new$0(ExoPlayerImpl.java:323)
       at androidx.media3.common.util.ListenerSet$ListenerHolder.iterationFinished(ListenerSet.java:477)
       at androidx.media3.common.util.ListenerSet.handleMessage(ListenerSet.java:421)
       at android.os.Handler.dispatchMessage(Handler.java:128)
       ...

The event comes from the local ExoPlayer, so it reported isLoading == true together with STATE_IDLE or STATE_ENDED.

Looking at the 1.11.1 sources, a likely path is ExoPlayerImplInternal.doSomeWork():

if (finishedRendering && playingPeriodHolder.info.isFinal) {
  setState(Player.STATE_ENDED);
  stopRenderers();
}

setState only copies the playback state, and isLoading stays at whatever updateIsLoading() set earlier in the same iteration (shouldContinueLoading || loadingPeriod.mediaPeriod.isLoading()). If the loading period is still loading when the final period finishes rendering, the ENDED update is published with isLoading == true. Because doSomeWork() returns early in STATE_ENDED, it is not corrected afterwards. The other setState(STATE_ENDED) call sites go through resetInternal(), which sets isLoading to false, and ExoPlayerImpl.maskPlaybackState() also clears it, so this path seems to be the odd one out.

This looks similar to #2873 (fixed in 1.10.0), but that fix is already in the versions we see the crash on.

Media

Live HLS audio streams (not publicly shareable test case available at the moment).

Bug Report

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions