From 494510d6adca2ac658ed96392ab0a6f397794682 Mon Sep 17 00:00:00 2001 From: olly Date: Thu, 23 Jun 2016 09:27:20 -0700 Subject: [PATCH] Fix ready and ended conditions. 1. The readiness of the timeline is only relevant if there aren't any enabled renderers. It's also only ready if the source after the playing source is actually prepared (if not, we're waiting for preparation). 2. Prevent early transition to the ENDED state when the playback position hits the duration, but we're not at the final entry in the playlist. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=125685193 --- .../exoplayer/ExoPlayerImplInternal.java | 48 ++++++++++++------- 1 file changed, 32 insertions(+), 16 deletions(-) diff --git a/library/src/main/java/com/google/android/exoplayer/ExoPlayerImplInternal.java b/library/src/main/java/com/google/android/exoplayer/ExoPlayerImplInternal.java index c3c414097f..50281cdef4 100644 --- a/library/src/main/java/com/google/android/exoplayer/ExoPlayerImplInternal.java +++ b/library/src/main/java/com/google/android/exoplayer/ExoPlayerImplInternal.java @@ -397,21 +397,27 @@ import java.util.ArrayList; allRenderersReadyOrEnded = allRenderersReadyOrEnded && rendererReadyOrEnded; } - boolean timelineIsReady = timeline.isReady(); + // TODO: Have timeline.updateSources() above return whether the timeline is ready, and remove + // timeline.isReady(). This will avoid any inconsistencies that could arise due to the playback + // position update. We could probably return [ENDED|READY|BUFFERING] and get rid of isEnded too. if (allRenderersEnded && (playbackInfo.durationUs == C.UNSET_TIME_US - || playbackInfo.durationUs <= playbackInfo.positionUs)) { + || playbackInfo.durationUs <= playbackInfo.positionUs) && timeline.isEnded()) { setState(ExoPlayer.STATE_ENDED); stopRenderers(); - } else if (state == ExoPlayer.STATE_BUFFERING && allRenderersReadyOrEnded - && haveSufficientBuffer() && timelineIsReady) { - setState(ExoPlayer.STATE_READY); - if (playWhenReady) { - startRenderers(); + } else if (state == ExoPlayer.STATE_BUFFERING) { + if ((enabledRenderers.length > 0 ? allRenderersReadyOrEnded : timeline.isReady()) + && haveSufficientBuffer()) { + setState(ExoPlayer.STATE_READY); + if (playWhenReady) { + startRenderers(); + } + } + } else if (state == ExoPlayer.STATE_READY) { + if (enabledRenderers.length > 0 ? !allRenderersReadyOrEnded : !timeline.isReady()) { + rebuffering = playWhenReady; + setState(ExoPlayer.STATE_BUFFERING); + stopRenderers(); } - } else if (state == ExoPlayer.STATE_READY && (!allRenderersReadyOrEnded || !timelineIsReady)) { - rebuffering = playWhenReady; - setState(ExoPlayer.STATE_BUFFERING); - stopRenderers(); } handler.removeMessages(MSG_DO_SOME_WORK); @@ -576,6 +582,21 @@ import java.util.ArrayList; return playingSource == null ? null : playingSource.sampleSource; } + public boolean isEnded() { + if (playingSource == null) { + return false; + } + int sourceCount = sampleSourceProvider.getSourceCount(); + return sourceCount != SampleSourceProvider.UNKNOWN_SOURCE_COUNT + && playingSource.index == sourceCount - 1; + } + + public boolean isReady() { + return playingSourceEndPositionUs == C.UNSET_TIME_US + || internalPositionUs < playingSourceEndPositionUs + || (playingSource.nextSource != null && playingSource.nextSource.prepared); + } + public void updateSources() throws ExoPlaybackException, IOException { // TODO[playlists]: Let sample source providers invalidate sources that are already buffering. @@ -680,11 +701,6 @@ import java.util.ArrayList; } } - public boolean isReady() { - return playingSourceEndPositionUs == C.UNSET_TIME_US - || internalPositionUs < playingSourceEndPositionUs || playingSource.nextSource != null; - } - public void seekToSource(int sourceIndex) throws ExoPlaybackException { // Clear the timeline, but keep the requested source if it is already prepared. Source source = playingSource;