From 10033623e78827ba4f29b87db289c7fadbc9b4c7 Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Thu, 1 Feb 2018 09:32:21 -0800 Subject: [PATCH] Handle repeat mode/shuffle mode changes in MediaPeriodQueue This should be a no-op change. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=184150266 --- .../exoplayer2/ExoPlayerImplInternal.java | 65 +++++------------- .../android/exoplayer2/MediaPeriodQueue.java | 67 ++++++++++++++----- 2 files changed, 67 insertions(+), 65 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 977620c5de..c6e0460d54 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 @@ -416,54 +416,29 @@ import java.util.Collections; private void setRepeatModeInternal(@Player.RepeatMode int repeatMode) throws ExoPlaybackException { this.repeatMode = repeatMode; - queue.setRepeatMode(repeatMode); - validateExistingPeriodHolders(); + if (!queue.updateRepeatMode(repeatMode)) { + seekToCurrentPosition(/* sendDiscontinuity= */ true); + } } private void setShuffleModeEnabledInternal(boolean shuffleModeEnabled) throws ExoPlaybackException { this.shuffleModeEnabled = shuffleModeEnabled; - queue.setShuffleModeEnabled(shuffleModeEnabled); - validateExistingPeriodHolders(); + if (!queue.updateShuffleModeEnabled(shuffleModeEnabled)) { + seekToCurrentPosition(/* sendDiscontinuity= */ true); + } } - private void validateExistingPeriodHolders() throws ExoPlaybackException { - // Find the last existing period holder that matches the new period order. - MediaPeriodHolder lastValidPeriodHolder = queue.getFrontPeriod(); - if (lastValidPeriodHolder == null) { - return; - } - while (true) { - int nextPeriodIndex = playbackInfo.timeline.getNextPeriodIndex( - lastValidPeriodHolder.info.id.periodIndex, period, window, repeatMode, - shuffleModeEnabled); - while (lastValidPeriodHolder.next != null - && !lastValidPeriodHolder.info.isLastInTimelinePeriod) { - lastValidPeriodHolder = lastValidPeriodHolder.next; - } - if (nextPeriodIndex == C.INDEX_UNSET || lastValidPeriodHolder.next == null - || lastValidPeriodHolder.next.info.id.periodIndex != nextPeriodIndex) { - break; - } - lastValidPeriodHolder = lastValidPeriodHolder.next; - } - - // Release any period holders that don't match the new period order. - boolean readingPeriodRemoved = queue.removeAfter(lastValidPeriodHolder); - - // Update the period info for the last holder, as it may now be the last period in the timeline. - lastValidPeriodHolder.info = queue.getUpdatedMediaPeriodInfo(lastValidPeriodHolder.info); - - if (readingPeriodRemoved && queue.hasPlayingPeriod()) { - // Renderers may have read from a period that's been removed. Seek back to the current - // position of the playing period to make sure none of the removed period is played. - MediaPeriodId periodId = queue.getPlayingPeriod().info.id; - long newPositionUs = - seekToPeriodPosition( - periodId, playbackInfo.positionUs, /* forceDisableRenderers= */ true); - if (newPositionUs != playbackInfo.positionUs) { - playbackInfo = - playbackInfo.fromNewPosition(periodId, newPositionUs, playbackInfo.contentPositionUs); + private void seekToCurrentPosition(boolean sendDiscontinuity) throws ExoPlaybackException { + // Renderers may have read from a period that's been removed. Seek back to the current + // position of the playing period to make sure none of the removed period is played. + MediaPeriodId periodId = queue.getPlayingPeriod().info.id; + long newPositionUs = + seekToPeriodPosition(periodId, playbackInfo.positionUs, /* forceDisableRenderers= */ true); + if (newPositionUs != playbackInfo.positionUs) { + playbackInfo = + playbackInfo.fromNewPosition(periodId, newPositionUs, playbackInfo.contentPositionUs); + if (sendDiscontinuity) { playbackInfoUpdate.setPositionDiscontinuity(Player.DISCONTINUITY_REASON_INTERNAL); } } @@ -1271,13 +1246,7 @@ import java.util.Collections; // The holder is inconsistent with the new timeline. boolean readingPeriodRemoved = queue.removeAfter(previousPeriodHolder); if (readingPeriodRemoved) { - // Renderers may have read from a period that's been removed. Seek back to the current - // position of the playing period to make sure none of the removed period is played. - MediaPeriodId id = queue.getPlayingPeriod().info.id; - long newPositionUs = - seekToPeriodPosition(id, playbackInfo.positionUs, /* forceDisableRenderers= */ true); - playbackInfo = - playbackInfo.fromNewPosition(id, newPositionUs, playbackInfo.contentPositionUs); + seekToCurrentPosition(/* sendDiscontinuity= */ false); } break; } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/MediaPeriodQueue.java b/library/core/src/main/java/com/google/android/exoplayer2/MediaPeriodQueue.java index 8bc93ae243..65048795e6 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/MediaPeriodQueue.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/MediaPeriodQueue.java @@ -31,6 +31,7 @@ import com.google.android.exoplayer2.util.Assertions; * loading media period at the end of the queue, with methods for controlling loading and updating * the queue. Also has a reference to the media period currently being read. */ +@SuppressWarnings("UngroupedOverloads") /* package */ final class MediaPeriodQueue { /** @@ -66,19 +67,21 @@ import com.google.android.exoplayer2.util.Assertions; } /** - * Sets the {@link RepeatMode}. Call {@link #getUpdatedMediaPeriodInfo} to update period - * information taking into account the new repeat mode. + * Sets the {@link RepeatMode} and returns whether the repeat mode change has been fully handled. + * If not, it is necessary to seek to the current playback position. */ - public void setRepeatMode(@RepeatMode int repeatMode) { + public boolean updateRepeatMode(@RepeatMode int repeatMode) { this.repeatMode = repeatMode; + return updateForPlaybackModeChange(); } /** - * Sets whether shuffling is enabled. Call {@link #getUpdatedMediaPeriodInfo} to update period - * information taking into account the shuffle mode. + * Sets whether shuffling is enabled and returns whether the shuffle mode change has been fully + * handled. If not, it is necessary to seek to the current playback position. */ - public void setShuffleModeEnabled(boolean shuffleModeEnabled) { + public boolean updateShuffleModeEnabled(boolean shuffleModeEnabled) { this.shuffleModeEnabled = shuffleModeEnabled; + return updateForPlaybackModeChange(); } /** Returns whether {@code mediaPeriod} is the current loading media period. */ @@ -286,17 +289,6 @@ import com.google.android.exoplayer2.util.Assertions; length = 0; } - /** - * Returns new media period info based on specified {@code mediaPeriodInfo} but taking into - * account the current timeline. - * - * @param mediaPeriodInfo Media period info for a media period based on an old timeline. - * @return The updated media period info for the current timeline. - */ - public MediaPeriodInfo getUpdatedMediaPeriodInfo(MediaPeriodInfo mediaPeriodInfo) { - return getUpdatedMediaPeriodInfo(mediaPeriodInfo, mediaPeriodInfo.id); - } - /** * Returns new media period info based on specified {@code mediaPeriodInfo} but taking into * account the current timeline, and with the period index updated to {@code newPeriodIndex}. @@ -333,6 +325,47 @@ import com.google.android.exoplayer2.util.Assertions; // Internal methods. + /** + * Updates the queue for any playback mode change, and returns whether the change was fully + * handled. If not, it is necessary to seek to the current playback position. + */ + private boolean updateForPlaybackModeChange() { + // Find the last existing period holder that matches the new period order. + MediaPeriodHolder lastValidPeriodHolder = getFrontPeriod(); + if (lastValidPeriodHolder == null) { + return true; + } + while (true) { + int nextPeriodIndex = + timeline.getNextPeriodIndex( + lastValidPeriodHolder.info.id.periodIndex, + period, + window, + repeatMode, + shuffleModeEnabled); + while (lastValidPeriodHolder.next != null + && !lastValidPeriodHolder.info.isLastInTimelinePeriod) { + lastValidPeriodHolder = lastValidPeriodHolder.next; + } + if (nextPeriodIndex == C.INDEX_UNSET + || lastValidPeriodHolder.next == null + || lastValidPeriodHolder.next.info.id.periodIndex != nextPeriodIndex) { + break; + } + lastValidPeriodHolder = lastValidPeriodHolder.next; + } + + // Release any period holders that don't match the new period order. + boolean readingPeriodRemoved = removeAfter(lastValidPeriodHolder); + + // Update the period info for the last holder, as it may now be the last period in the timeline. + lastValidPeriodHolder.info = + getUpdatedMediaPeriodInfo(lastValidPeriodHolder.info, lastValidPeriodHolder.info.id); + + // If renderers may have read from a period that's been removed, it is necessary to restart. + return !readingPeriodRemoved || !hasPlayingPeriod(); + } + /** * Returns the first {@link MediaPeriodInfo} to play, based on the specified playback position. */