From 69e51505e46d56b8d2e565bb3b1e4198abc30f47 Mon Sep 17 00:00:00 2001 From: bachinger Date: Tue, 12 Nov 2019 15:32:57 +0000 Subject: [PATCH] use getPeriodByUid when searching for subsequent period of seek timeline Issue: #6641 PiperOrigin-RevId: 279963739 --- .../exoplayer2/ExoPlayerImplInternal.java | 6 +- .../android/exoplayer2/ExoPlayerTest.java | 66 ++++++++++++++++++- 2 files changed, 69 insertions(+), 3 deletions(-) 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 db5483be1da..4c25c180f43 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 @@ -1444,6 +1444,7 @@ private void handleSourceInfoRefreshEndedPlayback() { * @throws IllegalSeekPositionException If the window index of the seek position is outside the * bounds of the timeline. */ + @Nullable private Pair resolveSeekPosition( SeekPosition seekPosition, boolean trySubsequentPeriods) { Timeline timeline = playbackInfo.timeline; @@ -1479,11 +1480,12 @@ private Pair resolveSeekPosition( } if (trySubsequentPeriods) { // Try and find a subsequent period from the seek timeline in the internal timeline. + @Nullable Object periodUid = resolveSubsequentPeriod(periodPosition.first, seekTimeline, timeline); if (periodUid != null) { - // We found one. Map the SeekPosition onto the corresponding default position. + // We found one. Use the default position of the corresponding window. return getPeriodPosition( - timeline, timeline.getPeriod(periodIndex, period).windowIndex, C.TIME_UNSET); + timeline, timeline.getPeriodByUid(periodUid, period).windowIndex, C.TIME_UNSET); } } // We didn't find one. Give up. 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 0871d8efc3c..8bd6b1ba098 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 @@ -2168,6 +2168,70 @@ public void testRepeatedSeeksToUnpreparedPeriodInSameWindowKeepsWindowSequenceNu timeline.getUidOfPeriod(/* periodIndex= */ 1), /* windowSequenceNumber= */ 1)); } + @Test + public void testInvalidSeekFallsBackToSubsequentPeriodOfTheRemovedPeriod() throws Exception { + Timeline timeline = new FakeTimeline(/* windowCount= */ 1); + CountDownLatch sourceReleasedCountDownLatch = new CountDownLatch(/* count= */ 1); + MediaSource mediaSourceToRemove = + new FakeMediaSource(timeline) { + @Override + protected void releaseSourceInternal() { + super.releaseSourceInternal(); + sourceReleasedCountDownLatch.countDown(); + } + }; + ConcatenatingMediaSource mediaSource = + new ConcatenatingMediaSource(mediaSourceToRemove, new FakeMediaSource(timeline)); + final int[] windowCount = {C.INDEX_UNSET}; + final long[] position = {C.TIME_UNSET}; + ActionSchedule actionSchedule = + new ActionSchedule.Builder("testInvalidSeekFallsBackToSubsequentPeriodOfTheRemovedPeriod") + .pause() + .waitForTimelineChanged() + .executeRunnable( + new PlayerRunnable() { + @Override + public void run(SimpleExoPlayer player) { + mediaSource.removeMediaSource(/* index= */ 0); + try { + // Wait until the source to be removed is released on the playback thread. So + // the timeline in EPII has one window only, but the update here in EPI is + // stuck until we finished our executable here. So when seeking below, we will + // seek in the timeline which still has two windows in EPI, but when the seek + // arrives in EPII the actual timeline has one window only. Hence it tries to + // find the subsequent period of the removed period and finds it. + sourceReleasedCountDownLatch.await(); + } catch (InterruptedException e) { + throw new IllegalStateException(e); + } + player.seekTo(/* windowIndex= */ 0, /* positionMs= */ 1000L); + } + }) + .waitForSeekProcessed() + .executeRunnable( + new PlayerRunnable() { + @Override + public void run(SimpleExoPlayer player) { + windowCount[0] = player.getCurrentTimeline().getWindowCount(); + position[0] = player.getCurrentPosition(); + } + }) + .play() + .build(); + new ExoPlayerTestRunner.Builder() + .setMediaSource(mediaSource) + .setActionSchedule(actionSchedule) + .build(context) + .start() + .blockUntilActionScheduleFinished(TIMEOUT_MS) + .blockUntilEnded(TIMEOUT_MS); + + // Expect the first window to be the current. + assertThat(windowCount[0]).isEqualTo(1); + // Expect the position to be in the default position. + assertThat(position[0]).isEqualTo(0L); + } + @Test public void testRecursivePlayerChangesReportConsistentValuesForAllListeners() throws Exception { // We add two listeners to the player. The first stops the player as soon as it's ready and both @@ -2992,7 +3056,7 @@ public void testSeekTo_windowIndexIsReset() throws Exception { new PlayerRunnable() { @Override public void run(SimpleExoPlayer player) { - player.setMediaItem(mediaSource, /* positionMs= */ 5000); + player.setMediaItem(mediaSource, /* startPositionMs= */ 5000); player.prepare(); } })