mirror of
https://github.com/samsonjs/media.git
synced 2026-04-01 10:35:48 +00:00
Limit target buffer to media configured min/max values.
Issue: #4904 PiperOrigin-RevId: 340653126
This commit is contained in:
parent
c9e80a20e6
commit
2416d99857
2 changed files with 161 additions and 34 deletions
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue