**Changes**
When Exoplayer is used on the Android app it lets the server decide
which mode to use (direct play, direct stream, or transcode) based on
the device and content. If the content contains formats incompatible
with ExoPlayer (like compressed PGS subtitles), it will fail to load the
source. On the Android TV app it shows a similar source error in this
case, but still plays successfully. Checking the server shows that the
content is being remuxed without the subtitles, resolving the issue.
Similarly, enabling subtitles in the player forces a transcode that
allows the content to play.
This change adds similar fallback behavior, but it attempts to play the
highest quality stream on transient errors (like network flakiness).
This approach is based on
https://github.com/jellyfin/jellyfin-androidtv/pull/3916 and the
follow-up fix https://github.com/jellyfin/jellyfin-androidtv/pull/4999.
The retry workflow:
1. Try again without restrictions: it might have been a transient error
2. Try disabling direct play: maybe the container was an issue
3. Finally try transcoding when nothing else worked
The last error time is captured to reset the retry count after 30
seconds have elapsed. This should hopefully be enough time to avoid
falling back unnecessarily for transient issues. Retries will always
start with unrestricted again to maximize the quality and minimize the
stress on the server. Intentional track changes (audio or subtitle) also
reset the retry budget, since those are user-initiated reloads rather
than errors.
There's a race condition between retries in which the queue could try to
change the source. This is handled via coroutine cancellation. There's
still a small race which could cause the media from the current retry to
load briefly before the source change starts. This should be
self-correcting in practice.
**Issues**
Fixes#1931
* Add Trickplay view over the seekbar
* Fix a crash on protrait mode when the screen is narrow
* Improve style fidelity to the web-player trickplay view
* Resolve github-advanced-security bot comments
* Fix linter issues
A recent (?) AndroidX Media3 update caused MergingMediaPeriod to prepend the period ID to the track format's id, breaking the actual track selection. Only matching the substring fixes selecting external subtitles.
* Add complete audiobook support to Android Auto
Extends the existing Android Auto audiobook browsing (added in upstream
PR #1984) with several missing pieces:
- Include audiobooks in Favorites and Recently Played sections
- Include audiobooks in Genre browsing with direct playback action
- Add Audiobooks group to search results
- Resume audiobook playback from saved position (playbackPositionTicks)
rather than always starting from the beginning
* Change the 10000L tick to a private const
* Address PR review feedback: use SDK ticks conversion, encode resume position at browse time, explicit genre action mapping, and audiobooks string resource
* Fetch resume position from item instead of embedding it in the media ID
---------
Co-authored-by: Jordan Rushing <jordanmichaelrushing@users.noreply.github.com>
Instead of hardcoding H264 level "41" in nativeshell.js, query the
actual device max AVC level at runtime via
NativeInterface.getCodecCapabilities(). This lets devices that
support H264 level 4.2, 5.0, etc. direct-play content that was
previously forced to transcode.
The profile list (high/main/baseline/constrained baseline) is left
hardcoded deliberately: Chromium's <video> pipeline in the WebView
does not decode the full set of H264 profiles MediaCodec advertises
(notably 10-bit), so advertising them would risk regressions.
Fixes#1921
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>