mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00:00
Fix flaky ExoPlayerTest tests.
Some tests were flaky because of the PlayUntilPosition action which called player.setPlayWhenReady from the wrong thread. Also fixed some other misc flakiness. ExoPlayerTest seems to be non-flaky now (tested with 10000 runs). ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=209743076
This commit is contained in:
parent
8927993b03
commit
bf43cca302
2 changed files with 30 additions and 22 deletions
|
|
@ -29,7 +29,6 @@ import com.google.android.exoplayer2.source.ConcatenatingMediaSource;
|
||||||
import com.google.android.exoplayer2.source.MediaSource;
|
import com.google.android.exoplayer2.source.MediaSource;
|
||||||
import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
|
import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
|
||||||
import com.google.android.exoplayer2.source.MediaSourceEventListener.EventDispatcher;
|
import com.google.android.exoplayer2.source.MediaSourceEventListener.EventDispatcher;
|
||||||
import com.google.android.exoplayer2.source.ShuffleOrder;
|
|
||||||
import com.google.android.exoplayer2.source.TrackGroup;
|
import com.google.android.exoplayer2.source.TrackGroup;
|
||||||
import com.google.android.exoplayer2.source.TrackGroupArray;
|
import com.google.android.exoplayer2.source.TrackGroupArray;
|
||||||
import com.google.android.exoplayer2.source.ads.AdPlaybackState;
|
import com.google.android.exoplayer2.source.ads.AdPlaybackState;
|
||||||
|
|
@ -1290,12 +1289,12 @@ public final class ExoPlayerTest {
|
||||||
@Test
|
@Test
|
||||||
public void testPlaybackErrorDuringSourceInfoRefreshWithShuffleModeEnabledUsesCorrectFirstPeriod()
|
public void testPlaybackErrorDuringSourceInfoRefreshWithShuffleModeEnabledUsesCorrectFirstPeriod()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
Timeline timeline = new FakeTimeline(/* windowCount= */ 1);
|
FakeMediaSource mediaSource =
|
||||||
FakeMediaSource mediaSource = new FakeMediaSource(/* timeline= */ null, /* manifest= */ null);
|
new FakeMediaSource(new FakeTimeline(/* windowCount= */ 1), /* manifest= */ null);
|
||||||
ConcatenatingMediaSource concatenatingMediaSource =
|
ConcatenatingMediaSource concatenatingMediaSource =
|
||||||
new ConcatenatingMediaSource(
|
new ConcatenatingMediaSource(
|
||||||
/* isAtomic= */ false, new FakeShuffleOrder(0), mediaSource, mediaSource);
|
/* isAtomic= */ false, new FakeShuffleOrder(0), mediaSource, mediaSource);
|
||||||
AtomicInteger windowIndexAfterReprepare = new AtomicInteger();
|
AtomicInteger windowIndexAfterError = new AtomicInteger();
|
||||||
ActionSchedule actionSchedule =
|
ActionSchedule actionSchedule =
|
||||||
new ActionSchedule.Builder("testPlaybackErrorDuringSourceInfoRefreshUsesCorrectFirstPeriod")
|
new ActionSchedule.Builder("testPlaybackErrorDuringSourceInfoRefreshUsesCorrectFirstPeriod")
|
||||||
.setShuffleModeEnabled(true)
|
.setShuffleModeEnabled(true)
|
||||||
|
|
@ -1304,17 +1303,12 @@ public final class ExoPlayerTest {
|
||||||
// is still being prepared. The error will be thrown while the player handles the new
|
// is still being prepared. The error will be thrown while the player handles the new
|
||||||
// source info.
|
// source info.
|
||||||
.seek(/* windowIndex= */ 100, /* positionMs= */ 0)
|
.seek(/* windowIndex= */ 100, /* positionMs= */ 0)
|
||||||
.executeRunnable(() -> mediaSource.setNewSourceInfo(timeline, /* newManifest= */ null))
|
|
||||||
.waitForPlaybackState(Player.STATE_IDLE)
|
.waitForPlaybackState(Player.STATE_IDLE)
|
||||||
// Re-prepare to play the source in its default shuffled order.
|
|
||||||
.prepareSource(
|
|
||||||
concatenatingMediaSource, /* resetPosition= */ false, /* resetState= */ false)
|
|
||||||
.waitForTimelineChanged(null)
|
|
||||||
.executeRunnable(
|
.executeRunnable(
|
||||||
new PlayerRunnable() {
|
new PlayerRunnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run(SimpleExoPlayer player) {
|
public void run(SimpleExoPlayer player) {
|
||||||
windowIndexAfterReprepare.set(player.getCurrentWindowIndex());
|
windowIndexAfterError.set(player.getCurrentWindowIndex());
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.build();
|
.build();
|
||||||
|
|
@ -1330,7 +1324,7 @@ public final class ExoPlayerTest {
|
||||||
// Expected exception.
|
// Expected exception.
|
||||||
assertThat(e.getUnexpectedException()).isInstanceOf(IllegalSeekPositionException.class);
|
assertThat(e.getUnexpectedException()).isInstanceOf(IllegalSeekPositionException.class);
|
||||||
}
|
}
|
||||||
assertThat(windowIndexAfterReprepare.get()).isEqualTo(1);
|
assertThat(windowIndexAfterError.get()).isEqualTo(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -2253,21 +2247,20 @@ public final class ExoPlayerTest {
|
||||||
@Test
|
@Test
|
||||||
public void testUpdateTrackSelectorThenSeekToUnpreparedPeriod_returnsEmptyTrackGroups()
|
public void testUpdateTrackSelectorThenSeekToUnpreparedPeriod_returnsEmptyTrackGroups()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
Timeline fakeTimeline = new FakeTimeline(/* windowCount= */ 1);
|
// Use unset duration to prevent pre-loading of the second window.
|
||||||
|
Timeline fakeTimeline =
|
||||||
|
new FakeTimeline(
|
||||||
|
new TimelineWindowDefinition(
|
||||||
|
/* isSeekable= */ true, /* isDynamic= */ false, /* durationUs= */ C.TIME_UNSET));
|
||||||
MediaSource[] fakeMediaSources = {
|
MediaSource[] fakeMediaSources = {
|
||||||
new FakeMediaSource(fakeTimeline, null, Builder.VIDEO_FORMAT),
|
new FakeMediaSource(fakeTimeline, null, Builder.VIDEO_FORMAT),
|
||||||
new FakeMediaSource(fakeTimeline, null, Builder.AUDIO_FORMAT)
|
new FakeMediaSource(fakeTimeline, null, Builder.AUDIO_FORMAT)
|
||||||
};
|
};
|
||||||
MediaSource mediaSource =
|
MediaSource mediaSource = new ConcatenatingMediaSource(fakeMediaSources);
|
||||||
new ConcatenatingMediaSource(
|
|
||||||
/* isAtomic= */ false,
|
|
||||||
/* useLazyPreparation= */ true,
|
|
||||||
new ShuffleOrder.DefaultShuffleOrder(0),
|
|
||||||
fakeMediaSources);
|
|
||||||
FakeRenderer renderer = new FakeRenderer(Builder.VIDEO_FORMAT);
|
FakeRenderer renderer = new FakeRenderer(Builder.VIDEO_FORMAT);
|
||||||
DefaultTrackSelector trackSelector = new DefaultTrackSelector();
|
DefaultTrackSelector trackSelector = new DefaultTrackSelector();
|
||||||
ActionSchedule actionSchedule =
|
ActionSchedule actionSchedule =
|
||||||
new ActionSchedule.Builder("testSendMessages")
|
new ActionSchedule.Builder("testUpdateTrackSelectorThenSeekToUnpreparedPeriod")
|
||||||
.pause()
|
.pause()
|
||||||
.waitForPlaybackState(Player.STATE_READY)
|
.waitForPlaybackState(Player.STATE_READY)
|
||||||
.seek(/* windowIndex= */ 1, /* positionMs= */ 0)
|
.seek(/* windowIndex= */ 1, /* positionMs= */ 0)
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ import com.google.android.exoplayer2.testutil.ActionSchedule.PlayerRunnable;
|
||||||
import com.google.android.exoplayer2.testutil.ActionSchedule.PlayerTarget;
|
import com.google.android.exoplayer2.testutil.ActionSchedule.PlayerTarget;
|
||||||
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
|
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
|
||||||
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector.Parameters;
|
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector.Parameters;
|
||||||
|
import com.google.android.exoplayer2.util.ConditionVariable;
|
||||||
import com.google.android.exoplayer2.util.HandlerWrapper;
|
import com.google.android.exoplayer2.util.HandlerWrapper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -503,10 +504,24 @@ public abstract class Action {
|
||||||
final Surface surface,
|
final Surface surface,
|
||||||
final HandlerWrapper handler,
|
final HandlerWrapper handler,
|
||||||
final ActionNode nextAction) {
|
final ActionNode nextAction) {
|
||||||
// Schedule one message on the playback thread to pause the player immediately.
|
Handler testThreadHandler = new Handler();
|
||||||
|
// Schedule a message on the playback thread to ensure the player is paused immediately.
|
||||||
player
|
player
|
||||||
.createMessage(
|
.createMessage(
|
||||||
(messageType, payload) -> player.setPlayWhenReady(/* playWhenReady= */ false))
|
(messageType, payload) -> {
|
||||||
|
// Block playback thread until pause command has been sent from test thread.
|
||||||
|
ConditionVariable blockPlaybackThreadCondition = new ConditionVariable();
|
||||||
|
testThreadHandler.post(
|
||||||
|
() -> {
|
||||||
|
player.setPlayWhenReady(/* playWhenReady= */ false);
|
||||||
|
blockPlaybackThreadCondition.open();
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
blockPlaybackThreadCondition.block();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
// Ignore.
|
||||||
|
}
|
||||||
|
})
|
||||||
.setPosition(windowIndex, positionMs)
|
.setPosition(windowIndex, positionMs)
|
||||||
.send();
|
.send();
|
||||||
// Schedule another message on this test thread to continue action schedule.
|
// Schedule another message on this test thread to continue action schedule.
|
||||||
|
|
@ -515,7 +530,7 @@ public abstract class Action {
|
||||||
(messageType, payload) ->
|
(messageType, payload) ->
|
||||||
nextAction.schedule(player, trackSelector, surface, handler))
|
nextAction.schedule(player, trackSelector, surface, handler))
|
||||||
.setPosition(windowIndex, positionMs)
|
.setPosition(windowIndex, positionMs)
|
||||||
.setHandler(new Handler())
|
.setHandler(testThreadHandler)
|
||||||
.send();
|
.send();
|
||||||
player.setPlayWhenReady(true);
|
player.setPlayWhenReady(true);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue