Limit target buffer to media configured min/max values.

Issue: #4904
PiperOrigin-RevId: 340653126
This commit is contained in:
tonihei 2020-11-04 16:27:19 +00:00 committed by Andrew Lewis
parent c9e80a20e6
commit 2416d99857
2 changed files with 161 additions and 34 deletions

View file

@ -122,7 +122,7 @@ public final class DefaultLivePlaybackSpeedControl implements LivePlaybackSpeedC
* @return This builder, for convenience.
*/
public Builder setMinUpdateIntervalMs(long minUpdateIntervalMs) {
Assertions.checkArgument(minUpdateIntervalMs >= 0);
Assertions.checkArgument(minUpdateIntervalMs > 0);
this.minUpdateIntervalMs = minUpdateIntervalMs;
return this;
}
@ -160,8 +160,14 @@ public final class DefaultLivePlaybackSpeedControl implements LivePlaybackSpeedC
private final long minUpdateIntervalMs;
private final float proportionalControlFactor;
private LiveConfiguration mediaConfiguration;
private long mediaConfigurationTargetLiveOffsetUs;
private long targetLiveOffsetOverrideUs;
private long minTargetLiveOffsetUs;
private long maxTargetLiveOffsetUs;
private long currentTargetLiveOffsetUs;
private float maxPlaybackSpeed;
private float minPlaybackSpeed;
private float adjustedPlaybackSpeed;
private long lastPlaybackSpeedUpdateMs;
@ -174,28 +180,42 @@ public final class DefaultLivePlaybackSpeedControl implements LivePlaybackSpeedC
this.fallbackMaxPlaybackSpeed = fallbackMaxPlaybackSpeed;
this.minUpdateIntervalMs = minUpdateIntervalMs;
this.proportionalControlFactor = proportionalControlFactor;
mediaConfiguration = LiveConfiguration.UNSET;
mediaConfigurationTargetLiveOffsetUs = C.TIME_UNSET;
targetLiveOffsetOverrideUs = C.TIME_UNSET;
minTargetLiveOffsetUs = C.TIME_UNSET;
maxTargetLiveOffsetUs = C.TIME_UNSET;
minPlaybackSpeed = fallbackMinPlaybackSpeed;
maxPlaybackSpeed = fallbackMaxPlaybackSpeed;
adjustedPlaybackSpeed = 1.0f;
lastPlaybackSpeedUpdateMs = C.TIME_UNSET;
currentTargetLiveOffsetUs = C.TIME_UNSET;
}
@Override
public void setLiveConfiguration(LiveConfiguration liveConfiguration) {
this.mediaConfiguration = liveConfiguration;
lastPlaybackSpeedUpdateMs = C.TIME_UNSET;
mediaConfigurationTargetLiveOffsetUs = C.msToUs(liveConfiguration.targetLiveOffsetMs);
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
public void setTargetLiveOffsetOverrideUs(long liveOffsetUs) {
this.targetLiveOffsetOverrideUs = liveOffsetUs;
lastPlaybackSpeedUpdateMs = C.TIME_UNSET;
targetLiveOffsetOverrideUs = liveOffsetUs;
maybeResetTargetLiveOffsetUs();
}
@Override
public float getAdjustedPlaybackSpeed(long liveOffsetUs) {
long targetLiveOffsetUs = getTargetLiveOffsetUs();
if (targetLiveOffsetUs == C.TIME_UNSET) {
if (mediaConfigurationTargetLiveOffsetUs == C.TIME_UNSET) {
return 1f;
}
if (lastPlaybackSpeedUpdateMs != C.TIME_UNSET
@ -204,34 +224,40 @@ public final class DefaultLivePlaybackSpeedControl implements LivePlaybackSpeedC
}
lastPlaybackSpeedUpdateMs = SystemClock.elapsedRealtime();
long liveOffsetErrorUs = liveOffsetUs - targetLiveOffsetUs;
long liveOffsetErrorUs = liveOffsetUs - currentTargetLiveOffsetUs;
if (Math.abs(liveOffsetErrorUs) < MAXIMUM_LIVE_OFFSET_ERROR_US_FOR_UNIT_SPEED) {
adjustedPlaybackSpeed = 1f;
} else {
float calculatedSpeed = 1f + proportionalControlFactor * liveOffsetErrorUs;
adjustedPlaybackSpeed =
Util.constrainValue(calculatedSpeed, getMinPlaybackSpeed(), getMaxPlaybackSpeed());
Util.constrainValue(calculatedSpeed, minPlaybackSpeed, maxPlaybackSpeed);
}
return adjustedPlaybackSpeed;
}
@Override
public long getTargetLiveOffsetUs() {
return targetLiveOffsetOverrideUs != C.TIME_UNSET
&& mediaConfiguration.targetLiveOffsetMs != C.TIME_UNSET
? targetLiveOffsetOverrideUs
: C.msToUs(mediaConfiguration.targetLiveOffsetMs);
return currentTargetLiveOffsetUs;
}
private float getMinPlaybackSpeed() {
return mediaConfiguration.minPlaybackSpeed != C.RATE_UNSET
? mediaConfiguration.minPlaybackSpeed
: fallbackMinPlaybackSpeed;
}
private float getMaxPlaybackSpeed() {
return mediaConfiguration.maxPlaybackSpeed != C.RATE_UNSET
? mediaConfiguration.maxPlaybackSpeed
: fallbackMaxPlaybackSpeed;
private void maybeResetTargetLiveOffsetUs() {
long idealOffsetUs = C.TIME_UNSET;
if (mediaConfigurationTargetLiveOffsetUs != C.TIME_UNSET) {
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;
}
}

View file

@ -37,13 +37,13 @@ public class DefaultLivePlaybackSpeedControlTest {
}
@Test
public void getTargetLiveOffsetUs_afterUpdateLiveConfiguration_usesMediaLiveOffset() {
public void getTargetLiveOffsetUs_afterSetLiveConfiguration_usesMediaLiveOffset() {
DefaultLivePlaybackSpeedControl defaultLivePlaybackSpeedControl =
new DefaultLivePlaybackSpeedControl.Builder().build();
defaultLivePlaybackSpeedControl.setLiveConfiguration(
new LiveConfiguration(
/* targetLiveOffsetMs= */ 42,
/* minLiveOffsetMs= */ 200,
/* minLiveOffsetMs= */ 5,
/* maxLiveOffsetMs= */ 400,
/* minPlaybackSpeed= */ 1f,
/* maxPlaybackSpeed= */ 1f));
@ -52,7 +52,59 @@ public class DefaultLivePlaybackSpeedControlTest {
}
@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 =
new DefaultLivePlaybackSpeedControl.Builder().build();
@ -60,19 +112,39 @@ public class DefaultLivePlaybackSpeedControlTest {
defaultLivePlaybackSpeedControl.setLiveConfiguration(
new LiveConfiguration(
/* targetLiveOffsetMs= */ 42,
/* minLiveOffsetMs= */ 200,
/* minLiveOffsetMs= */ 5,
/* maxLiveOffsetMs= */ 400,
/* minPlaybackSpeed= */ 1f,
/* maxPlaybackSpeed= */ 1f));
long targetLiveOffsetUs = defaultLivePlaybackSpeedControl.getTargetLiveOffsetUs();
assertThat(targetLiveOffsetUs).isEqualTo(123_456_789);
assertThat(targetLiveOffsetUs).isEqualTo(400_000);
}
@Test
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 =
new DefaultLivePlaybackSpeedControl.Builder().build();
defaultLivePlaybackSpeedControl.setTargetLiveOffsetOverrideUs(123_456_789);
@ -84,14 +156,14 @@ public class DefaultLivePlaybackSpeedControlTest {
@Test
public void
getTargetLiveOffsetUs_afterOverrideTargetLiveOffsetUsWithTimeUnset_usesMediaLiveOffset() {
getTargetLiveOffsetUs_afterSetTargetLiveOffsetOverrideWithTimeUnset_usesMediaLiveOffset() {
DefaultLivePlaybackSpeedControl defaultLivePlaybackSpeedControl =
new DefaultLivePlaybackSpeedControl.Builder().build();
defaultLivePlaybackSpeedControl.setTargetLiveOffsetOverrideUs(123_456_789);
defaultLivePlaybackSpeedControl.setLiveConfiguration(
new LiveConfiguration(
/* targetLiveOffsetMs= */ 42,
/* minLiveOffsetMs= */ 200,
/* minLiveOffsetMs= */ 5,
/* maxLiveOffsetMs= */ 400,
/* minPlaybackSpeed= */ 1f,
/* maxPlaybackSpeed= */ 1f));
@ -294,7 +366,8 @@ public class DefaultLivePlaybackSpeedControlTest {
}
@Test
public void adjustPlaybackSpeed_repeatedCallAfterUpdateLiveConfiguration_updatesSpeedAgain() {
public void
adjustPlaybackSpeed_repeatedCallAfterUpdateLiveConfigurationWithSameOffset_returnsSameAdjustedSpeed() {
DefaultLivePlaybackSpeedControl defaultLivePlaybackSpeedControl =
new DefaultLivePlaybackSpeedControl.Builder().setMinUpdateIntervalMs(123).build();
defaultLivePlaybackSpeedControl.setLiveConfiguration(
@ -317,6 +390,34 @@ public class DefaultLivePlaybackSpeedControlTest {
float adjustedSpeed2 =
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);
}