Skip to content

Commit

Permalink
Limit target buffer to media configured min/max values.
Browse files Browse the repository at this point in the history
Issue: #4904
PiperOrigin-RevId: 340653126
  • Loading branch information
tonihei authored and andrewlewis committed Nov 6, 2020
1 parent c9e80a2 commit 2416d99
Show file tree
Hide file tree
Showing 2 changed files with 161 additions and 34 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ public Builder setFallbackMaxPlaybackSpeed(float fallbackMaxPlaybackSpeed) {
* @return This builder, for convenience.
*/
public Builder setMinUpdateIntervalMs(long minUpdateIntervalMs) {
Assertions.checkArgument(minUpdateIntervalMs >= 0);
Assertions.checkArgument(minUpdateIntervalMs > 0);
this.minUpdateIntervalMs = minUpdateIntervalMs;
return this;
}
Expand Down Expand Up @@ -160,8 +160,14 @@ public DefaultLivePlaybackSpeedControl build() {
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;

Expand All @@ -174,28 +180,42 @@ private DefaultLivePlaybackSpeedControl(
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
Expand All @@ -204,34 +224,40 @@ public float getAdjustedPlaybackSpeed(long liveOffsetUs) {
}
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);
}

private float getMinPlaybackSpeed() {
return mediaConfiguration.minPlaybackSpeed != C.RATE_UNSET
? mediaConfiguration.minPlaybackSpeed
: fallbackMinPlaybackSpeed;
return currentTargetLiveOffsetUs;
}

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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,13 @@ public void getTargetLiveOffsetUs_returnsUnset() {
}

@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));
Expand All @@ -52,27 +52,99 @@ public void getTargetLiveOffsetUs_afterUpdateLiveConfiguration_usesMediaLiveOffs
}

@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();

defaultLivePlaybackSpeedControl.setTargetLiveOffsetOverrideUs(123_456_789);
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);
Expand All @@ -84,14 +156,14 @@ public void getTargetLiveOffsetUs_withOverrideTargetLiveOffsetUs_usesOverride()

@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));
Expand Down Expand Up @@ -294,7 +366,8 @@ public void adjustPlaybackSpeed_repeatedCallWithinMinUpdateInterval_returnsSameA
}

@Test
public void adjustPlaybackSpeed_repeatedCallAfterUpdateLiveConfiguration_updatesSpeedAgain() {
public void
adjustPlaybackSpeed_repeatedCallAfterUpdateLiveConfigurationWithSameOffset_returnsSameAdjustedSpeed() {
DefaultLivePlaybackSpeedControl defaultLivePlaybackSpeedControl =
new DefaultLivePlaybackSpeedControl.Builder().setMinUpdateIntervalMs(123).build();
defaultLivePlaybackSpeedControl.setLiveConfiguration(
Expand All @@ -317,6 +390,34 @@ public void adjustPlaybackSpeed_repeatedCallAfterUpdateLiveConfiguration_updates
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);
}

Expand Down

0 comments on commit 2416d99

Please sign in to comment.