diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java
index f7abd4dd9d..441bb94d68 100644
--- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java
+++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java
@@ -186,10 +186,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
internalPlaybackThread.start();
handler = clock.createHandler(internalPlaybackThread.getLooper(), this);
deliverPendingMessageAtStartPositionRequired = true;
- mediaSourceList = new MediaSourceList(this);
- if (analyticsCollector != null) {
- mediaSourceList.setAnalyticsCollector(eventHandler, analyticsCollector);
- }
+ mediaSourceList = new MediaSourceList(/* listener= */ this, analyticsCollector, eventHandler);
}
public void experimental_setReleaseTimeoutMs(long releaseTimeoutMs) {
diff --git a/library/core/src/main/java/com/google/android/exoplayer2/MediaSourceList.java b/library/core/src/main/java/com/google/android/exoplayer2/MediaSourceList.java
index cffad118ad..518f7bc6cb 100644
--- a/library/core/src/main/java/com/google/android/exoplayer2/MediaSourceList.java
+++ b/library/core/src/main/java/com/google/android/exoplayer2/MediaSourceList.java
@@ -52,7 +52,7 @@ import java.util.Set;
*
*
With the exception of the constructor, all methods are called on the playback thread.
*/
-/* package */ class MediaSourceList {
+/* package */ final class MediaSourceList {
/** Listener for source events. */
public interface MediaSourceListInfoRefreshListener {
@@ -81,8 +81,20 @@ import java.util.Set;
@Nullable private TransferListener mediaTransferListener;
- @SuppressWarnings("initialization")
- public MediaSourceList(MediaSourceListInfoRefreshListener listener) {
+ /**
+ * Creates the media source list.
+ *
+ * @param listener The {@link MediaSourceListInfoRefreshListener} to be informed of timeline
+ * changes.
+ * @param analyticsCollector An optional {@link AnalyticsCollector} to be registered for media
+ * source events.
+ * @param analyticsCollectorHandler The {@link Handler} to call {@link AnalyticsCollector} methods
+ * on.
+ */
+ public MediaSourceList(
+ MediaSourceListInfoRefreshListener listener,
+ @Nullable AnalyticsCollector analyticsCollector,
+ Handler analyticsCollectorHandler) {
mediaSourceListInfoListener = listener;
shuffleOrder = new DefaultShuffleOrder(0);
mediaSourceByMediaPeriod = new IdentityHashMap<>();
@@ -91,6 +103,12 @@ import java.util.Set;
eventDispatcher = new MediaSourceEventListener.EventDispatcher();
childSources = new HashMap<>();
enabledMediaSourceHolders = new HashSet<>();
+ if (analyticsCollector != null) {
+ eventDispatcher.addEventListener(
+ analyticsCollectorHandler, analyticsCollector, MediaSourceEventListener.class);
+ eventDispatcher.addEventListener(
+ analyticsCollectorHandler, analyticsCollector, DrmSessionEventListener.class);
+ }
}
/**
@@ -100,8 +118,7 @@ import java.util.Set;
* @param shuffleOrder The new shuffle order.
* @return The new {@link Timeline}.
*/
- public final Timeline setMediaSources(
- List holders, ShuffleOrder shuffleOrder) {
+ public Timeline setMediaSources(List holders, ShuffleOrder shuffleOrder) {
removeMediaSourcesInternal(/* fromIndex= */ 0, /* toIndex= */ mediaSourceHolders.size());
return addMediaSources(/* index= */ this.mediaSourceHolders.size(), holders, shuffleOrder);
}
@@ -115,7 +132,7 @@ import java.util.Set;
* @param shuffleOrder The new shuffle order.
* @return The new {@link Timeline}.
*/
- public final Timeline addMediaSources(
+ public Timeline addMediaSources(
int index, List holders, ShuffleOrder shuffleOrder) {
if (!holders.isEmpty()) {
this.shuffleOrder = shuffleOrder;
@@ -165,8 +182,7 @@ import java.util.Set;
* @throws IllegalArgumentException When the range is malformed, i.e. {@code fromIndex} < 0,
* {@code toIndex} > {@link #getSize()}, {@code fromIndex} > {@code toIndex}
*/
- public final Timeline removeMediaSourceRange(
- int fromIndex, int toIndex, ShuffleOrder shuffleOrder) {
+ public Timeline removeMediaSourceRange(int fromIndex, int toIndex, ShuffleOrder shuffleOrder) {
Assertions.checkArgument(fromIndex >= 0 && fromIndex <= toIndex && toIndex <= getSize());
this.shuffleOrder = shuffleOrder;
removeMediaSourcesInternal(fromIndex, toIndex);
@@ -185,7 +201,7 @@ import java.util.Set;
* @throws IllegalArgumentException When an index is invalid, i.e. {@code currentIndex} < 0,
* {@code currentIndex} >= {@link #getSize()}, {@code newIndex} < 0
*/
- public final Timeline moveMediaSource(int currentIndex, int newIndex, ShuffleOrder shuffleOrder) {
+ public Timeline moveMediaSource(int currentIndex, int newIndex, ShuffleOrder shuffleOrder) {
return moveMediaSourceRange(currentIndex, currentIndex + 1, newIndex, shuffleOrder);
}
@@ -228,39 +244,28 @@ import java.util.Set;
}
/** Clears the playlist. */
- public final Timeline clear(@Nullable ShuffleOrder shuffleOrder) {
+ public Timeline clear(@Nullable ShuffleOrder shuffleOrder) {
this.shuffleOrder = shuffleOrder != null ? shuffleOrder : this.shuffleOrder.cloneAndClear();
removeMediaSourcesInternal(/* fromIndex= */ 0, /* toIndex= */ getSize());
return createTimeline();
}
/** Whether the playlist is prepared. */
- public final boolean isPrepared() {
+ public boolean isPrepared() {
return isPrepared;
}
/** Returns the number of media sources in the playlist. */
- public final int getSize() {
+ public int getSize() {
return mediaSourceHolders.size();
}
- /**
- * Sets the {@link AnalyticsCollector}.
- *
- * @param handler The handler on which to call the collector.
- * @param analyticsCollector The analytics collector.
- */
- public final void setAnalyticsCollector(Handler handler, AnalyticsCollector analyticsCollector) {
- eventDispatcher.addEventListener(handler, analyticsCollector, MediaSourceEventListener.class);
- eventDispatcher.addEventListener(handler, analyticsCollector, DrmSessionEventListener.class);
- }
-
/**
* Sets a new shuffle order to use when shuffling the child media sources.
*
* @param shuffleOrder A {@link ShuffleOrder}.
*/
- public final Timeline setShuffleOrder(ShuffleOrder shuffleOrder) {
+ public Timeline setShuffleOrder(ShuffleOrder shuffleOrder) {
int size = getSize();
if (shuffleOrder.getLength() != size) {
shuffleOrder =
@@ -273,7 +278,7 @@ import java.util.Set;
}
/** Prepares the playlist. */
- public final void prepare(@Nullable TransferListener mediaTransferListener) {
+ public void prepare(@Nullable TransferListener mediaTransferListener) {
Assertions.checkState(!isPrepared);
this.mediaTransferListener = mediaTransferListener;
for (int i = 0; i < mediaSourceHolders.size(); i++) {
@@ -312,7 +317,7 @@ import java.util.Set;
*
* @param mediaPeriod The period to release.
*/
- public final void releasePeriod(MediaPeriod mediaPeriod) {
+ public void releasePeriod(MediaPeriod mediaPeriod) {
MediaSourceHolder holder =
Assertions.checkNotNull(mediaSourceByMediaPeriod.remove(mediaPeriod));
holder.mediaSource.releasePeriod(mediaPeriod);
@@ -324,7 +329,7 @@ import java.util.Set;
}
/** Releases the playlist. */
- public final void release() {
+ public void release() {
for (MediaSourceAndListener childSource : childSources.values()) {
try {
childSource.mediaSource.releaseSource(childSource.caller);
@@ -340,14 +345,14 @@ import java.util.Set;
}
/** Throws any pending error encountered while loading or refreshing. */
- public final void maybeThrowSourceInfoRefreshError() throws IOException {
+ public void maybeThrowSourceInfoRefreshError() throws IOException {
for (MediaSourceAndListener childSource : childSources.values()) {
childSource.mediaSource.maybeThrowSourceInfoRefreshError();
}
}
/** Creates a timeline reflecting the current state of the playlist. */
- public final Timeline createTimeline() {
+ public Timeline createTimeline() {
if (mediaSourceHolders.isEmpty()) {
return Timeline.EMPTY;
}
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 0ca5dd60ef..efd88aacaf 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
@@ -23,18 +23,19 @@ import static org.robolectric.annotation.LooperMode.Mode.LEGACY;
import android.net.Uri;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
-import com.google.android.exoplayer2.source.ShuffleOrder;
import com.google.android.exoplayer2.source.SinglePeriodTimeline;
import com.google.android.exoplayer2.source.ads.AdPlaybackState;
import com.google.android.exoplayer2.source.ads.SinglePeriodAdTimeline;
import com.google.android.exoplayer2.testutil.FakeMediaSource;
+import com.google.android.exoplayer2.testutil.FakeShuffleOrder;
import com.google.android.exoplayer2.testutil.FakeTimeline;
import com.google.android.exoplayer2.testutil.FakeTimeline.TimelineWindowDefinition;
import com.google.android.exoplayer2.trackselection.TrackSelection;
import com.google.android.exoplayer2.trackselection.TrackSelector;
import com.google.android.exoplayer2.trackselection.TrackSelectorResult;
import com.google.android.exoplayer2.upstream.Allocator;
-import java.util.Collections;
+import com.google.android.exoplayer2.util.Util;
+import com.google.common.collect.ImmutableList;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -70,12 +71,15 @@ public final class MediaPeriodQueueTest {
private Allocator allocator;
private MediaSourceList mediaSourceList;
private FakeMediaSource fakeMediaSource;
- private MediaSourceList.MediaSourceHolder mediaSourceHolder;
@Before
public void setUp() {
mediaPeriodQueue = new MediaPeriodQueue();
- mediaSourceList = mock(MediaSourceList.class);
+ mediaSourceList =
+ new MediaSourceList(
+ mock(MediaSourceList.MediaSourceListInfoRefreshListener.class),
+ /* analyticsCollector= */ null,
+ Util.createHandlerForCurrentOrMainLooper());
rendererCapabilities = new RendererCapabilities[0];
trackSelector = mock(TrackSelector.class);
allocator = mock(Allocator.class);
@@ -408,10 +412,13 @@ public final class MediaPeriodQueueTest {
private void setupTimeline(Timeline timeline) {
fakeMediaSource = new FakeMediaSource(timeline);
- mediaSourceHolder = new MediaSourceList.MediaSourceHolder(fakeMediaSource, false);
+ MediaSourceList.MediaSourceHolder mediaSourceHolder =
+ new MediaSourceList.MediaSourceHolder(fakeMediaSource, /* useLazyPreparation= */ false);
+ mediaSourceList.setMediaSources(
+ ImmutableList.of(mediaSourceHolder), new FakeShuffleOrder(/* length= */ 1));
mediaSourceHolder.mediaSource.prepareSourceInternal(/* mediaTransferListener */ null);
- Timeline playlistTimeline = createPlaylistTimeline();
+ Timeline playlistTimeline = mediaSourceList.createTimeline();
firstPeriodUid = playlistTimeline.getUidOfPeriod(/* periodIndex= */ 0);
playbackInfo =
@@ -443,13 +450,7 @@ public final class MediaPeriodQueueTest {
SinglePeriodAdTimeline adTimeline =
new SinglePeriodAdTimeline(CONTENT_TIMELINE, adPlaybackState);
fakeMediaSource.setNewSourceInfo(adTimeline);
- playbackInfo = playbackInfo.copyWithTimeline(createPlaylistTimeline());
- }
-
- private MediaSourceList.PlaylistTimeline createPlaylistTimeline() {
- return new MediaSourceList.PlaylistTimeline(
- Collections.singleton(mediaSourceHolder),
- new ShuffleOrder.DefaultShuffleOrder(/* length= */ 1));
+ playbackInfo = playbackInfo.copyWithTimeline(mediaSourceList.createTimeline());
}
private void advance() {
diff --git a/library/core/src/test/java/com/google/android/exoplayer2/MediaSourceListTest.java b/library/core/src/test/java/com/google/android/exoplayer2/MediaSourceListTest.java
index bcea053115..b3ff5e5c55 100644
--- a/library/core/src/test/java/com/google/android/exoplayer2/MediaSourceListTest.java
+++ b/library/core/src/test/java/com/google/android/exoplayer2/MediaSourceListTest.java
@@ -31,6 +31,7 @@ import com.google.android.exoplayer2.source.ShuffleOrder;
import com.google.android.exoplayer2.testutil.FakeMediaSource;
import com.google.android.exoplayer2.testutil.FakeShuffleOrder;
import com.google.android.exoplayer2.testutil.FakeTimeline;
+import com.google.android.exoplayer2.util.Util;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -51,7 +52,10 @@ public class MediaSourceListTest {
@Before
public void setUp() {
mediaSourceList =
- new MediaSourceList(mock(MediaSourceList.MediaSourceListInfoRefreshListener.class));
+ new MediaSourceList(
+ mock(MediaSourceList.MediaSourceListInfoRefreshListener.class),
+ /* analyticsCollector= */ null,
+ Util.createHandlerForCurrentOrMainLooper());
}
@Test