Summary
Automatic version selection ranks candidates by resolution only, so among two same-resolution files — e.g. a 2160p Dolby Vision file and a 2160p HDR10 file — the winner is decided by list order rather than by which the display can best present. A Dolby-Vision-capable Android TV can auto-play the plain HDR10 file, and because the last-played file is then persisted as the version memory, the mis-pick reinforces itself on the next launch.
This is the Android counterpart of the Apple fix in Silo-Server/silo-apple (fix(player): automatic version selection prefers Dolby Vision on a capable, DV-enabled display, commit 741f15a), filed for parity per the client-alignment policy.
Where
shared/src/commonMain/kotlin/org/siloserver/silo/playback/PlaybackVersionSelector.kt — selectPlaybackVersion / bestAvailable sort by playbackResolutionRank only; no dynamic-range term and no deterministic tiebreak (equal ranks fall to sortedWith input order).
androidTvApp/.../detail/TvDetailVersionSelection.kt (selectTvDetailDisplayVersion) and the phone ItemDetailViewModel selector delegate to the same shared ranker, so the detail label and the play-time pick share the gap.
Reproduction
"How to Train Your Dragon: The Hidden World" (movie-tmdb-166428) has three files: 1080p AVC, 2160p HEVC HDR10 (63058), 2160p x265 Dolby Vision / HDR10+ (74032). With Version = Automatic on a DV-capable TV, selection returns the HDR10 file (63058) rather than the DV file.
Proposed fix (mirror the Apple change)
Add a dynamic-range tiebreak to the shared selector, applied only among equal-resolution candidates so it never overrides resolution or the user's quality cap:
- + (highest) when the file is Dolby Vision AND the display advertises DV (
Display.HdrCapabilities.getSupportedHdrTypes() contains HDR_TYPE_DOLBY_VISION) AND the user's Dolby Vision setting is on;
- + (middle) for any HDR presentation the display supports (including a DV file's HDR10 base layer when DV itself is unusable);
- 0 for SDR;
- break exact ties deterministically by
fileId so the result never depends on input order.
The magnitude must stay below one resolution step and below the quality-preference terms (as on Apple) so it is strictly a tiebreak. Feed display capability + the DV setting into selectPlaybackVersion as an explicit context so it stays unit-testable without a real display.
Apple reference
silo-apple iosApp/iosApp/Screens/Player/VersionDynamicRangePreference.swift (the shared rule) and its use in DetailVersionSelection + PlaybackSessionBridge.selectVersion, with tests in DetailVersionSelectionTests (DV wins when supported+enabled; does not win when the display can't present it or the setting is off; never beats a higher resolution; both selectors agree).
Not in scope
Server-side last_file_id persistence works correctly (the client posts progress to /api/v1/playback/{id}/progress, which writes the version hints). This is purely the client's dynamic-range-blind ranking.
🤖 Generated with Claude Code
Summary
Automatic version selection ranks candidates by resolution only, so among two same-resolution files — e.g. a 2160p Dolby Vision file and a 2160p HDR10 file — the winner is decided by list order rather than by which the display can best present. A Dolby-Vision-capable Android TV can auto-play the plain HDR10 file, and because the last-played file is then persisted as the version memory, the mis-pick reinforces itself on the next launch.
This is the Android counterpart of the Apple fix in Silo-Server/silo-apple (
fix(player): automatic version selection prefers Dolby Vision on a capable, DV-enabled display, commit741f15a), filed for parity per the client-alignment policy.Where
shared/src/commonMain/kotlin/org/siloserver/silo/playback/PlaybackVersionSelector.kt—selectPlaybackVersion/bestAvailablesort byplaybackResolutionRankonly; no dynamic-range term and no deterministic tiebreak (equal ranks fall tosortedWithinput order).androidTvApp/.../detail/TvDetailVersionSelection.kt(selectTvDetailDisplayVersion) and the phoneItemDetailViewModelselector delegate to the same shared ranker, so the detail label and the play-time pick share the gap.Reproduction
"How to Train Your Dragon: The Hidden World" (movie-tmdb-166428) has three files: 1080p AVC, 2160p HEVC HDR10 (63058), 2160p x265 Dolby Vision / HDR10+ (74032). With Version = Automatic on a DV-capable TV, selection returns the HDR10 file (63058) rather than the DV file.
Proposed fix (mirror the Apple change)
Add a dynamic-range tiebreak to the shared selector, applied only among equal-resolution candidates so it never overrides resolution or the user's quality cap:
Display.HdrCapabilities.getSupportedHdrTypes()containsHDR_TYPE_DOLBY_VISION) AND the user's Dolby Vision setting is on;fileIdso the result never depends on input order.The magnitude must stay below one resolution step and below the quality-preference terms (as on Apple) so it is strictly a tiebreak. Feed display capability + the DV setting into
selectPlaybackVersionas an explicit context so it stays unit-testable without a real display.Apple reference
silo-apple
iosApp/iosApp/Screens/Player/VersionDynamicRangePreference.swift(the shared rule) and its use inDetailVersionSelection+PlaybackSessionBridge.selectVersion, with tests inDetailVersionSelectionTests(DV wins when supported+enabled; does not win when the display can't present it or the setting is off; never beats a higher resolution; both selectors agree).Not in scope
Server-side
last_file_idpersistence works correctly (the client posts progress to/api/v1/playback/{id}/progress, which writes the version hints). This is purely the client's dynamic-range-blind ranking.🤖 Generated with Claude Code