From 25e31743d3f4221d60a7c00c1e61e1f7f7ec8d92 Mon Sep 17 00:00:00 2001 From: tonihei Date: Tue, 22 Sep 2020 12:23:24 +0100 Subject: [PATCH] Don't require the existence of the next period to wait for its stream. We have a workaround for uneven sample stream durarions in playlists that assumes a renderer allows playback if it's reading ahead or waiting for the next stream. https://github.com/google/ExoPlayer/commit/652c2f9c188bf9d9d6e323ff5333e5026454a082 changed this logic to no longer require to wait until the next stream is prepared due to a change in how we advance media periods in the queue. However, the code falsely still requires the next stream to exist (even if it's not prepared). This can cause a stuck buffering state when the difference in the duration of the streams is more than what we buffer ahead because we never create the next stream in such a case. Note: DefaultMediaClock.shouldUseStandaloneClock has roughly the same logic and also doesn't require the next stream to be present. Also fix a test that seemed to rely on this stuck buffering case to test stuck buffering detection. Changed the test to not read the end of stream to ensure it runs into the desired stuck buffering case. Issue:#7943 PiperOrigin-RevId: 333050285 --- RELEASENOTES.md | 4 ++++ .../android/exoplayer2/ExoPlayerImplInternal.java | 5 +---- .../google/android/exoplayer2/ExoPlayerTest.java | 15 +++++++-------- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index ffdfc1c1e7..2bae8256fe 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -2,6 +2,10 @@ ### dev-v2 (not yet released) +* Core library: + * Fix bug where streams with highly uneven durations may get stuck in a + buffering state + ([#7943](https://github.com/google/ExoPlayer/issues/7943)). * Track selection: * Add option to specify multiple preferred audio or text languages. * Data sources: 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 9739680e79..e33b93ac0e 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 @@ -897,10 +897,7 @@ import java.util.concurrent.atomic.AtomicBoolean; // tracks in the current period have uneven durations and are still being read by another // renderer. See: https://github.com/google/ExoPlayer/issues/1874. boolean isReadingAhead = playingPeriodHolder.sampleStreams[i] != renderer.getStream(); - boolean isWaitingForNextStream = - !isReadingAhead - && playingPeriodHolder.getNext() != null - && renderer.hasReadStreamToEnd(); + boolean isWaitingForNextStream = !isReadingAhead && renderer.hasReadStreamToEnd(); boolean allowsPlayback = isReadingAhead || isWaitingForNextStream || renderer.isReady() || renderer.isEnded(); renderersAllowPlayback = renderersAllowPlayback && allowsPlayback; 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 444640256f..7934298df0 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 @@ -7334,6 +7334,8 @@ public final class ExoPlayerTest { new DefaultLoadControl.Builder() .setTargetBufferBytes(10 * C.DEFAULT_BUFFER_SEGMENT_SIZE) .build(); + // Return no end of stream signal to prevent playback from ending. + FakeMediaPeriod.TrackDataFactory trackDataWithoutEos = (format, periodId) -> ImmutableList.of(); MediaSource continuouslyAllocatingMediaSource = new FakeMediaSource( new FakeTimeline(/* windowCount= */ 1), ExoPlayerTestRunner.VIDEO_FORMAT) { @@ -7348,8 +7350,11 @@ public final class ExoPlayerTest { @Nullable TransferListener transferListener) { return new FakeMediaPeriod( trackGroupArray, - TimelineWindowDefinition.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US, - mediaSourceEventDispatcher) { + trackDataWithoutEos, + mediaSourceEventDispatcher, + drmSessionManager, + drmEventDispatcher, + /* deferOnPrepared= */ false) { private final List allocations = new ArrayList<>(); @@ -7382,14 +7387,8 @@ public final class ExoPlayerTest { }; } }; - ActionSchedule actionSchedule = - new ActionSchedule.Builder(TAG) - // Prevent player from ever assuming it finished playing. - .setRepeatMode(Player.REPEAT_MODE_ALL) - .build(); ExoPlayerTestRunner testRunner = new ExoPlayerTestRunner.Builder(context) - .setActionSchedule(actionSchedule) .setMediaSources(continuouslyAllocatingMediaSource) .setLoadControl(loadControl) .build();