diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/ExoPlayerTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/ExoPlayerTest.java index a227aa3575..40b4b2d383 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/ExoPlayerTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/ExoPlayerTest.java @@ -35,6 +35,7 @@ import com.google.android.exoplayer2.testutil.FakeTrackSelection; import com.google.android.exoplayer2.testutil.FakeTrackSelector; import com.google.android.exoplayer2.upstream.Allocator; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.concurrent.CountDownLatch; import junit.framework.TestCase; @@ -111,6 +112,29 @@ public final class ExoPlayerTest extends TestCase { assertTrue(renderer.isEnded); } + /** Tests playback of periods with very short duration. */ + public void testPlayShortDurationPeriods() throws Exception { + // TimelineWindowDefinition.DEFAULT_WINDOW_DURATION_US / 100 = 1000 us per period. + Timeline timeline = + new FakeTimeline(new TimelineWindowDefinition(/* periodCount= */ 100, /* id= */ 0)); + FakeRenderer renderer = new FakeRenderer(Builder.VIDEO_FORMAT); + ExoPlayerTestRunner testRunner = + new ExoPlayerTestRunner.Builder() + .setTimeline(timeline) + .setRenderers(renderer) + .build() + .start() + .blockUntilEnded(TIMEOUT_MS); + int[] expectedReasons = new int[99]; + Arrays.fill(expectedReasons, Player.DISCONTINUITY_REASON_PERIOD_TRANSITION); + testRunner.assertPositionDiscontinuityReasonsEqual(expectedReasons); + testRunner.assertTimelinesEqual(timeline); + testRunner.assertTimelineChangeReasonsEqual(Player.TIMELINE_CHANGE_REASON_PREPARED); + assertEquals(100, renderer.formatReadCount); + assertEquals(1, renderer.bufferReadCount); + assertTrue(renderer.isEnded); + } + /** * Tests that the player does not unnecessarily reset renderers when playing a multi-period * source. 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 c34e947046..7b52f79be5 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 @@ -1303,16 +1303,22 @@ import java.io.IOException; } // Advance the playing period if necessary. + boolean advancedPlayingPeriod = false; while (playWhenReady && playingPeriodHolder != readingPeriodHolder && rendererPositionUs >= playingPeriodHolder.next.rendererPositionOffsetUs) { // All enabled renderers' streams have been read to the end, and the playback position reached // the end of the playing period, so advance playback to the next period. + if (advancedPlayingPeriod) { + // If we advance more than one period at a time, notify listeners after each update. + maybeNotifyPlaybackInfoChanged(); + } playingPeriodHolder.release(); setPlayingPeriodHolder(playingPeriodHolder.next); playbackInfo = playbackInfo.fromNewPosition(playingPeriodHolder.info.id, playingPeriodHolder.info.startPositionUs, playingPeriodHolder.info.contentPositionUs); playbackInfoUpdate.setPositionDiscontinuity(Player.DISCONTINUITY_REASON_PERIOD_TRANSITION); updatePlaybackPositions(); + advancedPlayingPeriod = true; } if (readingPeriodHolder.info.isFinal) {