fix(ios): bound large native playback queues - #266
Conversation
Keep the complete logical queue while materialising only a forward AVQueuePlayer window, replenishing it as playback advances. This avoids building and inserting thousands of AVPlayerItems on the main thread. Closes ghenry22#244
ff911e2 to
eb3c084
Compare
|
Hi, I wanted to add a brief note about the user impact and the current validation status. Without this fix, large Favorites lists are effectively unusable on iOS: tapping a track can make the entire app unresponsive for more than ten seconds before playback begins. This severely affects a core playback workflow and the overall user experience. I have rebased this PR onto the latest Given the impact, I would be very grateful if this could be reviewed and merged, or otherwise addressed, as soon as practical. Thank you very much for your time and for maintaining the project. |
Summary
AVQueuePlayerto a 32-item forward windowAVPlayerItembuild on non-preserving queue syncWhy
Starting a song from a large list could make the entire iOS UI unresponsive for several seconds even though the loading animation continued. On a 1,527-song Favorites list, a Search tap sent 100 ms after the song tap was still unapplied 6.497 seconds later.
Native instrumentation showed that RNQP performed two eager full-tail
AVPlayerItembuilds and then inserted 1,515 items intoAVQueuePlayersynchronously on the main actor. The complete operation occupied the main actor for 9.646–21.799 seconds in measured runs; the insertion loop alone took 3.4–11.7 seconds.The full queue already has an authoritative logical owner in
QueueState. Gapless playback only needs the current item plus a bounded forward window, so this change avoids materialising thousands of native items while preserving queue semantics. Crossfade keeps its existing full snapshot because its indexed transitions depend on it.Verification
npm run test:ios-large-queue(5 focused tests)npx tsc --noEmitnpx jest --no-coverage(404 suites / 7,048 tests)Public demo
The official Navidrome Demo contains 501 songs. In an isolated read-only baseline run, Search and Settings actions sent while playback was still
In progresswere accepted, returning about 1.19 s and 1.16 s after dispatch and appearing selected in the first captured state. This did not reproduce the multi-second unresponsive interval measured at 1,527 songs, so the Demo is a compatibility check rather than a reliable reproducer. Shared favorites were not modified.Closes #244