Tests for media classes accepting MediaDataSources.
Bug: 19429378
Change-Id: Ie734b51819785047c6596fd4d20eaf43c5d60a4b
diff --git a/tests/tests/media/src/android/media/cts/MediaExtractorTest.java b/tests/tests/media/src/android/media/cts/MediaExtractorTest.java
new file mode 100644
index 0000000..7ca498f
--- /dev/null
+++ b/tests/tests/media/src/android/media/cts/MediaExtractorTest.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2015 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 android.media.cts;
+
+import com.android.cts.media.R;
+
+import android.content.res.AssetFileDescriptor;
+import android.content.res.Resources;
+import android.media.MediaDataSource;
+import android.media.MediaExtractor;
+import android.test.AndroidTestCase;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+public class MediaExtractorTest extends AndroidTestCase {
+ protected Resources mResources;
+ protected MediaExtractor mExtractor;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mResources = getContext().getResources();
+ mExtractor = new MediaExtractor();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ mExtractor.release();
+ }
+
+ protected TestMediaDataSource getDataSourceFor(int resid) throws Exception {
+ AssetFileDescriptor afd = mResources.openRawResourceFd(resid);
+ return TestMediaDataSource.fromAssetFd(afd);
+ }
+
+ protected TestMediaDataSource setDataSource(int resid) throws Exception {
+ TestMediaDataSource ds = getDataSourceFor(resid);
+ mExtractor.setDataSource(ds);
+ return ds;
+ }
+
+ public void testNullMediaDataSourceIsRejected() throws Exception {
+ try {
+ mExtractor.setDataSource((MediaDataSource)null);
+ fail("Expected IllegalArgumentException.");
+ } catch (IllegalArgumentException ex) {
+ // Expected, test passed.
+ }
+ }
+
+ public void testMediaDataSourceIsClosedOnRelease() throws Exception {
+ TestMediaDataSource dataSource = setDataSource(R.raw.testvideo);
+ mExtractor.release();
+ assertTrue(dataSource.isClosed());
+ }
+
+ public void testExtractorFailsIfMediaDataSourceThrows() throws Exception {
+ TestMediaDataSource dataSource = getDataSourceFor(R.raw.testvideo);
+ dataSource.throwFromReadAt();
+ try {
+ mExtractor.setDataSource(dataSource);
+ fail("Expected IOException.");
+ } catch (IOException e) {
+ // Expected.
+ }
+ }
+
+ public void testExtractorFailsIfMediaDataSourceReturnsAnError() throws Exception {
+ TestMediaDataSource dataSource = getDataSourceFor(R.raw.testvideo);
+ dataSource.returnFromReadAt(-1);
+ try {
+ mExtractor.setDataSource(dataSource);
+ fail("Expected IOException.");
+ } catch (IOException e) {
+ // Expected.
+ }
+ }
+
+ // Smoke test MediaExtractor reading from a DataSource.
+ public void testExtractFromAMediaDataSource() throws Exception {
+ TestMediaDataSource dataSource = setDataSource(R.raw.testvideo);
+ // 1MB is enough for any sample.
+ final ByteBuffer buf = ByteBuffer.allocate(1024*1024);
+ final int trackCount = mExtractor.getTrackCount();
+
+ for (int i = 0; i < trackCount; i++) {
+ mExtractor.selectTrack(i);
+ }
+
+ for (int i = 0; i < trackCount; i++) {
+ assertTrue(mExtractor.readSampleData(buf, 0) > 0);
+ assertTrue(mExtractor.advance());
+ }
+ }
+}
diff --git a/tests/tests/media/src/android/media/cts/MediaMetadataRetrieverTest.java b/tests/tests/media/src/android/media/cts/MediaMetadataRetrieverTest.java
index 30c8370..622c0ec 100644
--- a/tests/tests/media/src/android/media/cts/MediaMetadataRetrieverTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaMetadataRetrieverTest.java
@@ -20,102 +20,133 @@
import android.content.res.AssetFileDescriptor;
import android.content.res.Resources;
+import android.media.MediaDataSource;
import android.media.MediaMetadataRetriever;
import android.test.AndroidTestCase;
public class MediaMetadataRetrieverTest extends AndroidTestCase {
+ protected Resources mResources;
+ protected MediaMetadataRetriever mRetriever;
@Override
protected void setUp() throws Exception {
super.setUp();
+ mResources = getContext().getResources();
+ mRetriever = new MediaMetadataRetriever();
}
@Override
protected void tearDown() throws Exception {
super.tearDown();
+ mRetriever.release();
}
- public void test3gppMetadata() {
- MediaMetadataRetriever retriever = new MediaMetadataRetriever();
-
+ protected void setDataSourceFd(int resid) {
try {
- Resources resources = getContext().getResources();
- AssetFileDescriptor afd = resources.openRawResourceFd(R.raw.testvideo);
-
- retriever.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
-
+ AssetFileDescriptor afd = mResources.openRawResourceFd(resid);
+ mRetriever.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
afd.close();
} catch (Exception e) {
fail("Unable to open file");
}
+ }
+
+ protected TestMediaDataSource setDataSourceCallback(int resid) {
+ TestMediaDataSource ds = null;
+ try {
+ AssetFileDescriptor afd = mResources.openRawResourceFd(resid);
+ ds = TestMediaDataSource.fromAssetFd(afd);
+ mRetriever.setDataSource(ds);
+ } catch (Exception e) {
+ fail("Unable to open file");
+ }
+ return ds;
+ }
+
+ public void test3gppMetadata() {
+ setDataSourceCallback(R.raw.testvideo);
assertEquals("Title was other than expected",
- "Title", retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_TITLE));
+ "Title", mRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_TITLE));
assertEquals("Artist was other than expected",
"UTF16LE エンディアン ",
- retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ARTIST));
+ mRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ARTIST));
assertEquals("Album was other than expected",
"Test album",
- retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ALBUM));
+ mRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ALBUM));
assertEquals("Track number was other than expected",
"10",
- retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_CD_TRACK_NUMBER));
+ mRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_CD_TRACK_NUMBER));
assertEquals("Year was other than expected",
- "2013", retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_YEAR));
+ "2013", mRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_YEAR));
assertNull("Writer was unexpected present",
- retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_WRITER));
+ mRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_WRITER));
}
- public void testSetDataSourceNull() {
- MediaMetadataRetriever retriever = new MediaMetadataRetriever();
+ public void testID3v2Metadata() {
+ setDataSourceFd(R.raw.video_480x360_mp4_h264_500kbps_25fps_aac_stereo_128kbps_44100hz_id3v2);
+ assertEquals("Title was other than expected",
+ "Title", mRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_TITLE));
+
+ assertEquals("Artist was other than expected",
+ "UTF16LE エンディアン ",
+ mRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ARTIST));
+
+ assertEquals("Album was other than expected",
+ "Test album",
+ mRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ALBUM));
+
+ assertEquals("Track number was other than expected",
+ "10",
+ mRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_CD_TRACK_NUMBER));
+
+ assertEquals("Year was other than expected",
+ "2013", mRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_YEAR));
+
+ assertNull("Writer was unexpectedly present",
+ mRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_WRITER));
+ }
+
+ public void testSetDataSourceNullPath() {
try {
- retriever.setDataSource((String)null);
+ mRetriever.setDataSource((String)null);
fail("Expected IllegalArgumentException.");
} catch (IllegalArgumentException ex) {
// Expected, test passed.
}
}
- public void testID3v2Metadata() {
- MediaMetadataRetriever retriever = new MediaMetadataRetriever();
-
+ public void testNullMediaDataSourceIsRejected() {
try {
- Resources resources = getContext().getResources();
- AssetFileDescriptor afd = resources.openRawResourceFd(
- R.raw.video_480x360_mp4_h264_500kbps_25fps_aac_stereo_128kbps_44100hz_id3v2);
-
- retriever.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
-
- afd.close();
- } catch (Exception e) {
- fail("Unable to open file");
+ mRetriever.setDataSource((MediaDataSource)null);
+ fail("Expected IllegalArgumentException.");
+ } catch (IllegalArgumentException ex) {
+ // Expected, test passed.
}
+ }
- assertEquals("Title was other than expected",
- "Title", retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_TITLE));
+ public void testMediaDataSourceIsClosedOnRelease() throws Exception {
+ TestMediaDataSource dataSource = setDataSourceCallback(R.raw.testvideo);
+ mRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_TITLE);
+ mRetriever.release();
+ assertTrue(dataSource.isClosed());
+ }
- assertEquals("Artist was other than expected",
- "UTF16LE エンディアン ",
- retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ARTIST));
+ public void testRetrieveFailsIfMediaDataSourceThrows() throws Exception {
+ TestMediaDataSource dataSource = setDataSourceCallback(R.raw.testvideo);
+ dataSource.throwFromReadAt();
+ assertTrue(mRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_TITLE) == null);
+ }
- assertEquals("Album was other than expected",
- "Test album",
- retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ALBUM));
-
- assertEquals("Track number was other than expected",
- "10",
- retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_CD_TRACK_NUMBER));
-
- assertEquals("Year was other than expected",
- "2013", retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_YEAR));
-
- assertNull("Writer was unexpectedly present",
- retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_WRITER));
+ public void testRetrieveFailsIfMediaDataSourceReturnsAnError() throws Exception {
+ TestMediaDataSource dataSource = setDataSourceCallback(R.raw.testvideo);
+ dataSource.returnFromReadAt(-1);
+ assertTrue(mRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_TITLE) == null);
}
}
diff --git a/tests/tests/media/src/android/media/cts/MediaPlayerTest.java b/tests/tests/media/src/android/media/cts/MediaPlayerTest.java
index 47467ac..44d0841 100644
--- a/tests/tests/media/src/android/media/cts/MediaPlayerTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaPlayerTest.java
@@ -23,6 +23,7 @@
import android.cts.util.MediaUtils;
import android.media.AudioManager;
import android.media.MediaCodec;
+import android.media.MediaDataSource;
import android.media.MediaExtractor;
import android.media.MediaFormat;
import android.media.MediaPlayer;
@@ -117,10 +118,10 @@
}
}
- public void testPlayNullSource() throws Exception {
+ public void testPlayNullSourcePath() throws Exception {
try {
mMediaPlayer.setDataSource((String) null);
- fail("Null URI was accepted");
+ fail("Null path was accepted");
} catch (RuntimeException e) {
// expected
}
@@ -1492,4 +1493,94 @@
return getActivity().getPackageManager().hasSystemFeature(
PackageManager.FEATURE_MICROPHONE);
}
+
+ // Smoke test playback from a MediaDataSource.
+ public void testPlaybackFromAMediaDataSource() throws Exception {
+ final int resid = R.raw.video_480x360_mp4_h264_1350kbps_30fps_aac_stereo_192kbps_44100hz;
+ final int duration = 10000;
+
+ if (!MediaUtils.hasCodecsForResource(mContext, resid)) {
+ return;
+ }
+
+ TestMediaDataSource dataSource =
+ TestMediaDataSource.fromAssetFd(mResources.openRawResourceFd(resid));
+ // Test returning -1 from getSize() to indicate unknown size.
+ dataSource.returnFromGetSize(-1);
+ mMediaPlayer.setDataSource(dataSource);
+ playLoadedVideo(null, null, -1);
+ assertTrue(mMediaPlayer.isPlaying());
+
+ // Test pause and restart.
+ mMediaPlayer.pause();
+ Thread.sleep(SLEEP_TIME);
+ assertFalse(mMediaPlayer.isPlaying());
+ mMediaPlayer.start();
+ assertTrue(mMediaPlayer.isPlaying());
+
+ // Test reset.
+ mMediaPlayer.stop();
+ mMediaPlayer.reset();
+ mMediaPlayer.setDataSource(dataSource);
+ mMediaPlayer.prepare();
+ mMediaPlayer.start();
+ assertTrue(mMediaPlayer.isPlaying());
+
+ // Test seek. Note: the seek position is cached and returned as the
+ // current position so there's no point in comparing them.
+ mMediaPlayer.seekTo(duration - SLEEP_TIME);
+ while (mMediaPlayer.isPlaying()) {
+ Thread.sleep(SLEEP_TIME);
+ }
+ }
+
+ public void testNullMediaDataSourceIsRejected() throws Exception {
+ try {
+ mMediaPlayer.setDataSource((MediaDataSource) null);
+ fail("Null MediaDataSource was accepted");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+ }
+
+ public void testMediaDataSourceIsClosedOnReset() throws Exception {
+ TestMediaDataSource dataSource = new TestMediaDataSource(new byte[0]);
+ mMediaPlayer.setDataSource(dataSource);
+ mMediaPlayer.reset();
+ assertTrue(dataSource.isClosed());
+ }
+
+ public void testPlaybackFailsIfMediaDataSourceThrows() throws Exception {
+ final int resid = R.raw.video_480x360_mp4_h264_1350kbps_30fps_aac_stereo_192kbps_44100hz;
+ if (!MediaUtils.hasCodecsForResource(mContext, resid)) {
+ return;
+ }
+
+ setOnErrorListener();
+ TestMediaDataSource dataSource =
+ TestMediaDataSource.fromAssetFd(mResources.openRawResourceFd(resid));
+ mMediaPlayer.setDataSource(dataSource);
+ mMediaPlayer.prepare();
+
+ dataSource.throwFromReadAt();
+ mMediaPlayer.start();
+ assertTrue(mOnErrorCalled.waitForSignal());
+ }
+
+ public void testPlaybackFailsIfMediaDataSourceReturnsAnError() throws Exception {
+ final int resid = R.raw.video_480x360_mp4_h264_1350kbps_30fps_aac_stereo_192kbps_44100hz;
+ if (!MediaUtils.hasCodecsForResource(mContext, resid)) {
+ return;
+ }
+
+ setOnErrorListener();
+ TestMediaDataSource dataSource =
+ TestMediaDataSource.fromAssetFd(mResources.openRawResourceFd(resid));
+ mMediaPlayer.setDataSource(dataSource);
+ mMediaPlayer.prepare();
+
+ dataSource.returnFromReadAt(-1);
+ mMediaPlayer.start();
+ assertTrue(mOnErrorCalled.waitForSignal());
+ }
}
diff --git a/tests/tests/media/src/android/media/cts/MediaPlayerTestBase.java b/tests/tests/media/src/android/media/cts/MediaPlayerTestBase.java
index b7283db..95cb43c 100644
--- a/tests/tests/media/src/android/media/cts/MediaPlayerTestBase.java
+++ b/tests/tests/media/src/android/media/cts/MediaPlayerTestBase.java
@@ -303,4 +303,14 @@
public boolean checkTv() {
return MediaUtils.check(isTv(), "not a TV");
}
+
+ protected void setOnErrorListener() {
+ mMediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
+ @Override
+ public boolean onError(MediaPlayer mp, int what, int extra) {
+ mOnErrorCalled.signal();
+ return false;
+ }
+ });
+ }
}
diff --git a/tests/tests/media/src/android/media/cts/TestMediaDataSource.java b/tests/tests/media/src/android/media/cts/TestMediaDataSource.java
new file mode 100644
index 0000000..87b4c59
--- /dev/null
+++ b/tests/tests/media/src/android/media/cts/TestMediaDataSource.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2015 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 android.media.cts;
+
+import android.content.res.AssetFileDescriptor;
+import android.media.cts.MediaPlayerTestBase.Monitor;
+import android.media.MediaDataSource;
+import android.util.Log;
+
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.io.IOException;
+
+/**
+ * A MediaDataSource that reads from a byte array for use in tests.
+ */
+public class TestMediaDataSource implements MediaDataSource {
+ private static final String TAG = "TestMediaDataSource";
+
+ private byte[] mData;
+
+ private boolean mThrowFromReadAt;
+ private boolean mThrowFromGetSize;
+ private Integer mReturnFromReadAt;
+ private Long mReturnFromGetSize;
+ private boolean mIsClosed;
+
+ // Read an asset fd into a new byte array data source. Closes afd.
+ public static TestMediaDataSource fromAssetFd(AssetFileDescriptor afd) throws IOException {
+ try {
+ InputStream in = afd.createInputStream();
+ final int size = (int) afd.getDeclaredLength();
+ byte[] data = new byte[(int) size];
+ int writeIndex = 0;
+ int numRead = 0;
+ do {
+ numRead = in.read(data, writeIndex, size - writeIndex);
+ writeIndex += numRead;
+ } while (numRead >= 0);
+ return new TestMediaDataSource(data);
+ } finally {
+ afd.close();
+ }
+ }
+
+ public TestMediaDataSource(byte[] data) {
+ mData = data;
+ }
+
+ @Override
+ public synchronized int readAt(long offset, byte[] buffer, int size) {
+ if (mThrowFromReadAt) {
+ throw new RuntimeException("Test exception from readAt()");
+ }
+ if (mReturnFromReadAt != null) {
+ return mReturnFromReadAt;
+ }
+
+ // Clamp reads past the end of the source.
+ if (offset >= mData.length) {
+ return 0;
+ }
+ if (offset + size > mData.length) {
+ size -= (offset + size) - mData.length;
+ }
+ System.arraycopy(mData, (int)offset, buffer, 0, size);
+ return size;
+ }
+
+ @Override
+ public synchronized long getSize() {
+ if (mThrowFromGetSize) {
+ throw new RuntimeException("Test exception from getSize()");
+ }
+ if (mReturnFromGetSize != null) {
+ return mReturnFromGetSize;
+ }
+
+ Log.v(TAG, "getSize: " + mData.length);
+ return mData.length;
+ }
+
+ // Note: it's fine to keep using this data source after closing it.
+ @Override
+ public synchronized void close() {
+ Log.v(TAG, "close()");
+ mIsClosed = true;
+ }
+
+ // Whether close() has been called.
+ public synchronized boolean isClosed() {
+ return mIsClosed;
+ }
+
+ public void throwFromReadAt() {
+ mThrowFromReadAt = true;
+ }
+
+ public void throwFromGetSize() {
+ mThrowFromGetSize = true;
+ }
+
+ public void returnFromReadAt(int numRead) {
+ mReturnFromReadAt = numRead;
+ }
+
+ public void returnFromGetSize(long size) {
+ mReturnFromGetSize = size;
+ }
+}
+