Commit 99957bba by olly Committed by Oliver Woodman

Correctly handle dynamic playlist modifications

- Fix bug where we'd try and call replaceStream having already
  notified the renderer that the current stream is final. This
  could occur if a period was added to the end of the playlist.
- If the current period being played is removed and a new period
  to play cannot be resolved, assume we've gone off the end of
  the playlist and transition to the ended state. This allows
  the current source to be re-used (unlike the previous behavior
  of considering it an error). Treat valid seeks that cannot be
  resolved due to concurrent timeline update similarly.
- Add seek sanity check back to ExoPlayerImpl. Meh. It's probably
  best to keep this, since it stops the exposed window index
  being invalid w.r.t the exposed timeline.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=141167151
parent 9ea8b020
...@@ -107,11 +107,16 @@ public abstract class BaseRenderer implements Renderer, RendererCapabilities { ...@@ -107,11 +107,16 @@ public abstract class BaseRenderer implements Renderer, RendererCapabilities {
} }
@Override @Override
public final void setCurrentStreamIsFinal() { public final void setCurrentStreamFinal() {
streamIsFinal = true; streamIsFinal = true;
} }
@Override @Override
public final boolean isCurrentStreamFinal() {
return streamIsFinal;
}
@Override
public final void maybeThrowStreamError() throws IOException { public final void maybeThrowStreamError() throws IOException {
stream.maybeThrowError(); stream.maybeThrowError();
} }
...@@ -243,7 +248,7 @@ public abstract class BaseRenderer implements Renderer, RendererCapabilities { ...@@ -243,7 +248,7 @@ public abstract class BaseRenderer implements Renderer, RendererCapabilities {
/** /**
* Reads from the enabled upstream source. If the upstream source has been read to the end then * Reads from the enabled upstream source. If the upstream source has been read to the end then
* {@link C#RESULT_BUFFER_READ} is only returned if {@link #setCurrentStreamIsFinal()} has been * {@link C#RESULT_BUFFER_READ} is only returned if {@link #setCurrentStreamFinal()} has been
* called. {@link C#RESULT_NOTHING_READ} is returned otherwise. * called. {@link C#RESULT_NOTHING_READ} is returned otherwise.
* *
* @see SampleStream#readData(FormatHolder, DecoderInputBuffer) * @see SampleStream#readData(FormatHolder, DecoderInputBuffer)
......
...@@ -179,6 +179,9 @@ import java.util.concurrent.CopyOnWriteArraySet; ...@@ -179,6 +179,9 @@ import java.util.concurrent.CopyOnWriteArraySet;
@Override @Override
public void seekTo(int windowIndex, long positionMs) { public void seekTo(int windowIndex, long positionMs) {
if (windowIndex < 0 || (!timeline.isEmpty() && windowIndex >= timeline.getWindowCount())) {
throw new IllegalSeekPositionException(timeline, windowIndex, positionMs);
}
pendingSeekAcks++; pendingSeekAcks++;
maskingWindowIndex = windowIndex; maskingWindowIndex = windowIndex;
if (positionMs == C.TIME_UNSET) { if (positionMs == C.TIME_UNSET) {
......
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.exoplayer2;
/**
* Thrown when an attempt is made to seek to a position that does not exist in the player's
* {@link Timeline}.
*/
public final class IllegalSeekPositionException extends IllegalStateException {
/**
* The {@link Timeline} in which the seek was attempted.
*/
public final Timeline timeline;
/**
* The index of the window being seeked to.
*/
public final int windowIndex;
/**
* The seek position in the specified window.
*/
public final long positionMs;
/**
* @param timeline The {@link Timeline} in which the seek was attempted.
* @param windowIndex The index of the window being seeked to.
* @param positionMs The seek position in the specified window.
*/
public IllegalSeekPositionException(Timeline timeline, int windowIndex, long positionMs) {
this.timeline = timeline;
this.windowIndex = windowIndex;
this.positionMs = positionMs;
}
}
...@@ -149,7 +149,13 @@ public interface Renderer extends ExoPlayerComponent { ...@@ -149,7 +149,13 @@ public interface Renderer extends ExoPlayerComponent {
* This method may be called when the renderer is in the following states: * This method may be called when the renderer is in the following states:
* {@link #STATE_ENABLED}, {@link #STATE_STARTED}. * {@link #STATE_ENABLED}, {@link #STATE_STARTED}.
*/ */
void setCurrentStreamIsFinal(); void setCurrentStreamFinal();
/**
* Returns whether the current {@link SampleStream} will be the final one supplied before the
* renderer is next disabled or reset.
*/
boolean isCurrentStreamFinal();
/** /**
* Throws an error that's preventing the renderer from reading from its {@link SampleStream}. Does * Throws an error that's preventing the renderer from reading from its {@link SampleStream}. Does
......
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