Commit 652c2f9c by tonihei Committed by Toni

Advance playing period even if the next one isn't prepared yet.

This solves various issues around event association for buffering and
error throwing around period discontinuities.

The main changes are:
 - Logic around being "ready" at the end of a period no longer checks if the
   next period is prepared.
 - Advancing the playing period no longer checks if the next one is prepared.
 - Prepare errors are always thrown for the playing period.

This changes the semantics and assumptions about the "playing" period:
 1. The playing period can no longer assumed to be prepared.
 2. We no longer have a case where the queue is non-empty and the playing or
    reading periods are unassigned (=null).
Most other code changes ensure that these changed assumptions are handled.

Issue:#5407
PiperOrigin-RevId: 263776304
parent 14f77cb8
......@@ -38,6 +38,8 @@
`ExoPlayer.Builder`.
* Inject `DrmSessionManager` into the `MediaSources` instead of `Renderers`
([#5619](https://github.com/google/ExoPlayer/issues/5619)).
* Fix issue where player errors are thrown too early at playlist transitions
([#5407](https://github.com/google/ExoPlayer/issues/5407)).
### 2.10.4 ###
......
......@@ -83,8 +83,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
private static final int MSG_SEND_MESSAGE_TO_TARGET_THREAD = 16;
private static final int MSG_PLAYBACK_PARAMETERS_CHANGED_INTERNAL = 17;
private static final int PREPARING_SOURCE_INTERVAL_MS = 10;
private static final int RENDERING_INTERVAL_MS = 10;
private static final int ACTIVE_INTERVAL_MS = 10;
private static final int IDLE_INTERVAL_MS = 1000;
private final Renderer[] renderers;
......@@ -514,22 +513,25 @@ import java.util.concurrent.atomic.AtomicBoolean;
}
private void updatePlaybackPositions() throws ExoPlaybackException {
if (!queue.hasPlayingPeriod()) {
MediaPeriodHolder playingPeriodHolder = queue.getPlayingPeriod();
if (playingPeriodHolder == null) {
return;
}
// Update the playback position.
MediaPeriodHolder playingPeriodHolder = queue.getPlayingPeriod();
long periodPositionUs = playingPeriodHolder.mediaPeriod.readDiscontinuity();
if (periodPositionUs != C.TIME_UNSET) {
resetRendererPosition(periodPositionUs);
long discontinuityPositionUs =
playingPeriodHolder.prepared
? playingPeriodHolder.mediaPeriod.readDiscontinuity()
: C.TIME_UNSET;
if (discontinuityPositionUs != C.TIME_UNSET) {
resetRendererPosition(discontinuityPositionUs);
// A MediaPeriod may report a discontinuity at the current playback position to ensure the
// renderers are flushed. Only report the discontinuity externally if the position changed.
if (periodPositionUs != playbackInfo.positionUs) {
if (discontinuityPositionUs != playbackInfo.positionUs) {
playbackInfo =
playbackInfo.copyWithNewPosition(
playbackInfo.periodId,
periodPositionUs,
discontinuityPositionUs,
playbackInfo.contentPositionUs,
getTotalBufferedDurationUs());
playbackInfoUpdate.setPositionDiscontinuity(Player.DISCONTINUITY_REASON_INTERNAL);
......@@ -538,7 +540,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
rendererPositionUs =
mediaClock.syncAndGetPositionUs(
/* isReadingAhead= */ playingPeriodHolder != queue.getReadingPeriod());
periodPositionUs = playingPeriodHolder.toPeriodTime(rendererPositionUs);
long periodPositionUs = playingPeriodHolder.toPeriodTime(rendererPositionUs);
maybeTriggerPendingMessages(playbackInfo.positionUs, periodPositionUs);
playbackInfo.positionUs = periodPositionUs;
}
......@@ -552,60 +554,71 @@ import java.util.concurrent.atomic.AtomicBoolean;
private void doSomeWork() throws ExoPlaybackException, IOException {
long operationStartTimeMs = clock.uptimeMillis();
updatePeriods();
if (!queue.hasPlayingPeriod()) {
// We're still waiting for the first period to be prepared.
maybeThrowPeriodPrepareError();
scheduleNextWork(operationStartTimeMs, PREPARING_SOURCE_INTERVAL_MS);
MediaPeriodHolder playingPeriodHolder = queue.getPlayingPeriod();
if (playingPeriodHolder == null) {
// We're still waiting until the playing period is available.
scheduleNextWork(operationStartTimeMs, ACTIVE_INTERVAL_MS);
return;
}
MediaPeriodHolder playingPeriodHolder = queue.getPlayingPeriod();
TraceUtil.beginSection("doSomeWork");
updatePlaybackPositions();
long rendererPositionElapsedRealtimeUs = SystemClock.elapsedRealtime() * 1000;
playingPeriodHolder.mediaPeriod.discardBuffer(playbackInfo.positionUs - backBufferDurationUs,
retainBackBufferFromKeyframe);
boolean renderersEnded = true;
boolean renderersReadyOrEnded = true;
for (Renderer renderer : enabledRenderers) {
// TODO: Each renderer should return the maximum delay before which it wishes to be called
// again. The minimum of these values should then be used as the delay before the next
// invocation of this method.
renderer.render(rendererPositionUs, rendererPositionElapsedRealtimeUs);
renderersEnded = renderersEnded && renderer.isEnded();
// Determine whether the renderer is ready (or ended). We override to assume the renderer is
// ready if it needs the next sample stream. This is necessary to avoid getting stuck if
// tracks in the current period have uneven durations. See:
// https://github.com/google/ExoPlayer/issues/1874
boolean rendererReadyOrEnded = renderer.isReady() || renderer.isEnded()
|| rendererWaitingForNextStream(renderer);
if (!rendererReadyOrEnded) {
renderer.maybeThrowStreamError();
boolean renderersAllowPlayback = true;
if (playingPeriodHolder.prepared) {
long rendererPositionElapsedRealtimeUs = SystemClock.elapsedRealtime() * 1000;
playingPeriodHolder.mediaPeriod.discardBuffer(
playbackInfo.positionUs - backBufferDurationUs, retainBackBufferFromKeyframe);
for (int i = 0; i < renderers.length; i++) {
Renderer renderer = renderers[i];
if (renderer.getState() == Renderer.STATE_DISABLED) {
continue;
}
// TODO: Each renderer should return the maximum delay before which it wishes to be called
// again. The minimum of these values should then be used as the delay before the next
// invocation of this method.
renderer.render(rendererPositionUs, rendererPositionElapsedRealtimeUs);
renderersEnded = renderersEnded && renderer.isEnded();
// Determine whether the renderer allows playback to continue. Playback can continue if the
// renderer is ready or ended. Also continue playback if the renderer is reading ahead into
// the next stream or is waiting for the next stream. This is to avoid getting stuck if
// 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 allowsPlayback =
isReadingAhead || isWaitingForNextStream || renderer.isReady() || renderer.isEnded();
renderersAllowPlayback = renderersAllowPlayback && allowsPlayback;
if (!allowsPlayback) {
renderer.maybeThrowStreamError();
}
}
renderersReadyOrEnded = renderersReadyOrEnded && rendererReadyOrEnded;
}
if (!renderersReadyOrEnded) {
maybeThrowPeriodPrepareError();
} else {
playingPeriodHolder.mediaPeriod.maybeThrowPrepareError();
}
long playingPeriodDurationUs = playingPeriodHolder.info.durationUs;
if (renderersEnded
&& playingPeriodHolder.prepared
&& (playingPeriodDurationUs == C.TIME_UNSET
|| playingPeriodDurationUs <= playbackInfo.positionUs)
&& playingPeriodHolder.info.isFinal) {
setState(Player.STATE_ENDED);
stopRenderers();
} else if (playbackInfo.playbackState == Player.STATE_BUFFERING
&& shouldTransitionToReadyState(renderersReadyOrEnded)) {
&& shouldTransitionToReadyState(renderersAllowPlayback)) {
setState(Player.STATE_READY);
if (playWhenReady) {
startRenderers();
}
} else if (playbackInfo.playbackState == Player.STATE_READY
&& !(enabledRenderers.length == 0 ? isTimelineReady() : renderersReadyOrEnded)) {
&& !(enabledRenderers.length == 0 ? isTimelineReady() : renderersAllowPlayback)) {
rebuffering = playWhenReady;
setState(Player.STATE_BUFFERING);
stopRenderers();
......@@ -619,7 +632,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
if ((playWhenReady && playbackInfo.playbackState == Player.STATE_READY)
|| playbackInfo.playbackState == Player.STATE_BUFFERING) {
scheduleNextWork(operationStartTimeMs, RENDERING_INTERVAL_MS);
scheduleNextWork(operationStartTimeMs, ACTIVE_INTERVAL_MS);
} else if (enabledRenderers.length != 0 && playbackInfo.playbackState != Player.STATE_ENDED) {
scheduleNextWork(operationStartTimeMs, IDLE_INTERVAL_MS);
} else {
......@@ -681,7 +694,9 @@ import java.util.concurrent.atomic.AtomicBoolean;
long newPeriodPositionUs = periodPositionUs;
if (periodId.equals(playbackInfo.periodId)) {
MediaPeriodHolder playingPeriodHolder = queue.getPlayingPeriod();
if (playingPeriodHolder != null && newPeriodPositionUs != 0) {
if (playingPeriodHolder != null
&& playingPeriodHolder.prepared
&& newPeriodPositionUs != 0) {
newPeriodPositionUs =
playingPeriodHolder.mediaPeriod.getAdjustedSeekPositionUs(
newPeriodPositionUs, seekParameters);
......@@ -771,10 +786,11 @@ import java.util.concurrent.atomic.AtomicBoolean;
}
private void resetRendererPosition(long periodPositionUs) throws ExoPlaybackException {
MediaPeriodHolder playingMediaPeriod = queue.getPlayingPeriod();
rendererPositionUs =
!queue.hasPlayingPeriod()
playingMediaPeriod == null
? periodPositionUs
: queue.getPlayingPeriod().toRendererTime(periodPositionUs);
: playingMediaPeriod.toRendererTime(periodPositionUs);
mediaClock.resetPosition(rendererPositionUs);
for (Renderer renderer : enabledRenderers) {
renderer.resetPosition(rendererPositionUs);
......@@ -1092,10 +1108,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
}
private void reselectTracksInternal() throws ExoPlaybackException {
if (!queue.hasPlayingPeriod()) {
// We don't have tracks yet, so we don't care.
return;
}
float playbackSpeed = mediaClock.getPlaybackParameters().speed;
// Reselect tracks on each period in turn, until the selection changes.
MediaPeriodHolder periodHolder = queue.getPlayingPeriod();
......@@ -1182,8 +1194,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
}
private void updateTrackSelectionPlaybackSpeed(float playbackSpeed) {
MediaPeriodHolder periodHolder = queue.getFrontPeriod();
while (periodHolder != null && periodHolder.prepared) {
MediaPeriodHolder periodHolder = queue.getPlayingPeriod();
while (periodHolder != null) {
TrackSelection[] trackSelections = periodHolder.getTrackSelectorResult().selections.getAll();
for (TrackSelection trackSelection : trackSelections) {
if (trackSelection != null) {
......@@ -1195,7 +1207,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
}
private void notifyTrackSelectionDiscontinuity() {
MediaPeriodHolder periodHolder = queue.getFrontPeriod();
MediaPeriodHolder periodHolder = queue.getPlayingPeriod();
while (periodHolder != null) {
TrackSelection[] trackSelections = periodHolder.getTrackSelectorResult().selections.getAll();
for (TrackSelection trackSelection : trackSelections) {
......@@ -1230,12 +1242,10 @@ import java.util.concurrent.atomic.AtomicBoolean;
private boolean isTimelineReady() {
MediaPeriodHolder playingPeriodHolder = queue.getPlayingPeriod();
MediaPeriodHolder nextPeriodHolder = playingPeriodHolder.getNext();
long playingPeriodDurationUs = playingPeriodHolder.info.durationUs;
return playingPeriodDurationUs == C.TIME_UNSET
|| playbackInfo.positionUs < playingPeriodDurationUs
|| (nextPeriodHolder != null
&& (nextPeriodHolder.prepared || nextPeriodHolder.info.id.isAd()));
return playingPeriodHolder.prepared
&& (playingPeriodDurationUs == C.TIME_UNSET
|| playbackInfo.positionUs < playingPeriodDurationUs);
}
private void maybeThrowSourceInfoRefreshError() throws IOException {
......@@ -1251,21 +1261,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
mediaSource.maybeThrowSourceInfoRefreshError();
}
private void maybeThrowPeriodPrepareError() throws IOException {
MediaPeriodHolder loadingPeriodHolder = queue.getLoadingPeriod();
MediaPeriodHolder readingPeriodHolder = queue.getReadingPeriod();
if (loadingPeriodHolder != null
&& !loadingPeriodHolder.prepared
&& (readingPeriodHolder == null || readingPeriodHolder.getNext() == loadingPeriodHolder)) {
for (Renderer renderer : enabledRenderers) {
if (!renderer.hasReadStreamToEnd()) {
return;
}
}
loadingPeriodHolder.mediaPeriod.maybeThrowPrepareError();
}
}
private void handleSourceInfoRefreshed(MediaSourceRefreshInfo sourceRefreshInfo)
throws ExoPlaybackException {
if (sourceRefreshInfo.source != mediaSource) {
......@@ -1335,7 +1330,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
}
} else {
// Something changed. Seek to new start position.
MediaPeriodHolder periodHolder = queue.getFrontPeriod();
MediaPeriodHolder periodHolder = queue.getPlayingPeriod();
if (periodHolder != null) {
// Update the new playing media period info if it already exists.
while (periodHolder.getNext() != null) {
......@@ -1361,6 +1356,9 @@ import java.util.concurrent.atomic.AtomicBoolean;
return 0;
}
long maxReadPositionUs = readingHolder.getRendererOffset();
if (!readingHolder.prepared) {
return maxReadPositionUs;
}
for (int i = 0; i < renderers.length; i++) {
if (renderers[i].getState() == Renderer.STATE_DISABLED
|| renderers[i].getStream() != readingHolder.sampleStreams[i]) {
......@@ -1494,23 +1492,26 @@ import java.util.concurrent.atomic.AtomicBoolean;
maybeUpdatePlayingPeriod();
}
private void maybeUpdateLoadingPeriod() throws IOException {
private void maybeUpdateLoadingPeriod() throws ExoPlaybackException, IOException {
queue.reevaluateBuffer(rendererPositionUs);
if (queue.shouldLoadNextMediaPeriod()) {
MediaPeriodInfo info = queue.getNextMediaPeriodInfo(rendererPositionUs, playbackInfo);
if (info == null) {
maybeThrowSourceInfoRefreshError();
} else {
MediaPeriod mediaPeriod =
queue.enqueueNextMediaPeriod(
MediaPeriodHolder mediaPeriodHolder =
queue.enqueueNextMediaPeriodHolder(
rendererCapabilities,
trackSelector,
loadControl.getAllocator(),
mediaSource,
info,
emptyTrackSelectorResult);
mediaPeriod.prepare(this, info.startPositionUs);
mediaPeriodHolder.mediaPeriod.prepare(this, info.startPositionUs);
setIsLoading(true);
if (queue.getPlayingPeriod() == mediaPeriodHolder) {
resetRendererPosition(mediaPeriodHolder.getStartPositionRendererTime());
}
handleLoadingMediaPeriodChanged(/* loadingTrackSelectionChanged= */ false);
}
}
......@@ -1522,7 +1523,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
}
}
private void maybeUpdateReadingPeriod() throws ExoPlaybackException, IOException {
private void maybeUpdateReadingPeriod() throws ExoPlaybackException {
MediaPeriodHolder readingPeriodHolder = queue.getReadingPeriod();
if (readingPeriodHolder == null) {
return;
......@@ -1552,7 +1553,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
if (!readingPeriodHolder.getNext().prepared) {
// The successor is not prepared yet.
maybeThrowPeriodPrepareError();
return;
}
......@@ -1607,6 +1607,11 @@ import java.util.concurrent.atomic.AtomicBoolean;
maybeNotifyPlaybackInfoChanged();
}
MediaPeriodHolder oldPlayingPeriodHolder = queue.getPlayingPeriod();
if (oldPlayingPeriodHolder == queue.getReadingPeriod()) {
// The reading period hasn't advanced yet, so we can't seamlessly replace the SampleStreams
// anymore and need to re-enable the renderers. Set all current streams final to do that.
setAllRendererStreamsFinal();
}
MediaPeriodHolder newPlayingPeriodHolder = queue.advancePlayingPeriod();
updatePlayingPeriodRenderers(oldPlayingPeriodHolder);
playbackInfo =
......@@ -1633,17 +1638,22 @@ import java.util.concurrent.atomic.AtomicBoolean;
if (playingPeriodHolder == null) {
return false;
}
MediaPeriodHolder nextPlayingPeriodHolder = playingPeriodHolder.getNext();
if (nextPlayingPeriodHolder == null) {
return false;
}
MediaPeriodHolder readingPeriodHolder = queue.getReadingPeriod();
if (playingPeriodHolder == readingPeriodHolder) {
if (playingPeriodHolder == readingPeriodHolder && !hasReadingPeriodFinishedReading()) {
return false;
}
MediaPeriodHolder nextPlayingPeriodHolder =
Assertions.checkNotNull(playingPeriodHolder.getNext());
return rendererPositionUs >= nextPlayingPeriodHolder.getStartPositionRendererTime();
}
private boolean hasReadingPeriodFinishedReading() {
MediaPeriodHolder readingPeriodHolder = queue.getReadingPeriod();
if (!readingPeriodHolder.prepared) {
return false;
}
for (int i = 0; i < renderers.length; i++) {
Renderer renderer = renderers[i];
SampleStream sampleStream = readingPeriodHolder.sampleStreams[i];
......@@ -1674,10 +1684,9 @@ import java.util.concurrent.atomic.AtomicBoolean;
mediaClock.getPlaybackParameters().speed, playbackInfo.timeline);
updateLoadControlTrackSelection(
loadingPeriodHolder.getTrackGroups(), loadingPeriodHolder.getTrackSelectorResult());
if (!queue.hasPlayingPeriod()) {
// This is the first prepared period, so start playing it.
MediaPeriodHolder playingPeriodHolder = queue.advancePlayingPeriod();
resetRendererPosition(playingPeriodHolder.info.startPositionUs);
if (loadingPeriodHolder == queue.getPlayingPeriod()) {
// This is the first prepared period, so update the position and the renderers.
resetRendererPosition(loadingPeriodHolder.info.startPositionUs);
updatePlayingPeriodRenderers(/* oldPlayingPeriodHolder= */ null);
}
maybeContinueLoading();
......@@ -1805,12 +1814,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
}
}
private boolean rendererWaitingForNextStream(Renderer renderer) {
MediaPeriodHolder readingPeriodHolder = queue.getReadingPeriod();
MediaPeriodHolder nextPeriodHolder = readingPeriodHolder.getNext();
return nextPeriodHolder != null && nextPeriodHolder.prepared && renderer.hasReadStreamToEnd();
}
private void handleLoadingMediaPeriodChanged(boolean loadingTrackSelectionChanged) {
MediaPeriodHolder loadingMediaPeriodHolder = queue.getLoadingPeriod();
MediaPeriodId loadingMediaPeriodId =
......
......@@ -128,8 +128,8 @@ import com.google.android.exoplayer2.util.Assertions;
}
/**
* Enqueues a new media period based on the specified information as the new loading media period,
* and returns it.
* Enqueues a new media period holder based on the specified information as the new loading media
* period, and returns it.
*
* @param rendererCapabilities The renderer capabilities.
* @param trackSelector The track selector.
......@@ -139,7 +139,7 @@ import com.google.android.exoplayer2.util.Assertions;
* @param emptyTrackSelectorResult A {@link TrackSelectorResult} with empty selections for each
* renderer.
*/
public MediaPeriod enqueueNextMediaPeriod(
public MediaPeriodHolder enqueueNextMediaPeriodHolder(
RendererCapabilities[] rendererCapabilities,
TrackSelector trackSelector,
Allocator allocator,
......@@ -162,13 +162,15 @@ import com.google.android.exoplayer2.util.Assertions;
info,
emptyTrackSelectorResult);
if (loading != null) {
Assertions.checkState(hasPlayingPeriod());
loading.setNext(newPeriodHolder);
} else {
playing = newPeriodHolder;
reading = newPeriodHolder;
}
oldFrontPeriodUid = null;
loading = newPeriodHolder;
length++;
return newPeriodHolder.mediaPeriod;
return newPeriodHolder;
}
/**
......@@ -182,37 +184,20 @@ import com.google.android.exoplayer2.util.Assertions;
/**
* Returns the playing period holder which is at the front of the queue, or null if the queue is
* empty or hasn't started playing.
* empty.
*/
@Nullable
public MediaPeriodHolder getPlayingPeriod() {
return playing;
}
/**
* Returns the reading period holder, or null if the queue is empty or the player hasn't started
* reading.
*/
/** Returns the reading period holder, or null if the queue is empty. */
@Nullable
public MediaPeriodHolder getReadingPeriod() {
return reading;
}
/**
* Returns the period holder in the front of the queue which is the playing period holder when
* playing, or null if the queue is empty.
*/
@Nullable
public MediaPeriodHolder getFrontPeriod() {
return hasPlayingPeriod() ? playing : loading;
}
/** Returns whether the reading and playing period holders are set. */
public boolean hasPlayingPeriod() {
return playing != null;
}
/**
* Continues reading from the next period holder in the queue.
*
* @return The updated reading period holder.
......@@ -225,29 +210,26 @@ import com.google.android.exoplayer2.util.Assertions;
/**
* Dequeues the playing period holder from the front of the queue and advances the playing period
* holder to be the next item in the queue. If the playing period holder is unset, set it to the
* item in the front of the queue.
* holder to be the next item in the queue.
*
* @return The updated playing period holder, or null if the queue is or becomes empty.
*/
@Nullable
public MediaPeriodHolder advancePlayingPeriod() {
if (playing != null) {
if (playing == reading) {
reading = playing.getNext();
}
playing.release();
length--;
if (length == 0) {
loading = null;
oldFrontPeriodUid = playing.uid;
oldFrontPeriodWindowSequenceNumber = playing.info.id.windowSequenceNumber;
}
playing = playing.getNext();
} else {
playing = loading;
reading = loading;
if (playing == null) {
return null;
}
if (playing == reading) {
reading = playing.getNext();
}
playing.release();
length--;
if (length == 0) {
loading = null;
oldFrontPeriodUid = playing.uid;
oldFrontPeriodWindowSequenceNumber = playing.info.id.windowSequenceNumber;
}
playing = playing.getNext();
return playing;
}
......@@ -283,7 +265,7 @@ import com.google.android.exoplayer2.util.Assertions;
* of queue (typically the playing one) for later reuse.
*/
public void clear(boolean keepFrontPeriodUid) {
MediaPeriodHolder front = getFrontPeriod();
MediaPeriodHolder front = playing;
if (front != null) {
oldFrontPeriodUid = keepFrontPeriodUid ? front.uid : null;
oldFrontPeriodWindowSequenceNumber = front.info.id.windowSequenceNumber;
......@@ -315,7 +297,7 @@ import com.google.android.exoplayer2.util.Assertions;
// is set, once all cases handled by ExoPlayerImplInternal.handleSourceInfoRefreshed can be
// handled here.
MediaPeriodHolder previousPeriodHolder = null;
MediaPeriodHolder periodHolder = getFrontPeriod();
MediaPeriodHolder periodHolder = playing;
while (periodHolder != null) {
MediaPeriodInfo oldPeriodInfo = periodHolder.info;
......@@ -451,7 +433,7 @@ import com.google.android.exoplayer2.util.Assertions;
}
}
}
MediaPeriodHolder mediaPeriodHolder = getFrontPeriod();
MediaPeriodHolder mediaPeriodHolder = playing;
while (mediaPeriodHolder != null) {
if (mediaPeriodHolder.uid.equals(periodUid)) {
// Reuse window sequence number of first exact period match.
......@@ -459,7 +441,7 @@ import com.google.android.exoplayer2.util.Assertions;
}
mediaPeriodHolder = mediaPeriodHolder.getNext();
}
mediaPeriodHolder = getFrontPeriod();
mediaPeriodHolder = playing;
while (mediaPeriodHolder != null) {
int indexOfHolderInTimeline = timeline.getIndexOfPeriod(mediaPeriodHolder.uid);
if (indexOfHolderInTimeline != C.INDEX_UNSET) {
......@@ -496,7 +478,7 @@ import com.google.android.exoplayer2.util.Assertions;
*/
private boolean updateForPlaybackModeChange() {
// Find the last existing period holder that matches the new period order.
MediaPeriodHolder lastValidPeriodHolder = getFrontPeriod();
MediaPeriodHolder lastValidPeriodHolder = playing;
if (lastValidPeriodHolder == null) {
return true;
}
......@@ -529,7 +511,7 @@ import com.google.android.exoplayer2.util.Assertions;
lastValidPeriodHolder.info = getUpdatedMediaPeriodInfo(lastValidPeriodHolder.info);
// If renderers may have read from a period that's been removed, it is necessary to restart.
return !readingPeriodRemoved || !hasPlayingPeriod();
return !readingPeriodRemoved;
}
/**
......
......@@ -370,7 +370,9 @@ public final class MediaPeriodQueueTest {
private void advance() {
enqueueNext();
advancePlaying();
if (mediaPeriodQueue.getLoadingPeriod() != mediaPeriodQueue.getPlayingPeriod()) {
advancePlaying();
}
}
private void advancePlaying() {
......@@ -382,7 +384,7 @@ public final class MediaPeriodQueueTest {
}
private void enqueueNext() {
mediaPeriodQueue.enqueueNextMediaPeriod(
mediaPeriodQueue.enqueueNextMediaPeriodHolder(
rendererCapabilities,
trackSelector,
allocator,
......@@ -460,7 +462,7 @@ public final class MediaPeriodQueueTest {
private int getQueueLength() {
int length = 0;
MediaPeriodHolder periodHolder = mediaPeriodQueue.getFrontPeriod();
MediaPeriodHolder periodHolder = mediaPeriodQueue.getPlayingPeriod();
while (periodHolder != null) {
length++;
periodHolder = periodHolder.getNext();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment