Handle !resetPosition as initial seek position.

The flag in ExoPlayer.prepare is documented as keeping the current window
index and window position. We are currently using the current period UID and
period position instead. This causes problems when the media source is changed
but the position is not reset.

Using the initial seek position instead ensures we actually use the window
index and position.

Issue:#5520
PiperOrigin-RevId: 236101024
This commit is contained in:
tonihei 2019-02-28 13:00:20 +00:00 committed by Oliver Woodman
parent 377e550d0f
commit 2ae07936ba
3 changed files with 48 additions and 0 deletions

View File

@ -64,6 +64,9 @@
([#5179](https://github.com/google/ExoPlayer/issues/5179)). ([#5179](https://github.com/google/ExoPlayer/issues/5179)).
* Fix issue with `TimelineQueueNavigator` not publishing the queue in shuffled * Fix issue with `TimelineQueueNavigator` not publishing the queue in shuffled
order when in shuffle mode. order when in shuffle mode.
* Fix issue where not resetting the position for a new `MediaSource` in calls to
`ExoPlayer.prepare` causes an `IndexOutOfBoundsException`
([#5520](https://github.com/google/ExoPlayer/issues/5520)).
### 2.9.6 ### ### 2.9.6 ###

View File

@ -436,6 +436,12 @@ import java.util.concurrent.atomic.AtomicBoolean;
private void prepareInternal(MediaSource mediaSource, boolean resetPosition, boolean resetState) { private void prepareInternal(MediaSource mediaSource, boolean resetPosition, boolean resetState) {
pendingPrepareCount++; pendingPrepareCount++;
if (!resetPosition && pendingInitialSeekPosition == null && !playbackInfo.timeline.isEmpty()) {
playbackInfo.timeline.getPeriodByUid(playbackInfo.periodId.periodUid, period);
long windowPositionUs = playbackInfo.positionUs + period.getPositionInWindowUs();
pendingInitialSeekPosition =
new SeekPosition(Timeline.EMPTY, period.windowIndex, windowPositionUs);
}
resetInternal( resetInternal(
/* resetRenderers= */ false, /* releaseMediaSource= */ true, resetPosition, resetState); /* resetRenderers= */ false, /* releaseMediaSource= */ true, resetPosition, resetState);
loadControl.onPrepared(); loadControl.onPrepared();

View File

@ -1124,6 +1124,45 @@ public final class ExoPlayerTest {
testRunner.assertPlayedPeriodIndices(0, 1); testRunner.assertPlayedPeriodIndices(0, 1);
} }
@Test
public void testReprepareAndKeepPositionWithNewMediaSource() throws Exception {
Timeline timeline =
new FakeTimeline(
new TimelineWindowDefinition(/* periodCount= */ 1, /* id= */ new Object()));
Timeline secondTimeline =
new FakeTimeline(
new TimelineWindowDefinition(/* periodCount= */ 1, /* id= */ new Object()));
MediaSource secondSource = new FakeMediaSource(secondTimeline, /* manifest= */ null);
AtomicLong positionAfterReprepare = new AtomicLong();
ActionSchedule actionSchedule =
new ActionSchedule.Builder("testReprepareAndKeepPositionWithNewMediaSource")
.pause()
.waitForPlaybackState(Player.STATE_READY)
.playUntilPosition(/* windowIndex= */ 0, /* positionMs= */ 2000)
.prepareSource(secondSource, /* resetPosition= */ false, /* resetState= */ true)
.waitForTimelineChanged(secondTimeline)
.executeRunnable(
new PlayerRunnable() {
@Override
public void run(SimpleExoPlayer player) {
positionAfterReprepare.set(player.getCurrentPosition());
}
})
.play()
.build();
ExoPlayerTestRunner testRunner =
new ExoPlayerTestRunner.Builder()
.setTimeline(timeline)
.setActionSchedule(actionSchedule)
.build(context)
.start()
.blockUntilActionScheduleFinished(TIMEOUT_MS)
.blockUntilEnded(TIMEOUT_MS);
testRunner.assertTimelinesEqual(timeline, Timeline.EMPTY, secondTimeline);
assertThat(positionAfterReprepare.get()).isAtLeast(2000L);
}
@Test @Test
public void testStopDuringPreparationOverwritesPreparation() throws Exception { public void testStopDuringPreparationOverwritesPreparation() throws Exception {
Timeline timeline = new FakeTimeline(/* windowCount= */ 1); Timeline timeline = new FakeTimeline(/* windowCount= */ 1);