Test setPlaybackParameters before preparation completes

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=176837939
This commit is contained in:
andrewlewis 2017-11-24 05:37:49 -08:00 committed by Oliver Woodman
parent de476ba4e6
commit 36255c42cf
4 changed files with 136 additions and 14 deletions

View File

@ -570,4 +570,48 @@ public final class ExoPlayerTest extends TestCase {
testRunner.assertPlayedPeriodIndices(0, 1, 0);
}
public void testSetPlaybackParametersBeforePreparationCompletesSucceeds() throws Exception {
// Test that no exception is thrown when playback parameters are updated between creating a
// period and preparation of the period completing.
final CountDownLatch createPeriodCalledCountDownLatch = new CountDownLatch(1);
final FakeMediaPeriod[] fakeMediaPeriodHolder = new FakeMediaPeriod[1];
MediaSource mediaSource =
new FakeMediaSource(new FakeTimeline(/* windowCount= */ 1), null, Builder.VIDEO_FORMAT) {
@Override
protected FakeMediaPeriod createFakeMediaPeriod(
MediaPeriodId id, TrackGroupArray trackGroupArray, Allocator allocator) {
// Defer completing preparation of the period until playback parameters have been set.
fakeMediaPeriodHolder[0] =
new FakeMediaPeriod(trackGroupArray, /* deferOnPrepared= */ true);
createPeriodCalledCountDownLatch.countDown();
return fakeMediaPeriodHolder[0];
}
};
ActionSchedule actionSchedule =
new ActionSchedule.Builder("testSetPlaybackParametersBeforePreparationCompletesSucceeds")
.waitForPlaybackState(Player.STATE_BUFFERING)
// Block until createPeriod has been called on the fake media source.
.executeRunnable(new Runnable() {
@Override
public void run() {
try {
createPeriodCalledCountDownLatch.await();
} catch (InterruptedException e) {
throw new IllegalStateException(e);
}
}
})
// Set playback parameters (while the fake media period is not yet prepared).
.setPlaybackParameters(new PlaybackParameters(2f, 2f))
// Complete preparation of the fake media period.
.executeRunnable(new Runnable() {
@Override
public void run() {
fakeMediaPeriodHolder[0].setPreparationComplete();
}
})
.build();
new ExoPlayerTestRunner.Builder().setMediaSource(mediaSource).setActionSchedule(actionSchedule)
.build().start().blockUntilEnded(TIMEOUT_MS);
}
}

View File

@ -19,6 +19,7 @@ import android.os.Handler;
import android.util.Log;
import android.view.Surface;
import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.PlaybackParameters;
import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.Timeline;
@ -303,6 +304,30 @@ public abstract class Action {
}
/**
* Calls {@link Player#setPlaybackParameters(PlaybackParameters)}.
*/
public static final class SetPlaybackParameters extends Action {
private final PlaybackParameters playbackParameters;
/**
* @param tag A tag to use for logging.
* @param playbackParameters The playback parameters.
*/
public SetPlaybackParameters(String tag, PlaybackParameters playbackParameters) {
super(tag, "SetPlaybackParameters:" + playbackParameters);
this.playbackParameters = playbackParameters;
}
@Override
protected void doActionImpl(SimpleExoPlayer player, MappingTrackSelector trackSelector,
Surface surface) {
player.setPlaybackParameters(playbackParameters);
}
}
/**
* Waits for {@link Player.EventListener#onTimelineChanged(Timeline, Object, int)}.
*/

View File

