Skip to content

Commit

Permalink
Increase target live offset when rebuffering.
Browse files Browse the repository at this point in the history
Issue: #4904
PiperOrigin-RevId: 340654178
  • Loading branch information
tonihei authored and andrewlewis committed Nov 6, 2020
1 parent 2416d99 commit effbc22
Show file tree
Hide file tree
Showing 4 changed files with 250 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@
* 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.
*
* <p>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 {

Expand Down Expand Up @@ -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.
Expand All @@ -73,13 +83,16 @@ public static final class Builder {
private float fallbackMaxPlaybackSpeed;
private long minUpdateIntervalMs;
private float proportionalControlFactorUs;
private long targetLiveOffsetIncrementOnRebufferUs;

/** Creates a builder. */
public Builder() {
fallbackMinPlaybackSpeed = DEFAULT_FALLBACK_MIN_PLAYBACK_SPEED;
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);
}

/**
Expand Down Expand Up @@ -145,23 +158,41 @@ public Builder setProportionalControlFactor(float proportionalControlFactor) {
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);
}
}

private final float fallbackMinPlaybackSpeed;
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;
Expand All @@ -175,11 +206,13 @@ private DefaultLivePlaybackSpeedControl(
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;
Expand All @@ -188,6 +221,7 @@ private DefaultLivePlaybackSpeedControl(
maxPlaybackSpeed = fallbackMaxPlaybackSpeed;
adjustedPlaybackSpeed = 1.0f;
lastPlaybackSpeedUpdateMs = C.TIME_UNSET;
idealTargetLiveOffsetUs = C.TIME_UNSET;
currentTargetLiveOffsetUs = C.TIME_UNSET;
}

Expand All @@ -213,6 +247,19 @@ public void setTargetLiveOffsetOverrideUs(long liveOffsetUs) {
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) {
Expand Down Expand Up @@ -254,9 +301,10 @@ private void maybeResetTargetLiveOffsetUs() {
idealOffsetUs = maxTargetLiveOffsetUs;
}
}
if (currentTargetLiveOffsetUs == idealOffsetUs) {
if (idealTargetLiveOffsetUs == idealOffsetUs) {
return;
}
idealTargetLiveOffsetUs = idealOffsetUs;
currentTargetLiveOffsetUs = idealOffsetUs;
lastPlaybackSpeedUpdateMs = C.TIME_UNSET;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ public interface PlaybackInfoUpdateListener {
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;
Expand Down Expand Up @@ -733,7 +733,7 @@ private void setPlayWhenReadyInternal(
playbackInfoUpdate.incrementPendingOperationAcks(operationAck ? 1 : 0);
playbackInfoUpdate.setPlayWhenReadyChangeReason(reason);
playbackInfo = playbackInfo.copyWithPlayWhenReady(playWhenReady, playbackSuppressionReason);
rebuffering = false;
isRebuffering = false;
if (!shouldPlayWhenReady()) {
stopRenderers();
updatePlaybackPositions();
Expand Down Expand Up @@ -811,7 +811,7 @@ private void seekToCurrentPosition(boolean sendDiscontinuity) throws ExoPlayback
}

private void startRenderers() throws ExoPlaybackException {
rebuffering = false;
isRebuffering = false;
mediaClock.start();
for (Renderer renderer : renderers) {
if (isRendererEnabled(renderer)) {
Expand Down Expand Up @@ -868,6 +868,7 @@ private void updatePlaybackPositions() throws ExoPlaybackException {

// Adjust live playback speed to new position.
if (playbackInfo.playWhenReady
&& playbackInfo.playbackState == Player.STATE_READY
&& isCurrentPeriodInMovingLiveWindow()
&& playbackInfo.playbackParameters.speed == 1f) {
float adjustedSpeed =
Expand Down Expand Up @@ -960,8 +961,9 @@ && shouldTransitionToReadyState(renderersAllowPlayback)) {
}
} else if (playbackInfo.playbackState == Player.STATE_READY
&& !(enabledRendererCount == 0 ? isTimelineReady() : renderersAllowPlayback)) {
rebuffering = shouldPlayWhenReady();
isRebuffering = shouldPlayWhenReady();
setState(Player.STATE_BUFFERING);
livePlaybackSpeedControl.notifyRebuffer();
stopRenderers();
}

Expand Down Expand Up @@ -1168,7 +1170,7 @@ private long seekToPeriodPosition(
boolean forceBufferingState)
throws ExoPlaybackException {
stopRenderers();
rebuffering = false;
isRebuffering = false;
if (forceBufferingState || playbackInfo.playbackState == Player.STATE_READY) {
setState(Player.STATE_BUFFERING);
}
Expand Down Expand Up @@ -1311,7 +1313,7 @@ private void resetInternal(
boolean releaseMediaSourceList,
boolean resetError) {
handler.removeMessages(MSG_DO_SOME_WORK);
rebuffering = false;
isRebuffering = false;
mediaClock.stop();
rendererPositionUs = 0;
for (Renderer renderer : renderers) {
Expand Down Expand Up @@ -1701,7 +1703,7 @@ private boolean shouldTransitionToReadyState(boolean renderersReadyOrEnded) {
|| loadControl.shouldStartPlayback(
getTotalBufferedDurationUs(),
mediaClock.getPlaybackParameters().speed,
rebuffering,
isRebuffering,
targetLiveOffsetUs);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,14 @@ public interface LivePlaybackSpeedControl {
*/
void setTargetLiveOffsetOverrideUs(long liveOffsetUs);

/**
* Notifies the live playback speed control that a rebuffer occurred.
*
* <p>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}.
Expand Down
Loading

0 comments on commit effbc22

Please sign in to comment.