Commit 2416d998 by tonihei Committed by Andrew Lewis

Limit target buffer to media configured min/max values.

Issue: #4904
PiperOrigin-RevId: 340653126
parent c9e80a20
...@@ -122,7 +122,7 @@ public final class DefaultLivePlaybackSpeedControl implements LivePlaybackSpeedC ...@@ -122,7 +122,7 @@ public final class DefaultLivePlaybackSpeedControl implements LivePlaybackSpeedC
* @return This builder, for convenience. * @return This builder, for convenience.
*/ */
public Builder setMinUpdateIntervalMs(long minUpdateIntervalMs) { public Builder setMinUpdateIntervalMs(long minUpdateIntervalMs) {
Assertions.checkArgument(minUpdateIntervalMs >= 0); Assertions.checkArgument(minUpdateIntervalMs > 0);
this.minUpdateIntervalMs = minUpdateIntervalMs; this.minUpdateIntervalMs = minUpdateIntervalMs;
return this; return this;
} }
...@@ -160,8 +160,14 @@ public final class DefaultLivePlaybackSpeedControl implements LivePlaybackSpeedC ...@@ -160,8 +160,14 @@ public final class DefaultLivePlaybackSpeedControl implements LivePlaybackSpeedC
private final long minUpdateIntervalMs; private final long minUpdateIntervalMs;
private final float proportionalControlFactor; private final float proportionalControlFactor;
private LiveConfiguration mediaConfiguration; private long mediaConfigurationTargetLiveOffsetUs;
private long targetLiveOffsetOverrideUs; private long targetLiveOffsetOverrideUs;
private long minTargetLiveOffsetUs;
private long maxTargetLiveOffsetUs;
private long currentTargetLiveOffsetUs;
private float maxPlaybackSpeed;
private float minPlaybackSpeed;
private float adjustedPlaybackSpeed; private float adjustedPlaybackSpeed;
private long lastPlaybackSpeedUpdateMs; private long lastPlaybackSpeedUpdateMs;
...@@ -174,28 +180,42 @@ public final class DefaultLivePlaybackSpeedControl implements LivePlaybackSpeedC ...@@ -174,28 +180,42 @@ public final class DefaultLivePlaybackSpeedControl implements LivePlaybackSpeedC
this.fallbackMaxPlaybackSpeed = fallbackMaxPlaybackSpeed; this.fallbackMaxPlaybackSpeed = fallbackMaxPlaybackSpeed;
this.minUpdateIntervalMs = minUpdateIntervalMs; this.minUpdateIntervalMs = minUpdateIntervalMs;
this.proportionalControlFactor = proportionalControlFactor; this.proportionalControlFactor = proportionalControlFactor;
mediaConfiguration = LiveConfiguration.UNSET; mediaConfigurationTargetLiveOffsetUs = C.TIME_UNSET;
targetLiveOffsetOverrideUs = C.TIME_UNSET; targetLiveOffsetOverrideUs = C.TIME_UNSET;
minTargetLiveOffsetUs = C.TIME_UNSET;
maxTargetLiveOffsetUs = C.TIME_UNSET;
minPlaybackSpeed = fallbackMinPlaybackSpeed;
maxPlaybackSpeed = fallbackMaxPlaybackSpeed;
adjustedPlaybackSpeed = 1.0f; adjustedPlaybackSpeed = 1.0f;
lastPlaybackSpeedUpdateMs = C.TIME_UNSET; lastPlaybackSpeedUpdateMs = C.TIME_UNSET;
currentTargetLiveOffsetUs = C.TIME_UNSET;
} }
@Override @Override
public void setLiveConfiguration(LiveConfiguration liveConfiguration) { public void setLiveConfiguration(LiveConfiguration liveConfiguration) {
this.mediaConfiguration = liveConfiguration; mediaConfigurationTargetLiveOffsetUs = C.msToUs(liveConfiguration.targetLiveOffsetMs);
lastPlaybackSpeedUpdateMs = C.TIME_UNSET; minTargetLiveOffsetUs = C.msToUs(liveConfiguration.minLiveOffsetMs);
maxTargetLiveOffsetUs = C.msToUs(liveConfiguration.maxLiveOffsetMs);
minPlaybackSpeed =
liveConfiguration.minPlaybackSpeed != C.RATE_UNSET
? liveConfiguration.minPlaybackSpeed
: fallbackMinPlaybackSpeed;
maxPlaybackSpeed =
liveConfiguration.maxPlaybackSpeed != C.RATE_UNSET
? liveConfiguration.maxPlaybackSpeed
: fallbackMaxPlaybackSpeed;
maybeResetTargetLiveOffsetUs();
} }
@Override @Override
public void setTargetLiveOffsetOverrideUs(long liveOffsetUs) { public void setTargetLiveOffsetOverrideUs(long liveOffsetUs) {
this.targetLiveOffsetOverrideUs = liveOffsetUs; targetLiveOffsetOverrideUs = liveOffsetUs;
lastPlaybackSpeedUpdateMs = C.TIME_UNSET; maybeResetTargetLiveOffsetUs();
} }
@Override @Override
public float getAdjustedPlaybackSpeed(long liveOffsetUs) { public float getAdjustedPlaybackSpeed(long liveOffsetUs) {
long targetLiveOffsetUs = getTargetLiveOffsetUs(); if (mediaConfigurationTargetLiveOffsetUs == C.TIME_UNSET) {
if (targetLiveOffsetUs == C.TIME_UNSET) {
return 1f; return 1f;
} }
if (lastPlaybackSpeedUpdateMs != C.TIME_UNSET if (lastPlaybackSpeedUpdateMs != C.TIME_UNSET
...@@ -204,34 +224,40 @@ public final class DefaultLivePlaybackSpeedControl implements LivePlaybackSpeedC ...@@ -204,34 +224,40 @@ public final class DefaultLivePlaybackSpeedControl implements LivePlaybackSpeedC
} }
lastPlaybackSpeedUpdateMs = SystemClock.elapsedRealtime(); lastPlaybackSpeedUpdateMs = SystemClock.elapsedRealtime();
long liveOffsetErrorUs = liveOffsetUs - targetLiveOffsetUs; long liveOffsetErrorUs = liveOffsetUs - currentTargetLiveOffsetUs;
if (Math.abs(liveOffsetErrorUs) < MAXIMUM_LIVE_OFFSET_ERROR_US_FOR_UNIT_SPEED) { if (Math.abs(liveOffsetErrorUs) < MAXIMUM_LIVE_OFFSET_ERROR_US_FOR_UNIT_SPEED) {
adjustedPlaybackSpeed = 1f; adjustedPlaybackSpeed = 1f;
} else { } else {
float calculatedSpeed = 1f + proportionalControlFactor * liveOffsetErrorUs; float calculatedSpeed = 1f + proportionalControlFactor * liveOffsetErrorUs;
adjustedPlaybackSpeed = adjustedPlaybackSpeed =
Util.constrainValue(calculatedSpeed, getMinPlaybackSpeed(), getMaxPlaybackSpeed()); Util.constrainValue(calculatedSpeed, minPlaybackSpeed, maxPlaybackSpeed);
} }
return adjustedPlaybackSpeed; return adjustedPlaybackSpeed;
} }
@Override @Override
public long getTargetLiveOffsetUs() { public long getTargetLiveOffsetUs() {
return targetLiveOffsetOverrideUs != C.TIME_UNSET return currentTargetLiveOffsetUs;
&& mediaConfiguration.targetLiveOffsetMs != C.TIME_UNSET
? targetLiveOffsetOverrideUs
: C.msToUs(mediaConfiguration.targetLiveOffsetMs);
}
private float getMinPlaybackSpeed() {
return mediaConfiguration.minPlaybackSpeed != C.RATE_UNSET
? mediaConfiguration.minPlaybackSpeed
: fallbackMinPlaybackSpeed;
} }
private float getMaxPlaybackSpeed() { private void maybeResetTargetLiveOffsetUs() {
return mediaConfiguration.maxPlaybackSpeed != C.RATE_UNSET long idealOffsetUs = C.TIME_UNSET;
? mediaConfiguration.maxPlaybackSpeed if (mediaConfigurationTargetLiveOffsetUs != C.TIME_UNSET) {
: fallbackMaxPlaybackSpeed; idealOffsetUs =
targetLiveOffsetOverrideUs != C.TIME_UNSET
? targetLiveOffsetOverrideUs
: mediaConfigurationTargetLiveOffsetUs;
if (minTargetLiveOffsetUs != C.TIME_UNSET && idealOffsetUs < minTargetLiveOffsetUs) {
idealOffsetUs = minTargetLiveOffsetUs;
}
if (maxTargetLiveOffsetUs != C.TIME_UNSET && idealOffsetUs > maxTargetLiveOffsetUs) {
idealOffsetUs = maxTargetLiveOffsetUs;
}
}
if (currentTargetLiveOffsetUs == idealOffsetUs) {
return;
}
currentTargetLiveOffsetUs = idealOffsetUs;
lastPlaybackSpeedUpdateMs = C.TIME_UNSET;
} }
} }
...@@ -37,13 +37,13 @@ public class DefaultLivePlaybackSpeedControlTest { ...@@ -37,13 +37,13 @@ public class DefaultLivePlaybackSpeedControlTest {
} }
@Test @Test
public void getTargetLiveOffsetUs_afterUpdateLiveConfiguration_usesMediaLiveOffset() { public void getTargetLiveOffsetUs_afterSetLiveConfiguration_usesMediaLiveOffset() {
DefaultLivePlaybackSpeedControl defaultLivePlaybackSpeedControl = DefaultLivePlaybackSpeedControl defaultLivePlaybackSpeedControl =
new DefaultLivePlaybackSpeedControl.Builder().build(); new DefaultLivePlaybackSpeedControl.Builder().build();
defaultLivePlaybackSpeedControl.setLiveConfiguration( defaultLivePlaybackSpeedControl.setLiveConfiguration(
new LiveConfiguration( new LiveConfiguration(
/* targetLiveOffsetMs= */ 42, /* targetLiveOffsetMs= */ 42,
/* minLiveOffsetMs= */ 200, /* minLiveOffsetMs= */ 5,
/* maxLiveOffsetMs= */ 400, /* maxLiveOffsetMs= */ 400,
/* minPlaybackSpeed= */ 1f, /* minPlaybackSpeed= */ 1f,
/* maxPlaybackSpeed= */ 1f)); /* maxPlaybackSpeed= */ 1f));
...@@ -52,7 +52,59 @@ public class DefaultLivePlaybackSpeedControlTest { ...@@ -52,7 +52,59 @@ public class DefaultLivePlaybackSpeedControlTest {
} }
@Test @Test
public void getTargetLiveOffsetUs_withOverrideTargetLiveOffsetUs_usesOverride() { public void
getTargetLiveOffsetUs_afterSetLiveConfigurationWithTargetGreaterThanMax_usesMaxLiveOffset() {
DefaultLivePlaybackSpeedControl defaultLivePlaybackSpeedControl =
new DefaultLivePlaybackSpeedControl.Builder().build();
defaultLivePlaybackSpeedControl.setLiveConfiguration(
new LiveConfiguration(
/* targetLiveOffsetMs= */ 4321,
/* minLiveOffsetMs= */ 5,
/* maxLiveOffsetMs= */ 400,
/* minPlaybackSpeed= */ 1f,
/* maxPlaybackSpeed= */ 1f));
assertThat(defaultLivePlaybackSpeedControl.getTargetLiveOffsetUs()).isEqualTo(400_000);
}
@Test
public void
getTargetLiveOffsetUs_afterSetLiveConfigurationWithTargetLessThanMin_usesMinLiveOffset() {
DefaultLivePlaybackSpeedControl defaultLivePlaybackSpeedControl =
new DefaultLivePlaybackSpeedControl.Builder().build();
defaultLivePlaybackSpeedControl.setLiveConfiguration(
new LiveConfiguration(
/* targetLiveOffsetMs= */ 3,
/* minLiveOffsetMs= */ 5,
/* maxLiveOffsetMs= */ 400,
/* minPlaybackSpeed= */ 1f,
/* maxPlaybackSpeed= */ 1f));
assertThat(defaultLivePlaybackSpeedControl.getTargetLiveOffsetUs()).isEqualTo(5_000);
}
@Test
public void getTargetLiveOffsetUs_withSetTargetLiveOffsetOverrideUs_usesOverride() {
DefaultLivePlaybackSpeedControl defaultLivePlaybackSpeedControl =
new DefaultLivePlaybackSpeedControl.Builder().build();
defaultLivePlaybackSpeedControl.setTargetLiveOffsetOverrideUs(321_000);
defaultLivePlaybackSpeedControl.setLiveConfiguration(
new LiveConfiguration(
/* targetLiveOffsetMs= */ 42,
/* minLiveOffsetMs= */ 5,
/* maxLiveOffsetMs= */ 400,
/* minPlaybackSpeed= */ 1f,
/* maxPlaybackSpeed= */ 1f));
long targetLiveOffsetUs = defaultLivePlaybackSpeedControl.getTargetLiveOffsetUs();
assertThat(targetLiveOffsetUs).isEqualTo(321_000);
}
@Test
public void
getTargetLiveOffsetUs_withSetTargetLiveOffsetOverrideUsGreaterThanMax_usesMaxLiveOffset() {
DefaultLivePlaybackSpeedControl defaultLivePlaybackSpeedControl = DefaultLivePlaybackSpeedControl defaultLivePlaybackSpeedControl =
new DefaultLivePlaybackSpeedControl.Builder().build(); new DefaultLivePlaybackSpeedControl.Builder().build();
...@@ -60,19 +112,39 @@ public class DefaultLivePlaybackSpeedControlTest { ...@@ -60,19 +112,39 @@ public class DefaultLivePlaybackSpeedControlTest {
defaultLivePlaybackSpeedControl.setLiveConfiguration( defaultLivePlaybackSpeedControl.setLiveConfiguration(
new LiveConfiguration( new LiveConfiguration(
/* targetLiveOffsetMs= */ 42, /* targetLiveOffsetMs= */ 42,
/* minLiveOffsetMs= */ 200, /* minLiveOffsetMs= */ 5,
/* maxLiveOffsetMs= */ 400, /* maxLiveOffsetMs= */ 400,
/* minPlaybackSpeed= */ 1f, /* minPlaybackSpeed= */ 1f,
/* maxPlaybackSpeed= */ 1f)); /* maxPlaybackSpeed= */ 1f));
long targetLiveOffsetUs = defaultLivePlaybackSpeedControl.getTargetLiveOffsetUs(); long targetLiveOffsetUs = defaultLivePlaybackSpeedControl.getTargetLiveOffsetUs();
assertThat(targetLiveOffsetUs).isEqualTo(123_456_789); assertThat(targetLiveOffsetUs).isEqualTo(400_000);
} }
@Test @Test
public void public void
getTargetLiveOffsetUs_afterOverrideTargetLiveOffset_withoutMediaConfiguration_returnsUnset() { getTargetLiveOffsetUs_withSetTargetLiveOffsetOverrideUsLessThanMin_usesMinLiveOffset() {
DefaultLivePlaybackSpeedControl defaultLivePlaybackSpeedControl =
new DefaultLivePlaybackSpeedControl.Builder().build();
defaultLivePlaybackSpeedControl.setTargetLiveOffsetOverrideUs(3_141);
defaultLivePlaybackSpeedControl.setLiveConfiguration(
new LiveConfiguration(
/* targetLiveOffsetMs= */ 42,
/* minLiveOffsetMs= */ 5,
/* maxLiveOffsetMs= */ 400,
/* minPlaybackSpeed= */ 1f,
/* maxPlaybackSpeed= */ 1f));
long targetLiveOffsetUs = defaultLivePlaybackSpeedControl.getTargetLiveOffsetUs();
assertThat(targetLiveOffsetUs).isEqualTo(5_000);
}
@Test
public void
getTargetLiveOffsetUs_afterSetTargetLiveOffsetOverrideWithoutMediaConfiguration_returnsUnset() {
DefaultLivePlaybackSpeedControl defaultLivePlaybackSpeedControl = DefaultLivePlaybackSpeedControl defaultLivePlaybackSpeedControl =
new DefaultLivePlaybackSpeedControl.Builder().build(); new DefaultLivePlaybackSpeedControl.Builder().build();
defaultLivePlaybackSpeedControl.setTargetLiveOffsetOverrideUs(123_456_789); defaultLivePlaybackSpeedControl.setTargetLiveOffsetOverrideUs(123_456_789);
...@@ -84,14 +156,14 @@ public class DefaultLivePlaybackSpeedControlTest { ...@@ -84,14 +156,14 @@ public class DefaultLivePlaybackSpeedControlTest {
@Test @Test
public void public void
getTargetLiveOffsetUs_afterOverrideTargetLiveOffsetUsWithTimeUnset_usesMediaLiveOffset() { getTargetLiveOffsetUs_afterSetTargetLiveOffsetOverrideWithTimeUnset_usesMediaLiveOffset() {
DefaultLivePlaybackSpeedControl defaultLivePlaybackSpeedControl = DefaultLivePlaybackSpeedControl defaultLivePlaybackSpeedControl =
new DefaultLivePlaybackSpeedControl.Builder().build(); new DefaultLivePlaybackSpeedControl.Builder().build();
defaultLivePlaybackSpeedControl.setTargetLiveOffsetOverrideUs(123_456_789); defaultLivePlaybackSpeedControl.setTargetLiveOffsetOverrideUs(123_456_789);
defaultLivePlaybackSpeedControl.setLiveConfiguration( defaultLivePlaybackSpeedControl.setLiveConfiguration(
new LiveConfiguration( new LiveConfiguration(
/* targetLiveOffsetMs= */ 42, /* targetLiveOffsetMs= */ 42,
/* minLiveOffsetMs= */ 200, /* minLiveOffsetMs= */ 5,
/* maxLiveOffsetMs= */ 400, /* maxLiveOffsetMs= */ 400,
/* minPlaybackSpeed= */ 1f, /* minPlaybackSpeed= */ 1f,
/* maxPlaybackSpeed= */ 1f)); /* maxPlaybackSpeed= */ 1f));
...@@ -294,7 +366,8 @@ public class DefaultLivePlaybackSpeedControlTest { ...@@ -294,7 +366,8 @@ public class DefaultLivePlaybackSpeedControlTest {
} }
@Test @Test
public void adjustPlaybackSpeed_repeatedCallAfterUpdateLiveConfiguration_updatesSpeedAgain() { public void
adjustPlaybackSpeed_repeatedCallAfterUpdateLiveConfigurationWithSameOffset_returnsSameAdjustedSpeed() {
DefaultLivePlaybackSpeedControl defaultLivePlaybackSpeedControl = DefaultLivePlaybackSpeedControl defaultLivePlaybackSpeedControl =
new DefaultLivePlaybackSpeedControl.Builder().setMinUpdateIntervalMs(123).build(); new DefaultLivePlaybackSpeedControl.Builder().setMinUpdateIntervalMs(123).build();
defaultLivePlaybackSpeedControl.setLiveConfiguration( defaultLivePlaybackSpeedControl.setLiveConfiguration(
...@@ -317,6 +390,34 @@ public class DefaultLivePlaybackSpeedControlTest { ...@@ -317,6 +390,34 @@ public class DefaultLivePlaybackSpeedControlTest {
float adjustedSpeed2 = float adjustedSpeed2 =
defaultLivePlaybackSpeedControl.getAdjustedPlaybackSpeed(/* liveOffsetUs= */ 2_500_000); defaultLivePlaybackSpeedControl.getAdjustedPlaybackSpeed(/* liveOffsetUs= */ 2_500_000);
assertThat(adjustedSpeed1).isEqualTo(adjustedSpeed2);
}
@Test
public void
adjustPlaybackSpeed_repeatedCallAfterUpdateLiveConfigurationWithNewOffset_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.setLiveConfiguration(
new LiveConfiguration(
/* targetLiveOffsetMs= */ 1_000,
/* minLiveOffsetMs= */ C.TIME_UNSET,
/* maxLiveOffsetMs= */ C.TIME_UNSET,
/* minPlaybackSpeed= */ C.RATE_UNSET,
/* maxPlaybackSpeed= */ C.RATE_UNSET));
float adjustedSpeed2 =
defaultLivePlaybackSpeedControl.getAdjustedPlaybackSpeed(/* liveOffsetUs= */ 2_500_000);
assertThat(adjustedSpeed1).isNotEqualTo(adjustedSpeed2); assertThat(adjustedSpeed1).isNotEqualTo(adjustedSpeed2);
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment