diff --git a/RELEASENOTES.md b/RELEASENOTES.md
index 349b904589..5743d9944c 100644
--- a/RELEASENOTES.md
+++ b/RELEASENOTES.md
@@ -80,6 +80,9 @@
and move it to the core library.
* Move `LibvpxVideoRenderer.MSG_SET_OUTPUT_BUFFER_RENDERER` to
`C.MSG_SET_OUTPUT_BUFFER_RENDERER`.
+* Add `Timeline.Window.isLive` to indicate that a window is a live stream
+ ([#2668](https://github.com/google/ExoPlayer/issues/2668) and
+ [#5973](https://github.com/google/ExoPlayer/issues/5973)).
### 2.10.5 (2019-09-20) ###
diff --git a/extensions/cast/src/main/java/com/google/android/exoplayer2/ext/cast/CastTimeline.java b/extensions/cast/src/main/java/com/google/android/exoplayer2/ext/cast/CastTimeline.java
index 2857141f8f..54ff7e6777 100644
--- a/extensions/cast/src/main/java/com/google/android/exoplayer2/ext/cast/CastTimeline.java
+++ b/extensions/cast/src/main/java/com/google/android/exoplayer2/ext/cast/CastTimeline.java
@@ -121,6 +121,7 @@ import java.util.Arrays;
/* windowStartTimeMs= */ C.TIME_UNSET,
/* isSeekable= */ !isDynamic,
isDynamic,
+ /* isLive= */ isDynamic,
defaultPositionsUs[windowIndex],
durationUs,
/* firstPeriodIndex= */ windowIndex,
diff --git a/extensions/ima/src/test/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoaderTest.java b/extensions/ima/src/test/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoaderTest.java
index 2995df4ab4..edaa4cde29 100644
--- a/extensions/ima/src/test/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoaderTest.java
+++ b/extensions/ima/src/test/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoaderTest.java
@@ -63,7 +63,8 @@ public class ImaAdsLoaderTest {
private static final long CONTENT_DURATION_US = 10 * C.MICROS_PER_SECOND;
private static final Timeline CONTENT_TIMELINE =
- new SinglePeriodTimeline(CONTENT_DURATION_US, /* isSeekable= */ true, /* isDynamic= */ false);
+ new SinglePeriodTimeline(
+ CONTENT_DURATION_US, /* isSeekable= */ true, /* isDynamic= */ false, /* isLive= */ false);
private static final Uri TEST_URI = Uri.EMPTY;
private static final long TEST_AD_DURATION_US = 5 * C.MICROS_PER_SECOND;
private static final long[][] PREROLL_ADS_DURATIONS_US = new long[][] {{TEST_AD_DURATION_US}};
diff --git a/library/core/src/main/java/com/google/android/exoplayer2/Timeline.java b/library/core/src/main/java/com/google/android/exoplayer2/Timeline.java
index c496052f94..ce1a58822c 100644
--- a/library/core/src/main/java/com/google/android/exoplayer2/Timeline.java
+++ b/library/core/src/main/java/com/google/android/exoplayer2/Timeline.java
@@ -66,8 +66,9 @@ import com.google.android.exoplayer2.util.Assertions;
* duration is unknown, since it's continually extending as more content is broadcast. If content
* only remains available for a limited period of time then the window may start at a non-zero
* position, defining the region of content that can still be played. The window will have {@link
- * Window#isDynamic} set to true if the stream is still live. Its default position is typically near
- * to the live edge (indicated by the black dot in the figure above).
+ * Window#isLive} set to true to indicate it's a live stream and {@link Window#isDynamic} set to
+ * true as long as we expect changes to the live window. Its default position is typically near to
+ * the live edge (indicated by the black dot in the figure above).
*
*
Live stream with indefinite availability
*
@@ -158,8 +159,13 @@ public abstract class Timeline {
public boolean isDynamic;
/**
- * The index of the first period that belongs to this window.
+ * Whether the media in this window is live. For informational purposes only.
+ *
+ *
Check {@link #isDynamic} to know whether this window may still change.
*/
+ public boolean isLive;
+
+ /** The index of the first period that belongs to this window. */
public int firstPeriodIndex;
/**
@@ -200,6 +206,7 @@ public abstract class Timeline {
long windowStartTimeMs,
boolean isSeekable,
boolean isDynamic,
+ boolean isLive,
long defaultPositionUs,
long durationUs,
int firstPeriodIndex,
@@ -212,6 +219,7 @@ public abstract class Timeline {
this.windowStartTimeMs = windowStartTimeMs;
this.isSeekable = isSeekable;
this.isDynamic = isDynamic;
+ this.isLive = isLive;
this.defaultPositionUs = defaultPositionUs;
this.durationUs = durationUs;
this.firstPeriodIndex = firstPeriodIndex;
diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/MaskingMediaSource.java b/library/core/src/main/java/com/google/android/exoplayer2/source/MaskingMediaSource.java
index 8727fc5ed9..891cb351c1 100644
--- a/library/core/src/main/java/com/google/android/exoplayer2/source/MaskingMediaSource.java
+++ b/library/core/src/main/java/com/google/android/exoplayer2/source/MaskingMediaSource.java
@@ -317,6 +317,7 @@ public final class MaskingMediaSource extends CompositeMediaSource {
/* isSeekable= */ false,
// Dynamic window to indicate pending timeline updates.
/* isDynamic= */ true,
+ /* isLive= */ false,
/* defaultPositionUs= */ 0,
/* durationUs= */ C.TIME_UNSET,
/* firstPeriodIndex= */ 0,
diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/ProgressiveMediaPeriod.java b/library/core/src/main/java/com/google/android/exoplayer2/source/ProgressiveMediaPeriod.java
index c768fe4981..4af5bafdda 100644
--- a/library/core/src/main/java/com/google/android/exoplayer2/source/ProgressiveMediaPeriod.java
+++ b/library/core/src/main/java/com/google/android/exoplayer2/source/ProgressiveMediaPeriod.java
@@ -74,13 +74,14 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
interface Listener {
/**
- * Called when the duration or ability to seek within the period changes.
+ * Called when the duration, the ability to seek within the period, or the categorization as
+ * live stream changes.
*
* @param durationUs The duration of the period, or {@link C#TIME_UNSET}.
* @param isSeekable Whether the period is seekable.
+ * @param isLive Whether the period is live.
*/
- void onSourceInfoRefreshed(long durationUs, boolean isSeekable);
-
+ void onSourceInfoRefreshed(long durationUs, boolean isSeekable, boolean isLive);
}
/**
@@ -129,6 +130,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
private int enabledTrackCount;
private long durationUs;
private long length;
+ private boolean isLive;
private long lastSeekPositionUs;
private long pendingResetPositionUs;
@@ -551,7 +553,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
long largestQueuedTimestampUs = getLargestQueuedTimestampUs();
durationUs = largestQueuedTimestampUs == Long.MIN_VALUE ? 0
: largestQueuedTimestampUs + DEFAULT_LAST_SAMPLE_DURATION_US;
- listener.onSourceInfoRefreshed(durationUs, isSeekable);
+ listener.onSourceInfoRefreshed(durationUs, isSeekable, isLive);
}
eventDispatcher.loadCompleted(
loadable.dataSpec,
@@ -740,14 +742,12 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
}
trackArray[i] = new TrackGroup(trackFormat);
}
- dataType =
- length == C.LENGTH_UNSET && seekMap.getDurationUs() == C.TIME_UNSET
- ? C.DATA_TYPE_MEDIA_PROGRESSIVE_LIVE
- : C.DATA_TYPE_MEDIA;
+ isLive = length == C.LENGTH_UNSET && seekMap.getDurationUs() == C.TIME_UNSET;
+ dataType = isLive ? C.DATA_TYPE_MEDIA_PROGRESSIVE_LIVE : C.DATA_TYPE_MEDIA;
preparedState =
new PreparedState(seekMap, new TrackGroupArray(trackArray), trackIsAudioVideoFlags);
prepared = true;
- listener.onSourceInfoRefreshed(durationUs, seekMap.isSeekable());
+ listener.onSourceInfoRefreshed(durationUs, seekMap.isSeekable(), isLive);
Assertions.checkNotNull(callback).onPrepared(this);
}
diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/ProgressiveMediaSource.java b/library/core/src/main/java/com/google/android/exoplayer2/source/ProgressiveMediaSource.java
index 80bcdcd029..c88972da62 100644
--- a/library/core/src/main/java/com/google/android/exoplayer2/source/ProgressiveMediaSource.java
+++ b/library/core/src/main/java/com/google/android/exoplayer2/source/ProgressiveMediaSource.java
@@ -220,6 +220,7 @@ public final class ProgressiveMediaSource extends BaseMediaSource
private long timelineDurationUs;
private boolean timelineIsSeekable;
+ private boolean timelineIsLive;
@Nullable private TransferListener transferListener;
// TODO: Make private when ExtractorMediaSource is deleted.
@@ -253,7 +254,7 @@ public final class ProgressiveMediaSource extends BaseMediaSource
protected void prepareSourceInternal(@Nullable TransferListener mediaTransferListener) {
transferListener = mediaTransferListener;
drmSessionManager.prepare();
- notifySourceInfoRefreshed(timelineDurationUs, timelineIsSeekable);
+ notifySourceInfoRefreshed(timelineDurationUs, timelineIsSeekable, timelineIsLive);
}
@Override
@@ -293,27 +294,32 @@ public final class ProgressiveMediaSource extends BaseMediaSource
// ProgressiveMediaPeriod.Listener implementation.
@Override
- public void onSourceInfoRefreshed(long durationUs, boolean isSeekable) {
+ public void onSourceInfoRefreshed(long durationUs, boolean isSeekable, boolean isLive) {
// If we already have the duration from a previous source info refresh, use it.
durationUs = durationUs == C.TIME_UNSET ? timelineDurationUs : durationUs;
- if (timelineDurationUs == durationUs && timelineIsSeekable == isSeekable) {
+ if (timelineDurationUs == durationUs
+ && timelineIsSeekable == isSeekable
+ && timelineIsLive == isLive) {
// Suppress no-op source info changes.
return;
}
- notifySourceInfoRefreshed(durationUs, isSeekable);
+ notifySourceInfoRefreshed(durationUs, isSeekable, isLive);
}
// Internal methods.
- private void notifySourceInfoRefreshed(long durationUs, boolean isSeekable) {
+ private void notifySourceInfoRefreshed(long durationUs, boolean isSeekable, boolean isLive) {
timelineDurationUs = durationUs;
timelineIsSeekable = isSeekable;
- // TODO: Make timeline dynamic until its duration is known. This is non-trivial. See b/69703223.
+ timelineIsLive = isLive;
+ // TODO: Split up isDynamic into multiple fields to indicate which values may change. Then
+ // indicate that the duration may change until it's known. See [internal: b/69703223].
refreshSourceInfo(
new SinglePeriodTimeline(
timelineDurationUs,
timelineIsSeekable,
/* isDynamic= */ false,
+ /* isLive= */ timelineIsLive,
/* manifest= */ null,
tag));
}
diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/SilenceMediaSource.java b/library/core/src/main/java/com/google/android/exoplayer2/source/SilenceMediaSource.java
index 3bb7ada7e0..a950a95457 100644
--- a/library/core/src/main/java/com/google/android/exoplayer2/source/SilenceMediaSource.java
+++ b/library/core/src/main/java/com/google/android/exoplayer2/source/SilenceMediaSource.java
@@ -68,7 +68,8 @@ public final class SilenceMediaSource extends BaseMediaSource {
@Override
protected void prepareSourceInternal(@Nullable TransferListener mediaTransferListener) {
refreshSourceInfo(
- new SinglePeriodTimeline(durationUs, /* isSeekable= */ true, /* isDynamic= */ false));
+ new SinglePeriodTimeline(
+ durationUs, /* isSeekable= */ true, /* isDynamic= */ false, /* isLive= */ false));
}
@Override
diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/SinglePeriodTimeline.java b/library/core/src/main/java/com/google/android/exoplayer2/source/SinglePeriodTimeline.java
index 49d67935a5..45f64cacf2 100644
--- a/library/core/src/main/java/com/google/android/exoplayer2/source/SinglePeriodTimeline.java
+++ b/library/core/src/main/java/com/google/android/exoplayer2/source/SinglePeriodTimeline.java
@@ -35,6 +35,7 @@ public final class SinglePeriodTimeline extends Timeline {
private final long windowDefaultStartPositionUs;
private final boolean isSeekable;
private final boolean isDynamic;
+ private final boolean isLive;
@Nullable private final Object tag;
@Nullable private final Object manifest;
@@ -44,9 +45,11 @@ public final class SinglePeriodTimeline extends Timeline {
* @param durationUs The duration of the period, in microseconds.
* @param isSeekable Whether seeking is supported within the period.
* @param isDynamic Whether the window may change when the timeline is updated.
+ * @param isLive Whether the window is live.
*/
- public SinglePeriodTimeline(long durationUs, boolean isSeekable, boolean isDynamic) {
- this(durationUs, isSeekable, isDynamic, /* manifest= */ null, /* tag= */ null);
+ public SinglePeriodTimeline(
+ long durationUs, boolean isSeekable, boolean isDynamic, boolean isLive) {
+ this(durationUs, isSeekable, isDynamic, isLive, /* manifest= */ null, /* tag= */ null);
}
/**
@@ -55,6 +58,7 @@ public final class SinglePeriodTimeline extends Timeline {
* @param durationUs The duration of the period, in microseconds.
* @param isSeekable Whether seeking is supported within the period.
* @param isDynamic Whether the window may change when the timeline is updated.
+ * @param isLive Whether the window is live.
* @param manifest The manifest. May be {@code null}.
* @param tag A tag used for {@link Window#tag}.
*/
@@ -62,6 +66,7 @@ public final class SinglePeriodTimeline extends Timeline {
long durationUs,
boolean isSeekable,
boolean isDynamic,
+ boolean isLive,
@Nullable Object manifest,
@Nullable Object tag) {
this(
@@ -71,6 +76,7 @@ public final class SinglePeriodTimeline extends Timeline {
/* windowDefaultStartPositionUs= */ 0,
isSeekable,
isDynamic,
+ isLive,
manifest,
tag);
}
@@ -87,6 +93,7 @@ public final class SinglePeriodTimeline extends Timeline {
* which to begin playback, in microseconds.
* @param isSeekable Whether seeking is supported within the window.
* @param isDynamic Whether the window may change when the timeline is updated.
+ * @param isLive Whether the window is live.
* @param manifest The manifest. May be (@code null}.
* @param tag A tag used for {@link Timeline.Window#tag}.
*/
@@ -97,6 +104,7 @@ public final class SinglePeriodTimeline extends Timeline {
long windowDefaultStartPositionUs,
boolean isSeekable,
boolean isDynamic,
+ boolean isLive,
@Nullable Object manifest,
@Nullable Object tag) {
this(
@@ -108,6 +116,7 @@ public final class SinglePeriodTimeline extends Timeline {
windowDefaultStartPositionUs,
isSeekable,
isDynamic,
+ isLive,
manifest,
tag);
}
@@ -127,6 +136,7 @@ public final class SinglePeriodTimeline extends Timeline {
* which to begin playback, in microseconds.
* @param isSeekable Whether seeking is supported within the window.
* @param isDynamic Whether the window may change when the timeline is updated.
+ * @param isLive Whether the window is live.
* @param manifest The manifest. May be {@code null}.
* @param tag A tag used for {@link Timeline.Window#tag}.
*/
@@ -139,6 +149,7 @@ public final class SinglePeriodTimeline extends Timeline {
long windowDefaultStartPositionUs,
boolean isSeekable,
boolean isDynamic,
+ boolean isLive,
@Nullable Object manifest,
@Nullable Object tag) {
this.presentationStartTimeMs = presentationStartTimeMs;
@@ -149,6 +160,7 @@ public final class SinglePeriodTimeline extends Timeline {
this.windowDefaultStartPositionUs = windowDefaultStartPositionUs;
this.isSeekable = isSeekable;
this.isDynamic = isDynamic;
+ this.isLive = isLive;
this.manifest = manifest;
this.tag = tag;
}
@@ -182,6 +194,7 @@ public final class SinglePeriodTimeline extends Timeline {
windowStartTimeMs,
isSeekable,
isDynamic,
+ isLive,
windowDefaultStartPositionUs,
windowDurationUs,
0,
diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/SingleSampleMediaSource.java b/library/core/src/main/java/com/google/android/exoplayer2/source/SingleSampleMediaSource.java
index 04ee3a153c..be939fd018 100644
--- a/library/core/src/main/java/com/google/android/exoplayer2/source/SingleSampleMediaSource.java
+++ b/library/core/src/main/java/com/google/android/exoplayer2/source/SingleSampleMediaSource.java
@@ -291,7 +291,12 @@ public final class SingleSampleMediaSource extends BaseMediaSource {
dataSpec = new DataSpec(uri, DataSpec.FLAG_ALLOW_GZIP);
timeline =
new SinglePeriodTimeline(
- durationUs, /* isSeekable= */ true, /* isDynamic= */ false, /* manifest= */ null, tag);
+ durationUs,
+ /* isSeekable= */ true,
+ /* isDynamic= */ false,
+ /* isLive= */ false,
+ /* manifest= */ null,
+ tag);
}
// MediaSource implementation.
diff --git a/library/core/src/test/java/com/google/android/exoplayer2/MediaPeriodQueueTest.java b/library/core/src/test/java/com/google/android/exoplayer2/MediaPeriodQueueTest.java
index afcce904e9..1a0e13b6c1 100644
--- a/library/core/src/test/java/com/google/android/exoplayer2/MediaPeriodQueueTest.java
+++ b/library/core/src/test/java/com/google/android/exoplayer2/MediaPeriodQueueTest.java
@@ -44,7 +44,8 @@ public final class MediaPeriodQueueTest {
private static final long SECOND_AD_START_TIME_US = 20 * C.MICROS_PER_SECOND;
private static final Timeline CONTENT_TIMELINE =
- new SinglePeriodTimeline(CONTENT_DURATION_US, /* isSeekable= */ true, /* isDynamic= */ false);
+ new SinglePeriodTimeline(
+ CONTENT_DURATION_US, /* isSeekable= */ true, /* isDynamic= */ false, /* isLive= */ false);
private static final Uri AD_URI = Uri.EMPTY;
private MediaPeriodQueue mediaPeriodQueue;
diff --git a/library/core/src/test/java/com/google/android/exoplayer2/source/ClippingMediaSourceTest.java b/library/core/src/test/java/com/google/android/exoplayer2/source/ClippingMediaSourceTest.java
index 89acb3ec3e..532ad61b85 100644
--- a/library/core/src/test/java/com/google/android/exoplayer2/source/ClippingMediaSourceTest.java
+++ b/library/core/src/test/java/com/google/android/exoplayer2/source/ClippingMediaSourceTest.java
@@ -64,7 +64,12 @@ public final class ClippingMediaSourceTest {
@Test
public void testNoClipping() throws IOException {
- Timeline timeline = new SinglePeriodTimeline(TEST_PERIOD_DURATION_US, true, false);
+ Timeline timeline =
+ new SinglePeriodTimeline(
+ TEST_PERIOD_DURATION_US,
+ /* isSeekable= */ true,
+ /* isDynamic= */ false,
+ /* isLive= */ false);
Timeline clippedTimeline = getClippedTimeline(timeline, 0, TEST_PERIOD_DURATION_US);
@@ -78,7 +83,12 @@ public final class ClippingMediaSourceTest {
@Test
public void testClippingUnseekableWindowThrows() throws IOException {
- Timeline timeline = new SinglePeriodTimeline(TEST_PERIOD_DURATION_US, false, false);
+ Timeline timeline =
+ new SinglePeriodTimeline(
+ TEST_PERIOD_DURATION_US,
+ /* isSeekable= */ false,
+ /* isDynamic= */ false,
+ /* isLive= */ false);
// If the unseekable window isn't clipped, clipping succeeds.
getClippedTimeline(timeline, 0, TEST_PERIOD_DURATION_US);
@@ -93,7 +103,12 @@ public final class ClippingMediaSourceTest {
@Test
public void testClippingStart() throws IOException {
- Timeline timeline = new SinglePeriodTimeline(TEST_PERIOD_DURATION_US, true, false);
+ Timeline timeline =
+ new SinglePeriodTimeline(
+ TEST_PERIOD_DURATION_US,
+ /* isSeekable= */ true,
+ /* isDynamic= */ false,
+ /* isLive= */ false);
Timeline clippedTimeline =
getClippedTimeline(timeline, TEST_CLIP_AMOUNT_US, TEST_PERIOD_DURATION_US);
@@ -105,7 +120,12 @@ public final class ClippingMediaSourceTest {
@Test
public void testClippingEnd() throws IOException {
- Timeline timeline = new SinglePeriodTimeline(TEST_PERIOD_DURATION_US, true, false);
+ Timeline timeline =
+ new SinglePeriodTimeline(
+ TEST_PERIOD_DURATION_US,
+ /* isSeekable= */ true,
+ /* isDynamic= */ false,
+ /* isLive= */ false);
Timeline clippedTimeline =
getClippedTimeline(timeline, 0, TEST_PERIOD_DURATION_US - TEST_CLIP_AMOUNT_US);
@@ -121,7 +141,8 @@ public final class ClippingMediaSourceTest {
// to it having loaded sufficient data to establish its duration and seekability. Such timelines
// should not result in clipping failure.
Timeline timeline =
- new SinglePeriodTimeline(C.TIME_UNSET, /* isSeekable= */ false, /* isDynamic= */ true);
+ new SinglePeriodTimeline(
+ C.TIME_UNSET, /* isSeekable= */ false, /* isDynamic= */ true, /* isLive= */ true);
Timeline clippedTimeline =
getClippedTimeline(
@@ -139,7 +160,8 @@ public final class ClippingMediaSourceTest {
new SinglePeriodTimeline(
/* durationUs= */ TEST_PERIOD_DURATION_US,
/* isSeekable= */ true,
- /* isDynamic= */ false);
+ /* isDynamic= */ false,
+ /* isLive= */ false);
// When clipping to the end, the clipped timeline should also have a duration.
Timeline clippedTimeline =
@@ -153,7 +175,10 @@ public final class ClippingMediaSourceTest {
// Create a child timeline that has an unknown duration.
Timeline timeline =
new SinglePeriodTimeline(
- /* durationUs= */ C.TIME_UNSET, /* isSeekable= */ true, /* isDynamic= */ false);
+ /* durationUs= */ C.TIME_UNSET,
+ /* isSeekable= */ true,
+ /* isDynamic= */ false,
+ /* isLive= */ false);
// When clipping to the end, the clipped timeline should also have an unset duration.
Timeline clippedTimeline =
@@ -164,7 +189,12 @@ public final class ClippingMediaSourceTest {
@Test
public void testClippingStartAndEnd() throws IOException {
- Timeline timeline = new SinglePeriodTimeline(TEST_PERIOD_DURATION_US, true, false);
+ Timeline timeline =
+ new SinglePeriodTimeline(
+ TEST_PERIOD_DURATION_US,
+ /* isSeekable= */ true,
+ /* isDynamic= */ false,
+ /* isLive= */ false);
Timeline clippedTimeline =
getClippedTimeline(
@@ -185,6 +215,7 @@ public final class ClippingMediaSourceTest {
/* windowDefaultStartPositionUs= */ TEST_CLIP_AMOUNT_US,
/* isSeekable= */ true,
/* isDynamic= */ true,
+ /* isLive= */ true,
/* manifest= */ null,
/* tag= */ null);
@@ -207,6 +238,7 @@ public final class ClippingMediaSourceTest {
/* windowDefaultStartPositionUs= */ TEST_CLIP_AMOUNT_US,
/* isSeekable= */ true,
/* isDynamic= */ true,
+ /* isLive= */ true,
/* manifest= */ null,
/* tag= */ null);
Timeline timeline2 =
@@ -217,6 +249,7 @@ public final class ClippingMediaSourceTest {
/* windowDefaultStartPositionUs= */ TEST_CLIP_AMOUNT_US,
/* isSeekable= */ true,
/* isDynamic= */ true,
+ /* isLive= */ true,
/* manifest= */ null,
/* tag= */ null);
@@ -256,6 +289,7 @@ public final class ClippingMediaSourceTest {
/* windowDefaultStartPositionUs= */ TEST_CLIP_AMOUNT_US,
/* isSeekable= */ true,
/* isDynamic= */ true,
+ /* isLive= */ true,
/* manifest= */ null,
/* tag= */ null);
Timeline timeline2 =
@@ -266,6 +300,7 @@ public final class ClippingMediaSourceTest {
/* windowDefaultStartPositionUs= */ TEST_CLIP_AMOUNT_US,
/* isSeekable= */ true,
/* isDynamic= */ true,
+ /* isLive= */ true,
/* manifest= */ null,
/* tag= */ null);
@@ -305,6 +340,7 @@ public final class ClippingMediaSourceTest {
/* windowDefaultStartPositionUs= */ TEST_CLIP_AMOUNT_US,
/* isSeekable= */ true,
/* isDynamic= */ true,
+ /* isLive= */ true,
/* manifest= */ null,
/* tag= */ null);
Timeline timeline2 =
@@ -315,6 +351,7 @@ public final class ClippingMediaSourceTest {
/* windowDefaultStartPositionUs= */ TEST_CLIP_AMOUNT_US,
/* isSeekable= */ true,
/* isDynamic= */ true,
+ /* isLive= */ true,
/* manifest= */ null,
/* tag= */ null);
@@ -355,6 +392,7 @@ public final class ClippingMediaSourceTest {
/* windowDefaultStartPositionUs= */ TEST_CLIP_AMOUNT_US,
/* isSeekable= */ true,
/* isDynamic= */ true,
+ /* isLive= */ true,
/* manifest= */ null,
/* tag= */ null);
Timeline timeline2 =
@@ -365,6 +403,7 @@ public final class ClippingMediaSourceTest {
/* windowDefaultStartPositionUs= */ TEST_CLIP_AMOUNT_US,
/* isSeekable= */ true,
/* isDynamic= */ true,
+ /* isLive= */ true,
/* manifest= */ null,
/* tag= */ null);
@@ -480,7 +519,10 @@ public final class ClippingMediaSourceTest {
throws IOException {
Timeline timeline =
new SinglePeriodTimeline(
- TEST_PERIOD_DURATION_US, /* isSeekable= */ true, /* isDynamic= */ false);
+ TEST_PERIOD_DURATION_US,
+ /* isSeekable= */ true,
+ /* isDynamic= */ false,
+ /* isLive= */ false);
FakeMediaSource fakeMediaSource =
new FakeMediaSource(timeline) {
@Override
diff --git a/library/core/src/test/java/com/google/android/exoplayer2/source/SinglePeriodTimelineTest.java b/library/core/src/test/java/com/google/android/exoplayer2/source/SinglePeriodTimelineTest.java
index cb21db8212..6ff4f78fa2 100644
--- a/library/core/src/test/java/com/google/android/exoplayer2/source/SinglePeriodTimelineTest.java
+++ b/library/core/src/test/java/com/google/android/exoplayer2/source/SinglePeriodTimelineTest.java
@@ -41,7 +41,9 @@ public final class SinglePeriodTimelineTest {
@Test
public void testGetPeriodPositionDynamicWindowUnknownDuration() {
- SinglePeriodTimeline timeline = new SinglePeriodTimeline(C.TIME_UNSET, false, true);
+ SinglePeriodTimeline timeline =
+ new SinglePeriodTimeline(
+ C.TIME_UNSET, /* isSeekable= */ false, /* isDynamic= */ true, /* isLive= */ true);
// Should return null with any positive position projection.
Pair