use of com.google.android.exoplayer2.testutil.ActionSchedule.PlayerRunnable in project ExoPlayer by google.
the class ExoPlayerTest method setMediaSources_whenEmpty_invalidInitialSeek_correctMasking.
@Test
public void setMediaSources_whenEmpty_invalidInitialSeek_correctMasking() throws Exception {
final int[] currentMediaItemIndices = { C.INDEX_UNSET, C.INDEX_UNSET, C.INDEX_UNSET };
final long[] currentPositions = { C.TIME_UNSET, C.TIME_UNSET, C.TIME_UNSET };
final long[] bufferedPositions = { C.TIME_UNSET, C.TIME_UNSET, C.TIME_UNSET };
ActionSchedule actionSchedule = new ActionSchedule.Builder(TAG).waitForPositionDiscontinuity().waitForPendingPlayerCommands().executeRunnable(new PlayerRunnable() {
@Override
public void run(ExoPlayer player) {
currentMediaItemIndices[0] = player.getCurrentMediaItemIndex();
currentPositions[0] = player.getCurrentPosition();
bufferedPositions[0] = player.getBufferedPosition();
// Increase current media item index.
player.addMediaSource(/* index= */
0, new FakeMediaSource());
currentMediaItemIndices[1] = player.getCurrentMediaItemIndex();
currentPositions[1] = player.getCurrentPosition();
bufferedPositions[1] = player.getBufferedPosition();
}
}).prepare().waitForTimelineChanged().executeRunnable(new PlayerRunnable() {
@Override
public void run(ExoPlayer player) {
currentMediaItemIndices[2] = player.getCurrentMediaItemIndex();
currentPositions[2] = player.getCurrentPosition();
bufferedPositions[2] = player.getBufferedPosition();
}
}).waitForPlaybackState(Player.STATE_ENDED).build();
new ExoPlayerTestRunner.Builder(context).initialSeek(/* mediaItemIndex= */
1, 2000).setMediaSources(new FakeMediaSource()).setActionSchedule(actionSchedule).build().start(/* doPrepare= */
false).blockUntilActionScheduleFinished(TIMEOUT_MS).blockUntilEnded(TIMEOUT_MS);
assertArrayEquals(new int[] { 0, 1, 1 }, currentMediaItemIndices);
assertArrayEquals(new long[] { 0, 0, 0 }, currentPositions);
assertArrayEquals(new long[] { 0, 0, 0 }, bufferedPositions);
}
use of com.google.android.exoplayer2.testutil.ActionSchedule.PlayerRunnable in project ExoPlayer by google.
the class ExoPlayerTest method recursivePlayerChangesAreReportedInCorrectOrder.
@Test
public void recursivePlayerChangesAreReportedInCorrectOrder() throws Exception {
// The listener stops the player as soon as it's ready (which should report a timeline and state
// change) and sets playWhenReady to false when the timeline callback is received.
final AtomicReference<Player> playerReference = new AtomicReference<>();
final List<Boolean> playerListenerPlayWhenReady = new ArrayList<>();
final List<Integer> playerListenerStates = new ArrayList<>();
List<Integer> sequence = new ArrayList<>();
final Player.Listener playerListener = new Player.Listener() {
@Override
public void onPlaybackStateChanged(@Player.State int playbackState) {
playerListenerStates.add(playbackState);
if (playbackState == Player.STATE_READY) {
playerReference.get().stop(/* reset= */
true);
sequence.add(0);
}
}
@Override
public void onTimelineChanged(Timeline timeline, int reason) {
if (timeline.isEmpty()) {
playerReference.get().pause();
sequence.add(1);
}
}
@Override
public void onPlayWhenReadyChanged(boolean playWhenReady, @Player.PlayWhenReadyChangeReason int reason) {
playerListenerPlayWhenReady.add(playWhenReady);
sequence.add(2);
}
};
ActionSchedule actionSchedule = new ActionSchedule.Builder(TAG).executeRunnable(new PlayerRunnable() {
@Override
public void run(ExoPlayer player) {
playerReference.set(player);
player.addListener(playerListener);
}
}).build();
new ExoPlayerTestRunner.Builder(context).setActionSchedule(actionSchedule).build().start().blockUntilEnded(TIMEOUT_MS);
assertThat(playerListenerStates).containsExactly(Player.STATE_BUFFERING, Player.STATE_READY, Player.STATE_IDLE).inOrder();
assertThat(playerListenerPlayWhenReady).containsExactly(false).inOrder();
assertThat(sequence).containsExactly(0, 1, 2).inOrder();
}
use of com.google.android.exoplayer2.testutil.ActionSchedule.PlayerRunnable in project ExoPlayer by google.
the class ExoPlayerTest method invalidSeekFallsBackToSubsequentPeriodOfTheRemovedPeriod.
@Test
public void invalidSeekFallsBackToSubsequentPeriodOfTheRemovedPeriod() throws Exception {
Timeline timeline = new FakeTimeline();
CountDownLatch sourceReleasedCountDownLatch = new CountDownLatch(/* count= */
1);
MediaSource mediaSourceToRemove = new FakeMediaSource(timeline) {
@Override
protected void releaseSourceInternal() {
super.releaseSourceInternal();
sourceReleasedCountDownLatch.countDown();
}
};
ConcatenatingMediaSource mediaSource = new ConcatenatingMediaSource(mediaSourceToRemove, new FakeMediaSource(timeline));
final int[] windowCount = { C.INDEX_UNSET };
final long[] position = { C.TIME_UNSET };
ActionSchedule actionSchedule = new ActionSchedule.Builder(TAG).pause().waitForPlaybackState(Player.STATE_READY).executeRunnable(new PlayerRunnable() {
@Override
public void run(ExoPlayer player) {
mediaSource.removeMediaSource(/* index= */
0);
try {
// Wait until the source to be removed is released on the playback thread. So
// the timeline in EPII has one window only, but the update here in EPI is
// stuck until we finished our executable here. So when seeking below, we will
// seek in the timeline which still has two windows in EPI, but when the seek
// arrives in EPII the actual timeline has one window only. Hence it tries to
// find the subsequent period of the removed period and finds it.
player.getClock().onThreadBlocked();
sourceReleasedCountDownLatch.await();
} catch (InterruptedException e) {
throw new IllegalStateException(e);
}
player.seekTo(/* mediaItemIndex= */
0, /* positionMs= */
1000L);
}
}).waitForPendingPlayerCommands().executeRunnable(new PlayerRunnable() {
@Override
public void run(ExoPlayer player) {
windowCount[0] = player.getCurrentTimeline().getWindowCount();
position[0] = player.getCurrentPosition();
}
}).play().build();
new ExoPlayerTestRunner.Builder(context).setMediaSources(mediaSource).setActionSchedule(actionSchedule).build().start().blockUntilActionScheduleFinished(TIMEOUT_MS).blockUntilEnded(TIMEOUT_MS);
// Expect the first window to be the current.
assertThat(windowCount[0]).isEqualTo(1);
// Expect the position to be in the default position.
assertThat(position[0]).isEqualTo(0L);
}
use of com.google.android.exoplayer2.testutil.ActionSchedule.PlayerRunnable in project ExoPlayer by google.
the class ExoPlayerTest method illegalSeekPositionDoesThrow.
@Test
public void illegalSeekPositionDoesThrow() throws Exception {
final IllegalSeekPositionException[] exception = new IllegalSeekPositionException[1];
ActionSchedule actionSchedule = new ActionSchedule.Builder(TAG).waitForPlaybackState(Player.STATE_BUFFERING).executeRunnable(new PlayerRunnable() {
@Override
public void run(ExoPlayer player) {
try {
player.seekTo(/* mediaItemIndex= */
100, /* positionMs= */
0);
} catch (IllegalSeekPositionException e) {
exception[0] = e;
}
}
}).waitForPlaybackState(Player.STATE_ENDED).build();
new ExoPlayerTestRunner.Builder(context).setActionSchedule(actionSchedule).build().start().blockUntilActionScheduleFinished(TIMEOUT_MS).blockUntilEnded(TIMEOUT_MS);
assertThat(exception[0]).isNotNull();
}
use of com.google.android.exoplayer2.testutil.ActionSchedule.PlayerRunnable in project ExoPlayer by google.
the class ExoPlayerTest method errorThrownDuringPlaylistUpdate_keepsConsistentPlayerState.
@Test
public void errorThrownDuringPlaylistUpdate_keepsConsistentPlayerState() {
FakeMediaSource source1 = new FakeMediaSource(new FakeTimeline(), ExoPlayerTestRunner.VIDEO_FORMAT, ExoPlayerTestRunner.AUDIO_FORMAT);
FakeMediaSource source2 = new FakeMediaSource(new FakeTimeline(), ExoPlayerTestRunner.AUDIO_FORMAT);
AtomicInteger audioRendererEnableCount = new AtomicInteger(0);
FakeRenderer videoRenderer = new FakeRenderer(C.TRACK_TYPE_VIDEO);
FakeRenderer audioRenderer = new FakeRenderer(C.TRACK_TYPE_AUDIO) {
@Override
protected void onEnabled(boolean joining, boolean mayRenderStartOfStream) throws ExoPlaybackException {
if (audioRendererEnableCount.incrementAndGet() == 2) {
// Fail when enabling the renderer for the second time during the playlist update.
throw createRendererException(new IllegalStateException(), ExoPlayerTestRunner.AUDIO_FORMAT, PlaybackException.ERROR_CODE_UNSPECIFIED);
}
}
};
AtomicReference<Timeline> timelineAfterError = new AtomicReference<>();
AtomicReference<TracksInfo> trackInfosAfterError = new AtomicReference<>();
AtomicReference<TrackSelectionArray> trackSelectionsAfterError = new AtomicReference<>();
AtomicInteger mediaItemIndexAfterError = new AtomicInteger();
ActionSchedule actionSchedule = new ActionSchedule.Builder(TAG).executeRunnable(new PlayerRunnable() {
@Override
public void run(ExoPlayer player) {
player.addAnalyticsListener(new AnalyticsListener() {
@Override
public void onPlayerError(EventTime eventTime, PlaybackException error) {
timelineAfterError.set(player.getCurrentTimeline());
trackInfosAfterError.set(player.getCurrentTracksInfo());
trackSelectionsAfterError.set(player.getCurrentTrackSelections());
mediaItemIndexAfterError.set(player.getCurrentMediaItemIndex());
}
});
}
}).pause().waitForIsLoading(true).waitForIsLoading(false).removeMediaItem(0).build();
ExoPlayerTestRunner testRunner = new ExoPlayerTestRunner.Builder(context).setMediaSources(source1, source2).setActionSchedule(actionSchedule).setRenderers(videoRenderer, audioRenderer).build();
assertThrows(ExoPlaybackException.class, () -> testRunner.start(/* doPrepare= */
true).blockUntilActionScheduleFinished(TIMEOUT_MS).blockUntilEnded(TIMEOUT_MS));
assertThat(timelineAfterError.get().getWindowCount()).isEqualTo(1);
assertThat(mediaItemIndexAfterError.get()).isEqualTo(0);
assertThat(trackInfosAfterError.get().getTrackGroupInfos()).hasSize(1);
assertThat(trackInfosAfterError.get().getTrackGroupInfos().get(0).getTrackGroup().getFormat(0)).isEqualTo(ExoPlayerTestRunner.AUDIO_FORMAT);
// Video renderer.
assertThat(trackSelectionsAfterError.get().get(0)).isNull();
// Audio renderer.
assertThat(trackSelectionsAfterError.get().get(1)).isNotNull();
}
Aggregations