diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/trackselection/AdaptiveTrackSelection.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/trackselection/AdaptiveTrackSelection.java index 40dfa34a12d..0d1c02e80f6 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/trackselection/AdaptiveTrackSelection.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/trackselection/AdaptiveTrackSelection.java @@ -16,6 +16,7 @@ package androidx.media3.exoplayer.trackselection; import static java.lang.Math.max; +import static java.lang.Math.min; import androidx.annotation.CallSuper; import androidx.annotation.Nullable; @@ -605,10 +606,8 @@ private int determineIdealSelectedIndex(long nowMs, long chunkDurationUs) { } private long minDurationForQualityIncreaseUs(long availableDurationUs, long chunkDurationUs) { - boolean isAvailableDurationTooShort = - availableDurationUs != C.TIME_UNSET - && availableDurationUs <= minDurationForQualityIncreaseUs; - if (!isAvailableDurationTooShort) { + if (availableDurationUs == C.TIME_UNSET) { + // We are not in a live stream. Use the configured value. return minDurationForQualityIncreaseUs; } if (chunkDurationUs != C.TIME_UNSET) { @@ -619,7 +618,9 @@ private long minDurationForQualityIncreaseUs(long availableDurationUs, long chun // actually achievable. availableDurationUs -= chunkDurationUs; } - return (long) (availableDurationUs * bufferedFractionToLiveEdgeForQualityIncrease); + long adjustedMinDurationForQualityIncreaseUs = + (long) (availableDurationUs * bufferedFractionToLiveEdgeForQualityIncrease); + return min(adjustedMinDurationForQualityIncreaseUs, minDurationForQualityIncreaseUs); } /** diff --git a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/trackselection/AdaptiveTrackSelectionTest.java b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/trackselection/AdaptiveTrackSelectionTest.java index f2915110f96..b8cc647d9f2 100644 --- a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/trackselection/AdaptiveTrackSelectionTest.java +++ b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/trackselection/AdaptiveTrackSelectionTest.java @@ -175,7 +175,9 @@ public void updateSelectedTrack_liveStream_switchesUpWhenBufferedFractionToLiveE when(mockBandwidthMeter.getBitrateEstimate()).thenReturn(1000L, 2000L); AdaptiveTrackSelection adaptiveTrackSelection = prepareAdaptiveTrackSelectionWithBufferedFractionToLiveEdgeForQualiyIncrease( - trackGroup, /* bufferedFractionToLiveEdgeForQualityIncrease= */ 0.75f); + trackGroup, + /* bufferedFractionToLiveEdgeForQualityIncrease= */ 0.75f, + /* minDurationForQualityIncreaseMs= */ 5000); // Not buffered close to live edge yet. adaptiveTrackSelection.updateSelectedTrack( @@ -188,6 +190,8 @@ public void updateSelectedTrack_liveStream_switchesUpWhenBufferedFractionToLiveE assertThat(adaptiveTrackSelection.getSelectedFormat()).isEqualTo(format2); // Buffered all possible chunks (except for newly added chunk of 2 seconds). + // Intentionally choose a situation where availableDurationUs > minDurationForQualityIncreaseMs + // to ensure the live calculation is used regardless. adaptiveTrackSelection.updateSelectedTrack( /* playbackPositionUs= */ 0, /* bufferedDurationUs= */ 3_600_000, @@ -768,14 +772,16 @@ private AdaptiveTrackSelection prepareAdaptiveTrackSelectionWithMaxResolutionToD private AdaptiveTrackSelection prepareAdaptiveTrackSelectionWithBufferedFractionToLiveEdgeForQualiyIncrease( - TrackGroup trackGroup, float bufferedFractionToLiveEdgeForQualityIncrease) { + TrackGroup trackGroup, + float bufferedFractionToLiveEdgeForQualityIncrease, + long minDurationForQualityIncreaseMs) { return prepareTrackSelection( new AdaptiveTrackSelection( trackGroup, selectedAllTracksInGroup(trackGroup), TrackSelection.TYPE_UNSET, mockBandwidthMeter, - AdaptiveTrackSelection.DEFAULT_MIN_DURATION_FOR_QUALITY_INCREASE_MS, + minDurationForQualityIncreaseMs, AdaptiveTrackSelection.DEFAULT_MAX_DURATION_FOR_QUALITY_DECREASE_MS, AdaptiveTrackSelection.DEFAULT_MIN_DURATION_TO_RETAIN_AFTER_DISCARD_MS, AdaptiveTrackSelection.DEFAULT_MAX_WIDTH_TO_DISCARD,