Add MediaSourceTestRunner for MediaSource tests.

- MediaSourceTestRunner aims to encapsulate some of the logic
  currently used in DynamicConcatenatingMediaSourceTest, so it
  can be re-used for testing other MediaSource implementations.
- The change also fixes DynamicConcatenatingMediaSourceTest to
  execute calls on the correct threads, and to release handler
  threads at the end of each test.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=176117535
This commit is contained in:
olly 2017-11-17 09:22:17 -08:00 committed by Oliver Woodman
parent 8455d10366
commit 676f3bfc49
5 changed files with 572 additions and 359 deletions

View file

@ -23,6 +23,7 @@ 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.testutil.MediaSourceTestRunner;
import com.google.android.exoplayer2.testutil.TestUtil;
import com.google.android.exoplayer2.testutil.TimelineAsserts;
import junit.framework.TestCase;
@ -32,6 +33,8 @@ import junit.framework.TestCase;
*/
public final class ConcatenatingMediaSourceTest extends TestCase {
private static final int TIMEOUT_MS = 10000;
public void testEmptyConcatenation() {
for (boolean atomic : new boolean[] {false, true}) {
Timeline timeline = getConcatenatedTimeline(atomic);
@ -208,18 +211,22 @@ public final class ConcatenatingMediaSourceTest extends TestCase {
ConcatenatingMediaSource mediaSource = new ConcatenatingMediaSource(mediaSourceContentOnly,
mediaSourceWithAds);
// Prepare and assert timeline contains ad groups.
Timeline timeline = TestUtil.extractTimelineFromMediaSource(mediaSource);
TimelineAsserts.assertAdGroupCounts(timeline, 0, 0, 1, 1);
MediaSourceTestRunner testRunner = new MediaSourceTestRunner(mediaSource, null, TIMEOUT_MS);
try {
Timeline timeline = testRunner.prepareSource();
TimelineAsserts.assertAdGroupCounts(timeline, 0, 0, 1, 1);
// Create all periods and assert period creation of child media sources has been called.
TimelineAsserts.assertAllPeriodsCanBeCreatedPreparedAndReleased(mediaSource, timeline, 10_000);
mediaSourceContentOnly.assertMediaPeriodCreated(new MediaPeriodId(0));
mediaSourceContentOnly.assertMediaPeriodCreated(new MediaPeriodId(1));
mediaSourceWithAds.assertMediaPeriodCreated(new MediaPeriodId(0));
mediaSourceWithAds.assertMediaPeriodCreated(new MediaPeriodId(1));
mediaSourceWithAds.assertMediaPeriodCreated(new MediaPeriodId(0, 0, 0));
mediaSourceWithAds.assertMediaPeriodCreated(new MediaPeriodId(1, 0, 0));
// Create all periods and assert period creation of child media sources has been called.
testRunner.assertPrepareAndReleaseAllPeriods();
mediaSourceContentOnly.assertMediaPeriodCreated(new MediaPeriodId(0));
mediaSourceContentOnly.assertMediaPeriodCreated(new MediaPeriodId(1));
mediaSourceWithAds.assertMediaPeriodCreated(new MediaPeriodId(0));
mediaSourceWithAds.assertMediaPeriodCreated(new MediaPeriodId(1));
mediaSourceWithAds.assertMediaPeriodCreated(new MediaPeriodId(0, 0, 0));
mediaSourceWithAds.assertMediaPeriodCreated(new MediaPeriodId(1, 0, 0));
} finally {
testRunner.release();
}
}
/**

View file

@ -20,19 +20,15 @@ import static org.mockito.Mockito.verify;
import android.os.ConditionVariable;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.source.MediaPeriod.Callback;
import com.google.android.exoplayer2.source.MediaSource.Listener;
import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
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.testutil.StubExoPlayer;
import com.google.android.exoplayer2.testutil.MediaSourceTestRunner;
import com.google.android.exoplayer2.testutil.TimelineAsserts;
import java.util.Arrays;
import junit.framework.TestCase;
@ -45,78 +41,84 @@ public final class DynamicConcatenatingMediaSourceTest extends TestCase {
private static final int TIMEOUT_MS = 10000;
private Timeline timeline;
private boolean timelineUpdated;
private boolean customRunnableCalled;
private DynamicConcatenatingMediaSource mediaSource;
private MediaSourceTestRunner testRunner;
public void testPlaylistChangesAfterPreparation() throws InterruptedException {
timeline = null;
FakeMediaSource[] childSources = createMediaSources(7);
DynamicConcatenatingMediaSource mediaSource = new DynamicConcatenatingMediaSource(
new FakeShuffleOrder(0));
prepareAndListenToTimelineUpdates(mediaSource);
assertNotNull(timeline);
waitForTimelineUpdate();
@Override
public void setUp() {
mediaSource = new DynamicConcatenatingMediaSource(new FakeShuffleOrder(0));
testRunner = new MediaSourceTestRunner(mediaSource, null, TIMEOUT_MS);
}
@Override
public void tearDown() {
testRunner.release();
}
public void testPlaylistChangesAfterPreparation() {
Timeline timeline = testRunner.prepareSource();
TimelineAsserts.assertEmpty(timeline);
FakeMediaSource[] childSources = createMediaSources(7);
// Add first source.
mediaSource.addMediaSource(childSources[0]);
waitForTimelineUpdate();
timeline = testRunner.assertTimelineChangeBlocking();
TimelineAsserts.assertPeriodCounts(timeline, 1);
TimelineAsserts.assertWindowIds(timeline, 111);
// Add at front of queue.
mediaSource.addMediaSource(0, childSources[1]);
waitForTimelineUpdate();
timeline = testRunner.assertTimelineChangeBlocking();
TimelineAsserts.assertPeriodCounts(timeline, 2, 1);
TimelineAsserts.assertWindowIds(timeline, 222, 111);
// Add at back of queue.
mediaSource.addMediaSource(childSources[2]);
waitForTimelineUpdate();
timeline = testRunner.assertTimelineChangeBlocking();
TimelineAsserts.assertPeriodCounts(timeline, 2, 1, 3);
TimelineAsserts.assertWindowIds(timeline, 222, 111, 333);
// Add in the middle.
mediaSource.addMediaSource(1, childSources[3]);
waitForTimelineUpdate();
timeline = testRunner.assertTimelineChangeBlocking();
TimelineAsserts.assertPeriodCounts(timeline, 2, 4, 1, 3);
TimelineAsserts.assertWindowIds(timeline, 222, 444, 111, 333);
// Add bulk.
mediaSource.addMediaSources(3, Arrays.asList((MediaSource) childSources[4],
(MediaSource) childSources[5], (MediaSource) childSources[6]));
waitForTimelineUpdate();
mediaSource.addMediaSources(3, Arrays.<MediaSource>asList(childSources[4], childSources[5],
childSources[6]));
timeline = testRunner.assertTimelineChangeBlocking();
TimelineAsserts.assertPeriodCounts(timeline, 2, 4, 1, 5, 6, 7, 3);
TimelineAsserts.assertWindowIds(timeline, 222, 444, 111, 555, 666, 777, 333);
// Move sources.
mediaSource.moveMediaSource(2, 3);
waitForTimelineUpdate();
timeline = testRunner.assertTimelineChangeBlocking();
TimelineAsserts.assertPeriodCounts(timeline, 2, 4, 5, 1, 6, 7, 3);
TimelineAsserts.assertWindowIds(timeline, 222, 444, 555, 111, 666, 777, 333);
mediaSource.moveMediaSource(3, 2);
waitForTimelineUpdate();
timeline = testRunner.assertTimelineChangeBlocking();
TimelineAsserts.assertPeriodCounts(timeline, 2, 4, 1, 5, 6, 7, 3);
TimelineAsserts.assertWindowIds(timeline, 222, 444, 111, 555, 666, 777, 333);
mediaSource.moveMediaSource(0, 6);
waitForTimelineUpdate();
timeline = testRunner.assertTimelineChangeBlocking();
TimelineAsserts.assertPeriodCounts(timeline, 4, 1, 5, 6, 7, 3, 2);
TimelineAsserts.assertWindowIds(timeline, 444, 111, 555, 666, 777, 333, 222);
mediaSource.moveMediaSource(6, 0);
waitForTimelineUpdate();
timeline = testRunner.assertTimelineChangeBlocking();
TimelineAsserts.assertPeriodCounts(timeline, 2, 4, 1, 5, 6, 7, 3);
TimelineAsserts.assertWindowIds(timeline, 222, 444, 111, 555, 666, 777, 333);
// Remove in the middle.
mediaSource.removeMediaSource(3);
waitForTimelineUpdate();
testRunner.assertTimelineChangeBlocking();
mediaSource.removeMediaSource(3);
waitForTimelineUpdate();
testRunner.assertTimelineChangeBlocking();
mediaSource.removeMediaSource(3);
waitForTimelineUpdate();
testRunner.assertTimelineChangeBlocking();
mediaSource.removeMediaSource(1);
waitForTimelineUpdate();
timeline = testRunner.assertTimelineChangeBlocking();
TimelineAsserts.assertPeriodCounts(timeline, 2, 1, 3);
TimelineAsserts.assertWindowIds(timeline, 222, 111, 333);
for (int i = 3; i <= 6; i++) {
@ -146,35 +148,31 @@ public final class DynamicConcatenatingMediaSourceTest extends TestCase {
assertEquals(0, timeline.getLastWindowIndex(true));
// Assert all periods can be prepared.
TimelineAsserts.assertAllPeriodsCanBeCreatedPreparedAndReleased(mediaSource, timeline,
TIMEOUT_MS);
testRunner.assertPrepareAndReleaseAllPeriods();
// Remove at front of queue.
mediaSource.removeMediaSource(0);
waitForTimelineUpdate();
timeline = testRunner.assertTimelineChangeBlocking();
TimelineAsserts.assertPeriodCounts(timeline, 1, 3);
TimelineAsserts.assertWindowIds(timeline, 111, 333);
childSources[1].assertReleased();
// Remove at back of queue.
mediaSource.removeMediaSource(1);
waitForTimelineUpdate();
timeline = testRunner.assertTimelineChangeBlocking();
TimelineAsserts.assertPeriodCounts(timeline, 1);
TimelineAsserts.assertWindowIds(timeline, 111);
childSources[2].assertReleased();
// Remove last source.
mediaSource.removeMediaSource(0);
waitForTimelineUpdate();
timeline = testRunner.assertTimelineChangeBlocking();
TimelineAsserts.assertEmpty(timeline);
childSources[3].assertReleased();
}
public void testPlaylistChangesBeforePreparation() throws InterruptedException {
timeline = null;
public void testPlaylistChangesBeforePreparation() {
FakeMediaSource[] childSources = createMediaSources(4);
DynamicConcatenatingMediaSource mediaSource = new DynamicConcatenatingMediaSource(
new FakeShuffleOrder(0));
mediaSource.addMediaSource(childSources[0]);
mediaSource.addMediaSource(childSources[1]);
mediaSource.addMediaSource(0, childSources[2]);
@ -182,11 +180,9 @@ public final class DynamicConcatenatingMediaSourceTest extends TestCase {
mediaSource.removeMediaSource(0);
mediaSource.moveMediaSource(1, 0);
mediaSource.addMediaSource(1, childSources[3]);
assertNull(timeline);
testRunner.assertNoTimelineChange();
prepareAndListenToTimelineUpdates(mediaSource);
waitForTimelineUpdate();
assertNotNull(timeline);
Timeline timeline = testRunner.prepareSource();
TimelineAsserts.assertPeriodCounts(timeline, 3, 4, 2);
TimelineAsserts.assertWindowIds(timeline, 333, 444, 222);
TimelineAsserts.assertNextWindowIndices(timeline, Player.REPEAT_MODE_OFF, false,
@ -198,98 +194,94 @@ public final class DynamicConcatenatingMediaSourceTest extends TestCase {
TimelineAsserts.assertPreviousWindowIndices(timeline, Player.REPEAT_MODE_OFF, true,
1, 2, C.INDEX_UNSET);
TimelineAsserts.assertAllPeriodsCanBeCreatedPreparedAndReleased(mediaSource, timeline,
TIMEOUT_MS);
testRunner.assertPrepareAndReleaseAllPeriods();
mediaSource.releaseSource();
for (int i = 1; i < 4; i++) {
childSources[i].assertReleased();
}
}
public void testPlaylistWithLazyMediaSource() throws InterruptedException {
timeline = null;
public void testPlaylistWithLazyMediaSource() {
// Create some normal (immediately preparing) sources and some lazy sources whose timeline
// updates need to be triggered.
FakeMediaSource[] fastSources = createMediaSources(2);
FakeMediaSource[] lazySources = new FakeMediaSource[4];
final FakeMediaSource[] lazySources = new FakeMediaSource[4];
for (int i = 0; i < 4; i++) {
lazySources[i] = new FakeMediaSource(null, null);
}
// Add lazy sources and normal sources before preparation. Also remove one lazy source again
// before preparation to check it doesn't throw or change the result.
DynamicConcatenatingMediaSource mediaSource = new DynamicConcatenatingMediaSource();
mediaSource.addMediaSource(lazySources[0]);
mediaSource.addMediaSource(0, fastSources[0]);
mediaSource.removeMediaSource(1);
mediaSource.addMediaSource(1, lazySources[1]);
assertNull(timeline);
testRunner.assertNoTimelineChange();
// Prepare and assert that the timeline contains all information for normal sources while having
// placeholder information for lazy sources.
prepareAndListenToTimelineUpdates(mediaSource);
waitForTimelineUpdate();
assertNotNull(timeline);
Timeline timeline = testRunner.prepareSource();
TimelineAsserts.assertPeriodCounts(timeline, 1, 1);
TimelineAsserts.assertWindowIds(timeline, 111, null);
TimelineAsserts.assertWindowIsDynamic(timeline, false, true);
// Trigger source info refresh for lazy source and check that the timeline now contains all
// information for all windows.
lazySources[1].setNewSourceInfo(createFakeTimeline(8), null);
waitForTimelineUpdate();
testRunner.runOnPlaybackThread(new Runnable() {
@Override
public void run() {
lazySources[1].setNewSourceInfo(createFakeTimeline(8), null);
}
});
timeline = testRunner.assertTimelineChange();
TimelineAsserts.assertPeriodCounts(timeline, 1, 9);
TimelineAsserts.assertWindowIds(timeline, 111, 999);
TimelineAsserts.assertWindowIsDynamic(timeline, false, false);
TimelineAsserts.assertAllPeriodsCanBeCreatedPreparedAndReleased(mediaSource, timeline,
TIMEOUT_MS);
testRunner.assertPrepareAndReleaseAllPeriods();
// Add further lazy and normal sources after preparation. Also remove one lazy source again to
// check it doesn't throw or change the result.
mediaSource.addMediaSource(1, lazySources[2]);
waitForTimelineUpdate();
testRunner.assertTimelineChangeBlocking();
mediaSource.addMediaSource(2, fastSources[1]);
waitForTimelineUpdate();
testRunner.assertTimelineChangeBlocking();
mediaSource.addMediaSource(0, lazySources[3]);
waitForTimelineUpdate();
testRunner.assertTimelineChangeBlocking();
mediaSource.removeMediaSource(2);
waitForTimelineUpdate();
timeline = testRunner.assertTimelineChangeBlocking();
TimelineAsserts.assertPeriodCounts(timeline, 1, 1, 2, 9);
TimelineAsserts.assertWindowIds(timeline, null, 111, 222, 999);
TimelineAsserts.assertWindowIsDynamic(timeline, true, false, false, false);
// Create a period from an unprepared lazy media source and assert Callback.onPrepared is not
// called yet.
MediaPeriod lazyPeriod = mediaSource.createPeriod(new MediaPeriodId(0), null);
assertNotNull(lazyPeriod);
final ConditionVariable lazyPeriodPrepared = new ConditionVariable();
lazyPeriod.prepare(new Callback() {
@Override
public void onPrepared(MediaPeriod mediaPeriod) {
lazyPeriodPrepared.open();
}
@Override
public void onContinueLoadingRequested(MediaPeriod source) {}
}, 0);
assertFalse(lazyPeriodPrepared.block(1));
MediaPeriod lazyPeriod = testRunner.createPeriod(new MediaPeriodId(0));
ConditionVariable preparedCondition = testRunner.preparePeriod(lazyPeriod, 0);
assertFalse(preparedCondition.block(1));
// Assert that a second period can also be created and released without problems.
MediaPeriod secondLazyPeriod = mediaSource.createPeriod(new MediaPeriodId(0), null);
assertNotNull(secondLazyPeriod);
mediaSource.releasePeriod(secondLazyPeriod);
MediaPeriod secondLazyPeriod = testRunner.createPeriod(new MediaPeriodId(0));
testRunner.releasePeriod(secondLazyPeriod);
// Trigger source info refresh for lazy media source. Assert that now all information is
// available again and the previously created period now also finished preparing.
lazySources[3].setNewSourceInfo(createFakeTimeline(7), null);
waitForTimelineUpdate();
testRunner.runOnPlaybackThread(new Runnable() {
@Override
public void run() {
lazySources[3].setNewSourceInfo(createFakeTimeline(7), null);
}
});
timeline = testRunner.assertTimelineChange();
TimelineAsserts.assertPeriodCounts(timeline, 8, 1, 2, 9);
TimelineAsserts.assertWindowIds(timeline, 888, 111, 222, 999);
TimelineAsserts.assertWindowIsDynamic(timeline, false, false, false, false);
assertTrue(lazyPeriodPrepared.block(TIMEOUT_MS));
mediaSource.releasePeriod(lazyPeriod);
assertTrue(preparedCondition.block(1));
// Release media source and assert all normal and lazy media sources are fully released as well.
mediaSource.releaseSource();
// Release the period and source.
testRunner.releasePeriod(lazyPeriod);
testRunner.releaseSource();
// Assert all sources were fully released.
for (FakeMediaSource fastSource : fastSources) {
fastSource.assertReleased();
}
@ -298,17 +290,12 @@ public final class DynamicConcatenatingMediaSourceTest extends TestCase {
}
}
public void testEmptyTimelineMediaSource() throws InterruptedException {
timeline = null;
DynamicConcatenatingMediaSource mediaSource = new DynamicConcatenatingMediaSource(
new FakeShuffleOrder(0));
prepareAndListenToTimelineUpdates(mediaSource);
assertNotNull(timeline);
waitForTimelineUpdate();
public void testEmptyTimelineMediaSource() {
Timeline timeline = testRunner.prepareSource();
TimelineAsserts.assertEmpty(timeline);
mediaSource.addMediaSource(new FakeMediaSource(Timeline.EMPTY, null));
waitForTimelineUpdate();
timeline = testRunner.assertTimelineChangeBlocking();
TimelineAsserts.assertEmpty(timeline);
mediaSource.addMediaSources(Arrays.asList(new MediaSource[] {
@ -316,18 +303,18 @@ public final class DynamicConcatenatingMediaSourceTest extends TestCase {
new FakeMediaSource(Timeline.EMPTY, null), new FakeMediaSource(Timeline.EMPTY, null),
new FakeMediaSource(Timeline.EMPTY, null), new FakeMediaSource(Timeline.EMPTY, null)
}));
waitForTimelineUpdate();
timeline = testRunner.assertTimelineChangeBlocking();
TimelineAsserts.assertEmpty(timeline);
// Insert non-empty media source to leave empty sources at the start, the end, and the middle
// (with single and multiple empty sources in a row).
MediaSource[] mediaSources = createMediaSources(3);
mediaSource.addMediaSource(1, mediaSources[0]);
waitForTimelineUpdate();
testRunner.assertTimelineChangeBlocking();
mediaSource.addMediaSource(4, mediaSources[1]);
waitForTimelineUpdate();
testRunner.assertTimelineChangeBlocking();
mediaSource.addMediaSource(6, mediaSources[2]);
waitForTimelineUpdate();
timeline = testRunner.assertTimelineChangeBlocking();
TimelineAsserts.assertWindowIds(timeline, 111, 222, 333);
TimelineAsserts.assertPeriodCounts(timeline, 1, 2, 3);
TimelineAsserts.assertPreviousWindowIndices(timeline, Player.REPEAT_MODE_OFF, false,
@ -350,12 +337,10 @@ public final class DynamicConcatenatingMediaSourceTest extends TestCase {
assertEquals(2, timeline.getLastWindowIndex(false));
assertEquals(2, timeline.getFirstWindowIndex(true));
assertEquals(0, timeline.getLastWindowIndex(true));
TimelineAsserts.assertAllPeriodsCanBeCreatedPreparedAndReleased(mediaSource, timeline,
TIMEOUT_MS);
testRunner.assertPrepareAndReleaseAllPeriods();
}
public void testIllegalArguments() {
DynamicConcatenatingMediaSource mediaSource = new DynamicConcatenatingMediaSource();
MediaSource validSource = new FakeMediaSource(createFakeTimeline(1), null);
// Null sources.
@ -394,7 +379,6 @@ public final class DynamicConcatenatingMediaSourceTest extends TestCase {
}
public void testCustomCallbackBeforePreparationAddSingle() {
DynamicConcatenatingMediaSource mediaSource = new DynamicConcatenatingMediaSource();
Runnable runnable = Mockito.mock(Runnable.class);
mediaSource.addMediaSource(createFakeMediaSource(), runnable);
@ -402,7 +386,6 @@ public final class DynamicConcatenatingMediaSourceTest extends TestCase {
}
public void testCustomCallbackBeforePreparationAddMultiple() {
DynamicConcatenatingMediaSource mediaSource = new DynamicConcatenatingMediaSource();
Runnable runnable = Mockito.mock(Runnable.class);
mediaSource.addMediaSources(Arrays.asList(
@ -411,7 +394,6 @@ public final class DynamicConcatenatingMediaSourceTest extends TestCase {
}
public void testCustomCallbackBeforePreparationAddSingleWithIndex() {
DynamicConcatenatingMediaSource mediaSource = new DynamicConcatenatingMediaSource();
Runnable runnable = Mockito.mock(Runnable.class);
mediaSource.addMediaSource(/* index */ 0, createFakeMediaSource(), runnable);
@ -419,134 +401,159 @@ public final class DynamicConcatenatingMediaSourceTest extends TestCase {
}
public void testCustomCallbackBeforePreparationAddMultipleWithIndex() {
DynamicConcatenatingMediaSource mediaSource = new DynamicConcatenatingMediaSource();
Runnable runnable = Mockito.mock(Runnable.class);
mediaSource.addMediaSources(/* index */ 0, Arrays.asList(
new MediaSource[]{createFakeMediaSource(), createFakeMediaSource()}), runnable);
mediaSource.addMediaSources(/* index */ 0,
Arrays.asList(new MediaSource[] {createFakeMediaSource(), createFakeMediaSource()}),
runnable);
verify(runnable).run();
}
public void testCustomCallbackBeforePreparationRemove() throws InterruptedException {
DynamicConcatenatingMediaSource mediaSource = new DynamicConcatenatingMediaSource();
public void testCustomCallbackBeforePreparationRemove() {
Runnable runnable = Mockito.mock(Runnable.class);
mediaSource.addMediaSource(createFakeMediaSource());
mediaSource.addMediaSource(createFakeMediaSource());
mediaSource.removeMediaSource(/* index */ 0, runnable);
verify(runnable).run();
}
public void testCustomCallbackBeforePreparationMove() throws InterruptedException {
DynamicConcatenatingMediaSource mediaSource = new DynamicConcatenatingMediaSource();
public void testCustomCallbackBeforePreparationMove() {
Runnable runnable = Mockito.mock(Runnable.class);
mediaSource.addMediaSources(Arrays.asList(
new MediaSource[]{createFakeMediaSource(), createFakeMediaSource()}));
mediaSource.addMediaSources(
Arrays.asList(new MediaSource[] {createFakeMediaSource(), createFakeMediaSource()}));
mediaSource.moveMediaSource(/* fromIndex */ 1, /* toIndex */ 0, runnable);
verify(runnable).run();
}
public void testCustomCallbackAfterPreparationAddSingle() throws InterruptedException {
final DynamicConcatenatingMediaSourceAndHandler sourceHandlerPair =
setUpDynamicMediaSourceOnHandlerThread();
final Runnable runnable = createCustomRunnable();
sourceHandlerPair.mainHandler.post(new Runnable() {
@Override
public void run() {
sourceHandlerPair.mediaSource.addMediaSource(createFakeMediaSource(), runnable);
}
});
waitForCustomRunnable();
public void testCustomCallbackAfterPreparationAddSingle() {
DummyMainThread dummyMainThread = new DummyMainThread();
try {
testRunner.prepareSource();
final TimelineGrabber timelineGrabber = new TimelineGrabber(testRunner);
dummyMainThread.runOnMainThread(new Runnable() {
@Override
public void run() {
mediaSource.addMediaSource(createFakeMediaSource(), timelineGrabber);
}
});
Timeline timeline = timelineGrabber.assertTimelineChangeBlocking();
assertEquals(1, timeline.getWindowCount());
} finally {
dummyMainThread.release();
}
}
public void testCustomCallbackAfterPreparationAddMultiple() throws InterruptedException {
final DynamicConcatenatingMediaSourceAndHandler sourceHandlerPair =
setUpDynamicMediaSourceOnHandlerThread();
final Runnable runnable = createCustomRunnable();
sourceHandlerPair.mainHandler.post(new Runnable() {
@Override
public void run() {
sourceHandlerPair.mediaSource.addMediaSources(Arrays.asList(
new MediaSource[] {createFakeMediaSource(), createFakeMediaSource()}), runnable);
}
});
waitForCustomRunnable();
public void testCustomCallbackAfterPreparationAddMultiple() {
DummyMainThread dummyMainThread = new DummyMainThread();
try {
testRunner.prepareSource();
final TimelineGrabber timelineGrabber = new TimelineGrabber(testRunner);
dummyMainThread.runOnMainThread(new Runnable() {
@Override
public void run() {
mediaSource.addMediaSources(
Arrays.asList(new MediaSource[] {createFakeMediaSource(), createFakeMediaSource()}),
timelineGrabber);
}
});
Timeline timeline = timelineGrabber.assertTimelineChangeBlocking();
assertEquals(2, timeline.getWindowCount());
} finally {
dummyMainThread.release();
}
}
public void testCustomCallbackAfterPreparationAddSingleWithIndex() throws InterruptedException {
final DynamicConcatenatingMediaSourceAndHandler sourceHandlerPair =
setUpDynamicMediaSourceOnHandlerThread();
final Runnable runnable = createCustomRunnable();
sourceHandlerPair.mainHandler.post(new Runnable() {
@Override
public void run() {
sourceHandlerPair.mediaSource.addMediaSource(/* index */ 0, createFakeMediaSource(),
runnable);
}
});
waitForCustomRunnable();
public void testCustomCallbackAfterPreparationAddSingleWithIndex() {
DummyMainThread dummyMainThread = new DummyMainThread();
try {
testRunner.prepareSource();
final TimelineGrabber timelineGrabber = new TimelineGrabber(testRunner);
dummyMainThread.runOnMainThread(new Runnable() {
@Override
public void run() {
mediaSource.addMediaSource(/* index */ 0, createFakeMediaSource(), timelineGrabber);
}
});
Timeline timeline = timelineGrabber.assertTimelineChangeBlocking();
assertEquals(1, timeline.getWindowCount());
} finally {
dummyMainThread.release();
}
}
public void testCustomCallbackAfterPreparationAddMultipleWithIndex() throws InterruptedException {
final DynamicConcatenatingMediaSourceAndHandler sourceHandlerPair =
setUpDynamicMediaSourceOnHandlerThread();
final Runnable runnable = createCustomRunnable();
sourceHandlerPair.mainHandler.post(new Runnable() {
@Override
public void run() {
sourceHandlerPair.mediaSource.addMediaSources(/* index */ 0, Arrays.asList(
new MediaSource[]{createFakeMediaSource(), createFakeMediaSource()}), runnable);
}
});
waitForCustomRunnable();
public void testCustomCallbackAfterPreparationAddMultipleWithIndex() {
DummyMainThread dummyMainThread = new DummyMainThread();
try {
testRunner.prepareSource();
final TimelineGrabber timelineGrabber = new TimelineGrabber(testRunner);
dummyMainThread.runOnMainThread(new Runnable() {
@Override
public void run() {
mediaSource.addMediaSources(/* index */ 0,
Arrays.asList(new MediaSource[] {createFakeMediaSource(), createFakeMediaSource()}),
timelineGrabber);
}
});
Timeline timeline = timelineGrabber.assertTimelineChangeBlocking();
assertEquals(2, timeline.getWindowCount());
} finally {
dummyMainThread.release();
}
}
public void testCustomCallbackAfterPreparationRemove() throws InterruptedException {
final DynamicConcatenatingMediaSourceAndHandler sourceHandlerPair =
setUpDynamicMediaSourceOnHandlerThread();
final Runnable runnable = createCustomRunnable();
sourceHandlerPair.mainHandler.post(new Runnable() {
@Override
public void run() {
sourceHandlerPair.mediaSource.addMediaSource(createFakeMediaSource());
}
});
waitForTimelineUpdate();
public void testCustomCallbackAfterPreparationRemove() {
DummyMainThread dummyMainThread = new DummyMainThread();
try {
testRunner.prepareSource();
dummyMainThread.runOnMainThread(new Runnable() {
@Override
public void run() {
mediaSource.addMediaSource(createFakeMediaSource());
}
});
testRunner.assertTimelineChangeBlocking();
sourceHandlerPair.mainHandler.post(new Runnable() {
@Override
public void run() {
sourceHandlerPair.mediaSource.removeMediaSource(/* index */ 0, runnable);
}
});
waitForCustomRunnable();
final TimelineGrabber timelineGrabber = new TimelineGrabber(testRunner);
dummyMainThread.runOnMainThread(new Runnable() {
@Override
public void run() {
mediaSource.removeMediaSource(/* index */ 0, timelineGrabber);
}
});
Timeline timeline = timelineGrabber.assertTimelineChangeBlocking();
assertEquals(0, timeline.getWindowCount());
} finally {
dummyMainThread.release();
}
}
public void testCustomCallbackAfterPreparationMove() throws InterruptedException {
final DynamicConcatenatingMediaSourceAndHandler sourceHandlerPair =
setUpDynamicMediaSourceOnHandlerThread();
final Runnable runnable = createCustomRunnable();
sourceHandlerPair.mainHandler.post(new Runnable() {
@Override
public void run() {
sourceHandlerPair.mediaSource.addMediaSources(Arrays.asList(
new MediaSource[]{createFakeMediaSource(), createFakeMediaSource()}));
}
});
waitForTimelineUpdate();
public void testCustomCallbackAfterPreparationMove() {
DummyMainThread dummyMainThread = new DummyMainThread();
try {
testRunner.prepareSource();
dummyMainThread.runOnMainThread(new Runnable() {
@Override
public void run() {
mediaSource.addMediaSources(Arrays.asList(
new MediaSource[] {createFakeMediaSource(), createFakeMediaSource()}));
}
});
testRunner.assertTimelineChangeBlocking();
sourceHandlerPair.mainHandler.post(new Runnable() {
@Override
public void run() {
sourceHandlerPair.mediaSource.moveMediaSource(/* fromIndex */ 1, /* toIndex */ 0,
runnable);
}
});
waitForCustomRunnable();
final TimelineGrabber timelineGrabber = new TimelineGrabber(testRunner);
dummyMainThread.runOnMainThread(new Runnable() {
@Override
public void run() {
mediaSource.moveMediaSource(/* fromIndex */ 1, /* toIndex */ 0,
timelineGrabber);
}
});
Timeline timeline = timelineGrabber.assertTimelineChangeBlocking();
assertEquals(2, timeline.getWindowCount());
} finally {
dummyMainThread.release();
}
}
public void testPeriodCreationWithAds() throws InterruptedException {
@ -557,19 +564,16 @@ public final class DynamicConcatenatingMediaSourceTest extends TestCase {
new TimelineWindowDefinition(2, 222, true, false, 10 * C.MICROS_PER_SECOND, 1, 1));
FakeMediaSource mediaSourceContentOnly = new FakeMediaSource(timelineContentOnly, null);
FakeMediaSource mediaSourceWithAds = new FakeMediaSource(timelineWithAds, null);
DynamicConcatenatingMediaSource mediaSource = new DynamicConcatenatingMediaSource();
mediaSource.addMediaSource(mediaSourceContentOnly);
mediaSource.addMediaSource(mediaSourceWithAds);
assertNull(timeline);
// Prepare and assert timeline contains ad groups.
prepareAndListenToTimelineUpdates(mediaSource);
waitForTimelineUpdate();
Timeline timeline = testRunner.prepareSource();
// Assert the timeline contains ad groups.
TimelineAsserts.assertAdGroupCounts(timeline, 0, 0, 1, 1);
// Create all periods and assert period creation of child media sources has been called.
TimelineAsserts.assertAllPeriodsCanBeCreatedPreparedAndReleased(mediaSource, timeline,
TIMEOUT_MS);
testRunner.assertPrepareAndReleaseAllPeriods();
mediaSourceContentOnly.assertMediaPeriodCreated(new MediaPeriodId(0));
mediaSourceContentOnly.assertMediaPeriodCreated(new MediaPeriodId(1));
mediaSourceWithAds.assertMediaPeriodCreated(new MediaPeriodId(0));
@ -578,66 +582,6 @@ public final class DynamicConcatenatingMediaSourceTest extends TestCase {
mediaSourceWithAds.assertMediaPeriodCreated(new MediaPeriodId(1, 0, 0));
}
private DynamicConcatenatingMediaSourceAndHandler setUpDynamicMediaSourceOnHandlerThread()
throws InterruptedException {
final DynamicConcatenatingMediaSource mediaSource = new DynamicConcatenatingMediaSource();
prepareAndListenToTimelineUpdates(mediaSource);
waitForTimelineUpdate();
HandlerThread handlerThread = new HandlerThread("TestCustomCallbackExecutionThread");
handlerThread.start();
Handler handler = new Handler(handlerThread.getLooper());
return new DynamicConcatenatingMediaSourceAndHandler(mediaSource, handler);
}
private void prepareAndListenToTimelineUpdates(MediaSource mediaSource) {
mediaSource.prepareSource(new MessageHandlingExoPlayer(), true, new Listener() {
@Override
public void onSourceInfoRefreshed(MediaSource source, Timeline newTimeline, Object manifest) {
timeline = newTimeline;
synchronized (DynamicConcatenatingMediaSourceTest.this) {
timelineUpdated = true;
DynamicConcatenatingMediaSourceTest.this.notify();
}
}
});
}
private synchronized void waitForTimelineUpdate() throws InterruptedException {
long deadlineMs = System.currentTimeMillis() + TIMEOUT_MS;
while (!timelineUpdated) {
wait(TIMEOUT_MS);
if (System.currentTimeMillis() >= deadlineMs) {
fail("No timeline update occurred within timeout.");
}
}
timelineUpdated = false;
}
private Runnable createCustomRunnable() {
return new Runnable() {
@Override
public void run() {
synchronized (DynamicConcatenatingMediaSourceTest.this) {
assertTrue(timelineUpdated);
timelineUpdated = false;
customRunnableCalled = true;
DynamicConcatenatingMediaSourceTest.this.notify();
}
}
};
}
private synchronized void waitForCustomRunnable() throws InterruptedException {
long deadlineMs = System.currentTimeMillis() + TIMEOUT_MS;
while (!customRunnableCalled) {
wait(TIMEOUT_MS);
if (System.currentTimeMillis() >= deadlineMs) {
fail("No custom runnable call occurred within timeout.");
}
}
customRunnableCalled = false;
}
private static FakeMediaSource[] createMediaSources(int count) {
FakeMediaSource[] sources = new FakeMediaSource[count];
for (int i = 0; i < count; i++) {
@ -654,48 +598,69 @@ public final class DynamicConcatenatingMediaSourceTest extends TestCase {
return new FakeTimeline(new TimelineWindowDefinition(index + 1, (index + 1) * 111));
}
private static class DynamicConcatenatingMediaSourceAndHandler {
private static final class DummyMainThread {
public final DynamicConcatenatingMediaSource mediaSource;
public final Handler mainHandler;
private final HandlerThread thread;
private final Handler handler;
public DynamicConcatenatingMediaSourceAndHandler(DynamicConcatenatingMediaSource mediaSource,
Handler mainHandler) {
this.mediaSource = mediaSource;
this.mainHandler = mainHandler;
private DummyMainThread() {
thread = new HandlerThread("DummyMainThread");
thread.start();
handler = new Handler(thread.getLooper());
}
/**
* Runs the provided {@link Runnable} on the main thread, blocking until execution completes.
*
* @param runnable The {@link Runnable} to run.
*/
public void runOnMainThread(final Runnable runnable) {
final ConditionVariable finishedCondition = new ConditionVariable();
handler.post(new Runnable() {
@Override
public void run() {
runnable.run();
finishedCondition.open();
}
});
assertTrue(finishedCondition.block(TIMEOUT_MS));
}
public void release() {
thread.quit();
}
}
/**
* ExoPlayer that only accepts custom messages and runs them on a separate handler thread.
*/
private static class MessageHandlingExoPlayer extends StubExoPlayer implements Handler.Callback {
private static final class TimelineGrabber implements Runnable {
private final Handler handler;
private final MediaSourceTestRunner testRunner;
private final ConditionVariable finishedCondition;
public MessageHandlingExoPlayer() {
HandlerThread handlerThread = new HandlerThread("StubExoPlayerThread");
handlerThread.start();
handler = new Handler(handlerThread.getLooper(), this);
private Timeline timeline;
private AssertionError error;
public TimelineGrabber(MediaSourceTestRunner testRunner) {
this.testRunner = testRunner;
finishedCondition = new ConditionVariable();
}
@Override
public void sendMessages(ExoPlayerMessage... messages) {
handler.obtainMessage(0, messages).sendToTarget();
}
@Override
public boolean handleMessage(Message msg) {
ExoPlayerMessage[] messages = (ExoPlayerMessage[]) msg.obj;
for (ExoPlayerMessage message : messages) {
try {
message.target.handleMessage(message.messageType, message.message);
} catch (ExoPlaybackException e) {
fail("Unexpected ExoPlaybackException.");
}
public void run() {
try {
timeline = testRunner.assertTimelineChange();
} catch (AssertionError e) {
error = e;
}
return true;
finishedCondition.open();
}
public Timeline assertTimelineChangeBlocking() {
assertTrue(finishedCondition.block(TIMEOUT_MS));
if (error != null) {
throw error;
}
return timeline;
}
}

View file

@ -0,0 +1,290 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.exoplayer2.testutil;
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertTrue;
import static junit.framework.Assert.fail;
import android.os.ConditionVariable;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.source.MediaPeriod;
import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
import com.google.android.exoplayer2.upstream.Allocator;
import com.google.android.exoplayer2.util.Assertions;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.TimeUnit;
/**
* A runner for {@link MediaSource} tests.
*/
public class MediaSourceTestRunner {
private final long timeoutMs;
private final StubExoPlayer player;
private final MediaSource mediaSource;
private final MediaSourceListener mediaSourceListener;
private final HandlerThread playbackThread;
private final Handler playbackHandler;
private final Allocator allocator;
private final LinkedBlockingDeque<Timeline> timelines;
private Timeline timeline;
/**
* @param mediaSource The source under test.
* @param allocator The allocator to use during the test run.
* @param timeoutMs The timeout for operations in milliseconds.
*/
public MediaSourceTestRunner(MediaSource mediaSource, Allocator allocator, long timeoutMs) {
this.mediaSource = mediaSource;
this.allocator = allocator;
this.timeoutMs = timeoutMs;
playbackThread = new HandlerThread("PlaybackThread");
playbackThread.start();
Looper playbackLooper = playbackThread.getLooper();
playbackHandler = new Handler(playbackLooper);
player = new EventHandlingExoPlayer(playbackLooper);
mediaSourceListener = new MediaSourceListener();
timelines = new LinkedBlockingDeque<>();
}
/**
* Runs the provided {@link Runnable} on the playback thread, blocking until execution completes.
*
* @param runnable The {@link Runnable} to run.
*/
public void runOnPlaybackThread(final Runnable runnable) {
final ConditionVariable finishedCondition = new ConditionVariable();
playbackHandler.post(new Runnable() {
@Override
public void run() {
runnable.run();
finishedCondition.open();
}
});
assertTrue(finishedCondition.block(timeoutMs));
}
/**
* Prepares the source on the playback thread, asserting that it provides an initial timeline.
*
* @return The initial {@link Timeline}.
*/
public Timeline prepareSource() {
runOnPlaybackThread(new Runnable() {
@Override
public void run() {
mediaSource.prepareSource(player, true, mediaSourceListener);
}
});
return assertTimelineChangeBlocking();
}
/**
* Calls {@link MediaSource#createPeriod(MediaSource.MediaPeriodId, Allocator)} on the playback
* thread, asserting that a non-null {@link MediaPeriod} is returned.
*
* @param periodId The id of the period to create.
* @return The created {@link MediaPeriod}.
*/
public MediaPeriod createPeriod(final MediaPeriodId periodId) {
final MediaPeriod[] holder = new MediaPeriod[1];
runOnPlaybackThread(new Runnable() {
@Override
public void run() {
holder[0] = mediaSource.createPeriod(periodId, allocator);
}
});
assertNotNull(holder[0]);
return holder[0];
}
/**
* Calls {@link MediaPeriod#prepare(MediaPeriod.Callback, long)} on the playback thread.
*
* @param mediaPeriod The {@link MediaPeriod} to prepare.
* @param positionUs The position at which to prepare.
* @return A {@link ConditionVariable} that will be opened when preparation completes.
*/
public ConditionVariable preparePeriod(final MediaPeriod mediaPeriod, final long positionUs) {
final ConditionVariable preparedCondition = new ConditionVariable();
runOnPlaybackThread(new Runnable() {
@Override
public void run() {
mediaPeriod.prepare(new MediaPeriod.Callback() {
@Override
public void onPrepared(MediaPeriod mediaPeriod) {
preparedCondition.open();
}
@Override
public void onContinueLoadingRequested(MediaPeriod source) {
// Do nothing.
}
}, positionUs);
}
});
return preparedCondition;
}
/**
* Calls {@link MediaSource#releasePeriod(MediaPeriod)} on the playback thread.
*
* @param mediaPeriod The {@link MediaPeriod} to release.
*/
public void releasePeriod(final MediaPeriod mediaPeriod) {
runOnPlaybackThread(new Runnable() {
@Override
public void run() {
mediaSource.releasePeriod(mediaPeriod);
}
});
}
/**
* Calls {@link MediaSource#releaseSource()} on the playback thread.
*/
public void releaseSource() {
runOnPlaybackThread(new Runnable() {
@Override
public void run() {
mediaSource.releaseSource();
}
});
}
/**
* Asserts that the source has not notified its listener of a timeline change since the last call
* to {@link #assertTimelineChangeBlocking()} or {@link #assertTimelineChange()} (or since the
* runner was created if neither method has been called).
*/
public void assertNoTimelineChange() {
assertTrue(timelines.isEmpty());
}
/**
* Asserts that the source has notified its listener of a single timeline change.
*
* @return The new {@link Timeline}.
*/
public Timeline assertTimelineChange() {
timeline = timelines.removeFirst();
assertNoTimelineChange();
return timeline;
}
/**
* Asserts that the source notifies its listener of a single timeline change. If the source has
* not yet notified its listener, it has up to the timeout passed to the constructor to do so.
*
* @return The new {@link Timeline}.
*/
public Timeline assertTimelineChangeBlocking() {
try {
timeline = timelines.poll(timeoutMs, TimeUnit.MILLISECONDS);
assertNotNull(timeline); // Null indicates the poll timed out.
assertNoTimelineChange();
return timeline;
} catch (InterruptedException e) {
// Should never happen.
throw new RuntimeException(e);
}
}
/**
* Creates and releases all periods (including ad periods) defined in the last timeline to be
* returned from {@link #prepareSource()}, {@link #assertTimelineChange()} or
* {@link #assertTimelineChangeBlocking()}.
*/
public void assertPrepareAndReleaseAllPeriods() {
Timeline.Period period = new Timeline.Period();
for (int i = 0; i < timeline.getPeriodCount(); i++) {
assertPrepareAndReleasePeriod(new MediaPeriodId(i));
timeline.getPeriod(i, period);
for (int adGroupIndex = 0; adGroupIndex < period.getAdGroupCount(); adGroupIndex++) {
for (int adIndex = 0; adIndex < period.getAdCountInAdGroup(adGroupIndex); adIndex++) {
assertPrepareAndReleasePeriod(new MediaPeriodId(i, adGroupIndex, adIndex));
}
}
}
}
private void assertPrepareAndReleasePeriod(MediaPeriodId mediaPeriodId) {
MediaPeriod mediaPeriod = createPeriod(mediaPeriodId);
ConditionVariable preparedCondition = preparePeriod(mediaPeriod, 0);
assertTrue(preparedCondition.block(timeoutMs));
// MediaSource is supposed to support multiple calls to createPeriod with the same id without an
// intervening call to releasePeriod.
MediaPeriod secondMediaPeriod = createPeriod(mediaPeriodId);
ConditionVariable secondPreparedCondition = preparePeriod(secondMediaPeriod, 0);
assertTrue(secondPreparedCondition.block(timeoutMs));
// Release the periods.
releasePeriod(mediaPeriod);
releasePeriod(secondMediaPeriod);
}
/**
* Releases the runner. Should be called when the runner is no longer required.
*/
public void release() {
playbackThread.quit();
}
private class MediaSourceListener implements MediaSource.Listener {
@Override
public void onSourceInfoRefreshed(MediaSource source, Timeline timeline, Object manifest) {
Assertions.checkState(Looper.myLooper() == playbackThread.getLooper());
timelines.addLast(timeline);
}
}
private static class EventHandlingExoPlayer extends StubExoPlayer implements Handler.Callback {
private final Handler handler;
public EventHandlingExoPlayer(Looper looper) {
this.handler = new Handler(looper, this);
}
@Override
public void sendMessages(ExoPlayerMessage... messages) {
handler.obtainMessage(0, messages).sendToTarget();
}
@Override
public boolean handleMessage(Message msg) {
ExoPlayerMessage[] messages = (ExoPlayerMessage[]) msg.obj;
for (ExoPlayerMessage message : messages) {
try {
message.target.handleMessage(message.messageType, message.message);
} catch (ExoPlaybackException e) {
fail("Unexpected ExoPlaybackException.");
}
}
return true;
}
}
}

View file

@ -146,6 +146,7 @@ public class TestUtil {
/**
* Extracts the timeline from a media source.
*/
// TODO: Remove this method and transition callers over to MediaSourceTestRunner.
public static Timeline extractTimelineFromMediaSource(MediaSource mediaSource) {
class TimelineListener implements Listener {
private Timeline timeline;

View file

@ -16,19 +16,11 @@
package com.google.android.exoplayer2.testutil;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertTrue;
import android.os.ConditionVariable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.Timeline.Period;
import com.google.android.exoplayer2.Timeline.Window;
import com.google.android.exoplayer2.source.MediaPeriod;
import com.google.android.exoplayer2.source.MediaPeriod.Callback;
import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
/**
* Unit test for {@link Timeline}.
@ -157,46 +149,4 @@ public final class TimelineAsserts {
}
}
/**
* Asserts that all period (including ad periods) can be created from the source, prepared, and
* released without exception and within timeout.
*/
public static void assertAllPeriodsCanBeCreatedPreparedAndReleased(MediaSource mediaSource,
Timeline timeline, long timeoutMs) {
Period period = new Period();
for (int i = 0; i < timeline.getPeriodCount(); i++) {
assertPeriodCanBeCreatedPreparedAndReleased(mediaSource, new MediaPeriodId(i), timeoutMs);
timeline.getPeriod(i, period);
for (int adGroupIndex = 0; adGroupIndex < period.getAdGroupCount(); adGroupIndex++) {
for (int adIndex = 0; adIndex < period.getAdCountInAdGroup(adGroupIndex); adIndex++) {
assertPeriodCanBeCreatedPreparedAndReleased(mediaSource,
new MediaPeriodId(i, adGroupIndex, adIndex), timeoutMs);
}
}
}
}
private static void assertPeriodCanBeCreatedPreparedAndReleased(MediaSource mediaSource,
MediaPeriodId mediaPeriodId, long timeoutMs) {
MediaPeriod mediaPeriod = mediaSource.createPeriod(mediaPeriodId, null);
assertNotNull(mediaPeriod);
final ConditionVariable mediaPeriodPrepared = new ConditionVariable();
mediaPeriod.prepare(new Callback() {
@Override
public void onPrepared(MediaPeriod mediaPeriod) {
mediaPeriodPrepared.open();
}
@Override
public void onContinueLoadingRequested(MediaPeriod source) {}
}, /* positionUs= */ 0);
assertTrue(mediaPeriodPrepared.block(timeoutMs));
// MediaSource is supposed to support multiple calls to createPeriod with the same id without an
// intervening call to releasePeriod.
MediaPeriod secondMediaPeriod = mediaSource.createPeriod(mediaPeriodId, null);
assertNotNull(secondMediaPeriod);
mediaSource.releasePeriod(secondMediaPeriod);
mediaSource.releasePeriod(mediaPeriod);
}
}