Fix session command queue stall that detaches Now Playing (fixes #31)#32
Merged
Conversation
Media3 serializes controller commands behind each session callback's ListenableFuture; a future that never completes permanently wedges the controller's command queue. onAddMediaItems/onSetMediaItems/onGetItem/ onPlaybackResumption had no timeout guards, so resolving a large uncached playlist on flaky connectivity (one API call per track, each retried x3) could hang forever - Now Playing froze on the old track while playback continued, and playlist switches/search were ignored until an infotainment restart. - Guard all queue-mutating callbacks with timeouts so every future completes; failures complete exceptionally, which Media3 drops while keeping the queue alive - Configure explicit Jellyfin SDK HTTP timeouts (5s connect / 7s request / 7s socket) - Add a 10s per-attempt hard cap in JellyfinMediaTree.retryOnFailure and stop it swallowing CancellationException from outer guards - Add JellyfinApiTimeoutTest pinning the timeout config against a server that accepts connections but never responds Co-Authored-By: Claude Fable 5 <[email protected]>
Fix the frozen Now Playing screen that required an infotainment restart, plus QuickConnect sign-in crashes Full release notes: - Fix the intermittent freeze where Now Playing kept showing a previous song while other tracks played, and playlists, search, and browsing stopped responding until the infotainment system was restarted — the app now recovers on its own within seconds on flaky connections - Fix QuickConnect showing a wrong sign-in code when the code had leading zeros, and a crash on short codes - Fix a crash when QuickConnect polling hit a network error or an expired code — it now shows "Unavailable" instead - Fix a possible crash when a connected controller sent an unsupported rating type while favouriting - Fix playback starting at the wrong track when the cached library was out of date - More robust handling of corrupted settings values and low-level stability fixes (thread-safe album art lookups, coroutine cleanup on service shutdown, safer account and keyboard handling) - Security hardening: app data is no longer included in device backups
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.
Fixes #31
Root cause
Media3 serializes controller commands per controller:
ConnectedControllersManager.flushCommandQueue()only advances when the previous callback'sListenableFuturecompletes. Four callbacks inDashTuneSessionCallbackcould return futures that never complete —onAddMediaItems,onSetMediaItems,onGetItem, andonPlaybackResumptionhad no timeout guards (unlikeonGetChildren/onSearch, which already use an 8swithTimeoutOrNull).Resolving a large uncached playlist chains one Jellyfin API call per track (each retried ×3 with backoff in
JellyfinMediaTree.retryOnFailure), so on flaky car connectivity a singleonSetMediaItemscould hang effectively forever. One wedged future permanently stalls the AAOS Media Center's command queue, which explains every reported symptom:Changes
DashTuneSessionCallback: all four unguarded callbacks now complete within 8–10s.onAddMediaItems/onSetMediaItemscomplete exceptionally on timeout/failure — verified in media3-session 1.9.2 sources that Media3 drops the failed command and keeps the queue alive (the current playlist keeps playing).onGetItemreturns the existing error-with-Retry result;onPlaybackResumptionfalls back to an empty restore. TheonSetMediaItemsbody was extracted verbatim intoresolveSetMediaItems()to sit under the guard.DashTuneMusicService: explicit Jellyfin SDK HTTP timeouts (5s connect / 7s request / 7s socket) instead of the 30s defaults, so a single call always fails before the callback guard fires.JellyfinMediaTree.retryOnFailure: 10s per-attempt hard cap as defense in depth for all 9 tree network paths, and rethrowsCancellationExceptioninstead of swallowing it (which would have broken the outer guards).JellyfinApiTimeoutTest: pins the timeout config against a server that accepts TCP connections but never responds — passes in 7.2s, exactly the configured request timeout.Also includes the v1.2.9(25) release commit.
Testing
./gradlew :automotive:assembleDebug✅./gradlew :automotive:testDebugUnitTest✅ (including the new timeout test)nc -lk 8096 > /dev/null(accepts connections, never responds) and switch playlists — commands should fail within ~10s with the session staying responsive, and recover without an infotainment restart once the server is back.🤖 Generated with Claude Code