Ensure seeks are not ignored in ended state.

We should only ignore seek to the current position if we are
currently READY or BUFFERING. Also, pending initial seek positions
should only be saved while we have an empty timeline, independent of
the player state.

Issue:#6886
PiperOrigin-RevId: 297813854
This commit is contained in:
tonihei 2020-02-28 12:13:58 +00:00 committed by Oliver Woodman
parent 68c401b53e
commit 6c7a2c3cfd
2 changed files with 44 additions and 3 deletions

View File

@ -902,12 +902,14 @@ import java.util.concurrent.atomic.AtomicBoolean;
}
try {
if (playbackInfo.timeline.isEmpty() || !playlist.isPrepared()) {
if (playbackInfo.timeline.isEmpty()) {
// Save seek position for later, as we are still waiting for a prepared source.
pendingInitialSeekPosition = seekPosition;
} else if (resolvedSeekPosition == null) {
// End playback, as we didn't manage to find a valid seek position.
setState(Player.STATE_ENDED);
if (playbackInfo.playbackState != Player.STATE_IDLE) {
setState(Player.STATE_ENDED);
}
resetInternal(
/* resetRenderers= */ false,
/* resetPosition= */ true,
@ -926,7 +928,9 @@ import java.util.concurrent.atomic.AtomicBoolean;
playingPeriodHolder.mediaPeriod.getAdjustedSeekPositionUs(
newPeriodPositionUs, seekParameters);
}
if (C.usToMs(newPeriodPositionUs) == C.usToMs(playbackInfo.positionUs)) {
if (C.usToMs(newPeriodPositionUs) == C.usToMs(playbackInfo.positionUs)
&& (playbackInfo.playbackState == Player.STATE_BUFFERING
|| playbackInfo.playbackState == Player.STATE_READY)) {
// Seek will be performed to the current position. Do nothing.
periodPositionUs = playbackInfo.positionUs;
return;

View File

@ -5728,6 +5728,43 @@ public final class ExoPlayerTest {
assertThat(trackSelectionsAfterError.get().get(1)).isNotNull(); // Audio renderer.
}
@Test
public void seekToCurrentPosition_inEndedState_switchesToBufferingStateAndContinuesPlayback()
throws Exception {
MediaSource mediaSource = new FakeMediaSource(new FakeTimeline(/* windowCount = */ 1));
AtomicInteger windowIndexAfterFinalEndedState = new AtomicInteger();
ActionSchedule actionSchedule =
new ActionSchedule.Builder("seekToCurrentPosition_inEndedState")
.waitForPlaybackState(Player.STATE_ENDED)
.addMediaSources(mediaSource)
.executeRunnable(
new PlayerRunnable() {
@Override
public void run(SimpleExoPlayer player) {
player.seekTo(player.getCurrentPosition());
}
})
.waitForPlaybackState(Player.STATE_READY)
.waitForPlaybackState(Player.STATE_ENDED)
.executeRunnable(
new PlayerRunnable() {
@Override
public void run(SimpleExoPlayer player) {
windowIndexAfterFinalEndedState.set(player.getCurrentWindowIndex());
}
})
.build();
new Builder()
.setMediaSources(mediaSource)
.setActionSchedule(actionSchedule)
.build(context)
.start()
.blockUntilActionScheduleFinished(TIMEOUT_MS)
.blockUntilEnded(TIMEOUT_MS);
assertThat(windowIndexAfterFinalEndedState.get()).isEqualTo(1);
}
// Internal methods.
private static ActionSchedule.Builder addSurfaceSwitch(ActionSchedule.Builder builder) {