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)
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()) {
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);
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;
}

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
* 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.
*/