Media2 tests: Simplify code

- Use ExoPlayer DataSource instrumentation to intercept reads
- Use ExoPlayer Resource URIs
- Use ExoPlayer DefaultMediaSourceFactory

PiperOrigin-RevId: 326912324
This commit is contained in:
olly 2020-08-16 18:50:34 +01:00 committed by kim-vde
parent 94b66f4c24
commit 42cf213aea
7 changed files with 207 additions and 286 deletions

View file

@ -58,7 +58,7 @@ public class MediaSessionUtilTest {
SessionPlayerConnector sessionPlayerConnector = playerTestRule.getSessionPlayerConnector();
MediaSession.SessionCallback sessionCallback =
new SessionCallbackBuilder(context, sessionPlayerConnector).build();
TestUtils.loadResource(context, R.raw.audio, sessionPlayerConnector);
TestUtils.loadResource(R.raw.audio, sessionPlayerConnector);
ListenableFuture<PlayerResult> prepareResult = sessionPlayerConnector.prepare();
CountDownLatch latch = new CountDownLatch(1);
sessionPlayerConnector.registerPlayerCallback(

View file

@ -27,7 +27,8 @@ import com.google.android.exoplayer2.ext.media2.test.R;
import com.google.android.exoplayer2.util.Util;
/** Stub activity to play media contents on. */
public class MediaStubActivity extends Activity {
public final class MediaStubActivity extends Activity {
private static final String TAG = "MediaStubActivity";
@Override

View file

@ -17,22 +17,41 @@
package com.google.android.exoplayer2.ext.media2;
import android.content.Context;
import android.media.AudioManager;
import android.net.Uri;
import android.os.Looper;
import androidx.annotation.Nullable;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.platform.app.InstrumentationRegistry;
import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.source.DefaultMediaSourceFactory;
import com.google.android.exoplayer2.upstream.DataSource;
import com.google.android.exoplayer2.upstream.DataSpec;
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
import com.google.android.exoplayer2.upstream.TransferListener;
import com.google.android.exoplayer2.util.Util;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.junit.rules.ExternalResource;
/** Rule for tests that use {@link SessionPlayerConnector}. */
public class PlayerTestRule extends ExternalResource {
/* package */ final class PlayerTestRule extends ExternalResource {
/** Instrumentation to attach to {@link DataSource} instances used by the player. */
public interface DataSourceInstrumentation {
/** Called at the start of {@link DataSource#open}. */
void onPreOpen(DataSpec dataSpec);
}
private Context context;
private ExecutorService executor;
private SessionPlayerConnector sessionPlayerConnector;
private SimpleExoPlayer exoPlayer;
@Nullable private DataSourceInstrumentation dataSourceInstrumentation;
@Override
protected void before() {
@ -48,15 +67,15 @@ public class PlayerTestRule extends ExternalResource {
// Without posting this, audio focus listeners wouldn't be called because the
// listeners would be posted to the test thread (here) where it waits until the
// tests are finished.
AudioManager audioManager =
(AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
context.getSystemService(Context.AUDIO_SERVICE);
DefaultMediaItemConverter converter = new DefaultMediaItemConverter(context);
DataSource.Factory dataSourceFactory = new InstrumentingDataSourceFactory(context);
exoPlayer =
new SimpleExoPlayer.Builder(context)
.setLooper(Looper.myLooper())
.setMediaSourceFactory(converter)
.setMediaSourceFactory(new DefaultMediaSourceFactory(dataSourceFactory, null))
.build();
DefaultMediaItemConverter converter = new DefaultMediaItemConverter(context);
sessionPlayerConnector = new SessionPlayerConnector(exoPlayer, converter);
});
}
@ -81,6 +100,11 @@ public class PlayerTestRule extends ExternalResource {
}
}
public void setDataSourceInstrumentation(
@Nullable DataSourceInstrumentation dataSourceInstrumentation) {
this.dataSourceInstrumentation = dataSourceInstrumentation;
}
public ExecutorService getExecutor() {
return executor;
}
@ -92,4 +116,66 @@ public class PlayerTestRule extends ExternalResource {
public SimpleExoPlayer getSimpleExoPlayer() {
return exoPlayer;
}
private final class InstrumentingDataSourceFactory implements DataSource.Factory {
private final DefaultDataSourceFactory defaultDataSourceFactory;
public InstrumentingDataSourceFactory(Context context) {
defaultDataSourceFactory =
new DefaultDataSourceFactory(context, Util.getUserAgent(context, "media2-test"));
}
@Override
public DataSource createDataSource() {
DataSource dataSource = defaultDataSourceFactory.createDataSource();
return dataSourceInstrumentation == null
? dataSource
: new InstrumentedDataSource(dataSource, dataSourceInstrumentation);
}
}
private static final class InstrumentedDataSource implements DataSource {
private final DataSource wrappedDataSource;
private final DataSourceInstrumentation instrumentation;
public InstrumentedDataSource(
DataSource wrappedDataSource, DataSourceInstrumentation instrumentation) {
this.wrappedDataSource = wrappedDataSource;
this.instrumentation = instrumentation;
}
@Override
public void addTransferListener(TransferListener transferListener) {
wrappedDataSource.addTransferListener(transferListener);
}
@Override
public long open(DataSpec dataSpec) throws IOException {
instrumentation.onPreOpen(dataSpec);
return wrappedDataSource.open(dataSpec);
}
@Nullable
@Override
public Uri getUri() {
return wrappedDataSource.getUri();
}
@Override
public Map<String, List<String>> getResponseHeaders() {
return wrappedDataSource.getResponseHeaders();
}
@Override
public int read(byte[] target, int offset, int length) throws IOException {
return wrappedDataSource.read(target, offset, length);
}
@Override
public void close() throws IOException {
wrappedDataSource.close();
}
}
}

View file

@ -28,8 +28,6 @@ import android.text.TextUtils;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import androidx.media2.common.CallbackMediaItem;
import androidx.media2.common.DataSourceCallback;
import androidx.media2.common.MediaItem;
import androidx.media2.common.Rating;
import androidx.media2.common.SessionPlayer;
@ -47,6 +45,7 @@ import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.rule.ActivityTestRule;
import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.ext.media2.test.R;
import com.google.android.exoplayer2.upstream.RawResourceDataSource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@ -99,8 +98,7 @@ public class SessionCallbackBuilderTest {
createMediaSession(
sessionPlayerConnector,
new SessionCallbackBuilder(context, sessionPlayerConnector).build())) {
assertPlayerResultSuccess(
sessionPlayerConnector.setMediaItem(TestUtils.createMediaItem(context)));
assertPlayerResultSuccess(sessionPlayerConnector.setMediaItem(TestUtils.createMediaItem()));
assertPlayerResultSuccess(sessionPlayerConnector.prepare());
OnConnectedListener listener =
@ -140,8 +138,7 @@ public class SessionCallbackBuilderTest {
.setFastForwardIncrementMs(testFastForwardIncrementMs)
.setMediaItemProvider(new SessionCallbackBuilder.DefaultMediaItemProvider())
.build())) {
assertPlayerResultSuccess(
sessionPlayerConnector.setMediaItem(TestUtils.createMediaItem(context)));
assertPlayerResultSuccess(sessionPlayerConnector.setMediaItem(TestUtils.createMediaItem()));
assertPlayerResultSuccess(sessionPlayerConnector.prepare());
CountDownLatch latch = new CountDownLatch(1);
@ -168,8 +165,8 @@ public class SessionCallbackBuilderTest {
@Test
public void allowedCommand_whenPlaylistSet_allowsSkipTo() throws Exception {
List<MediaItem> testPlaylist = new ArrayList<>();
testPlaylist.add(TestUtils.createMediaItem(context, R.raw.video_desks));
testPlaylist.add(TestUtils.createMediaItem(context, R.raw.video_not_seekable));
testPlaylist.add(TestUtils.createMediaItem(R.raw.video_desks));
testPlaylist.add(TestUtils.createMediaItem(R.raw.video_not_seekable));
int testRewindIncrementMs = 100;
int testFastForwardIncrementMs = 100;
@ -238,36 +235,22 @@ public class SessionCallbackBuilderTest {
public void allowedCommand_afterCurrentMediaItemPrepared_notifiesSeekToAvailable()
throws Exception {
List<MediaItem> testPlaylist = new ArrayList<>();
testPlaylist.add(TestUtils.createMediaItem(context));
testPlaylist.add(TestUtils.createMediaItem(R.raw.video_desks));
UriMediaItem secondPlaylistItem = TestUtils.createMediaItem(R.raw.video_big_buck_bunny);
testPlaylist.add(secondPlaylistItem);
int resid = R.raw.video_big_buck_bunny;
TestDataSourceCallback source =
TestDataSourceCallback.fromAssetFd(context.getResources().openRawResourceFd(resid));
CountDownLatch readAllowedLatch = new CountDownLatch(1);
DataSourceCallback dataSource =
new DataSourceCallback() {
@Override
public int readAt(long position, byte[] buffer, int offset, int size) {
playerTestRule.setDataSourceInstrumentation(
dataSpec -> {
if (dataSpec.uri.equals(secondPlaylistItem.getUri())) {
try {
assertThat(readAllowedLatch.await(PLAYER_STATE_CHANGE_WAIT_TIME_MS, MILLISECONDS))
.isTrue();
} catch (Exception e) {
assertWithMessage("Unexpected exception %s", e).fail();
}
return source.readAt(position, buffer, offset, size);
}
@Override
public long getSize() {
return source.getSize();
}
@Override
public void close() {
source.close();
}
};
testPlaylist.add(new CallbackMediaItem.Builder(dataSource).build());
});
try (MediaSession session =
createMediaSession(
@ -388,7 +371,7 @@ public class SessionCallbackBuilderTest {
int testSeekPosition = 2_000;
int testRewindIncrementMs = 500;
TestUtils.loadResource(context, testResId, sessionPlayerConnector);
TestUtils.loadResource(testResId, sessionPlayerConnector);
// seekTo() sometimes takes couple of seconds. Disable default timeout behavior.
try (MediaSession session =
@ -432,7 +415,7 @@ public class SessionCallbackBuilderTest {
int testSeekPosition = 2_000;
int testFastForwardIncrementMs = 300;
TestUtils.loadResource(context, testResId, sessionPlayerConnector);
TestUtils.loadResource(testResId, sessionPlayerConnector);
// seekTo() sometimes takes couple of seconds. Disable default timeout behavior.
try (MediaSession session =
@ -469,15 +452,14 @@ public class SessionCallbackBuilderTest {
@Test
public void setMediaItemProvider_withMediaItemProvider_receivesOnCreateMediaItem()
throws Exception {
int testResId = R.raw.audio;
Uri testMediaIdUri = TestUtils.createResourceUri(context, testResId);
Uri testMediaUri = RawResourceDataSource.buildRawResourceUri(R.raw.audio);
CountDownLatch providerLatch = new CountDownLatch(1);
SessionCallbackBuilder.DefaultMediaItemProvider defaultMediaItemProvider =
new SessionCallbackBuilder.DefaultMediaItemProvider();
SessionCallbackBuilder.MediaItemProvider provider =
(session, controllerInfo, mediaId) -> {
assertThat(mediaId).isEqualTo(testMediaIdUri.toString());
assertThat(mediaId).isEqualTo(testMediaUri.toString());
providerLatch.countDown();
return defaultMediaItemProvider.onCreateMediaItem(session, controllerInfo, mediaId);
};
@ -489,7 +471,7 @@ public class SessionCallbackBuilderTest {
@Override
public void onCurrentMediaItemChanged(
@NonNull SessionPlayer player, @NonNull MediaItem item) {
assertThat(((UriMediaItem) item).getUri()).isEqualTo(testMediaIdUri);
assertThat(((UriMediaItem) item).getUri()).isEqualTo(testMediaUri);
currentMediaItemChangedLatch.countDown();
}
});
@ -502,7 +484,7 @@ public class SessionCallbackBuilderTest {
.build())) {
try (MediaController controller = createConnectedController(session)) {
assertSessionResultSuccess(
controller.setMediaItem(testMediaIdUri.toString()),
controller.setMediaItem(testMediaUri.toString()),
PLAYER_STATE_CHANGE_OVER_SESSION_WAIT_TIME_MS);
assertThat(providerLatch.await(0, MILLISECONDS)).isTrue();
assertThat(

View file

@ -27,15 +27,13 @@ import static com.google.common.truth.Truth.assertWithMessage;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import android.content.Context;
import android.content.res.Resources;
import android.media.AudioManager;
import android.os.Build;
import android.os.Build.VERSION_CODES;
import android.os.Looper;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.media.AudioAttributesCompat;
import androidx.media2.common.CallbackMediaItem;
import androidx.media2.common.DataSourceCallback;
import androidx.media2.common.MediaItem;
import androidx.media2.common.MediaMetadata;
import androidx.media2.common.SessionPlayer;
@ -54,8 +52,8 @@ import com.google.android.exoplayer2.DefaultControlDispatcher;
import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.ext.media2.test.R;
import com.google.android.exoplayer2.upstream.RawResourceDataSource;
import com.google.common.util.concurrent.ListenableFuture;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@ -84,14 +82,12 @@ public class SessionPlayerConnectorTest {
private static final float FLOAT_TOLERANCE = .0001f;
private Context context;
private Resources resources;
private Executor executor;
private SessionPlayerConnector sessionPlayerConnector;
@Before
public void setUp() {
context = ApplicationProvider.getApplicationContext();
resources = context.getResources();
executor = playerTestRule.getExecutor();
sessionPlayerConnector = playerTestRule.getSessionPlayerConnector();
@ -110,7 +106,7 @@ public class SessionPlayerConnectorTest {
@LargeTest
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT)
public void play_onceWithAudioResource_changesPlayerStateToPlaying() throws Exception {
TestUtils.loadResource(context, R.raw.audio, sessionPlayerConnector);
TestUtils.loadResource(R.raw.audio, sessionPlayerConnector);
AudioAttributesCompat attributes =
new AudioAttributesCompat.Builder().setLegacyStreamType(AudioManager.STREAM_MUSIC).build();
@ -144,7 +140,7 @@ public class SessionPlayerConnectorTest {
.runOnMainSync(
() -> {
try {
TestUtils.loadResource(context, R.raw.audio, sessionPlayerConnector);
TestUtils.loadResource(R.raw.audio, sessionPlayerConnector);
} catch (Exception e) {
assertWithMessage(e.getMessage()).fail();
}
@ -193,7 +189,6 @@ public class SessionPlayerConnectorTest {
simpleExoPlayer =
new SimpleExoPlayer.Builder(context)
.setLooper(Looper.myLooper())
.setMediaSourceFactory(converter)
.build();
try (SessionPlayerConnector player =
new SessionPlayerConnector(simpleExoPlayer, converter, controlDispatcher)) {
@ -210,7 +205,7 @@ public class SessionPlayerConnectorTest {
@LargeTest
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT)
public void setMediaItem_withAudioResource_notifiesOnPlaybackCompleted() throws Exception {
TestUtils.loadResource(context, R.raw.audio, sessionPlayerConnector);
TestUtils.loadResource(R.raw.audio, sessionPlayerConnector);
CountDownLatch onPlaybackCompletedLatch = new CountDownLatch(1);
sessionPlayerConnector.registerPlayerCallback(
@ -235,7 +230,7 @@ public class SessionPlayerConnectorTest {
@LargeTest
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT)
public void setMediaItem_withVideoResource_notifiesOnPlaybackCompleted() throws Exception {
TestUtils.loadResource(context, R.raw.video_desks, sessionPlayerConnector);
TestUtils.loadResource(R.raw.video_desks, sessionPlayerConnector);
CountDownLatch onPlaybackCompletedLatch = new CountDownLatch(1);
sessionPlayerConnector.registerPlayerCallback(
executor,
@ -267,7 +262,7 @@ public class SessionPlayerConnectorTest {
@MediumTest
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT)
public void getDuration_afterPrepared_returnsDuration() throws Exception {
TestUtils.loadResource(context, R.raw.video_desks, sessionPlayerConnector);
TestUtils.loadResource(R.raw.video_desks, sessionPlayerConnector);
assertPlayerResultSuccess(sessionPlayerConnector.prepare());
assertThat(sessionPlayerConnector.getPlayerState())
@ -307,11 +302,7 @@ public class SessionPlayerConnectorTest {
@LargeTest
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT)
public void play_withDataSourceCallback_changesPlayerState() throws Exception {
int resid = R.raw.video_big_buck_bunny;
TestDataSourceCallback dataSource =
TestDataSourceCallback.fromAssetFd(resources.openRawResourceFd(resid));
sessionPlayerConnector.setMediaItem(new CallbackMediaItem.Builder(dataSource).build());
sessionPlayerConnector.setMediaItem(TestUtils.createMediaItem(R.raw.video_big_buck_bunny));
sessionPlayerConnector.prepare();
assertPlayerResultSuccess(sessionPlayerConnector.play());
assertThat(sessionPlayerConnector.getPlayerState()).isEqualTo(PLAYER_STATE_PLAYING);
@ -341,21 +332,16 @@ public class SessionPlayerConnectorTest {
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT)
public void setPlaybackSpeed_afterPlayback_remainsSame() throws Exception {
int resId1 = R.raw.video_big_buck_bunny;
long start1 = 6_000;
long end1 = 7_000;
MediaItem mediaItem1 =
new UriMediaItem.Builder(TestUtils.createResourceUri(context, resId1))
.setStartPosition(start1)
.setEndPosition(end1)
new UriMediaItem.Builder(RawResourceDataSource.buildRawResourceUri(resId1))
.setStartPosition(6_000)
.setEndPosition(7_000)
.build();
int resId2 = R.raw.video_desks;
long start2 = 3_000;
long end2 = 4_000;
MediaItem mediaItem2 =
new UriMediaItem.Builder(TestUtils.createResourceUri(context, resId2))
.setStartPosition(start2)
.setEndPosition(end2)
new UriMediaItem.Builder(RawResourceDataSource.buildRawResourceUri(resId1))
.setStartPosition(3_000)
.setEndPosition(4_000)
.build();
List<MediaItem> items = new ArrayList<>();
@ -388,8 +374,7 @@ public class SessionPlayerConnectorTest {
@LargeTest
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT)
public void seekTo_withSeriesOfSeek_succeeds() throws Exception {
int resid = R.raw.video_big_buck_bunny;
TestUtils.loadResource(context, resid, sessionPlayerConnector);
TestUtils.loadResource(R.raw.video_big_buck_bunny, sessionPlayerConnector);
assertPlayerResultSuccess(sessionPlayerConnector.prepare());
@ -404,35 +389,18 @@ public class SessionPlayerConnectorTest {
@LargeTest
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT)
public void seekTo_skipsUnnecessarySeek() throws Exception {
int resid = R.raw.video_big_buck_bunny;
TestDataSourceCallback source =
TestDataSourceCallback.fromAssetFd(resources.openRawResourceFd(resid));
CountDownLatch readAllowedLatch = new CountDownLatch(1);
DataSourceCallback dataSource =
new DataSourceCallback() {
@Override
public int readAt(long position, byte[] buffer, int offset, int size) throws IOException {
try {
assertThat(readAllowedLatch.await(PLAYBACK_COMPLETED_WAIT_TIME_MS, MILLISECONDS))
.isTrue();
} catch (Exception e) {
assertWithMessage("Unexpected exception %s", e).fail();
}
return source.readAt(position, buffer, offset, size);
playerTestRule.setDataSourceInstrumentation(
dataSpec -> {
try {
assertThat(readAllowedLatch.await(PLAYBACK_COMPLETED_WAIT_TIME_MS, MILLISECONDS))
.isTrue();
} catch (Exception e) {
assertWithMessage("Unexpected exception %s", e).fail();
}
});
@Override
public long getSize() throws IOException {
return source.getSize();
}
@Override
public void close() throws IOException {
source.close();
}
};
sessionPlayerConnector.setMediaItem(new CallbackMediaItem.Builder(dataSource).build());
sessionPlayerConnector.setMediaItem(TestUtils.createMediaItem(R.raw.video_big_buck_bunny));
// prepare() will be pending until readAllowed is countDowned.
sessionPlayerConnector.prepare();
@ -478,8 +446,7 @@ public class SessionPlayerConnectorTest {
@LargeTest
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT)
public void seekTo_whenUnderlyingPlayerAlsoSeeks_throwsNoException() throws Exception {
int resid = R.raw.video_big_buck_bunny;
TestUtils.loadResource(context, resid, sessionPlayerConnector);
TestUtils.loadResource(R.raw.video_big_buck_bunny, sessionPlayerConnector);
assertPlayerResultSuccess(sessionPlayerConnector.prepare());
SimpleExoPlayer simpleExoPlayer = playerTestRule.getSimpleExoPlayer();
@ -500,8 +467,7 @@ public class SessionPlayerConnectorTest {
@LargeTest
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT)
public void seekTo_byUnderlyingPlayer_notifiesOnSeekCompleted() throws Exception {
int resid = R.raw.video_big_buck_bunny;
TestUtils.loadResource(context, resid, sessionPlayerConnector);
TestUtils.loadResource(R.raw.video_big_buck_bunny, sessionPlayerConnector);
assertPlayerResultSuccess(sessionPlayerConnector.prepare());
SimpleExoPlayer simpleExoPlayer = playerTestRule.getSimpleExoPlayer();
long testSeekPosition = 1023;
@ -530,7 +496,7 @@ public class SessionPlayerConnectorTest {
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT)
public void getPlayerState_withCallingPrepareAndPlayAndPause_reflectsPlayerState()
throws Throwable {
TestUtils.loadResource(context, R.raw.video_desks, sessionPlayerConnector);
TestUtils.loadResource(R.raw.video_desks, sessionPlayerConnector);
assertThat(sessionPlayerConnector.getBufferingState())
.isEqualTo(SessionPlayer.BUFFERING_STATE_UNKNOWN);
assertThat(sessionPlayerConnector.getPlayerState()).isEqualTo(SessionPlayer.PLAYER_STATE_IDLE);
@ -564,9 +530,9 @@ public class SessionPlayerConnectorTest {
@Test
@LargeTest
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT)
@SdkSuppress(minSdkVersion = VERSION_CODES.KITKAT)
public void prepare_twice_finishes() throws Exception {
TestUtils.loadResource(context, R.raw.audio, sessionPlayerConnector);
TestUtils.loadResource(R.raw.audio, sessionPlayerConnector);
assertPlayerResultSuccess(sessionPlayerConnector.prepare());
assertPlayerResult(sessionPlayerConnector.prepare(), RESULT_INFO_SKIPPED);
}
@ -575,7 +541,7 @@ public class SessionPlayerConnectorTest {
@LargeTest
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT)
public void prepare_notifiesOnPlayerStateChanged() throws Throwable {
TestUtils.loadResource(context, R.raw.video_big_buck_bunny, sessionPlayerConnector);
TestUtils.loadResource(R.raw.video_big_buck_bunny, sessionPlayerConnector);
CountDownLatch onPlayerStatePaused = new CountDownLatch(1);
SessionPlayer.PlayerCallback callback =
@ -597,7 +563,7 @@ public class SessionPlayerConnectorTest {
@LargeTest
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT)
public void prepare_notifiesBufferingCompletedOnce() throws Throwable {
TestUtils.loadResource(context, R.raw.video_big_buck_bunny, sessionPlayerConnector);
TestUtils.loadResource(R.raw.video_big_buck_bunny, sessionPlayerConnector);
CountDownLatch onBufferingCompletedLatch = new CountDownLatch(2);
CopyOnWriteArrayList<Integer> bufferingStateChanges = new CopyOnWriteArrayList<>();
@ -633,7 +599,7 @@ public class SessionPlayerConnectorTest {
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT)
public void seekTo_whenPrepared_notifiesOnSeekCompleted() throws Throwable {
long mp4DurationMs = 8_484L;
TestUtils.loadResource(context, R.raw.video_big_buck_bunny, sessionPlayerConnector);
TestUtils.loadResource(R.raw.video_big_buck_bunny, sessionPlayerConnector);
assertPlayerResultSuccess(sessionPlayerConnector.prepare());
@ -656,7 +622,7 @@ public class SessionPlayerConnectorTest {
@LargeTest
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT)
public void setPlaybackSpeed_whenPrepared_notifiesOnPlaybackSpeedChanged() throws Throwable {
TestUtils.loadResource(context, R.raw.video_big_buck_bunny, sessionPlayerConnector);
TestUtils.loadResource(R.raw.video_big_buck_bunny, sessionPlayerConnector);
assertPlayerResultSuccess(sessionPlayerConnector.prepare());
@ -705,7 +671,7 @@ public class SessionPlayerConnectorTest {
@LargeTest
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT)
public void close_throwsNoExceptionAndDoesNotCrash() throws Exception {
TestUtils.loadResource(context, R.raw.audio, sessionPlayerConnector);
TestUtils.loadResource(R.raw.audio, sessionPlayerConnector);
AudioAttributesCompat attributes =
new AudioAttributesCompat.Builder().setLegacyStreamType(AudioManager.STREAM_MUSIC).build();
sessionPlayerConnector.setAudioAttributes(attributes);
@ -727,35 +693,18 @@ public class SessionPlayerConnectorTest {
CountDownLatch readRequestedLatch = new CountDownLatch(1);
CountDownLatch readAllowedLatch = new CountDownLatch(1);
// Need to wait from prepare() to counting down readAllowedLatch.
DataSourceCallback dataSource =
new DataSourceCallback() {
TestDataSourceCallback testSource =
TestDataSourceCallback.fromAssetFd(resources.openRawResourceFd(R.raw.audio));
@Override
public int readAt(long position, byte[] buffer, int offset, int size) throws IOException {
readRequestedLatch.countDown();
try {
assertThat(readAllowedLatch.await(PLAYER_STATE_CHANGE_WAIT_TIME_MS, MILLISECONDS))
.isTrue();
} catch (Exception e) {
assertWithMessage("Unexpected exception %s", e).fail();
}
return testSource.readAt(position, buffer, offset, size);
playerTestRule.setDataSourceInstrumentation(
dataSpec -> {
readRequestedLatch.countDown();
try {
assertThat(readAllowedLatch.await(PLAYER_STATE_CHANGE_WAIT_TIME_MS, MILLISECONDS))
.isTrue();
} catch (Exception e) {
assertWithMessage("Unexpected exception %s", e).fail();
}
@Override
public long getSize() throws IOException {
return testSource.getSize();
}
@Override
public void close() {
testSource.close();
}
};
});
assertPlayerResultSuccess(
sessionPlayerConnector.setMediaItem(new CallbackMediaItem.Builder(dataSource).build()));
sessionPlayerConnector.setMediaItem(TestUtils.createMediaItem(R.raw.audio)));
// prepare() will be pending until readAllowed is countDowned.
ListenableFuture<PlayerResult> prepareFuture = sessionPlayerConnector.prepare();
@ -781,7 +730,7 @@ public class SessionPlayerConnectorTest {
@SmallTest
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT)
public void setPlaylist_withNullPlaylist_throwsException() throws Exception {
List<MediaItem> playlist = TestUtils.createPlaylist(context, 10);
List<MediaItem> playlist = TestUtils.createPlaylist(10);
try {
sessionPlayerConnector.setPlaylist(null, null);
assertWithMessage("null playlist shouldn't be allowed").fail();
@ -808,7 +757,7 @@ public class SessionPlayerConnectorTest {
@LargeTest
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT)
public void setPlaylist_setsPlaylistAndCurrentMediaItem() throws Exception {
List<MediaItem> playlist = TestUtils.createPlaylist(context, 10);
List<MediaItem> playlist = TestUtils.createPlaylist(10);
CountDownLatch onCurrentMediaItemChangedLatch = new CountDownLatch(1);
sessionPlayerConnector.registerPlayerCallback(
executor, new PlayerCallbackForPlaylist(playlist, onCurrentMediaItemChangedLatch));
@ -825,7 +774,7 @@ public class SessionPlayerConnectorTest {
@LargeTest
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT)
public void setPlaylist_calledOnlyOnce_notifiesPlaylistChangeOnlyOnce() throws Exception {
List<MediaItem> playlist = TestUtils.createPlaylist(context, 10);
List<MediaItem> playlist = TestUtils.createPlaylist(10);
CountDownLatch onPlaylistChangedLatch = new CountDownLatch(2);
sessionPlayerConnector.registerPlayerCallback(
executor,
@ -850,13 +799,13 @@ public class SessionPlayerConnectorTest {
@LargeTest
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT)
public void addPlaylistItem_calledOnlyOnce_notifiesPlaylistChangeOnlyOnce() throws Exception {
List<MediaItem> playlist = TestUtils.createPlaylist(context, 10);
List<MediaItem> playlist = TestUtils.createPlaylist(10);
assertPlayerResultSuccess(sessionPlayerConnector.setPlaylist(playlist, /* metadata= */ null));
assertPlayerResultSuccess(sessionPlayerConnector.prepare());
CountDownLatch onPlaylistChangedLatch = new CountDownLatch(2);
int addIndex = 2;
MediaItem newMediaItem = TestUtils.createMediaItem(context);
MediaItem newMediaItem = TestUtils.createMediaItem();
playlist.add(addIndex, newMediaItem);
sessionPlayerConnector.registerPlayerCallback(
executor,
@ -879,7 +828,7 @@ public class SessionPlayerConnectorTest {
@LargeTest
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT)
public void removePlaylistItem_calledOnlyOnce_notifiesPlaylistChangeOnlyOnce() throws Exception {
List<MediaItem> playlist = TestUtils.createPlaylist(context, 10);
List<MediaItem> playlist = TestUtils.createPlaylist(10);
assertPlayerResultSuccess(sessionPlayerConnector.setPlaylist(playlist, /* metadata= */ null));
assertPlayerResultSuccess(sessionPlayerConnector.prepare());
@ -907,13 +856,13 @@ public class SessionPlayerConnectorTest {
@LargeTest
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT)
public void replacePlaylistItem_calledOnlyOnce_notifiesPlaylistChangeOnlyOnce() throws Exception {
List<MediaItem> playlist = TestUtils.createPlaylist(context, 10);
List<MediaItem> playlist = TestUtils.createPlaylist(10);
assertPlayerResultSuccess(sessionPlayerConnector.setPlaylist(playlist, /* metadata= */ null));
assertPlayerResultSuccess(sessionPlayerConnector.prepare());
CountDownLatch onPlaylistChangedLatch = new CountDownLatch(2);
int replaceIndex = 2;
MediaItem newMediaItem = TestUtils.createMediaItem(context);
MediaItem newMediaItem = TestUtils.createMediaItem();
playlist.set(replaceIndex, newMediaItem);
sessionPlayerConnector.registerPlayerCallback(
executor,
@ -937,7 +886,7 @@ public class SessionPlayerConnectorTest {
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT)
public void setPlaylist_withPlaylist_notifiesOnCurrentMediaItemChanged() throws Exception {
int listSize = 2;
List<MediaItem> playlist = TestUtils.createPlaylist(context, listSize);
List<MediaItem> playlist = TestUtils.createPlaylist(listSize);
CountDownLatch onCurrentMediaItemChangedLatch = new CountDownLatch(1);
sessionPlayerConnector.registerPlayerCallback(
@ -953,7 +902,7 @@ public class SessionPlayerConnectorTest {
@LargeTest
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT)
public void play_twice_finishes() throws Exception {
TestUtils.loadResource(context, R.raw.audio, sessionPlayerConnector);
TestUtils.loadResource(R.raw.audio, sessionPlayerConnector);
assertPlayerResultSuccess(sessionPlayerConnector.prepare());
assertPlayerResultSuccess(sessionPlayerConnector.play());
assertPlayerResult(sessionPlayerConnector.play(), RESULT_INFO_SKIPPED);
@ -965,9 +914,9 @@ public class SessionPlayerConnectorTest {
public void play_withPlaylist_notifiesOnCurrentMediaItemChangedAndOnPlaybackCompleted()
throws Exception {
List<MediaItem> playlist = new ArrayList<>();
playlist.add(TestUtils.createMediaItem(context, R.raw.video_1));
playlist.add(TestUtils.createMediaItem(context, R.raw.video_2));
playlist.add(TestUtils.createMediaItem(context, R.raw.video_3));
playlist.add(TestUtils.createMediaItem(R.raw.video_1));
playlist.add(TestUtils.createMediaItem(R.raw.video_2));
playlist.add(TestUtils.createMediaItem(R.raw.video_3));
CountDownLatch onPlaybackCompletedLatch = new CountDownLatch(1);
sessionPlayerConnector.registerPlayerCallback(
@ -980,10 +929,9 @@ public class SessionPlayerConnectorTest {
@NonNull SessionPlayer player, @NonNull MediaItem item) {
assertThat(item).isEqualTo(player.getCurrentMediaItem());
int currentIdx = player.getCurrentMediaItemIndex();
int expectedCurrentIdx = currentMediaItemChangedCount++;
assertThat(currentIdx).isEqualTo(expectedCurrentIdx);
assertThat(item).isEqualTo(playlist.get(expectedCurrentIdx));
int expectedCurrentIndex = currentMediaItemChangedCount++;
assertThat(player.getCurrentMediaItemIndex()).isEqualTo(expectedCurrentIndex);
assertThat(item).isEqualTo(playlist.get(expectedCurrentIndex));
}
@Override
@ -1004,7 +952,7 @@ public class SessionPlayerConnectorTest {
@LargeTest
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT)
public void play_byUnderlyingPlayer_notifiesOnPlayerStateChanges() throws Exception {
TestUtils.loadResource(context, R.raw.audio, sessionPlayerConnector);
TestUtils.loadResource(R.raw.audio, sessionPlayerConnector);
SimpleExoPlayer simpleExoPlayer = playerTestRule.getSimpleExoPlayer();
CountDownLatch onPlayingLatch = new CountDownLatch(1);
@ -1030,7 +978,7 @@ public class SessionPlayerConnectorTest {
@LargeTest
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT)
public void pause_twice_finishes() throws Exception {
TestUtils.loadResource(context, R.raw.audio, sessionPlayerConnector);
TestUtils.loadResource(R.raw.audio, sessionPlayerConnector);
assertPlayerResultSuccess(sessionPlayerConnector.prepare());
assertPlayerResultSuccess(sessionPlayerConnector.play());
assertPlayerResultSuccess(sessionPlayerConnector.pause());
@ -1041,7 +989,7 @@ public class SessionPlayerConnectorTest {
@LargeTest
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT)
public void pause_byUnderlyingPlayer_notifiesOnPlayerStateChanges() throws Exception {
TestUtils.loadResource(context, R.raw.audio, sessionPlayerConnector);
TestUtils.loadResource(R.raw.audio, sessionPlayerConnector);
SimpleExoPlayer simpleExoPlayer = playerTestRule.getSimpleExoPlayer();
assertPlayerResultSuccess(sessionPlayerConnector.prepare());
@ -1068,7 +1016,7 @@ public class SessionPlayerConnectorTest {
@LargeTest
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT)
public void pause_byUnderlyingPlayerInListener_changesToPlayerStatePaused() throws Exception {
TestUtils.loadResource(context, R.raw.audio, sessionPlayerConnector);
TestUtils.loadResource(R.raw.audio, sessionPlayerConnector);
SimpleExoPlayer simpleExoPlayer = playerTestRule.getSimpleExoPlayer();
CountDownLatch playerStateChangesLatch = new CountDownLatch(3);
@ -1115,9 +1063,9 @@ public class SessionPlayerConnectorTest {
public void skipToNextAndPrevious_calledInARow_notifiesOnCurrentMediaItemChanged()
throws Exception {
List<MediaItem> playlist = new ArrayList<>();
playlist.add(TestUtils.createMediaItem(context, R.raw.video_1));
playlist.add(TestUtils.createMediaItem(context, R.raw.video_2));
playlist.add(TestUtils.createMediaItem(context, R.raw.video_3));
playlist.add(TestUtils.createMediaItem(R.raw.video_1));
playlist.add(TestUtils.createMediaItem(R.raw.video_2));
playlist.add(TestUtils.createMediaItem(R.raw.video_3));
assertThat(sessionPlayerConnector.setPlaylist(playlist, /* metadata= */ null)).isNotNull();
// STEP 1: prepare()
@ -1131,10 +1079,9 @@ public class SessionPlayerConnectorTest {
public void onCurrentMediaItemChanged(
@NonNull SessionPlayer player, @NonNull MediaItem item) {
super.onCurrentMediaItemChanged(player, item);
int expectedIndex = 1;
assertThat(player.getCurrentMediaItemIndex()).isEqualTo(expectedIndex);
assertThat(player.getCurrentMediaItemIndex()).isEqualTo(1);
assertThat(item).isEqualTo(player.getCurrentMediaItem());
assertThat(item).isEqualTo(playlist.get(expectedIndex));
assertThat(item).isEqualTo(playlist.get(1));
onNextMediaItemLatch.countDown();
}
};
@ -1151,10 +1098,9 @@ public class SessionPlayerConnectorTest {
public void onCurrentMediaItemChanged(
@NonNull SessionPlayer player, @NonNull MediaItem item) {
super.onCurrentMediaItemChanged(player, item);
int expectedIndex = 0;
assertThat(player.getCurrentMediaItemIndex()).isEqualTo(expectedIndex);
assertThat(player.getCurrentMediaItemIndex()).isEqualTo(0);
assertThat(item).isEqualTo(player.getCurrentMediaItem());
assertThat(item).isEqualTo(playlist.get(expectedIndex));
assertThat(item).isEqualTo(playlist.get(0));
onPreviousMediaItemLatch.countDown();
}
};
@ -1171,15 +1117,13 @@ public class SessionPlayerConnectorTest {
public void setRepeatMode_withRepeatAll_continuesToPlayPlaylistWithoutBeingCompleted()
throws Exception {
List<MediaItem> playlist = new ArrayList<>();
playlist.add(TestUtils.createMediaItem(context, R.raw.video_1));
playlist.add(TestUtils.createMediaItem(context, R.raw.video_2));
playlist.add(TestUtils.createMediaItem(context, R.raw.video_3));
playlist.add(TestUtils.createMediaItem(R.raw.video_1));
playlist.add(TestUtils.createMediaItem(R.raw.video_2));
playlist.add(TestUtils.createMediaItem(R.raw.video_3));
int listSize = playlist.size();
// Any value more than list size + 1, to see repeat mode with the recorded video.
int expectedCurrentMediaItemChanges = listSize + 2;
CountDownLatch onCurrentMediaItemChangedLatch =
new CountDownLatch(expectedCurrentMediaItemChanges);
CountDownLatch onCurrentMediaItemChangedLatch = new CountDownLatch(listSize + 2);
CopyOnWriteArrayList<MediaItem> currentMediaItemChanges = new CopyOnWriteArrayList<>();
PlayerCallbackForPlaylist callback =
new PlayerCallbackForPlaylist(playlist, onCurrentMediaItemChangedLatch) {
@ -1226,7 +1170,7 @@ public class SessionPlayerConnectorTest {
@Test
@LargeTest
public void getPlayerState_withPrepareAndPlayAndPause_changesAsExpected() throws Exception {
TestUtils.loadResource(context, R.raw.audio, sessionPlayerConnector);
TestUtils.loadResource(R.raw.audio, sessionPlayerConnector);
AudioAttributesCompat attributes =
new AudioAttributesCompat.Builder().setLegacyStreamType(AudioManager.STREAM_MUSIC).build();
@ -1252,8 +1196,8 @@ public class SessionPlayerConnectorTest {
@Override
public void onCurrentMediaItemChanged(@NonNull SessionPlayer player, @NonNull MediaItem item) {
int currentIdx = playlist.indexOf(item);
assertThat(sessionPlayerConnector.getCurrentMediaItemIndex()).isEqualTo(currentIdx);
int currentIndex = playlist.indexOf(item);
assertThat(sessionPlayerConnector.getCurrentMediaItemIndex()).isEqualTo(currentIndex);
onCurrentMediaItemChangedLatch.countDown();
}
}

View file

@ -1,77 +0,0 @@
/*
* Copyright 2019 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.ext.media2;
import android.content.res.AssetFileDescriptor;
import android.util.Log;
import androidx.media2.common.DataSourceCallback;
import java.io.IOException;
import java.io.InputStream;
/** A DataSourceCallback that reads from a byte array for use in tests. */
public class TestDataSourceCallback extends DataSourceCallback {
private static final String TAG = "TestDataSourceCallback";
private byte[] data;
// Read an asset fd into a new byte array media item. Closes afd.
public static TestDataSourceCallback fromAssetFd(AssetFileDescriptor afd) throws IOException {
try {
InputStream in = afd.createInputStream();
int size = (int) afd.getDeclaredLength();
byte[] data = new byte[size];
int writeIndex = 0;
int numRead;
do {
numRead = in.read(data, writeIndex, size - writeIndex);
writeIndex += numRead;
} while (numRead >= 0);
return new TestDataSourceCallback(data);
} finally {
afd.close();
}
}
public TestDataSourceCallback(byte[] data) {
this.data = data;
}
@Override
public synchronized int readAt(long position, byte[] buffer, int offset, int size) {
// Clamp reads past the end of the source.
if (position >= data.length) {
return -1; // -1 indicates EOF
}
if (position + size > data.length) {
size -= (position + size) - data.length;
}
System.arraycopy(data, (int) position, buffer, offset, size);
return size;
}
@Override
public synchronized long getSize() {
Log.v(TAG, "getSize: " + data.length);
return data.length;
}
// Note: it's fine to keep using this media item after closing it.
@Override
public synchronized void close() {
Log.v(TAG, "close()");
}
}

View file

@ -20,60 +20,45 @@ import static androidx.media2.common.SessionPlayer.PlayerResult.RESULT_SUCCESS;
import static com.google.common.truth.Truth.assertThat;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import android.content.ContentResolver;
import android.content.Context;
import android.content.res.Resources;
import android.net.Uri;
import androidx.media2.common.MediaItem;
import androidx.media2.common.MediaMetadata;
import androidx.media2.common.SessionPlayer;
import androidx.media2.common.SessionPlayer.PlayerResult;
import androidx.media2.common.UriMediaItem;
import com.google.android.exoplayer2.ext.media2.test.R;
import com.google.android.exoplayer2.upstream.RawResourceDataSource;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Future;
/** Utilities for tests. */
/* package */ final class TestUtils {
private static final long PLAYER_STATE_CHANGE_WAIT_TIME_MS = 5_000;
public static Uri createResourceUri(Context context, int resId) {
Resources resources = context.getResources();
return new Uri.Builder()
.scheme(ContentResolver.SCHEME_ANDROID_RESOURCE)
.authority(resources.getResourcePackageName(resId))
.appendPath(resources.getResourceTypeName(resId))
.appendPath(resources.getResourceEntryName(resId))
public static UriMediaItem createMediaItem() {
return createMediaItem(R.raw.video_desks);
}
public static UriMediaItem createMediaItem(int resId) {
MediaMetadata metadata =
new MediaMetadata.Builder()
.putString(MediaMetadata.METADATA_KEY_MEDIA_ID, Integer.toString(resId))
.build();
return new UriMediaItem.Builder(RawResourceDataSource.buildRawResourceUri(resId))
.setMetadata(metadata)
.build();
}
public static MediaItem createMediaItem(Context context) {
return createMediaItem(context, R.raw.video_desks);
}
public static MediaItem createMediaItem(Context context, int resId) {
Uri resourceUri = createResourceUri(context, resId);
String resourceName = context.getResources().getResourceName(resId);
MediaMetadata metadata =
new MediaMetadata.Builder()
.putString(MediaMetadata.METADATA_KEY_MEDIA_ID, resourceName)
.build();
return new UriMediaItem.Builder(resourceUri).setMetadata(metadata).build();
}
public static List<MediaItem> createPlaylist(Context context, int size) {
public static List<MediaItem> createPlaylist(int size) {
List<MediaItem> items = new ArrayList<>();
for (int i = 0; i < size; ++i) {
items.add(createMediaItem(context));
items.add(createMediaItem());
}
return items;
}
public static void loadResource(Context context, int resId, SessionPlayer sessionPlayer)
throws Exception {
MediaItem mediaItem = createMediaItem(context, resId);
public static void loadResource(int resId, SessionPlayer sessionPlayer) throws Exception {
MediaItem mediaItem = createMediaItem(resId);
assertPlayerResultSuccess(sessionPlayer.setMediaItem(mediaItem));
}