diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java index 1ba8a6d4a8..16320637d5 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java @@ -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; diff --git a/library/core/src/test/java/com/google/android/exoplayer2/ExoPlayerTest.java b/library/core/src/test/java/com/google/android/exoplayer2/ExoPlayerTest.java index 1be3e2f7fe..decf198142 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/ExoPlayerTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/ExoPlayerTest.java @@ -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) {