feat(exoplayer): let the read-ahead buffer depth be chosen instead of fixed at 50s
ExoPlayer's DefaultLoadControl was built with hard-coded durations picked from one memory tier, so read-ahead stopped at 50s on any device reporting 2GB or less free, with no way to raise it. On hardware where mpv cannot render at all that ceiling is the whole buffer budget. Playback Buffer offers Auto, Large and Extra Large. The durations are taken from jellyfin-androidtv and jellyfin-android so the same words mean the same thing across Jellyfin clients; Auto keeps the memory-tiered values that shipped. Named tiers rather than a duration because a duration would be a promise the load control cannot keep: prioritizeTimeOverSizeThresholds is disabled, so targetBufferBytes stops the loader even below minBufferMs and the byte cap binds first above roughly 23 Mbit/s. The tier crosses the method channel as a string and resolves in the core, where an unrecognised name falls back to Auto. LoadControlPolicy clamps the resulting pair: media3 validates the ordering with Guava Preconditions, an unconditional throw R8 does not elide, so a bad pair would be an IllegalArgumentException out of player construction rather than a bad buffer. The two play-start thresholds stay fixed even though the Jellyfin tiers move them. BufferingStallPolicy.MIN_BUFFER_AHEAD_MS is a const derived from BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS, so a runtime value there would make the stall watchdog indict a player that is obeying its own load control. That leaves the byte target as a second, often smaller ceiling, and nothing surfaced either. The resolved values now reach getStats, and the overlay's Buffer section gains a Cache Limit row reading "120s / 128MB" next to the buffered-ahead duration, so a tier that appears to do nothing on a high-bitrate file explains itself. close #1816
This commit is contained in:
@@ -588,6 +588,21 @@ class Translations$settings$en {
|
||||
/// en: '${heap}MB memory available. A ${size}MB buffer may affect playback.'
|
||||
String bufferSizeWarning({required Object heap, required Object size}) => '${heap}MB memory available. A ${size}MB buffer may affect playback.';
|
||||
|
||||
/// en: 'Playback Buffer'
|
||||
String get playbackBuffer => 'Playback Buffer';
|
||||
|
||||
/// en: 'Auto (Recommended)'
|
||||
String get playbackBufferAuto => 'Auto (Recommended)';
|
||||
|
||||
/// en: 'Large'
|
||||
String get playbackBufferLarge => 'Large';
|
||||
|
||||
/// en: 'Extra Large'
|
||||
String get playbackBufferExtraLarge => 'Extra Large';
|
||||
|
||||
/// en: 'Buffer more against unstable connections. Also limited by Buffer Size.'
|
||||
String get playbackBufferDescription => 'Buffer more against unstable connections. Also limited by Buffer Size.';
|
||||
|
||||
/// en: 'Default Quality'
|
||||
String get defaultQualityTitle => 'Default Quality';
|
||||
|
||||
@@ -6261,6 +6276,11 @@ extension on Translations {
|
||||
'settings.bufferSizeMB' => ({required Object size}) => '${size}MB',
|
||||
'settings.bufferSizeAuto' => 'Auto (Recommended)',
|
||||
'settings.bufferSizeWarning' => ({required Object heap, required Object size}) => '${heap}MB memory available. A ${size}MB buffer may affect playback.',
|
||||
'settings.playbackBuffer' => 'Playback Buffer',
|
||||
'settings.playbackBufferAuto' => 'Auto (Recommended)',
|
||||
'settings.playbackBufferLarge' => 'Large',
|
||||
'settings.playbackBufferExtraLarge' => 'Extra Large',
|
||||
'settings.playbackBufferDescription' => 'Buffer more against unstable connections. Also limited by Buffer Size.',
|
||||
'settings.defaultQualityTitle' => 'Default Quality',
|
||||
'settings.musicQualityTitle' => 'Music Quality',
|
||||
'settings.subtitleStyling' => 'Subtitle Styling',
|
||||
@@ -6610,13 +6630,13 @@ extension on Translations {
|
||||
'mediaMenu.deleteMovieTitle' => 'Delete this movie?',
|
||||
'mediaMenu.deleteEpisodeConfirm' => 'Delete episode',
|
||||
'mediaMenu.deleteSeasonConfirm' => 'Delete season',
|
||||
_ => null,
|
||||
} ?? switch (path) {
|
||||
'mediaMenu.deleteShowConfirm' => 'Delete show',
|
||||
'mediaMenu.deleteMovieConfirm' => 'Delete movie',
|
||||
'mediaMenu.deleteAnyway' => 'Delete anyway',
|
||||
'mediaMenu.confirmDeleteTarget' => ({required Object title}) => 'Permanently delete ${title} from your server?',
|
||||
'mediaMenu.deleteMultipleWarning' => 'This includes all episodes and their files.',
|
||||
_ => null,
|
||||
} ?? switch (path) {
|
||||
'mediaMenu.deleteEpisodeCountWarning' => ({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('en'))(n, one: 'This deletes all ${n} episode in it, and its file.', other: 'This deletes all ${n} episodes in it, and their files.', ),
|
||||
'mediaMenu.deleteMultiPartWarning' => ({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('en'))(n, one: 'This item is stored as ${n} file, which will be deleted.', other: 'This item is stored across ${n} files, and all of them will be deleted.', ),
|
||||
'mediaMenu.deleteSharedFileHeading' => ({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('en'))(n, one: '${n} other episode is stored in the same file and will be deleted too:', other: '${n} other episodes are stored in the same file and will be deleted too:', ),
|
||||
@@ -7124,13 +7144,13 @@ extension on Translations {
|
||||
'explore.badge.pendingApproval' => 'Pending approval',
|
||||
'explore.badge.processing' => 'Processing',
|
||||
'explore.badge.declined' => 'Declined',
|
||||
_ => null,
|
||||
} ?? switch (path) {
|
||||
'explore.badge.requestFailed' => 'Request failed',
|
||||
'explore.badge.requested4k' => '4K requested',
|
||||
'explore.badge.seasonsAvailable' => ({required Object available, required Object total}) => '${available}/${total} seasons',
|
||||
'explore.badge.nextEpisodeIn' => ({required Object episode, required Object duration}) => 'Ep ${episode} in ${duration}',
|
||||
'explore.badge.nextAiringIn' => ({required Object duration}) => 'Next in ${duration}',
|
||||
_ => null,
|
||||
} ?? switch (path) {
|
||||
'explore.badge.episodesShort' => ({required Object n}) => '${n} eps',
|
||||
'explore.badge.minutesPerEpisode' => ({required Object n}) => '${n} min/ep',
|
||||
'explore.badge.adult' => '18+',
|
||||
@@ -7638,13 +7658,13 @@ extension on Translations {
|
||||
'performanceOverlay.dvRpus' => 'DV RPUs',
|
||||
'performanceOverlay.dvRpuAverage' => 'DV RPU Avg',
|
||||
'performanceOverlay.dvSampleAverage' => 'DV Sample Avg',
|
||||
_ => null,
|
||||
} ?? switch (path) {
|
||||
'performanceOverlay.maxLuma' => 'Max Luma',
|
||||
'performanceOverlay.minLuma' => 'Min Luma',
|
||||
'performanceOverlay.maxCll' => 'MaxCLL',
|
||||
'performanceOverlay.maxFall' => 'MaxFALL',
|
||||
'performanceOverlay.cacheUsed' => 'Cache Used',
|
||||
_ => null,
|
||||
} ?? switch (path) {
|
||||
'performanceOverlay.cacheLimit' => 'Cache Limit',
|
||||
'performanceOverlay.speed' => 'Speed',
|
||||
'performanceOverlay.player' => 'Player',
|
||||
|
||||
Reference in New Issue
Block a user