diff --git a/library/src/main/java/com/google/android/exoplayer2/Timeline.java b/library/src/main/java/com/google/android/exoplayer2/Timeline.java
index 1cc2773ad5..e0ac0d2b2b 100644
--- a/library/src/main/java/com/google/android/exoplayer2/Timeline.java
+++ b/library/src/main/java/com/google/android/exoplayer2/Timeline.java
@@ -62,13 +62,7 @@ public interface Timeline {
/**
* Returns a unique identifier for the period at {@code periodIndex}, or {@code null} if the
* period at {@code periodIndex} is not known. The identifier is stable across {@link Timeline}
- * instances.
- *
- * When the timeline changes the player uses period identifiers to determine what periods are
- * unchanged. Implementations that associate an object with each period can return the object for
- * the provided index to guarantee uniqueness. Other implementations must be careful to return
- * identifiers that can't clash with (for example) identifiers used by other timelines that may be
- * concatenated with this one.
+ * changes.
*
* @param periodIndex A period index.
* @return An identifier for the period, or {@code null} if the period is not known.
@@ -79,7 +73,7 @@ public interface Timeline {
* Returns the index of the window to which the period with the specified index belongs.
*
* @param periodIndex The period index.
- * @return The index of the corresponding seek window.
+ * @return The index of the corresponding window.
*/
int getPeriodWindowIndex(int periodIndex);
diff --git a/library/src/main/java/com/google/android/exoplayer2/source/ConcatenatingMediaSource.java b/library/src/main/java/com/google/android/exoplayer2/source/ConcatenatingMediaSource.java
index 66d3011f06..ba10f06f02 100644
--- a/library/src/main/java/com/google/android/exoplayer2/source/ConcatenatingMediaSource.java
+++ b/library/src/main/java/com/google/android/exoplayer2/source/ConcatenatingMediaSource.java
@@ -210,17 +210,22 @@ public final class ConcatenatingMediaSource implements MediaSource {
@Override
public int getIndexOfPeriod(Object id) {
- // The id was returned by getPeriodId, so it is always a Pair.
+ if (!(id instanceof Pair)) {
+ return NO_PERIOD_INDEX;
+ }
@SuppressWarnings("unchecked")
Pair sourceIndexAndPeriodId = (Pair) id;
+ if (!(sourceIndexAndPeriodId.first instanceof Integer)) {
+ return NO_PERIOD_INDEX;
+ }
int sourceIndex = sourceIndexAndPeriodId.first;
Object periodId = sourceIndexAndPeriodId.second;
- int periodIndexInSource = timelines[sourceIndex].getIndexOfPeriod(periodId);
- if (periodIndexInSource != NO_PERIOD_INDEX) {
- int firstPeriodIndexInSource = getFirstPeriodIndexInSource(sourceIndex);
- return firstPeriodIndexInSource + periodIndexInSource;
+ if (sourceIndex < 0 || sourceIndex >= timelines.length) {
+ return NO_PERIOD_INDEX;
}
- return NO_PERIOD_INDEX;
+ int periodIndexInSource = timelines[sourceIndex].getIndexOfPeriod(periodId);
+ return periodIndexInSource == NO_PERIOD_INDEX ? NO_PERIOD_INDEX
+ : getFirstPeriodIndexInSource(sourceIndex) + periodIndexInSource;
}
@Override
diff --git a/library/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java b/library/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java
index ce6aef1c67..3a7c6a1c63 100644
--- a/library/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java
+++ b/library/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java
@@ -298,7 +298,7 @@ import java.util.Arrays;
durationUs = largestQueuedTimestampUs == Long.MIN_VALUE ? 0
: largestQueuedTimestampUs + DEFAULT_LAST_SAMPLE_DURATION_US;
sourceListener.onSourceInfoRefreshed(
- new SinglePeriodTimeline(0, durationUs, seekMap.isSeekable()), null);
+ new SinglePeriodTimeline(durationUs, seekMap.isSeekable()), null);
}
}
@@ -381,7 +381,7 @@ import java.util.Arrays;
tracks = new TrackGroupArray(trackArray);
prepared = true;
sourceListener.onSourceInfoRefreshed(
- new SinglePeriodTimeline(0, durationUs, seekMap.isSeekable()), null);
+ new SinglePeriodTimeline(durationUs, seekMap.isSeekable()), null);
callback.onPrepared(this);
}
diff --git a/library/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaSource.java b/library/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaSource.java
index 67645925d6..e1a0d3c140 100644
--- a/library/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaSource.java
+++ b/library/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaSource.java
@@ -135,7 +135,7 @@ public final class ExtractorMediaSource implements MediaSource, MediaSource.List
@Override
public void prepareSource(MediaSource.Listener listener) {
sourceListener = listener;
- timeline = new SinglePeriodTimeline(0, C.UNSET_TIME_US, false);
+ timeline = new SinglePeriodTimeline(C.UNSET_TIME_US, false);
listener.onSourceInfoRefreshed(timeline, null);
}
diff --git a/library/src/main/java/com/google/android/exoplayer2/source/SinglePeriodTimeline.java b/library/src/main/java/com/google/android/exoplayer2/source/SinglePeriodTimeline.java
index 3544468810..d29cbbb8a3 100644
--- a/library/src/main/java/com/google/android/exoplayer2/source/SinglePeriodTimeline.java
+++ b/library/src/main/java/com/google/android/exoplayer2/source/SinglePeriodTimeline.java
@@ -26,7 +26,8 @@ import com.google.android.exoplayer2.util.Assertions;
*/
public final class SinglePeriodTimeline implements Timeline {
- private final Object id;
+ private static final Object ID = new Object();
+
private final boolean isFinal;
private final long durationUs;
private final Window window;
@@ -35,24 +36,21 @@ public final class SinglePeriodTimeline implements Timeline {
* Creates a final timeline with one period of known duration and a window extending from
* zero to its duration.
*
- * @param id The identifier for the period.
* @param durationUs The duration of the period, in microseconds.
* @param isSeekable Whether seeking is supported within the period.
*/
- public SinglePeriodTimeline(Object id, long durationUs, boolean isSeekable) {
- this(id, durationUs, Window.createWindowFromZero(durationUs, isSeekable));
+ public SinglePeriodTimeline(long durationUs, boolean isSeekable) {
+ this(durationUs, Window.createWindowFromZero(durationUs, isSeekable));
}
/**
* Creates a final timeline with one period of known duration and a window extending from
* zero to its duration.
*
- * @param id The identifier for the period.
* @param durationUs The duration of the period, in microseconds.
* @param window The available window within the period.
*/
- public SinglePeriodTimeline(Object id, long durationUs, Window window) {
- this.id = Assertions.checkNotNull(id);
+ public SinglePeriodTimeline(long durationUs, Window window) {
this.durationUs = durationUs;
this.window = window;
this.isFinal = true; // TODO: Remove.
@@ -88,7 +86,7 @@ public final class SinglePeriodTimeline implements Timeline {
@Override
public Object getPeriodId(int periodIndex) {
Assertions.checkIndex(periodIndex, 0, 1);
- return id;
+ return ID;
}
@Override
@@ -99,7 +97,7 @@ public final class SinglePeriodTimeline implements Timeline {
@Override
public int getIndexOfPeriod(Object id) {
- return id.equals(this.id) ? 0 : Timeline.NO_PERIOD_INDEX;
+ return ID.equals(id) ? 0 : Timeline.NO_PERIOD_INDEX;
}
@Override
diff --git a/library/src/main/java/com/google/android/exoplayer2/source/SingleSampleMediaSource.java b/library/src/main/java/com/google/android/exoplayer2/source/SingleSampleMediaSource.java
index d924aaa0fd..876a89d05b 100644
--- a/library/src/main/java/com/google/android/exoplayer2/source/SingleSampleMediaSource.java
+++ b/library/src/main/java/com/google/android/exoplayer2/source/SingleSampleMediaSource.java
@@ -79,7 +79,7 @@ public final class SingleSampleMediaSource implements MediaSource {
this.eventHandler = eventHandler;
this.eventListener = eventListener;
this.eventSourceId = eventSourceId;
- timeline = new SinglePeriodTimeline(0, durationUs, true);
+ timeline = new SinglePeriodTimeline(durationUs, true);
}
// MediaSource implementation.
diff --git a/library/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java b/library/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java
index 13bf9f305b..3a9e738a12 100644
--- a/library/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java
+++ b/library/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java
@@ -539,7 +539,12 @@ public final class DashMediaSource implements MediaSource {
@Override
public int getIndexOfPeriod(Object id) {
- return ((Integer) id) - firstPeriodId;
+ if (!(id instanceof Integer)) {
+ return NO_PERIOD_INDEX;
+ }
+ int periodId = (int) id;
+ return periodId < firstPeriodId || periodId >= firstPeriodId + getPeriodCount()
+ ? NO_PERIOD_INDEX : periodId - firstPeriodId;
}
@Override
diff --git a/library/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriod.java b/library/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriod.java
index bdb5c928ba..5f62400d01 100644
--- a/library/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriod.java
+++ b/library/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriod.java
@@ -281,7 +281,7 @@ import java.util.List;
callback.onPrepared(this);
// TODO[playlists]: Calculate the window.
- Timeline timeline = new SinglePeriodTimeline(0, durationUs, !isLive);
+ Timeline timeline = new SinglePeriodTimeline(durationUs, !isLive);
sourceListener.onSourceInfoRefreshed(timeline, playlist);
}
diff --git a/library/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaSource.java b/library/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaSource.java
index 6673d47e1b..086ea61689 100644
--- a/library/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaSource.java
+++ b/library/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaSource.java
@@ -65,8 +65,7 @@ public final class HlsMediaSource implements MediaSource {
public void prepareSource(MediaSource.Listener listener) {
sourceListener = listener;
// TODO: Defer until the playlist has been loaded.
- listener.onSourceInfoRefreshed(
- new SinglePeriodTimeline(this, C.UNSET_TIME_US, false), null);
+ listener.onSourceInfoRefreshed(new SinglePeriodTimeline(C.UNSET_TIME_US, false), null);
}
@Override
diff --git a/library/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaSource.java b/library/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaSource.java
index 0293192fde..2b53390095 100644
--- a/library/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaSource.java
+++ b/library/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaSource.java
@@ -185,16 +185,16 @@ public final class SsMediaSource implements MediaSource,
}
if (startTimeUs == Long.MAX_VALUE || manifest.dvrWindowLengthUs == C.UNSET_TIME_US
|| manifest.dvrWindowLengthUs == 0) {
- timeline = new SinglePeriodTimeline(0, C.UNSET_TIME_US, false);
+ timeline = new SinglePeriodTimeline(C.UNSET_TIME_US, false);
} else {
long periodDurationUs = startTimeUs + manifest.dvrWindowLengthUs;
Window window = Window.createWindow(0, startTimeUs, 0, periodDurationUs,
manifest.dvrWindowLengthUs, true);
- timeline = new SinglePeriodTimeline(0, periodDurationUs, window);
+ timeline = new SinglePeriodTimeline(periodDurationUs, window);
}
} else {
boolean isSeekable = manifest.durationUs != C.UNSET_TIME_US;
- timeline = new SinglePeriodTimeline(0, manifest.durationUs, isSeekable);
+ timeline = new SinglePeriodTimeline(manifest.durationUs, isSeekable);
}
window = timeline.getWindow(0);
sourceListener.onSourceInfoRefreshed(timeline, manifest);