Skip to content

fix(android): Reset prepared state on ExoPlayer STATE_IDLE in audioplayers_android_exo#1999

Open
leonardo-oliveir-a wants to merge 1 commit into
bluefireteam:mainfrom
leonardo-oliveir-a:fix/exo-idle-prepared
Open

fix(android): Reset prepared state on ExoPlayer STATE_IDLE in audioplayers_android_exo#1999
leonardo-oliveir-a wants to merge 1 commit into
bluefireteam:mainfrom
leonardo-oliveir-a:fix/exo-idle-prepared

Conversation

@leonardo-oliveir-a

@leonardo-oliveir-a leonardo-oliveir-a commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Description

onPlaybackStateChanged currently treats Player.STATE_IDLE as a no-op (TODO(gustl22): may can use or leave as no-op). ExoPlayer enters STATE_IDLE after a playback error (and after stop()/release()), and from IDLE it cannot play again without a new prepare().

Leaving prepared = true after an error means both sides keep believing the player is usable:

  • WrappedPlayer.resume() calls play() on an idle player — a silent no-op, audio just never starts;
  • the Dart side never receives audio.onPrepared with value: false, so getDuration()/getCurrentPosition() keep being queried on a dead player.

This resets prepared via a new WrappedPlayer.onIdle() callback. For the intentional IDLE paths (player creation, release(), source set to null) this is a no-op: the prepared setter only reacts to actual value changes, and those flows already reset it before the async listener callback arrives.

Checklist

  • The title of my PR starts with a [Conventional Commit] prefix (fix:, feat:, docs: etc).
  • I have read the [Contributor Guide] and followed the process outlined for submitting PRs.
  • I have updated/added tests for ALL new/updated/fixed functionality — no test infra exists for the Kotlin layer of this package.
  • I have updated/added relevant documentation — KDoc added on onIdle() explaining when it fires and why.
  • I have updated/added relevant examples in examples — reproducible in the example app: stream a URL, kill connectivity mid-playback until ExoPlayer errors out, observe that without this patch no onPrepared(false) event arrives.

Breaking Change

  • Yes, this is a breaking change.
  • No, this is not a breaking change.

Related Issues

Complements the error path of #1721 (background audio stops and never recovers): after this change, apps can at least observe the unprepared state and re-prepare.

…ayers_android_exo

STATE_IDLE was a no-op TODO. ExoPlayer enters IDLE after a playback
error (and after stop()/release()), and from IDLE it cannot play again
without prepare(). Keeping prepared=true after an error leaves both the
wrapper and the Dart side believing the player is usable: resume() calls
play() on an idle player (silent no-op) and the Dart side never receives
audio.onPrepared(false).

Reset prepared via a new WrappedPlayer.onIdle() callback. For the
intentional paths (creation, stop, release) this is a no-op since the
prepared setter only reacts to actual changes and those flows already
reset it.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant