Simplify MediaSourceList setup and make class final.

The class was only non-final to allow mocking. Using the real class
in the test works equally well.

PiperOrigin-RevId: 317858805
This commit is contained in:
tonihei 2020-06-23 15:11:56 +01:00 committed by Christos Tsilopoulos
parent 093f9931b4
commit 9d8f54ab3a
4 changed files with 54 additions and 47 deletions

View File

@ -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) {

View File

@ -52,7 +52,7 @@ import java.util.Set;
*
* <p>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<MediaSourceHolder> holders, ShuffleOrder shuffleOrder) {
public Timeline setMediaSources(List<MediaSourceHolder> 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<MediaSourceHolder> 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} &lt; 0,
* {@code toIndex} &gt; {@link #getSize()}, {@code fromIndex} &gt; {@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} &lt; 0,
* {@code currentIndex} &gt;= {@link #getSize()}, {@code newIndex} &lt; 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;
}

View File

@ -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() {

View File

@ -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