Repository navigation
fix(mobile): keep redux play state in sync when the iOS queue ends - #14653
Merged
Merged
Conversation
When the native queue ends, RNTP fires PlaybackQueueEnded and the player stops with playWhenReady false, but the handler ignored the event, so redux kept `playing: true`. The play button kept showing pause, and the next play (Previous restarting the track, Previous to an earlier track, tapping a track) never called TrackPlayer.play() because `playing` did not change. The track sat paused while the scrubber kept moving. - On PlaybackQueueEnded, mark redux paused. - After TrackPlayer.skip(), call play() if redux is playing. On iOS, skip only keeps playing when the player is in the playing state, so a skip while loading or buffering (Next then Previous quickly) also loaded the new track paused. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Bug
On iOS, after a list plays to its end:
PlaybackQueueEnded, noPlaybackActiveTrackChanged).Both symptoms come from the same cause. They aren't related to #14649 or to the SwiftAudioEx index bug in #14650: native
currentIndexis correct at every step.Root cause
When the queue ends, SwiftAudioEx stops with
playWhenReady = falseand RNTP emitsPlaybackQueueEnded.AudioPlayer.tsxsubscribes to that event but has never handled it. It was a// TODObefore the #14220 refactor, and it was silently dropped after. So redux keepsplaying: true.TrackPlayer.play()is only called fromhandleTogglePlay, when reduxplayingchanges. After the queue ends it is alreadytrue, so:reset({ shouldAutoplay: true }), which seeks to 0 and setsplaying: trueagain. That is not a change, soplay()is never called.skip(index). RNTP iOS callsjumpToItem(atIndex:, playWhenReady: playerState == .playing), which isfalsehere, so the track loads paused.The same
skipbehavior also stalls without a queue end: Next then Previous quickly skips while the player is still buffering, so the track loads paused while redux says playing.Simulator logs from an instrumented build (native state read through RNTP after each event):
Fix
PlaybackQueueEnded, dispatchpause({ onlySetState: true })so redux matches the stopped player. The next play is then a realfalse -> truechange and reachesTrackPlayer.play().TrackPlayer.skip()inhandleQueueIdxChange, callTrackPlayer.play()if redux is playing. On Android, skip already keepsplayWhenReady, so this does nothing there.JS only, so it can ship OTA.
Testing
iOS 26.5 simulator, Release build, old arch (JS thread is
com.facebook.react.JavaScript), production env, with this branch's bundle. I used a 2-track album and an instrumented bundle that logs native state on each RNTP event and auto-seeks near the end of each track.pwr=falsewith reduxplaying=true, and the album and mini player show Pauseplaying=false, and the album and mini player show PlayplayWhenReady, thenplay()brings it back, and playback continues and auto-advanceseslintis clean and the mobile tests pass (8 suites, 25 tests).tsc --noEmit -p packages/mobileshows the same 4 errors with and without this change, in unrelated files.🤖 Generated with Claude Code