Commit 01a4cf98 by bachinger Committed by Oliver Woodman

add default methods isSingleWindow and getInitialTimeline to MediaSource interface

PiperOrigin-RevId: 277695826
parent df251ad1
...@@ -19,6 +19,7 @@ import android.util.Pair; ...@@ -19,6 +19,7 @@ import android.util.Pair;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import com.google.android.exoplayer2.source.ads.AdPlaybackState; import com.google.android.exoplayer2.source.ads.AdPlaybackState;
import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.Util;
/** /**
* A flexible representation of the structure of media. A timeline is able to represent the * A flexible representation of the structure of media. A timeline is able to represent the
...@@ -278,6 +279,48 @@ public abstract class Timeline { ...@@ -278,6 +279,48 @@ public abstract class Timeline {
return positionInFirstPeriodUs; return positionInFirstPeriodUs;
} }
@Override
public boolean equals(@Nullable Object obj) {
if (this == obj) {
return true;
}
if (obj == null || !getClass().equals(obj.getClass())) {
return false;
}
Window that = (Window) obj;
return Util.areEqual(uid, that.uid)
&& Util.areEqual(tag, that.tag)
&& Util.areEqual(manifest, that.manifest)
&& presentationStartTimeMs == that.presentationStartTimeMs
&& windowStartTimeMs == that.windowStartTimeMs
&& isSeekable == that.isSeekable
&& isDynamic == that.isDynamic
&& isLive == that.isLive
&& defaultPositionUs == that.defaultPositionUs
&& durationUs == that.durationUs
&& firstPeriodIndex == that.firstPeriodIndex
&& lastPeriodIndex == that.lastPeriodIndex
&& positionInFirstPeriodUs == that.positionInFirstPeriodUs;
}
@Override
public int hashCode() {
int result = 7;
result = 31 * result + uid.hashCode();
result = 31 * result + (tag == null ? 0 : tag.hashCode());
result = 31 * result + (manifest == null ? 0 : manifest.hashCode());
result = 31 * result + (int) (presentationStartTimeMs ^ (presentationStartTimeMs >>> 32));
result = 31 * result + (int) (windowStartTimeMs ^ (windowStartTimeMs >>> 32));
result = 31 * result + (isSeekable ? 1 : 0);
result = 31 * result + (isDynamic ? 1 : 0);
result = 31 * result + (isLive ? 1 : 0);
result = 31 * result + (int) (defaultPositionUs ^ (defaultPositionUs >>> 32));
result = 31 * result + (int) (durationUs ^ (durationUs >>> 32));
result = 31 * result + firstPeriodIndex;
result = 31 * result + lastPeriodIndex;
result = 31 * result + (int) (positionInFirstPeriodUs ^ (positionInFirstPeriodUs >>> 32));
return result;
}
} }
/** /**
...@@ -534,6 +577,34 @@ public abstract class Timeline { ...@@ -534,6 +577,34 @@ public abstract class Timeline {
return adPlaybackState.adResumePositionUs; return adPlaybackState.adResumePositionUs;
} }
@Override
public boolean equals(@Nullable Object obj) {
if (this == obj) {
return true;
}
if (obj == null || !getClass().equals(obj.getClass())) {
return false;
}
Period that = (Period) obj;
return Util.areEqual(id, that.id)
&& Util.areEqual(uid, that.uid)
&& windowIndex == that.windowIndex
&& durationUs == that.durationUs
&& positionInWindowUs == that.positionInWindowUs
&& Util.areEqual(adPlaybackState, that.adPlaybackState);
}
@Override
public int hashCode() {
int result = 7;
result = 31 * result + (id == null ? 0 : id.hashCode());
result = 31 * result + (uid == null ? 0 : uid.hashCode());
result = 31 * result + windowIndex;
result = 31 * result + (int) (durationUs ^ (durationUs >>> 32));
result = 31 * result + (int) (positionInWindowUs ^ (positionInWindowUs >>> 32));
result = 31 * result + (adPlaybackState == null ? 0 : adPlaybackState.hashCode());
return result;
}
} }
/** An empty timeline. */ /** An empty timeline. */
......
...@@ -139,6 +139,23 @@ public final class ConcatenatingMediaSource extends CompositeMediaSource<MediaSo ...@@ -139,6 +139,23 @@ public final class ConcatenatingMediaSource extends CompositeMediaSource<MediaSo
addMediaSources(Arrays.asList(mediaSources)); addMediaSources(Arrays.asList(mediaSources));
} }
@Override
public synchronized Timeline getInitialTimeline() {
ShuffleOrder shuffleOrder =
this.shuffleOrder.getLength() != mediaSourcesPublic.size()
? this.shuffleOrder
.cloneAndClear()
.cloneAndInsert(
/* insertionIndex= */ 0, /* insertionCount= */ mediaSourcesPublic.size())
: this.shuffleOrder;
return new ConcatenatedTimeline(mediaSourcesPublic, shuffleOrder, isAtomic);
}
@Override
public boolean isSingleWindow() {
return false;
}
/** /**
* Appends a {@link MediaSource} to the playlist. * Appends a {@link MediaSource} to the playlist.
* *
......
...@@ -35,7 +35,7 @@ import java.util.Map; ...@@ -35,7 +35,7 @@ import java.util.Map;
*/ */
public final class LoopingMediaSource extends CompositeMediaSource<Void> { public final class LoopingMediaSource extends CompositeMediaSource<Void> {
private final MediaSource childSource; private final MaskingMediaSource maskingMediaSource;
private final int loopCount; private final int loopCount;
private final Map<MediaPeriodId, MediaPeriodId> childMediaPeriodIdToMediaPeriodId; private final Map<MediaPeriodId, MediaPeriodId> childMediaPeriodIdToMediaPeriodId;
private final Map<MediaPeriod, MediaPeriodId> mediaPeriodToChildMediaPeriodId; private final Map<MediaPeriod, MediaPeriodId> mediaPeriodToChildMediaPeriodId;
...@@ -58,7 +58,7 @@ public final class LoopingMediaSource extends CompositeMediaSource<Void> { ...@@ -58,7 +58,7 @@ public final class LoopingMediaSource extends CompositeMediaSource<Void> {
*/ */
public LoopingMediaSource(MediaSource childSource, int loopCount) { public LoopingMediaSource(MediaSource childSource, int loopCount) {
Assertions.checkArgument(loopCount > 0); Assertions.checkArgument(loopCount > 0);
this.childSource = childSource; this.maskingMediaSource = new MaskingMediaSource(childSource, /* useLazyPreparation= */ false);
this.loopCount = loopCount; this.loopCount = loopCount;
childMediaPeriodIdToMediaPeriodId = new HashMap<>(); childMediaPeriodIdToMediaPeriodId = new HashMap<>();
mediaPeriodToChildMediaPeriodId = new HashMap<>(); mediaPeriodToChildMediaPeriodId = new HashMap<>();
...@@ -67,32 +67,45 @@ public final class LoopingMediaSource extends CompositeMediaSource<Void> { ...@@ -67,32 +67,45 @@ public final class LoopingMediaSource extends CompositeMediaSource<Void> {
@Override @Override
@Nullable @Nullable
public Object getTag() { public Object getTag() {
return childSource.getTag(); return maskingMediaSource.getTag();
}
@Nullable
@Override
public Timeline getInitialTimeline() {
return loopCount != Integer.MAX_VALUE
? new LoopingTimeline(maskingMediaSource.getTimeline(), loopCount)
: new InfinitelyLoopingTimeline(maskingMediaSource.getTimeline());
}
@Override
public boolean isSingleWindow() {
return false;
} }
@Override @Override
protected void prepareSourceInternal(@Nullable TransferListener mediaTransferListener) { protected void prepareSourceInternal(@Nullable TransferListener mediaTransferListener) {
super.prepareSourceInternal(mediaTransferListener); super.prepareSourceInternal(mediaTransferListener);
prepareChildSource(/* id= */ null, childSource); prepareChildSource(/* id= */ null, maskingMediaSource);
} }
@Override @Override
public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator, long startPositionUs) { public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator, long startPositionUs) {
if (loopCount == Integer.MAX_VALUE) { if (loopCount == Integer.MAX_VALUE) {
return childSource.createPeriod(id, allocator, startPositionUs); return maskingMediaSource.createPeriod(id, allocator, startPositionUs);
} }
Object childPeriodUid = LoopingTimeline.getChildPeriodUidFromConcatenatedUid(id.periodUid); Object childPeriodUid = LoopingTimeline.getChildPeriodUidFromConcatenatedUid(id.periodUid);
MediaPeriodId childMediaPeriodId = id.copyWithPeriodUid(childPeriodUid); MediaPeriodId childMediaPeriodId = id.copyWithPeriodUid(childPeriodUid);
childMediaPeriodIdToMediaPeriodId.put(childMediaPeriodId, id); childMediaPeriodIdToMediaPeriodId.put(childMediaPeriodId, id);
MediaPeriod mediaPeriod = MediaPeriod mediaPeriod =
childSource.createPeriod(childMediaPeriodId, allocator, startPositionUs); maskingMediaSource.createPeriod(childMediaPeriodId, allocator, startPositionUs);
mediaPeriodToChildMediaPeriodId.put(mediaPeriod, childMediaPeriodId); mediaPeriodToChildMediaPeriodId.put(mediaPeriod, childMediaPeriodId);
return mediaPeriod; return mediaPeriod;
} }
@Override @Override
public void releasePeriod(MediaPeriod mediaPeriod) { public void releasePeriod(MediaPeriod mediaPeriod) {
childSource.releasePeriod(mediaPeriod); maskingMediaSource.releasePeriod(mediaPeriod);
MediaPeriodId childMediaPeriodId = mediaPeriodToChildMediaPeriodId.remove(mediaPeriod); MediaPeriodId childMediaPeriodId = mediaPeriodToChildMediaPeriodId.remove(mediaPeriod);
if (childMediaPeriodId != null) { if (childMediaPeriodId != null) {
childMediaPeriodIdToMediaPeriodId.remove(childMediaPeriodId); childMediaPeriodIdToMediaPeriodId.remove(childMediaPeriodId);
......
...@@ -43,6 +43,7 @@ public final class MaskingMediaSource extends CompositeMediaSource<Void> { ...@@ -43,6 +43,7 @@ public final class MaskingMediaSource extends CompositeMediaSource<Void> {
@Nullable private EventDispatcher unpreparedMaskingMediaPeriodEventDispatcher; @Nullable private EventDispatcher unpreparedMaskingMediaPeriodEventDispatcher;
private boolean hasStartedPreparing; private boolean hasStartedPreparing;
private boolean isPrepared; private boolean isPrepared;
private boolean hasRealTimeline;
/** /**
* Creates the masking media source. * Creates the masking media source.
...@@ -54,14 +55,22 @@ public final class MaskingMediaSource extends CompositeMediaSource<Void> { ...@@ -54,14 +55,22 @@ public final class MaskingMediaSource extends CompositeMediaSource<Void> {
*/ */
public MaskingMediaSource(MediaSource mediaSource, boolean useLazyPreparation) { public MaskingMediaSource(MediaSource mediaSource, boolean useLazyPreparation) {
this.mediaSource = mediaSource; this.mediaSource = mediaSource;
this.useLazyPreparation = useLazyPreparation; this.useLazyPreparation = useLazyPreparation && mediaSource.isSingleWindow();
window = new Timeline.Window(); window = new Timeline.Window();
period = new Timeline.Period(); period = new Timeline.Period();
Timeline initialTimeline = mediaSource.getInitialTimeline();
if (initialTimeline != null) {
timeline =
MaskingTimeline.createWithRealTimeline(
initialTimeline, /* firstWindowUid= */ null, /* firstPeriodUid= */ null);
hasRealTimeline = true;
} else {
timeline = MaskingTimeline.createWithDummyTimeline(mediaSource.getTag()); timeline = MaskingTimeline.createWithDummyTimeline(mediaSource.getTag());
} }
}
/** Returns the {@link Timeline}. */ /** Returns the {@link Timeline}. */
public Timeline getTimeline() { public synchronized Timeline getTimeline() {
return timeline; return timeline;
} }
...@@ -129,13 +138,15 @@ public final class MaskingMediaSource extends CompositeMediaSource<Void> { ...@@ -129,13 +138,15 @@ public final class MaskingMediaSource extends CompositeMediaSource<Void> {
} }
@Override @Override
protected void onChildSourceInfoRefreshed( protected synchronized void onChildSourceInfoRefreshed(
Void id, MediaSource mediaSource, Timeline newTimeline) { Void id, MediaSource mediaSource, Timeline newTimeline) {
if (isPrepared) { if (isPrepared) {
timeline = timeline.cloneWithUpdatedTimeline(newTimeline); timeline = timeline.cloneWithUpdatedTimeline(newTimeline);
} else if (newTimeline.isEmpty()) { } else if (newTimeline.isEmpty()) {
timeline = timeline =
MaskingTimeline.createWithRealTimeline( hasRealTimeline
? timeline.cloneWithUpdatedTimeline(newTimeline)
: MaskingTimeline.createWithRealTimeline(
newTimeline, Window.SINGLE_WINDOW_UID, MaskingTimeline.DUMMY_EXTERNAL_PERIOD_UID); newTimeline, Window.SINGLE_WINDOW_UID, MaskingTimeline.DUMMY_EXTERNAL_PERIOD_UID);
} else { } else {
// Determine first period and the start position. // Determine first period and the start position.
...@@ -164,7 +175,10 @@ public final class MaskingMediaSource extends CompositeMediaSource<Void> { ...@@ -164,7 +175,10 @@ public final class MaskingMediaSource extends CompositeMediaSource<Void> {
window, period, /* windowIndex= */ 0, windowStartPositionUs); window, period, /* windowIndex= */ 0, windowStartPositionUs);
Object periodUid = periodPosition.first; Object periodUid = periodPosition.first;
long periodPositionUs = periodPosition.second; long periodPositionUs = periodPosition.second;
timeline = MaskingTimeline.createWithRealTimeline(newTimeline, windowUid, periodUid); timeline =
hasRealTimeline
? timeline.cloneWithUpdatedTimeline(newTimeline)
: MaskingTimeline.createWithRealTimeline(newTimeline, windowUid, periodUid);
if (unpreparedMaskingMediaPeriod != null) { if (unpreparedMaskingMediaPeriod != null) {
MaskingMediaPeriod maskingPeriod = unpreparedMaskingMediaPeriod; MaskingMediaPeriod maskingPeriod = unpreparedMaskingMediaPeriod;
maskingPeriod.overridePreparePositionUs(periodPositionUs); maskingPeriod.overridePreparePositionUs(periodPositionUs);
...@@ -173,6 +187,7 @@ public final class MaskingMediaSource extends CompositeMediaSource<Void> { ...@@ -173,6 +187,7 @@ public final class MaskingMediaSource extends CompositeMediaSource<Void> {
maskingPeriod.createPeriod(idInSource); maskingPeriod.createPeriod(idInSource);
} }
} }
hasRealTimeline = true;
isPrepared = true; isPrepared = true;
refreshSourceInfo(this.timeline); refreshSourceInfo(this.timeline);
} }
...@@ -193,13 +208,15 @@ public final class MaskingMediaSource extends CompositeMediaSource<Void> { ...@@ -193,13 +208,15 @@ public final class MaskingMediaSource extends CompositeMediaSource<Void> {
} }
private Object getInternalPeriodUid(Object externalPeriodUid) { private Object getInternalPeriodUid(Object externalPeriodUid) {
return externalPeriodUid.equals(MaskingTimeline.DUMMY_EXTERNAL_PERIOD_UID) return timeline.replacedInternalPeriodUid != null
&& externalPeriodUid.equals(MaskingTimeline.DUMMY_EXTERNAL_PERIOD_UID)
? timeline.replacedInternalPeriodUid ? timeline.replacedInternalPeriodUid
: externalPeriodUid; : externalPeriodUid;
} }
private Object getExternalPeriodUid(Object internalPeriodUid) { private Object getExternalPeriodUid(Object internalPeriodUid) {
return timeline.replacedInternalPeriodUid.equals(internalPeriodUid) return timeline.replacedInternalPeriodUid != null
&& timeline.replacedInternalPeriodUid.equals(internalPeriodUid)
? MaskingTimeline.DUMMY_EXTERNAL_PERIOD_UID ? MaskingTimeline.DUMMY_EXTERNAL_PERIOD_UID
: internalPeriodUid; : internalPeriodUid;
} }
...@@ -212,8 +229,8 @@ public final class MaskingMediaSource extends CompositeMediaSource<Void> { ...@@ -212,8 +229,8 @@ public final class MaskingMediaSource extends CompositeMediaSource<Void> {
public static final Object DUMMY_EXTERNAL_PERIOD_UID = new Object(); public static final Object DUMMY_EXTERNAL_PERIOD_UID = new Object();
private final Object replacedInternalWindowUid; @Nullable private final Object replacedInternalWindowUid;
private final Object replacedInternalPeriodUid; @Nullable private final Object replacedInternalPeriodUid;
/** /**
* Returns an instance with a dummy timeline using the provided window tag. * Returns an instance with a dummy timeline using the provided window tag.
...@@ -236,12 +253,14 @@ public final class MaskingMediaSource extends CompositeMediaSource<Void> { ...@@ -236,12 +253,14 @@ public final class MaskingMediaSource extends CompositeMediaSource<Void> {
* assigned {@link #DUMMY_EXTERNAL_PERIOD_UID}. * assigned {@link #DUMMY_EXTERNAL_PERIOD_UID}.
*/ */
public static MaskingTimeline createWithRealTimeline( public static MaskingTimeline createWithRealTimeline(
Timeline timeline, Object firstWindowUid, Object firstPeriodUid) { Timeline timeline, @Nullable Object firstWindowUid, @Nullable Object firstPeriodUid) {
return new MaskingTimeline(timeline, firstWindowUid, firstPeriodUid); return new MaskingTimeline(timeline, firstWindowUid, firstPeriodUid);
} }
private MaskingTimeline( private MaskingTimeline(
Timeline timeline, Object replacedInternalWindowUid, Object replacedInternalPeriodUid) { Timeline timeline,
@Nullable Object replacedInternalWindowUid,
@Nullable Object replacedInternalPeriodUid) {
super(timeline); super(timeline);
this.replacedInternalWindowUid = replacedInternalWindowUid; this.replacedInternalWindowUid = replacedInternalWindowUid;
this.replacedInternalPeriodUid = replacedInternalPeriodUid; this.replacedInternalPeriodUid = replacedInternalPeriodUid;
...@@ -273,7 +292,7 @@ public final class MaskingMediaSource extends CompositeMediaSource<Void> { ...@@ -273,7 +292,7 @@ public final class MaskingMediaSource extends CompositeMediaSource<Void> {
@Override @Override
public Period getPeriod(int periodIndex, Period period, boolean setIds) { public Period getPeriod(int periodIndex, Period period, boolean setIds) {
timeline.getPeriod(periodIndex, period, setIds); timeline.getPeriod(periodIndex, period, setIds);
if (Util.areEqual(period.uid, replacedInternalPeriodUid)) { if (Util.areEqual(period.uid, replacedInternalPeriodUid) && setIds) {
period.uid = DUMMY_EXTERNAL_PERIOD_UID; period.uid = DUMMY_EXTERNAL_PERIOD_UID;
} }
return period; return period;
...@@ -282,7 +301,9 @@ public final class MaskingMediaSource extends CompositeMediaSource<Void> { ...@@ -282,7 +301,9 @@ public final class MaskingMediaSource extends CompositeMediaSource<Void> {
@Override @Override
public int getIndexOfPeriod(Object uid) { public int getIndexOfPeriod(Object uid) {
return timeline.getIndexOfPeriod( return timeline.getIndexOfPeriod(
DUMMY_EXTERNAL_PERIOD_UID.equals(uid) ? replacedInternalPeriodUid : uid); DUMMY_EXTERNAL_PERIOD_UID.equals(uid) && replacedInternalPeriodUid != null
? replacedInternalPeriodUid
: uid);
} }
@Override @Override
...@@ -333,8 +354,8 @@ public final class MaskingMediaSource extends CompositeMediaSource<Void> { ...@@ -333,8 +354,8 @@ public final class MaskingMediaSource extends CompositeMediaSource<Void> {
@Override @Override
public Period getPeriod(int periodIndex, Period period, boolean setIds) { public Period getPeriod(int periodIndex, Period period, boolean setIds) {
return period.set( return period.set(
/* id= */ 0, /* id= */ setIds ? 0 : null,
/* uid= */ MaskingTimeline.DUMMY_EXTERNAL_PERIOD_UID, /* uid= */ setIds ? MaskingTimeline.DUMMY_EXTERNAL_PERIOD_UID : null,
/* windowIndex= */ 0, /* windowIndex= */ 0,
/* durationUs = */ C.TIME_UNSET, /* durationUs = */ C.TIME_UNSET,
/* positionInWindowUs= */ 0); /* positionInWindowUs= */ 0);
......
...@@ -228,6 +228,33 @@ public interface MediaSource { ...@@ -228,6 +228,33 @@ public interface MediaSource {
*/ */
void removeEventListener(MediaSourceEventListener eventListener); void removeEventListener(MediaSourceEventListener eventListener);
/**
* Returns the initial dummy timeline that is returned immediately when the real timeline is not
* yet known, or null to let the player create an initial timeline.
*
* <p>The initial timeline must use the same uids for windows and periods that the real timeline
* will use. It also must provide windows which are marked as dynamic to indicate that the window
* is expected to change when the real timeline arrives.
*
* <p>Any media source which has multiple windows should typically provide such an initial
* timeline to make sure the player reports the correct number of windows immediately.
*/
@Nullable
default Timeline getInitialTimeline() {
return null;
}
/**
* Returns true if the media source is guaranteed to never have zero or more than one window.
*
* <p>The default implementation returns {@code true}.
*
* @return true if the source has exactly one window.
*/
default boolean isSingleWindow() {
return true;
}
/** Returns the tag set on the media source, or null if none was set. */ /** Returns the tag set on the media source, or null if none was set. */
@Nullable @Nullable
default Object getTag() { default Object getTag() {
......
...@@ -15,6 +15,8 @@ ...@@ -15,6 +15,8 @@
*/ */
package com.google.android.exoplayer2; package com.google.android.exoplayer2;
import static com.google.common.truth.Truth.assertThat;
import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.android.exoplayer2.testutil.FakeTimeline; import com.google.android.exoplayer2.testutil.FakeTimeline;
import com.google.android.exoplayer2.testutil.FakeTimeline.TimelineWindowDefinition; import com.google.android.exoplayer2.testutil.FakeTimeline.TimelineWindowDefinition;
...@@ -58,4 +60,148 @@ public class TimelineTest { ...@@ -58,4 +60,148 @@ public class TimelineTest {
TimelineAsserts.assertNextWindowIndices(timeline, Player.REPEAT_MODE_ONE, false, 0); TimelineAsserts.assertNextWindowIndices(timeline, Player.REPEAT_MODE_ONE, false, 0);
TimelineAsserts.assertNextWindowIndices(timeline, Player.REPEAT_MODE_ALL, false, 0); TimelineAsserts.assertNextWindowIndices(timeline, Player.REPEAT_MODE_ALL, false, 0);
} }
@Test
public void testWindowEquals() {
Timeline.Window window = new Timeline.Window();
assertThat(window).isEqualTo(new Timeline.Window());
Timeline.Window otherWindow = new Timeline.Window();
otherWindow.tag = new Object();
assertThat(window).isNotEqualTo(otherWindow);
otherWindow = new Timeline.Window();
otherWindow.manifest = new Object();
assertThat(window).isNotEqualTo(otherWindow);
otherWindow = new Timeline.Window();
otherWindow.presentationStartTimeMs = C.TIME_UNSET;
assertThat(window).isNotEqualTo(otherWindow);
otherWindow = new Timeline.Window();
otherWindow.windowStartTimeMs = C.TIME_UNSET;
assertThat(window).isNotEqualTo(otherWindow);
otherWindow = new Timeline.Window();
otherWindow.isSeekable = true;
assertThat(window).isNotEqualTo(otherWindow);
otherWindow = new Timeline.Window();
otherWindow.isDynamic = true;
assertThat(window).isNotEqualTo(otherWindow);
otherWindow = new Timeline.Window();
otherWindow.isLive = true;
assertThat(window).isNotEqualTo(otherWindow);
otherWindow = new Timeline.Window();
otherWindow.defaultPositionUs = C.TIME_UNSET;
assertThat(window).isNotEqualTo(otherWindow);
otherWindow = new Timeline.Window();
otherWindow.durationUs = C.TIME_UNSET;
assertThat(window).isNotEqualTo(otherWindow);
otherWindow = new Timeline.Window();
otherWindow.firstPeriodIndex = 1;
assertThat(window).isNotEqualTo(otherWindow);
otherWindow = new Timeline.Window();
otherWindow.lastPeriodIndex = 1;
assertThat(window).isNotEqualTo(otherWindow);
otherWindow = new Timeline.Window();
otherWindow.positionInFirstPeriodUs = C.TIME_UNSET;
assertThat(window).isNotEqualTo(otherWindow);
window.uid = new Object();
window.tag = new Object();
window.manifest = new Object();
window.presentationStartTimeMs = C.TIME_UNSET;
window.windowStartTimeMs = C.TIME_UNSET;
window.isSeekable = true;
window.isDynamic = true;
window.isLive = true;
window.defaultPositionUs = C.TIME_UNSET;
window.durationUs = C.TIME_UNSET;
window.firstPeriodIndex = 1;
window.lastPeriodIndex = 1;
window.positionInFirstPeriodUs = C.TIME_UNSET;
otherWindow =
otherWindow.set(
window.uid,
window.tag,
window.manifest,
window.presentationStartTimeMs,
window.windowStartTimeMs,
window.isSeekable,
window.isDynamic,
window.isLive,
window.defaultPositionUs,
window.durationUs,
window.firstPeriodIndex,
window.lastPeriodIndex,
window.positionInFirstPeriodUs);
assertThat(window).isEqualTo(otherWindow);
}
@Test
public void testWindowHashCode() {
Timeline.Window window = new Timeline.Window();
Timeline.Window otherWindow = new Timeline.Window();
assertThat(window.hashCode()).isEqualTo(otherWindow.hashCode());
window.tag = new Object();
assertThat(window.hashCode()).isNotEqualTo(otherWindow.hashCode());
otherWindow.tag = window.tag;
assertThat(window.hashCode()).isEqualTo(otherWindow.hashCode());
}
@Test
public void testPeriodEquals() {
Timeline.Period period = new Timeline.Period();
assertThat(period).isEqualTo(new Timeline.Period());
Timeline.Period otherPeriod = new Timeline.Period();
otherPeriod.id = new Object();
assertThat(period).isNotEqualTo(otherPeriod);
otherPeriod = new Timeline.Period();
otherPeriod.uid = new Object();
assertThat(period).isNotEqualTo(otherPeriod);
otherPeriod = new Timeline.Period();
otherPeriod.windowIndex = 12;
assertThat(period).isNotEqualTo(otherPeriod);
otherPeriod = new Timeline.Period();
otherPeriod.durationUs = 11L;
assertThat(period).isNotEqualTo(otherPeriod);
otherPeriod = new Timeline.Period();
period.id = new Object();
period.uid = new Object();
period.windowIndex = 1;
period.durationUs = 123L;
otherPeriod =
otherPeriod.set(
period.id,
period.uid,
period.windowIndex,
period.durationUs,
/* positionInWindowUs= */ 0);
assertThat(period).isEqualTo(otherPeriod);
}
@Test
public void testPeriodHashCode() {
Timeline.Period period = new Timeline.Period();
Timeline.Period otherPeriod = new Timeline.Period();
assertThat(period.hashCode()).isEqualTo(otherPeriod.hashCode());
period.windowIndex = 12;
assertThat(period.hashCode()).isNotEqualTo(otherPeriod.hashCode());
otherPeriod.windowIndex = period.windowIndex;
assertThat(period.hashCode()).isEqualTo(otherPeriod.hashCode());
}
} }
...@@ -40,6 +40,7 @@ public final class FakeTimeline extends Timeline { ...@@ -40,6 +40,7 @@ public final class FakeTimeline extends Timeline {
public final Object id; public final Object id;
public final boolean isSeekable; public final boolean isSeekable;
public final boolean isDynamic; public final boolean isDynamic;
public final boolean isLive;
public final long durationUs; public final long durationUs;
public final AdPlaybackState adPlaybackState; public final AdPlaybackState adPlaybackState;
...@@ -99,10 +100,41 @@ public final class FakeTimeline extends Timeline { ...@@ -99,10 +100,41 @@ public final class FakeTimeline extends Timeline {
boolean isDynamic, boolean isDynamic,
long durationUs, long durationUs,
AdPlaybackState adPlaybackState) { AdPlaybackState adPlaybackState) {
this(
periodCount,
id,
isSeekable,
isDynamic,
/* isLive= */ isDynamic,
durationUs,
adPlaybackState);
}
/**
* Creates a window definition with ad groups.
*
* @param periodCount The number of periods in the window. Each period get an equal slice of the
* total window duration.
* @param id The UID of the window.
* @param isSeekable Whether the window is seekable.
* @param isDynamic Whether the window is dynamic.
* @param isLive Whether the window is live.
* @param durationUs The duration of the window in microseconds.
* @param adPlaybackState The ad playback state.
*/
public TimelineWindowDefinition(
int periodCount,
Object id,
boolean isSeekable,
boolean isDynamic,
boolean isLive,
long durationUs,
AdPlaybackState adPlaybackState) {
this.periodCount = periodCount; this.periodCount = periodCount;
this.id = id; this.id = id;
this.isSeekable = isSeekable; this.isSeekable = isSeekable;
this.isDynamic = isDynamic; this.isDynamic = isDynamic;
this.isLive = isLive;
this.durationUs = durationUs; this.durationUs = durationUs;
this.adPlaybackState = adPlaybackState; this.adPlaybackState = adPlaybackState;
} }
...@@ -189,7 +221,7 @@ public final class FakeTimeline extends Timeline { ...@@ -189,7 +221,7 @@ public final class FakeTimeline extends Timeline {
/* windowStartTimeMs= */ C.TIME_UNSET, /* windowStartTimeMs= */ C.TIME_UNSET,
windowDefinition.isSeekable, windowDefinition.isSeekable,
windowDefinition.isDynamic, windowDefinition.isDynamic,
/* isLive= */ windowDefinition.isDynamic, windowDefinition.isLive,
/* defaultPositionUs= */ 0, /* defaultPositionUs= */ 0,
windowDefinition.durationUs, windowDefinition.durationUs,
periodOffsets[windowIndex], periodOffsets[windowIndex],
......
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