Commit 3e7eeceb by tonihei

Fix some playback parameter signalling problems.

Playback parameter signalling can be quite complex because
 (a) the renderer clock often has a delay before it realizes
     that it doesn't support a previously set speed and
 (b) the speed set on media clock sometimes intentionally
     differs from the one surfaced to the user, e.g. during
     live speed adjustment or when overriding ad playback
     speed to 1.0f.

This change fixes two problems related to this signalling:
 1. When resetting the media clock speed at a period transition,
    we don't currently tell the renderers that this happened.
 2. When a delayed speed change update from the media clock is
    pending and the renderer for this media clock is disabled
    before the change can be handled, the pending update becomes
    stale but it still applied later and overrides any other valid
    speed set in the meantime.

Both edge cases are also covered by extended or new player tests.

Issue: google/ExoPlayer#10882

PiperOrigin-RevId: 512658918
(cherry picked from commit d3639771)
parent 38639e5a
...@@ -938,7 +938,7 @@ import java.util.concurrent.atomic.AtomicBoolean; ...@@ -938,7 +938,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
livePlaybackSpeedControl.getAdjustedPlaybackSpeed( livePlaybackSpeedControl.getAdjustedPlaybackSpeed(
getCurrentLiveOffsetUs(), getTotalBufferedDurationUs()); getCurrentLiveOffsetUs(), getTotalBufferedDurationUs());
if (mediaClock.getPlaybackParameters().speed != adjustedSpeed) { if (mediaClock.getPlaybackParameters().speed != adjustedSpeed) {
mediaClock.setPlaybackParameters(playbackInfo.playbackParameters.withSpeed(adjustedSpeed)); setMediaClockPlaybackParameters(playbackInfo.playbackParameters.withSpeed(adjustedSpeed));
handlePlaybackParameters( handlePlaybackParameters(
playbackInfo.playbackParameters, playbackInfo.playbackParameters,
/* currentPlaybackSpeed= */ mediaClock.getPlaybackParameters().speed, /* currentPlaybackSpeed= */ mediaClock.getPlaybackParameters().speed,
...@@ -948,6 +948,12 @@ import java.util.concurrent.atomic.AtomicBoolean; ...@@ -948,6 +948,12 @@ import java.util.concurrent.atomic.AtomicBoolean;
} }
} }
private void setMediaClockPlaybackParameters(PlaybackParameters playbackParameters) {
// Previously sent speed updates from the media clock now become stale.
handler.removeMessages(MSG_PLAYBACK_PARAMETERS_CHANGED_INTERNAL);
mediaClock.setPlaybackParameters(playbackParameters);
}
private void notifyTrackSelectionRebuffer() { private void notifyTrackSelectionRebuffer() {
MediaPeriodHolder periodHolder = queue.getPlayingPeriod(); MediaPeriodHolder periodHolder = queue.getPlayingPeriod();
while (periodHolder != null) { while (periodHolder != null) {
...@@ -1334,7 +1340,7 @@ import java.util.concurrent.atomic.AtomicBoolean; ...@@ -1334,7 +1340,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
private void setPlaybackParametersInternal(PlaybackParameters playbackParameters) private void setPlaybackParametersInternal(PlaybackParameters playbackParameters)
throws ExoPlaybackException { throws ExoPlaybackException {
mediaClock.setPlaybackParameters(playbackParameters); setMediaClockPlaybackParameters(playbackParameters);
handlePlaybackParameters(mediaClock.getPlaybackParameters(), /* acknowledgeCommand= */ true); handlePlaybackParameters(mediaClock.getPlaybackParameters(), /* acknowledgeCommand= */ true);
} }
...@@ -1649,7 +1655,7 @@ import java.util.concurrent.atomic.AtomicBoolean; ...@@ -1649,7 +1655,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
nextPendingMessageIndexHint = nextPendingMessageIndex; nextPendingMessageIndexHint = nextPendingMessageIndex;
} }
private void ensureStopped(Renderer renderer) throws ExoPlaybackException { private void ensureStopped(Renderer renderer) {
if (renderer.getState() == Renderer.STATE_STARTED) { if (renderer.getState() == Renderer.STATE_STARTED) {
renderer.stop(); renderer.stop();
} }
...@@ -1906,14 +1912,20 @@ import java.util.concurrent.atomic.AtomicBoolean; ...@@ -1906,14 +1912,20 @@ import java.util.concurrent.atomic.AtomicBoolean;
MediaPeriodId newPeriodId, MediaPeriodId newPeriodId,
Timeline oldTimeline, Timeline oldTimeline,
MediaPeriodId oldPeriodId, MediaPeriodId oldPeriodId,
long positionForTargetOffsetOverrideUs) { long positionForTargetOffsetOverrideUs)
throws ExoPlaybackException {
if (!shouldUseLivePlaybackSpeedControl(newTimeline, newPeriodId)) { if (!shouldUseLivePlaybackSpeedControl(newTimeline, newPeriodId)) {
// Live playback speed control is unused for the current period, reset speed to user-defined // Live playback speed control is unused for the current period, reset speed to user-defined
// playback parameters or 1.0 for ad playback. // playback parameters or 1.0 for ad playback.
PlaybackParameters targetPlaybackParameters = PlaybackParameters targetPlaybackParameters =
newPeriodId.isAd() ? PlaybackParameters.DEFAULT : playbackInfo.playbackParameters; newPeriodId.isAd() ? PlaybackParameters.DEFAULT : playbackInfo.playbackParameters;
if (!mediaClock.getPlaybackParameters().equals(targetPlaybackParameters)) { if (!mediaClock.getPlaybackParameters().equals(targetPlaybackParameters)) {
mediaClock.setPlaybackParameters(targetPlaybackParameters); setMediaClockPlaybackParameters(targetPlaybackParameters);
handlePlaybackParameters(
playbackInfo.playbackParameters,
targetPlaybackParameters.speed,
/* updatePlaybackInfo= */ false,
/* acknowledgeCommand= */ false);
} }
return; return;
} }
...@@ -1962,7 +1974,7 @@ import java.util.concurrent.atomic.AtomicBoolean; ...@@ -1962,7 +1974,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
return maxReadPositionUs; return maxReadPositionUs;
} }
private void updatePeriods() throws ExoPlaybackException, IOException { private void updatePeriods() throws ExoPlaybackException {
if (playbackInfo.timeline.isEmpty() || !mediaSourceList.isPrepared()) { if (playbackInfo.timeline.isEmpty() || !mediaSourceList.isPrepared()) {
// No periods available. // No periods available.
return; return;
...@@ -2004,7 +2016,7 @@ import java.util.concurrent.atomic.AtomicBoolean; ...@@ -2004,7 +2016,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
} }
} }
private void maybeUpdateReadingPeriod() { private void maybeUpdateReadingPeriod() throws ExoPlaybackException {
@Nullable MediaPeriodHolder readingPeriodHolder = queue.getReadingPeriod(); @Nullable MediaPeriodHolder readingPeriodHolder = queue.getReadingPeriod();
if (readingPeriodHolder == null) { if (readingPeriodHolder == null) {
return; return;
......
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