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
This commit is contained in:
andrewlewis 2018-02-01 09:32:21 -08:00 committed by Andrew Lewis
parent a075b23893
commit 10033623e7
2 changed files with 67 additions and 65 deletions

View File

@ -416,54 +416,29 @@ import java.util.Collections;
private void setRepeatModeInternal(@Player.RepeatMode int repeatMode) private void setRepeatModeInternal(@Player.RepeatMode int repeatMode)
throws ExoPlaybackException { throws ExoPlaybackException {
this.repeatMode = repeatMode; this.repeatMode = repeatMode;
queue.setRepeatMode(repeatMode); if (!queue.updateRepeatMode(repeatMode)) {
validateExistingPeriodHolders(); seekToCurrentPosition(/* sendDiscontinuity= */ true);
}
} }
private void setShuffleModeEnabledInternal(boolean shuffleModeEnabled) private void setShuffleModeEnabledInternal(boolean shuffleModeEnabled)
throws ExoPlaybackException { throws ExoPlaybackException {
this.shuffleModeEnabled = shuffleModeEnabled; this.shuffleModeEnabled = shuffleModeEnabled;
queue.setShuffleModeEnabled(shuffleModeEnabled); if (!queue.updateShuffleModeEnabled(shuffleModeEnabled)) {
validateExistingPeriodHolders(); seekToCurrentPosition(/* sendDiscontinuity= */ true);
}
} }
private void validateExistingPeriodHolders() throws ExoPlaybackException { private void seekToCurrentPosition(boolean sendDiscontinuity) 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 // 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. // position of the playing period to make sure none of the removed period is played.
MediaPeriodId periodId = queue.getPlayingPeriod().info.id; MediaPeriodId periodId = queue.getPlayingPeriod().info.id;
long newPositionUs = long newPositionUs =
seekToPeriodPosition( seekToPeriodPosition(periodId, playbackInfo.positionUs, /* forceDisableRenderers= */ true);
periodId, playbackInfo.positionUs, /* forceDisableRenderers= */ true);
if (newPositionUs != playbackInfo.positionUs) { if (newPositionUs != playbackInfo.positionUs) {
playbackInfo = playbackInfo =
playbackInfo.fromNewPosition(periodId, newPositionUs, playbackInfo.contentPositionUs); playbackInfo.fromNewPosition(periodId, newPositionUs, playbackInfo.contentPositionUs);
if (sendDiscontinuity) {
playbackInfoUpdate.setPositionDiscontinuity(Player.DISCONTINUITY_REASON_INTERNAL); playbackInfoUpdate.setPositionDiscontinuity(Player.DISCONTINUITY_REASON_INTERNAL);
} }
} }
@ -1271,13 +1246,7 @@ import java.util.Collections;
// The holder is inconsistent with the new timeline. // The holder is inconsistent with the new timeline.
boolean readingPeriodRemoved = queue.removeAfter(previousPeriodHolder); boolean readingPeriodRemoved = queue.removeAfter(previousPeriodHolder);
if (readingPeriodRemoved) { if (readingPeriodRemoved) {
// Renderers may have read from a period that's been removed. Seek back to the current seekToCurrentPosition(/* sendDiscontinuity= */ false);
// 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);
} }
break; break;
} }

View File

@ -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 * 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. * the queue. Also has a reference to the media period currently being read.
*/ */
@SuppressWarnings("UngroupedOverloads")
/* package */ final class MediaPeriodQueue { /* 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 * Sets the {@link RepeatMode} and returns whether the repeat mode change has been fully handled.
* information taking into account the new repeat mode. * 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; this.repeatMode = repeatMode;
return updateForPlaybackModeChange();
} }
/** /**
* Sets whether shuffling is enabled. Call {@link #getUpdatedMediaPeriodInfo} to update period * Sets whether shuffling is enabled and returns whether the shuffle mode change has been fully
* information taking into account the shuffle mode. * 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; this.shuffleModeEnabled = shuffleModeEnabled;
return updateForPlaybackModeChange();
} }
/** Returns whether {@code mediaPeriod} is the current loading media period. */ /** Returns whether {@code mediaPeriod} is the current loading media period. */
@ -286,17 +289,6 @@ import com.google.android.exoplayer2.util.Assertions;
length = 0; 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 * 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}. * 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. // 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. * Returns the first {@link MediaPeriodInfo} to play, based on the specified playback position.
*/ */