diff --git a/library/core/src/main/java/com/google/android/exoplayer2/DefaultLivePlaybackSpeedControl.java b/library/core/src/main/java/com/google/android/exoplayer2/DefaultLivePlaybackSpeedControl.java index 63de8cf581..6ea6f08321 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/DefaultLivePlaybackSpeedControl.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/DefaultLivePlaybackSpeedControl.java @@ -33,6 +33,10 @@ import com.google.android.exoplayer2.util.Util; * fallback values set with {@link Builder#setFallbackMinPlaybackSpeed(float)} and {@link * Builder#setFallbackMaxPlaybackSpeed(float)} or the {@link #DEFAULT_FALLBACK_MIN_PLAYBACK_SPEED * minimum} and {@link #DEFAULT_FALLBACK_MAX_PLAYBACK_SPEED maximum} fallback default values. + * + *

When the player rebuffers, the target live offset {@link + * Builder#setTargetLiveOffsetIncrementOnRebufferMs(long) is increased} to adjust to the reduced + * network capabilities. */ public final class DefaultLivePlaybackSpeedControl implements LivePlaybackSpeedControl { @@ -60,6 +64,12 @@ public final class DefaultLivePlaybackSpeedControl implements LivePlaybackSpeedC */ public static final float DEFAULT_PROPORTIONAL_CONTROL_FACTOR = 0.05f; + /** + * The default increment applied to the target live offset each time the player is rebuffering, in + * milliseconds + */ + public static final long DEFAULT_TARGET_LIVE_OFFSET_INCREMENT_ON_REBUFFER_MS = 500; + /** * The maximum difference between the current live offset and the target live offset for which * unit speed (1.0f) is used. @@ -73,6 +83,7 @@ public final class DefaultLivePlaybackSpeedControl implements LivePlaybackSpeedC private float fallbackMaxPlaybackSpeed; private long minUpdateIntervalMs; private float proportionalControlFactorUs; + private long targetLiveOffsetIncrementOnRebufferUs; /** Creates a builder. */ public Builder() { @@ -80,6 +91,8 @@ public final class DefaultLivePlaybackSpeedControl implements LivePlaybackSpeedC fallbackMaxPlaybackSpeed = DEFAULT_FALLBACK_MAX_PLAYBACK_SPEED; minUpdateIntervalMs = DEFAULT_MIN_UPDATE_INTERVAL_MS; proportionalControlFactorUs = DEFAULT_PROPORTIONAL_CONTROL_FACTOR / C.MICROS_PER_SECOND; + targetLiveOffsetIncrementOnRebufferUs = + C.msToUs(DEFAULT_TARGET_LIVE_OFFSET_INCREMENT_ON_REBUFFER_MS); } /** @@ -145,13 +158,29 @@ public final class DefaultLivePlaybackSpeedControl implements LivePlaybackSpeedC return this; } + /** + * Sets the increment applied to the target live offset each time the player is rebuffering, in + * milliseconds. + * + * @param targetLiveOffsetIncrementOnRebufferMs The increment applied to the target live offset + * when the player is rebuffering, in milliseconds + * @return This builder, for convenience. + */ + public Builder setTargetLiveOffsetIncrementOnRebufferMs( + long targetLiveOffsetIncrementOnRebufferMs) { + Assertions.checkArgument(targetLiveOffsetIncrementOnRebufferMs >= 0); + this.targetLiveOffsetIncrementOnRebufferUs = C.msToUs(targetLiveOffsetIncrementOnRebufferMs); + return this; + } + /** Builds an instance. */ public DefaultLivePlaybackSpeedControl build() { return new DefaultLivePlaybackSpeedControl( fallbackMinPlaybackSpeed, fallbackMaxPlaybackSpeed, minUpdateIntervalMs, - proportionalControlFactorUs); + proportionalControlFactorUs, + targetLiveOffsetIncrementOnRebufferUs); } } @@ -159,9 +188,11 @@ public final class DefaultLivePlaybackSpeedControl implements LivePlaybackSpeedC private final float fallbackMaxPlaybackSpeed; private final long minUpdateIntervalMs; private final float proportionalControlFactor; + private final long targetLiveOffsetRebufferDeltaUs; private long mediaConfigurationTargetLiveOffsetUs; private long targetLiveOffsetOverrideUs; + private long idealTargetLiveOffsetUs; private long minTargetLiveOffsetUs; private long maxTargetLiveOffsetUs; private long currentTargetLiveOffsetUs; @@ -175,11 +206,13 @@ public final class DefaultLivePlaybackSpeedControl implements LivePlaybackSpeedC float fallbackMinPlaybackSpeed, float fallbackMaxPlaybackSpeed, long minUpdateIntervalMs, - float proportionalControlFactor) { + float proportionalControlFactor, + long targetLiveOffsetRebufferDeltaUs) { this.fallbackMinPlaybackSpeed = fallbackMinPlaybackSpeed; this.fallbackMaxPlaybackSpeed = fallbackMaxPlaybackSpeed; this.minUpdateIntervalMs = minUpdateIntervalMs; this.proportionalControlFactor = proportionalControlFactor; + this.targetLiveOffsetRebufferDeltaUs = targetLiveOffsetRebufferDeltaUs; mediaConfigurationTargetLiveOffsetUs = C.TIME_UNSET; targetLiveOffsetOverrideUs = C.TIME_UNSET; minTargetLiveOffsetUs = C.TIME_UNSET; @@ -188,6 +221,7 @@ public final class DefaultLivePlaybackSpeedControl implements LivePlaybackSpeedC maxPlaybackSpeed = fallbackMaxPlaybackSpeed; adjustedPlaybackSpeed = 1.0f; lastPlaybackSpeedUpdateMs = C.TIME_UNSET; + idealTargetLiveOffsetUs = C.TIME_UNSET; currentTargetLiveOffsetUs = C.TIME_UNSET; } @@ -213,6 +247,19 @@ public final class DefaultLivePlaybackSpeedControl implements LivePlaybackSpeedC maybeResetTargetLiveOffsetUs(); } + @Override + public void notifyRebuffer() { + if (currentTargetLiveOffsetUs == C.TIME_UNSET) { + return; + } + currentTargetLiveOffsetUs += targetLiveOffsetRebufferDeltaUs; + if (maxTargetLiveOffsetUs != C.TIME_UNSET + && currentTargetLiveOffsetUs > maxTargetLiveOffsetUs) { + currentTargetLiveOffsetUs = maxTargetLiveOffsetUs; + } + lastPlaybackSpeedUpdateMs = C.TIME_UNSET; + } + @Override public float getAdjustedPlaybackSpeed(long liveOffsetUs) { if (mediaConfigurationTargetLiveOffsetUs == C.TIME_UNSET) { @@ -254,9 +301,10 @@ public final class DefaultLivePlaybackSpeedControl implements LivePlaybackSpeedC idealOffsetUs = maxTargetLiveOffsetUs; } } - if (currentTargetLiveOffsetUs == idealOffsetUs) { + if (idealTargetLiveOffsetUs == idealOffsetUs) { return; } + idealTargetLiveOffsetUs = idealOffsetUs; currentTargetLiveOffsetUs = idealOffsetUs; lastPlaybackSpeedUpdateMs = C.TIME_UNSET; } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java index 21b7635b40..20a5201e0d 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java @@ -189,7 +189,7 @@ import java.util.concurrent.atomic.AtomicBoolean; private boolean released; private boolean pauseAtEndOfWindow; private boolean pendingPauseAtEndOfPeriod; - private boolean rebuffering; + private boolean isRebuffering; private boolean shouldContinueLoading; @Player.RepeatMode private int repeatMode; private boolean shuffleModeEnabled; @@ -733,7 +733,7 @@ import java.util.concurrent.atomic.AtomicBoolean; playbackInfoUpdate.incrementPendingOperationAcks(operationAck ? 1 : 0); playbackInfoUpdate.setPlayWhenReadyChangeReason(reason); playbackInfo = playbackInfo.copyWithPlayWhenReady(playWhenReady, playbackSuppressionReason); - rebuffering = false; + isRebuffering = false; if (!shouldPlayWhenReady()) { stopRenderers(); updatePlaybackPositions(); @@ -811,7 +811,7 @@ import java.util.concurrent.atomic.AtomicBoolean; } private void startRenderers() throws ExoPlaybackException { - rebuffering = false; + isRebuffering = false; mediaClock.start(); for (Renderer renderer : renderers) { if (isRendererEnabled(renderer)) { @@ -868,6 +868,7 @@ import java.util.concurrent.atomic.AtomicBoolean; // Adjust live playback speed to new position. if (playbackInfo.playWhenReady + && playbackInfo.playbackState == Player.STATE_READY && isCurrentPeriodInMovingLiveWindow() && playbackInfo.playbackParameters.speed == 1f) { float adjustedSpeed = @@ -960,8 +961,9 @@ import java.util.concurrent.atomic.AtomicBoolean; } } else if (playbackInfo.playbackState == Player.STATE_READY && !(enabledRendererCount == 0 ? isTimelineReady() : renderersAllowPlayback)) { - rebuffering = shouldPlayWhenReady(); + isRebuffering = shouldPlayWhenReady(); setState(Player.STATE_BUFFERING); + livePlaybackSpeedControl.notifyRebuffer(); stopRenderers(); } @@ -1168,7 +1170,7 @@ import java.util.concurrent.atomic.AtomicBoolean; boolean forceBufferingState) throws ExoPlaybackException { stopRenderers(); - rebuffering = false; + isRebuffering = false; if (forceBufferingState || playbackInfo.playbackState == Player.STATE_READY) { setState(Player.STATE_BUFFERING); } @@ -1311,7 +1313,7 @@ import java.util.concurrent.atomic.AtomicBoolean; boolean releaseMediaSourceList, boolean resetError) { handler.removeMessages(MSG_DO_SOME_WORK); - rebuffering = false; + isRebuffering = false; mediaClock.stop(); rendererPositionUs = 0; for (Renderer renderer : renderers) { @@ -1701,7 +1703,7 @@ import java.util.concurrent.atomic.AtomicBoolean; || loadControl.shouldStartPlayback( getTotalBufferedDurationUs(), mediaClock.getPlaybackParameters().speed, - rebuffering, + isRebuffering, targetLiveOffsetUs); } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/LivePlaybackSpeedControl.java b/library/core/src/main/java/com/google/android/exoplayer2/LivePlaybackSpeedControl.java index 03aa325307..8844c62908 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/LivePlaybackSpeedControl.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/LivePlaybackSpeedControl.java @@ -40,6 +40,14 @@ public interface LivePlaybackSpeedControl { */ void setTargetLiveOffsetOverrideUs(long liveOffsetUs); + /** + * Notifies the live playback speed control that a rebuffer occurred. + * + *

A rebuffer is defined to be caused by buffer depletion rather than a user action. Hence this + * method is not called during initial or when buffering as a result of a seek operation. + */ + void notifyRebuffer(); + /** * Returns the adjusted playback speed in order get closer towards the {@link * #getTargetLiveOffsetUs() target live offset}. diff --git a/library/core/src/test/java/com/google/android/exoplayer2/DefaultLivePlaybackSpeedControlTest.java b/library/core/src/test/java/com/google/android/exoplayer2/DefaultLivePlaybackSpeedControlTest.java index 8ec49ebabc..9c08b9999b 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/DefaultLivePlaybackSpeedControlTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/DefaultLivePlaybackSpeedControlTest.java @@ -19,7 +19,10 @@ import static com.google.common.truth.Truth.assertThat; import androidx.test.ext.junit.runners.AndroidJUnit4; import com.google.android.exoplayer2.MediaItem.LiveConfiguration; +import com.google.common.collect.Iterables; import java.time.Duration; +import java.util.ArrayList; +import java.util.List; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.shadows.ShadowSystemClock; @@ -37,7 +40,7 @@ public class DefaultLivePlaybackSpeedControlTest { } @Test - public void getTargetLiveOffsetUs_afterSetLiveConfiguration_usesMediaLiveOffset() { + public void getTargetLiveOffsetUs_afterSetLiveConfiguration_returnsMediaLiveOffset() { DefaultLivePlaybackSpeedControl defaultLivePlaybackSpeedControl = new DefaultLivePlaybackSpeedControl.Builder().build(); defaultLivePlaybackSpeedControl.setLiveConfiguration( @@ -53,7 +56,7 @@ public class DefaultLivePlaybackSpeedControlTest { @Test public void - getTargetLiveOffsetUs_afterSetLiveConfigurationWithTargetGreaterThanMax_usesMaxLiveOffset() { + getTargetLiveOffsetUs_afterSetLiveConfigurationWithTargetGreaterThanMax_returnsMaxLiveOffset() { DefaultLivePlaybackSpeedControl defaultLivePlaybackSpeedControl = new DefaultLivePlaybackSpeedControl.Builder().build(); defaultLivePlaybackSpeedControl.setLiveConfiguration( @@ -69,7 +72,7 @@ public class DefaultLivePlaybackSpeedControlTest { @Test public void - getTargetLiveOffsetUs_afterSetLiveConfigurationWithTargetLessThanMin_usesMinLiveOffset() { + getTargetLiveOffsetUs_afterSetLiveConfigurationWithTargetLessThanMin_returnsMinLiveOffset() { DefaultLivePlaybackSpeedControl defaultLivePlaybackSpeedControl = new DefaultLivePlaybackSpeedControl.Builder().build(); defaultLivePlaybackSpeedControl.setLiveConfiguration( @@ -84,7 +87,7 @@ public class DefaultLivePlaybackSpeedControlTest { } @Test - public void getTargetLiveOffsetUs_withSetTargetLiveOffsetOverrideUs_usesOverride() { + public void getTargetLiveOffsetUs_afterSetTargetLiveOffsetOverrideUs_returnsOverride() { DefaultLivePlaybackSpeedControl defaultLivePlaybackSpeedControl = new DefaultLivePlaybackSpeedControl.Builder().build(); @@ -104,7 +107,7 @@ public class DefaultLivePlaybackSpeedControlTest { @Test public void - getTargetLiveOffsetUs_withSetTargetLiveOffsetOverrideUsGreaterThanMax_usesMaxLiveOffset() { + getTargetLiveOffsetUs_afterSetTargetLiveOffsetOverrideUsGreaterThanMax_returnsMaxLiveOffset() { DefaultLivePlaybackSpeedControl defaultLivePlaybackSpeedControl = new DefaultLivePlaybackSpeedControl.Builder().build(); @@ -124,7 +127,7 @@ public class DefaultLivePlaybackSpeedControlTest { @Test public void - getTargetLiveOffsetUs_withSetTargetLiveOffsetOverrideUsLessThanMin_usesMinLiveOffset() { + getTargetLiveOffsetUs_afterSetTargetLiveOffsetOverrideUsLessThanMin_returnsMinLiveOffset() { DefaultLivePlaybackSpeedControl defaultLivePlaybackSpeedControl = new DefaultLivePlaybackSpeedControl.Builder().build(); @@ -156,7 +159,7 @@ public class DefaultLivePlaybackSpeedControlTest { @Test public void - getTargetLiveOffsetUs_afterSetTargetLiveOffsetOverrideWithTimeUnset_usesMediaLiveOffset() { + getTargetLiveOffsetUs_afterSetTargetLiveOffsetOverrideWithTimeUnset_returnsMediaLiveOffset() { DefaultLivePlaybackSpeedControl defaultLivePlaybackSpeedControl = new DefaultLivePlaybackSpeedControl.Builder().build(); defaultLivePlaybackSpeedControl.setTargetLiveOffsetOverrideUs(123_456_789); @@ -174,6 +177,153 @@ public class DefaultLivePlaybackSpeedControlTest { assertThat(targetLiveOffsetUs).isEqualTo(42_000); } + @Test + public void getTargetLiveOffsetUs_afterNotifyRebuffer_returnsIncreasedTargetOffset() { + DefaultLivePlaybackSpeedControl defaultLivePlaybackSpeedControl = + new DefaultLivePlaybackSpeedControl.Builder() + .setTargetLiveOffsetIncrementOnRebufferMs(3) + .build(); + defaultLivePlaybackSpeedControl.setLiveConfiguration( + new LiveConfiguration( + /* targetLiveOffsetMs= */ 42, + /* minLiveOffsetMs= */ 5, + /* maxLiveOffsetMs= */ 400, + /* minPlaybackSpeed= */ 1f, + /* maxPlaybackSpeed= */ 1f)); + + long targetLiveOffsetBeforeUs = defaultLivePlaybackSpeedControl.getTargetLiveOffsetUs(); + defaultLivePlaybackSpeedControl.notifyRebuffer(); + long targetLiveOffsetAfterUs = defaultLivePlaybackSpeedControl.getTargetLiveOffsetUs(); + + assertThat(targetLiveOffsetAfterUs).isGreaterThan(targetLiveOffsetBeforeUs); + assertThat(targetLiveOffsetAfterUs - targetLiveOffsetBeforeUs).isEqualTo(3_000); + } + + @Test + public void getTargetLiveOffsetUs_afterRepeatedNotifyRebuffer_returnsMaxLiveOffset() { + DefaultLivePlaybackSpeedControl defaultLivePlaybackSpeedControl = + new DefaultLivePlaybackSpeedControl.Builder() + .setTargetLiveOffsetIncrementOnRebufferMs(3) + .build(); + defaultLivePlaybackSpeedControl.setLiveConfiguration( + new LiveConfiguration( + /* targetLiveOffsetMs= */ 42, + /* minLiveOffsetMs= */ 5, + /* maxLiveOffsetMs= */ 400, + /* minPlaybackSpeed= */ 1f, + /* maxPlaybackSpeed= */ 1f)); + + List targetOffsetsUs = new ArrayList<>(); + for (int i = 0; i < 500; i++) { + targetOffsetsUs.add(defaultLivePlaybackSpeedControl.getTargetLiveOffsetUs()); + defaultLivePlaybackSpeedControl.notifyRebuffer(); + } + + assertThat(targetOffsetsUs).isInOrder(); + assertThat(Iterables.getLast(targetOffsetsUs)).isEqualTo(400_000); + } + + @Test + public void + getTargetLiveOffsetUs_afterNotifyRebufferWithIncrementOfZero_returnsOriginalTargetOffset() { + DefaultLivePlaybackSpeedControl defaultLivePlaybackSpeedControl = + new DefaultLivePlaybackSpeedControl.Builder() + .setTargetLiveOffsetIncrementOnRebufferMs(0) + .build(); + defaultLivePlaybackSpeedControl.setLiveConfiguration( + new LiveConfiguration( + /* targetLiveOffsetMs= */ 42, + /* minLiveOffsetMs= */ 5, + /* maxLiveOffsetMs= */ 400, + /* minPlaybackSpeed= */ 1f, + /* maxPlaybackSpeed= */ 1f)); + + defaultLivePlaybackSpeedControl.notifyRebuffer(); + long targetLiveOffsetUs = defaultLivePlaybackSpeedControl.getTargetLiveOffsetUs(); + + assertThat(targetLiveOffsetUs).isEqualTo(42_000); + } + + @Test + public void + getTargetLiveOffsetUs_afterNotifyRebufferAndSetTargetLiveOffsetOverrideUs_returnsOverride() { + DefaultLivePlaybackSpeedControl defaultLivePlaybackSpeedControl = + new DefaultLivePlaybackSpeedControl.Builder() + .setTargetLiveOffsetIncrementOnRebufferMs(3) + .build(); + defaultLivePlaybackSpeedControl.setLiveConfiguration( + new LiveConfiguration( + /* targetLiveOffsetMs= */ 42, + /* minLiveOffsetMs= */ 5, + /* maxLiveOffsetMs= */ 400, + /* minPlaybackSpeed= */ 1f, + /* maxPlaybackSpeed= */ 1f)); + + defaultLivePlaybackSpeedControl.notifyRebuffer(); + defaultLivePlaybackSpeedControl.setTargetLiveOffsetOverrideUs(321_000); + long targetLiveOffsetUs = defaultLivePlaybackSpeedControl.getTargetLiveOffsetUs(); + + assertThat(targetLiveOffsetUs).isEqualTo(321_000); + } + + @Test + public void + getTargetLiveOffsetUs_afterNotifyRebufferAndSetLiveConfigurationWithSameOffset_returnsIncreasedTargetOffset() { + DefaultLivePlaybackSpeedControl defaultLivePlaybackSpeedControl = + new DefaultLivePlaybackSpeedControl.Builder() + .setTargetLiveOffsetIncrementOnRebufferMs(3) + .build(); + defaultLivePlaybackSpeedControl.setLiveConfiguration( + new LiveConfiguration( + /* targetLiveOffsetMs= */ 42, + /* minLiveOffsetMs= */ 5, + /* maxLiveOffsetMs= */ 400, + /* minPlaybackSpeed= */ 1f, + /* maxPlaybackSpeed= */ 1f)); + + long targetLiveOffsetBeforeUs = defaultLivePlaybackSpeedControl.getTargetLiveOffsetUs(); + defaultLivePlaybackSpeedControl.notifyRebuffer(); + defaultLivePlaybackSpeedControl.setLiveConfiguration( + new LiveConfiguration( + /* targetLiveOffsetMs= */ 42, + /* minLiveOffsetMs= */ 3, + /* maxLiveOffsetMs= */ 450, + /* minPlaybackSpeed= */ 0.9f, + /* maxPlaybackSpeed= */ 1.1f)); + long targetLiveOffsetAfterUs = defaultLivePlaybackSpeedControl.getTargetLiveOffsetUs(); + + assertThat(targetLiveOffsetAfterUs).isGreaterThan(targetLiveOffsetBeforeUs); + assertThat(targetLiveOffsetAfterUs - targetLiveOffsetBeforeUs).isEqualTo(3_000); + } + + @Test + public void + getTargetLiveOffsetUs_afterNotifyRebufferAndSetLiveConfigurationWithNewOffset_returnsNewOffset() { + DefaultLivePlaybackSpeedControl defaultLivePlaybackSpeedControl = + new DefaultLivePlaybackSpeedControl.Builder() + .setTargetLiveOffsetIncrementOnRebufferMs(3) + .build(); + defaultLivePlaybackSpeedControl.setLiveConfiguration( + new LiveConfiguration( + /* targetLiveOffsetMs= */ 42, + /* minLiveOffsetMs= */ 5, + /* maxLiveOffsetMs= */ 400, + /* minPlaybackSpeed= */ 1f, + /* maxPlaybackSpeed= */ 1f)); + + defaultLivePlaybackSpeedControl.notifyRebuffer(); + defaultLivePlaybackSpeedControl.setLiveConfiguration( + new LiveConfiguration( + /* targetLiveOffsetMs= */ 39, + /* minLiveOffsetMs= */ 3, + /* maxLiveOffsetMs= */ 450, + /* minPlaybackSpeed= */ 0.9f, + /* maxPlaybackSpeed= */ 1.1f)); + long targetLiveOffsetUs = defaultLivePlaybackSpeedControl.getTargetLiveOffsetUs(); + + assertThat(targetLiveOffsetUs).isEqualTo(39_000); + } + @Test public void adjustPlaybackSpeed_liveOffsetMatchesTargetOffset_returnsUnitSpeed() { DefaultLivePlaybackSpeedControl defaultLivePlaybackSpeedControl = @@ -367,7 +517,7 @@ public class DefaultLivePlaybackSpeedControlTest { @Test public void - adjustPlaybackSpeed_repeatedCallAfterUpdateLiveConfigurationWithSameOffset_returnsSameAdjustedSpeed() { + adjustPlaybackSpeed_repeatedCallAfterSetLiveConfigurationWithSameOffset_returnsSameAdjustedSpeed() { DefaultLivePlaybackSpeedControl defaultLivePlaybackSpeedControl = new DefaultLivePlaybackSpeedControl.Builder().setMinUpdateIntervalMs(123).build(); defaultLivePlaybackSpeedControl.setLiveConfiguration( @@ -395,7 +545,7 @@ public class DefaultLivePlaybackSpeedControlTest { @Test public void - adjustPlaybackSpeed_repeatedCallAfterUpdateLiveConfigurationWithNewOffset_updatesSpeedAgain() { + adjustPlaybackSpeed_repeatedCallAfterSetLiveConfigurationWithNewOffset_updatesSpeedAgain() { DefaultLivePlaybackSpeedControl defaultLivePlaybackSpeedControl = new DefaultLivePlaybackSpeedControl.Builder().setMinUpdateIntervalMs(123).build(); defaultLivePlaybackSpeedControl.setLiveConfiguration( @@ -422,7 +572,8 @@ public class DefaultLivePlaybackSpeedControlTest { } @Test - public void adjustPlaybackSpeed_repeatedCallAfterNewTargetLiveOffset_updatesSpeedAgain() { + public void + adjustPlaybackSpeed_repeatedCallAfterSetTargetLiveOffsetOverrideUs_updatesSpeedAgain() { DefaultLivePlaybackSpeedControl defaultLivePlaybackSpeedControl = new DefaultLivePlaybackSpeedControl.Builder().setMinUpdateIntervalMs(123).build(); defaultLivePlaybackSpeedControl.setLiveConfiguration( @@ -441,4 +592,25 @@ public class DefaultLivePlaybackSpeedControlTest { assertThat(adjustedSpeed1).isNotEqualTo(adjustedSpeed2); } + + @Test + public void adjustPlaybackSpeed_repeatedCallAfterNotifyRebuffer_updatesSpeedAgain() { + DefaultLivePlaybackSpeedControl defaultLivePlaybackSpeedControl = + new DefaultLivePlaybackSpeedControl.Builder().setMinUpdateIntervalMs(123).build(); + defaultLivePlaybackSpeedControl.setLiveConfiguration( + new LiveConfiguration( + /* targetLiveOffsetMs= */ 2_000, + /* minLiveOffsetMs= */ C.TIME_UNSET, + /* maxLiveOffsetMs= */ C.TIME_UNSET, + /* minPlaybackSpeed= */ C.RATE_UNSET, + /* maxPlaybackSpeed= */ C.RATE_UNSET)); + + float adjustedSpeed1 = + defaultLivePlaybackSpeedControl.getAdjustedPlaybackSpeed(/* liveOffsetUs= */ 1_500_000); + defaultLivePlaybackSpeedControl.notifyRebuffer(); + float adjustedSpeed2 = + defaultLivePlaybackSpeedControl.getAdjustedPlaybackSpeed(/* liveOffsetUs= */ 2_500_000); + + assertThat(adjustedSpeed1).isNotEqualTo(adjustedSpeed2); + } }