@ -19,6 +19,7 @@ import android.os.Handler;
import android.os.Looper;
import android.view.Surface;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.PlaybackParameters;
import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.Timeline;
@ -28,6 +29,7 @@ import com.google.android.exoplayer2.testutil.Action.ExecuteRunnable;
import com.google.android.exoplayer2.testutil.Action.PrepareSource;
import com.google.android.exoplayer2.testutil.Action.Seek;
import com.google.android.exoplayer2.testutil.Action.SetPlayWhenReady;
import com.google.android.exoplayer2.testutil.Action.SetPlaybackParameters;
import com.google.android.exoplayer2.testutil.Action.SetRendererDisabled;
import com.google.android.exoplayer2.testutil.Action.SetRepeatMode;
import com.google.android.exoplayer2.testutil.Action.SetShuffleModeEnabled;
@ -151,6 +153,17 @@ public final class ActionSchedule {
.apply(new WaitForPlaybackState(tag, Player.STATE_READY));
}
/**
* Schedules a playback parameters setting action to be executed.
*
* @param playbackParameters The playback parameters to set.
* @return The builder, for convenience.
* @see Player#setPlaybackParameters(PlaybackParameters)
*/
public Builder setPlaybackParameters(PlaybackParameters playbackParameters) {
return apply(new SetPlaybackParameters(tag, playbackParameters));
}
/**
* Schedules a stop action to be executed.
*

View File

@ -15,6 +15,8 @@
*/
package com.google.android.exoplayer2.testutil;
import android.os.Handler;
import android.support.annotation.Nullable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.source.MediaPeriod;
import com.google.android.exoplayer2.source.SampleStream;
@ -32,12 +34,30 @@ public class FakeMediaPeriod implements MediaPeriod {
private final TrackGroupArray trackGroupArray;
private boolean preparedPeriod;
@Nullable private Handler playerHandler;
@Nullable private Callback prepareCallback;
private boolean deferOnPrepared;
private boolean prepared;
private long seekOffsetUs;
private long discontinuityPositionUs;
/**
* @param trackGroupArray The track group array.
*/
public FakeMediaPeriod(TrackGroupArray trackGroupArray) {
this(trackGroupArray, false);
}
/**
* @param trackGroupArray The track group array.
* @param deferOnPrepared Whether {@link MediaPeriod.Callback#onPrepared(MediaPeriod)} should be
* called only after {@link #setPreparationComplete()} has been called. If {@code false}
* preparation completes immediately.
*/
public FakeMediaPeriod(TrackGroupArray trackGroupArray, boolean deferOnPrepared) {
this.trackGroupArray = trackGroupArray;
this.deferOnPrepared = deferOnPrepared;
discontinuityPositionUs = C.TIME_UNSET;
}
@ -51,6 +71,22 @@ public class FakeMediaPeriod implements MediaPeriod {
this.discontinuityPositionUs = discontinuityPositionUs;
}
/**
* Allows the fake media period to complete preparation. May be called on any thread.
*/
public synchronized void setPreparationComplete() {
deferOnPrepared = false;
if (playerHandler != null && prepareCallback != null) {
playerHandler.post(new Runnable() {
@Override
public void run() {
prepared = true;
prepareCallback.onPrepared(FakeMediaPeriod.this);
}
});
}
}
/**
* Sets an offset to be applied to positions returned by {@link #seekToUs(long)}.
*
@ -61,31 +97,35 @@ public class FakeMediaPeriod implements MediaPeriod {
}
public void release() {
preparedPeriod = false;
prepared = false;
}
@Override
public void prepare(Callback callback, long positionUs) {
Assert.assertFalse(preparedPeriod);
preparedPeriod = true;
callback.onPrepared(this);
public synchronized void prepare(Callback callback, long positionUs) {
if (deferOnPrepared) {
playerHandler = new Handler();
prepareCallback = callback;
} else {
prepared = true;
callback.onPrepared(this);
}
}
@Override
public void maybeThrowPrepareError() throws IOException {
Assert.assertTrue(preparedPeriod);
// Do nothing.
}
@Override
public TrackGroupArray getTrackGroups() {
Assert.assertTrue(preparedPeriod);
Assert.assertTrue(prepared);
return trackGroupArray;
}
@Override
public long selectTracks(TrackSelection[] selections, boolean[] mayRetainStreamFlags,
SampleStream[] streams, boolean[] streamResetFlags, long positionUs) {
Assert.assertTrue(preparedPeriod);
Assert.assertTrue(prepared);
int rendererCount = selections.length;
for (int i = 0; i < rendererCount; i++) {
if (streams[i] != null && (selections[i] == null || !mayRetainStreamFlags[i])) {
@ -113,7 +153,7 @@ public class FakeMediaPeriod implements MediaPeriod {
@Override
public long readDiscontinuity() {
Assert.assertTrue(preparedPeriod);
Assert.assertTrue(prepared);
long positionDiscontinuityUs = this.discontinuityPositionUs;
this.discontinuityPositionUs = C.TIME_UNSET;
return positionDiscontinuityUs;
@ -121,25 +161,25 @@ public class FakeMediaPeriod implements MediaPeriod {
@Override
public long getBufferedPositionUs() {
Assert.assertTrue(preparedPeriod);
Assert.assertTrue(prepared);
return C.TIME_END_OF_SOURCE;
}
@Override
public long seekToUs(long positionUs) {
Assert.assertTrue(preparedPeriod);
Assert.assertTrue(prepared);
return positionUs + seekOffsetUs;
}
@Override
public long getNextLoadPositionUs() {
Assert.assertTrue(preparedPeriod);
Assert.assertTrue(prepared);
return C.TIME_END_OF_SOURCE;
}
@Override
public boolean continueLoading(long positionUs) {
Assert.assertTrue(preparedPeriod);
Assert.assertTrue(prepared);
return false;
}