blob: 722360566c6bc45321ef273ae7343533f01c232e [file] [log] [blame]
/*
* Copyright (C) 2009 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.Context;
import android.content.pm.PackageManager;
import android.content.res.AssetFileDescriptor;
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;
import android.media.MediaPlayer.OnErrorListener;
import android.media.MediaRecorder;
import android.media.MediaMetadataRetriever;
import android.media.PlaybackParams;
import android.media.TimedText;
import android.media.audiofx.AudioEffect;
import android.media.audiofx.Visualizer;
import android.media.cts.MediaPlayerTestBase.Monitor;
import android.net.Uri;
import android.os.Environment;
import android.os.IBinder;
import android.os.PowerManager;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.util.Log;
import java.io.BufferedReader;
import java.io.File;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
import java.util.UUID;
import java.util.Vector;
import java.util.concurrent.CountDownLatch;
import junit.framework.AssertionFailedError;
/**
* Tests for the MediaPlayer API and local video/audio playback.
*
* The files in res/raw used by testLocalVideo* are (c) copyright 2008,
* Blender Foundation / www.bigbuckbunny.org, and are licensed under the Creative Commons
* Attribution 3.0 License at http://creativecommons.org/licenses/by/3.0/us/.
*/
public class MediaPlayerTest extends MediaPlayerTestBase {
private String RECORDED_FILE;
private static final String LOG_TAG = "MediaPlayerTest";
private static final int RECORDED_VIDEO_WIDTH = 176;
private static final int RECORDED_VIDEO_HEIGHT = 144;
private static final long RECORDED_DURATION_MS = 3000;
private Vector<Integer> mTimedTextTrackIndex = new Vector<Integer>();
private int mSelectedTimedTextIndex;
private Monitor mOnTimedTextCalled = new Monitor();
private File mOutFile;
@Override
protected void setUp() throws Exception {
super.setUp();
RECORDED_FILE = new File(Environment.getExternalStorageDirectory(),
"mediaplayer_record.out").getAbsolutePath();
mOutFile = new File(RECORDED_FILE);
}
@Override
protected void tearDown() throws Exception {
super.tearDown();
if (mOutFile != null && mOutFile.exists()) {
mOutFile.delete();
}
}
// Bug 13652927
public void testVorbisCrash() throws Exception {
MediaPlayer mp = mMediaPlayer;
MediaPlayer mp2 = mMediaPlayer2;
AssetFileDescriptor afd2 = mResources.openRawResourceFd(R.raw.testmp3_2);
mp2.setDataSource(afd2.getFileDescriptor(), afd2.getStartOffset(), afd2.getLength());
afd2.close();
mp2.prepare();
mp2.setLooping(true);
mp2.start();
for (int i = 0; i < 20; i++) {
try {
AssetFileDescriptor afd = mResources.openRawResourceFd(R.raw.bug13652927);
mp.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
afd.close();
mp.prepare();
fail("shouldn't be here");
} catch (Exception e) {
// expected to fail
Log.i("@@@", "failed: " + e);
}
Thread.sleep(500);
assertTrue("media server died", mp2.isPlaying());
mp.reset();
}
}
public void testPlayNullSourcePath() throws Exception {
try {
mMediaPlayer.setDataSource((String) null);
fail("Null path was accepted");
} catch (RuntimeException e) {
// expected
}
}
public void testPlayAudioFromDataURI() throws Exception {
final int mp3Duration = 34909;
final int tolerance = 70;
final int seekDuration = 100;
// This is "R.raw.testmp3_2", base64-encoded.
final int resid = R.raw.testmp3_3;
InputStream is = mContext.getResources().openRawResource(resid);
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
StringBuilder builder = new StringBuilder();
builder.append("data:;base64,");
builder.append(reader.readLine());
Uri uri = Uri.parse(builder.toString());
MediaPlayer mp = MediaPlayer.create(mContext, uri);
try {
mp.setAudioStreamType(AudioManager.STREAM_MUSIC);
mp.setWakeMode(mContext, PowerManager.PARTIAL_WAKE_LOCK);
assertFalse(mp.isPlaying());
mp.start();
assertTrue(mp.isPlaying());
assertFalse(mp.isLooping());
mp.setLooping(true);
assertTrue(mp.isLooping());
assertEquals(mp3Duration, mp.getDuration(), tolerance);
int pos = mp.getCurrentPosition();
assertTrue(pos >= 0);
assertTrue(pos < mp3Duration - seekDuration);
mp.seekTo(pos + seekDuration);
assertEquals(pos + seekDuration, mp.getCurrentPosition(), tolerance);
// test pause and restart
mp.pause();
Thread.sleep(SLEEP_TIME);
assertFalse(mp.isPlaying());
mp.start();
assertTrue(mp.isPlaying());
// test stop and restart
mp.stop();
mp.reset();
mp.setDataSource(mContext, uri);
mp.prepare();
assertFalse(mp.isPlaying());
mp.start();
assertTrue(mp.isPlaying());
// waiting to complete
while(mp.isPlaying()) {
Thread.sleep(SLEEP_TIME);
}
} finally {
mp.release();
}
}
public void testPlayAudio() throws Exception {
final int resid = R.raw.testmp3_2;
final int mp3Duration = 34909;
final int tolerance = 70;
final int seekDuration = 100;
MediaPlayer mp = MediaPlayer.create(mContext, resid);
try {
mp.setAudioStreamType(AudioManager.STREAM_MUSIC);
mp.setWakeMode(mContext, PowerManager.PARTIAL_WAKE_LOCK);
assertFalse(mp.isPlaying());
mp.start();
assertTrue(mp.isPlaying());
assertFalse(mp.isLooping());
mp.setLooping(true);
assertTrue(mp.isLooping());
assertEquals(mp3Duration, mp.getDuration(), tolerance);
int pos = mp.getCurrentPosition();
assertTrue(pos >= 0);
assertTrue(pos < mp3Duration - seekDuration);
mp.seekTo(pos + seekDuration);
assertEquals(pos + seekDuration, mp.getCurrentPosition(), tolerance);
// test pause and restart
mp.pause();
Thread.sleep(SLEEP_TIME);
assertFalse(mp.isPlaying());
mp.start();
assertTrue(mp.isPlaying());
// test stop and restart
mp.stop();
mp.reset();
AssetFileDescriptor afd = mResources.openRawResourceFd(resid);
mp.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
afd.close();
mp.prepare();
assertFalse(mp.isPlaying());
mp.start();
assertTrue(mp.isPlaying());
// waiting to complete
while(mp.isPlaying()) {
Thread.sleep(SLEEP_TIME);
}
} finally {
mp.release();
}
}
public void testPlayMidi() throws Exception {
final int resid = R.raw.midi8sec;
final int midiDuration = 8000;
final int tolerance = 70;
final int seekDuration = 1000;
MediaPlayer mp = MediaPlayer.create(mContext, resid);
try {
mp.setAudioStreamType(AudioManager.STREAM_MUSIC);
mp.setWakeMode(mContext, PowerManager.PARTIAL_WAKE_LOCK);
mp.start();
assertFalse(mp.isLooping());
mp.setLooping(true);
assertTrue(mp.isLooping());
assertEquals(midiDuration, mp.getDuration(), tolerance);
int pos = mp.getCurrentPosition();
assertTrue(pos >= 0);
assertTrue(pos < midiDuration - seekDuration);
mp.seekTo(pos + seekDuration);
assertEquals(pos + seekDuration, mp.getCurrentPosition(), tolerance);
// test stop and restart
mp.stop();
mp.reset();
AssetFileDescriptor afd = mResources.openRawResourceFd(resid);
mp.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
afd.close();
mp.prepare();
mp.start();
Thread.sleep(SLEEP_TIME);
} finally {
mp.release();
}
}
static class OutputListener {
int mSession;
AudioEffect mVc;
Visualizer mVis;
byte [] mVisData;
boolean mSoundDetected;
OutputListener(int session) {
mSession = session;
// creating a volume controller on output mix ensures that ro.audio.silent mutes
// audio after the effects and not before
mVc = new AudioEffect(
AudioEffect.EFFECT_TYPE_NULL,
UUID.fromString("119341a0-8469-11df-81f9-0002a5d5c51b"),
0,
session);
mVc.setEnabled(true);
mVis = new Visualizer(session);
int size = 256;
int[] range = Visualizer.getCaptureSizeRange();
if (size < range[0]) {
size = range[0];
}
if (size > range[1]) {
size = range[1];
}
assertTrue(mVis.setCaptureSize(size) == Visualizer.SUCCESS);
mVis.setDataCaptureListener(new Visualizer.OnDataCaptureListener() {
@Override
public void onWaveFormDataCapture(Visualizer visualizer,
byte[] waveform, int samplingRate) {
if (!mSoundDetected) {
for (int i = 0; i < waveform.length; i++) {
// 8 bit unsigned PCM, zero level is at 128, which is -128 when
// seen as a signed byte
if (waveform[i] != -128) {
mSoundDetected = true;
break;
}
}
}
}
@Override
public void onFftDataCapture(Visualizer visualizer, byte[] fft, int samplingRate) {
}
}, 10000 /* milliHertz */, true /* PCM */, false /* FFT */);
assertTrue(mVis.setEnabled(true) == Visualizer.SUCCESS);
}
void reset() {
mSoundDetected = false;
}
boolean heardSound() {
return mSoundDetected;
}
void release() {
mVis.release();
mVc.release();
}
}
public void testPlayAudioTwice() throws Exception {
final int resid = R.raw.camera_click;
MediaPlayer mp = MediaPlayer.create(mContext, resid);
try {
mp.setAudioStreamType(AudioManager.STREAM_MUSIC);
mp.setWakeMode(mContext, PowerManager.PARTIAL_WAKE_LOCK);
OutputListener listener = new OutputListener(mp.getAudioSessionId());
Thread.sleep(SLEEP_TIME);
assertFalse("noise heard before test started", listener.heardSound());
mp.start();
Thread.sleep(SLEEP_TIME);
assertFalse("player was still playing after " + SLEEP_TIME + " ms", mp.isPlaying());
assertTrue("nothing heard while test ran", listener.heardSound());
listener.reset();
mp.seekTo(0);
mp.start();
Thread.sleep(SLEEP_TIME);
assertTrue("nothing heard when sound was replayed", listener.heardSound());
listener.release();
} finally {
mp.release();
}
}
public void testPlayVideo() throws Exception {
playVideoTest(R.raw.testvideo, 352, 288);
}
private void initMediaPlayer(MediaPlayer player) throws Exception {
AssetFileDescriptor afd = mResources.openRawResourceFd(R.raw.test1m1s);
try {
player.reset();
player.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
player.prepare();
player.seekTo(56000);
} finally {
afd.close();
}
}
public void testSetNextMediaPlayerWithReset() throws Exception {
initMediaPlayer(mMediaPlayer);
try {
initMediaPlayer(mMediaPlayer2);
mMediaPlayer2.reset();
mMediaPlayer.setNextMediaPlayer(mMediaPlayer2);
fail("setNextMediaPlayer() succeeded with unprepared player");
} catch (RuntimeException e) {
// expected
} finally {
mMediaPlayer.reset();
}
}
public void testSetNextMediaPlayerWithRelease() throws Exception {
initMediaPlayer(mMediaPlayer);
try {
initMediaPlayer(mMediaPlayer2);
mMediaPlayer2.release();
mMediaPlayer.setNextMediaPlayer(mMediaPlayer2);
fail("setNextMediaPlayer() succeeded with unprepared player");
} catch (RuntimeException e) {
// expected
} finally {
mMediaPlayer.reset();
}
}
public void testSetNextMediaPlayer() throws Exception {
initMediaPlayer(mMediaPlayer);
final Monitor mTestCompleted = new Monitor();
Thread timer = new Thread(new Runnable() {
@Override
public void run() {
long startTime = SystemClock.elapsedRealtime();
while(true) {
SystemClock.sleep(SLEEP_TIME);
if (mTestCompleted.isSignalled()) {
// done
return;
}
long now = SystemClock.elapsedRealtime();
if ((now - startTime) > 25000) {
// We've been running for 25 seconds and still aren't done, so we're stuck
// somewhere. Signal ourselves to dump the thread stacks.
android.os.Process.sendSignal(android.os.Process.myPid(), 3);
SystemClock.sleep(2000);
fail("Test is stuck, see ANR stack trace for more info. You may need to" +
" create /data/anr first");
return;
}
}
}
});
timer.start();
try {
for (int i = 0; i < 3; i++) {
initMediaPlayer(mMediaPlayer2);
mOnCompletionCalled.reset();
mOnInfoCalled.reset();
mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
assertEquals(mMediaPlayer, mp);
mOnCompletionCalled.signal();
}
});
mMediaPlayer2.setOnInfoListener(new MediaPlayer.OnInfoListener() {
@Override
public boolean onInfo(MediaPlayer mp, int what, int extra) {
assertEquals(mMediaPlayer2, mp);
if (what == MediaPlayer.MEDIA_INFO_STARTED_AS_NEXT) {
mOnInfoCalled.signal();
}
return false;
}
});
mMediaPlayer.setNextMediaPlayer(mMediaPlayer2);
mMediaPlayer.start();
assertTrue(mMediaPlayer.isPlaying());
assertFalse(mOnCompletionCalled.isSignalled());
assertFalse(mMediaPlayer2.isPlaying());
assertFalse(mOnInfoCalled.isSignalled());
while(mMediaPlayer.isPlaying()) {
Thread.sleep(SLEEP_TIME);
}
// wait a little longer in case the callbacks haven't quite made it through yet
Thread.sleep(100);
assertTrue(mMediaPlayer2.isPlaying());
assertTrue(mOnCompletionCalled.isSignalled());
assertTrue(mOnInfoCalled.isSignalled());
// At this point the 1st player is done, and the 2nd one is playing.
// Now swap them, and go through the loop again.
MediaPlayer tmp = mMediaPlayer;
mMediaPlayer = mMediaPlayer2;
mMediaPlayer2 = tmp;
}
// Now test that setNextMediaPlayer(null) works. 1 is still playing, 2 is done
mOnCompletionCalled.reset();
mOnInfoCalled.reset();
initMediaPlayer(mMediaPlayer2);
mMediaPlayer.setNextMediaPlayer(mMediaPlayer2);
mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
assertEquals(mMediaPlayer, mp);
mOnCompletionCalled.signal();
}
});
mMediaPlayer2.setOnInfoListener(new MediaPlayer.OnInfoListener() {
@Override
public boolean onInfo(MediaPlayer mp, int what, int extra) {
assertEquals(mMediaPlayer2, mp);
if (what == MediaPlayer.MEDIA_INFO_STARTED_AS_NEXT) {
mOnInfoCalled.signal();
}
return false;
}
});
assertTrue(mMediaPlayer.isPlaying());
assertFalse(mOnCompletionCalled.isSignalled());
assertFalse(mMediaPlayer2.isPlaying());
assertFalse(mOnInfoCalled.isSignalled());
Thread.sleep(SLEEP_TIME);
mMediaPlayer.setNextMediaPlayer(null);
while(mMediaPlayer.isPlaying()) {
Thread.sleep(SLEEP_TIME);
}
// wait a little longer in case the callbacks haven't quite made it through yet
Thread.sleep(100);
assertFalse(mMediaPlayer.isPlaying());
assertFalse(mMediaPlayer2.isPlaying());
assertTrue(mOnCompletionCalled.isSignalled());
assertFalse(mOnInfoCalled.isSignalled());
} finally {
mMediaPlayer.reset();
mMediaPlayer2.reset();
}
mTestCompleted.signal();
}
// The following tests are all a bit flaky, which is why they're retried a
// few times in a loop.
// This test uses one mp3 that is silent but has a strong positive DC offset,
// and a second mp3 that is also silent but has a strong negative DC offset.
// If the two are played back overlapped, they will cancel each other out,
// and result in zeroes being detected. If there is a gap in playback, that
// will also result in zeroes being detected.
// Note that this test does NOT guarantee that the correct data is played
public void testGapless1() throws Exception {
flakyTestWrapper(R.raw.monodcpos, R.raw.monodcneg);
}
// This test is similar, but uses two identical m4a files that have some noise
// with a strong positive DC offset. This is used to detect if there is
// a gap in playback
// Note that this test does NOT guarantee that the correct data is played
public void testGapless2() throws Exception {
flakyTestWrapper(R.raw.stereonoisedcpos, R.raw.stereonoisedcpos);
}
// same as above, but with a mono file
public void testGapless3() throws Exception {
flakyTestWrapper(R.raw.mononoisedcpos, R.raw.mononoisedcpos);
}
private void flakyTestWrapper(int resid1, int resid2) throws Exception {
boolean success = false;
// test usually succeeds within a few tries, but occasionally may fail
// many times in a row, so be aggressive and try up to 20 times
for (int i = 0; i < 20 && !success; i++) {
try {
testGapless(resid1, resid2);
success = true;
} catch (Throwable t) {
SystemClock.sleep(1000);
}
}
// Try one more time. If this succeeds, we'll consider the test a success,
// otherwise the exception gets thrown
if (!success) {
testGapless(resid1, resid2);
}
}
private void testGapless(int resid1, int resid2) throws Exception {
MediaPlayer mp1 = new MediaPlayer();
mp1.setAudioStreamType(AudioManager.STREAM_MUSIC);
try {
AssetFileDescriptor afd = mContext.getResources().openRawResourceFd(resid1);
mp1.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
afd.close();
mp1.prepare();
} catch (Exception e) {
assertTrue(false);
}
int session = mp1.getAudioSessionId();
MediaPlayer mp2 = new MediaPlayer();
mp2.setAudioSessionId(session);
mp2.setAudioStreamType(AudioManager.STREAM_MUSIC);
try {
AssetFileDescriptor afd = mContext.getResources().openRawResourceFd(resid2);
mp2.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
afd.close();
mp2.prepare();
} catch (Exception e) {
assertTrue(false);
}
// creating a volume controller on output mix ensures that ro.audio.silent mutes
// audio after the effects and not before
AudioEffect vc = new AudioEffect(
AudioEffect.EFFECT_TYPE_NULL,
UUID.fromString("119341a0-8469-11df-81f9-0002a5d5c51b"),
0,
session);
vc.setEnabled(true);
int captureintervalms = mp1.getDuration() + mp2.getDuration() - 2000;
int size = 256;
int[] range = Visualizer.getCaptureSizeRange();
if (size < range[0]) {
size = range[0];
}
if (size > range[1]) {
size = range[1];
}
byte [] vizdata = new byte[size];
Visualizer vis = new Visualizer(session);
AudioManager am = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
int oldRingerMode = am.getRingerMode();
am.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
int oldvolume = am.getStreamVolume(AudioManager.STREAM_MUSIC);
am.setStreamVolume(AudioManager.STREAM_MUSIC, 1, 0);
try {
assertEquals("setCaptureSize failed",
Visualizer.SUCCESS, vis.setCaptureSize(vizdata.length));
assertEquals("setEnabled failed", Visualizer.SUCCESS, vis.setEnabled(true));
mp1.setNextMediaPlayer(mp2);
mp1.start();
assertTrue(mp1.isPlaying());
assertFalse(mp2.isPlaying());
// allow playback to get started
Thread.sleep(SLEEP_TIME);
long start = SystemClock.elapsedRealtime();
// there should be no consecutive zeroes (-128) in the capture buffer
// when going to the next file. If silence is detected right away, then
// the volume is probably turned all the way down (visualizer data
// is captured after volume adjustment).
boolean first = true;
while((SystemClock.elapsedRealtime() - start) < captureintervalms) {
assertTrue(vis.getWaveForm(vizdata) == Visualizer.SUCCESS);
for (int i = 0; i < vizdata.length - 1; i++) {
if (vizdata[i] == -128 && vizdata[i + 1] == -128) {
if (first) {
fail("silence detected, please increase volume and rerun test");
} else {
fail("gap or overlap detected at t=" +
(SLEEP_TIME + SystemClock.elapsedRealtime() - start) +
", offset " + i);
}
break;
}
}
first = false;
}
} finally {
mp1.release();
mp2.release();
vis.release();
vc.release();
am.setRingerMode(oldRingerMode);
am.setStreamVolume(AudioManager.STREAM_MUSIC, oldvolume, 0);
}
}
/**
* Test for reseting a surface during video playback
* After reseting, the video should continue playing
* from the time setDisplay() was called
*/
public void testVideoSurfaceResetting() throws Exception {
final int tolerance = 150;
final int audioLatencyTolerance = 1000; /* covers audio path latency variability */
final int seekPos = 5000;
final CountDownLatch seekDone = new CountDownLatch(1);
mMediaPlayer.setOnSeekCompleteListener(new MediaPlayer.OnSeekCompleteListener() {
@Override
public void onSeekComplete(MediaPlayer mp) {
seekDone.countDown();
}
});
if (!checkLoadResource(R.raw.testvideo)) {
return; // skip;
}
playLoadedVideo(352, 288, -1);
Thread.sleep(SLEEP_TIME);
int posBefore = mMediaPlayer.getCurrentPosition();
mMediaPlayer.setDisplay(getActivity().getSurfaceHolder2());
int posAfter = mMediaPlayer.getCurrentPosition();
assertEquals(posAfter, posBefore, tolerance);
assertTrue(mMediaPlayer.isPlaying());
Thread.sleep(SLEEP_TIME);
mMediaPlayer.seekTo(seekPos);
seekDone.await();
posAfter = mMediaPlayer.getCurrentPosition();
assertEquals(seekPos, posAfter, tolerance + audioLatencyTolerance);
Thread.sleep(SLEEP_TIME / 2);
posBefore = mMediaPlayer.getCurrentPosition();
mMediaPlayer.setDisplay(null);
posAfter = mMediaPlayer.getCurrentPosition();
assertEquals(posAfter, posBefore, tolerance);
assertTrue(mMediaPlayer.isPlaying());
Thread.sleep(SLEEP_TIME);
posBefore = mMediaPlayer.getCurrentPosition();
mMediaPlayer.setDisplay(getActivity().getSurfaceHolder());
posAfter = mMediaPlayer.getCurrentPosition();
assertEquals(posAfter, posBefore, tolerance);
assertTrue(mMediaPlayer.isPlaying());
Thread.sleep(SLEEP_TIME);
}
public void testRecordedVideoPlayback0() throws Exception {
testRecordedVideoPlaybackWithAngle(0);
}
public void testRecordedVideoPlayback90() throws Exception {
testRecordedVideoPlaybackWithAngle(90);
}
public void testRecordedVideoPlayback180() throws Exception {
testRecordedVideoPlaybackWithAngle(180);
}
public void testRecordedVideoPlayback270() throws Exception {
testRecordedVideoPlaybackWithAngle(270);
}
private boolean hasCamera() {
return getActivity().getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA);
}
private void testRecordedVideoPlaybackWithAngle(int angle) throws Exception {
final int width = RECORDED_VIDEO_WIDTH;
final int height = RECORDED_VIDEO_HEIGHT;
final String file = RECORDED_FILE;
final long durationMs = RECORDED_DURATION_MS;
if (!hasCamera()) {
return;
}
checkOrientation(angle);
recordVideo(width, height, angle, file, durationMs);
checkDisplayedVideoSize(width, height, angle, file);
checkVideoRotationAngle(angle, file);
}
private void checkOrientation(int angle) throws Exception {
assertTrue(angle >= 0);
assertTrue(angle < 360);
assertTrue((angle % 90) == 0);
}
private void recordVideo(
int w, int h, int angle, String file, long durationMs) throws Exception {
MediaRecorder recorder = new MediaRecorder();
recorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
recorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT);
recorder.setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT);
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);
recorder.setOutputFile(file);
recorder.setOrientationHint(angle);
recorder.setVideoSize(w, h);
recorder.setPreviewDisplay(getActivity().getSurfaceHolder2().getSurface());
recorder.prepare();
recorder.start();
Thread.sleep(durationMs);
recorder.stop();
recorder.release();
recorder = null;
}
private void checkDisplayedVideoSize(
int w, int h, int angle, String file) throws Exception {
int displayWidth = w;
int displayHeight = h;
if ((angle % 180) != 0) {
displayWidth = h;
displayHeight = w;
}
playVideoTest(file, displayWidth, displayHeight);
}
private void checkVideoRotationAngle(int angle, String file) {
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
retriever.setDataSource(file);
String rotation = retriever.extractMetadata(
MediaMetadataRetriever.METADATA_KEY_VIDEO_ROTATION);
retriever.release();
retriever = null;
assertNotNull(rotation);
assertEquals(Integer.parseInt(rotation), angle);
}
public void testPlaybackRate() throws Exception {
final int toleranceMs = 1000;
if (!checkLoadResource(
R.raw.video_480x360_mp4_h264_1000kbps_30fps_aac_stereo_128kbps_44100hz)) {
return; // skip
}
mMediaPlayer.setDisplay(mActivity.getSurfaceHolder());
mMediaPlayer.prepare();
float[] rates = { 0.25f, 0.5f, 1.0f, 2.0f };
for (float playbackRate : rates) {
mMediaPlayer.seekTo(0);
Thread.sleep(1000);
int playTime = 4000; // The testing clip is about 10 second long.
mMediaPlayer.setPlaybackParams(new PlaybackParams().setSpeed(playbackRate));
mMediaPlayer.start();
Thread.sleep(playTime);
assertTrue("MediaPlayer should still be playing", mMediaPlayer.isPlaying());
int playedMediaDurationMs = mMediaPlayer.getCurrentPosition();
int diff = Math.abs((int)(playedMediaDurationMs / playbackRate) - playTime);
if (diff > toleranceMs) {
fail("Media player had error in playback rate " + playbackRate
+ ", play time is " + playTime + " vs expected " + playedMediaDurationMs);
}
mMediaPlayer.pause();
}
mMediaPlayer.stop();
}
public void testLocalVideo_MP4_H264_480x360_500kbps_25fps_AAC_Stereo_128kbps_44110Hz()
throws Exception {
playVideoTest(
R.raw.video_480x360_mp4_h264_500kbps_25fps_aac_stereo_128kbps_44100hz, 480, 360);
}
public void testLocalVideo_MP4_H264_480x360_500kbps_30fps_AAC_Stereo_128kbps_44110Hz()
throws Exception {
playVideoTest(
R.raw.video_480x360_mp4_h264_500kbps_30fps_aac_stereo_128kbps_44100hz, 480, 360);
}
public void testLocalVideo_MP4_H264_480x360_1000kbps_25fps_AAC_Stereo_128kbps_44110Hz()
throws Exception {
playVideoTest(
R.raw.video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz, 480, 360);
}
public void testLocalVideo_MP4_H264_480x360_1000kbps_30fps_AAC_Stereo_128kbps_44110Hz()
throws Exception {
playVideoTest(
R.raw.video_480x360_mp4_h264_1000kbps_30fps_aac_stereo_128kbps_44100hz, 480, 360);
}
public void testLocalVideo_MP4_H264_480x360_1350kbps_25fps_AAC_Stereo_128kbps_44110Hz()
throws Exception {
playVideoTest(
R.raw.video_480x360_mp4_h264_1350kbps_25fps_aac_stereo_128kbps_44100hz, 480, 360);
}
public void testLocalVideo_MP4_H264_480x360_1350kbps_30fps_AAC_Stereo_128kbps_44110Hz()
throws Exception {
playVideoTest(
R.raw.video_480x360_mp4_h264_1350kbps_30fps_aac_stereo_128kbps_44100hz, 480, 360);
}
public void testLocalVideo_MP4_H264_480x360_1350kbps_30fps_AAC_Stereo_128kbps_44110Hz_frag()
throws Exception {
playVideoTest(
R.raw.video_480x360_mp4_h264_1350kbps_30fps_aac_stereo_128kbps_44100hz_fragmented,
480, 360);
}
public void testLocalVideo_MP4_H264_480x360_1350kbps_30fps_AAC_Stereo_192kbps_44110Hz()
throws Exception {
playVideoTest(
R.raw.video_480x360_mp4_h264_1350kbps_30fps_aac_stereo_192kbps_44100hz, 480, 360);
}
public void testLocalVideo_3gp_H263_176x144_56kbps_12fps_AAC_Mono_24kbps_11025Hz()
throws Exception {
playVideoTest(
R.raw.video_176x144_3gp_h263_56kbps_12fps_aac_mono_24kbps_11025hz, 176, 144);
}
public void testLocalVideo_3gp_H263_176x144_56kbps_12fps_AAC_Mono_24kbps_22050Hz()
throws Exception {
playVideoTest(
R.raw.video_176x144_3gp_h263_56kbps_12fps_aac_mono_24kbps_22050hz, 176, 144);
}
public void testLocalVideo_3gp_H263_176x144_56kbps_12fps_AAC_Stereo_24kbps_11025Hz()
throws Exception {
playVideoTest(
R.raw.video_176x144_3gp_h263_56kbps_12fps_aac_stereo_24kbps_11025hz, 176, 144);
}
public void testLocalVideo_3gp_H263_176x144_56kbps_12fps_AAC_Stereo_24kbps_22050Hz()
throws Exception {
playVideoTest(
R.raw.video_176x144_3gp_h263_56kbps_12fps_aac_stereo_24kbps_11025hz, 176, 144);
}
public void testLocalVideo_3gp_H263_176x144_56kbps_12fps_AAC_Stereo_128kbps_11025Hz()
throws Exception {
playVideoTest(
R.raw.video_176x144_3gp_h263_56kbps_12fps_aac_stereo_128kbps_11025hz, 176, 144);
}
public void testLocalVideo_3gp_H263_176x144_56kbps_12fps_AAC_Stereo_128kbps_22050Hz()
throws Exception {
playVideoTest(
R.raw.video_176x144_3gp_h263_56kbps_12fps_aac_stereo_128kbps_11025hz, 176, 144);
}
public void testLocalVideo_3gp_H263_176x144_56kbps_25fps_AAC_Mono_24kbps_11025Hz()
throws Exception {
playVideoTest(
R.raw.video_176x144_3gp_h263_56kbps_25fps_aac_mono_24kbps_11025hz, 176, 144);
}
public void testLocalVideo_3gp_H263_176x144_56kbps_25fps_AAC_Mono_24kbps_22050Hz()
throws Exception {
playVideoTest(
R.raw.video_176x144_3gp_h263_56kbps_25fps_aac_mono_24kbps_22050hz, 176, 144);
}
public void testLocalVideo_3gp_H263_176x144_56kbps_25fps_AAC_Stereo_24kbps_11025Hz()
throws Exception {
playVideoTest(
R.raw.video_176x144_3gp_h263_56kbps_25fps_aac_stereo_24kbps_11025hz, 176, 144);
}
public void testLocalVideo_3gp_H263_176x144_56kbps_25fps_AAC_Stereo_24kbps_22050Hz()
throws Exception {
playVideoTest(
R.raw.video_176x144_3gp_h263_56kbps_25fps_aac_stereo_24kbps_11025hz, 176, 144);
}
public void testLocalVideo_3gp_H263_176x144_56kbps_25fps_AAC_Stereo_128kbps_11025Hz()
throws Exception {
playVideoTest(
R.raw.video_176x144_3gp_h263_56kbps_25fps_aac_stereo_128kbps_11025hz, 176, 144);
}
public void testLocalVideo_3gp_H263_176x144_56kbps_25fps_AAC_Stereo_128kbps_22050Hz()
throws Exception {
playVideoTest(
R.raw.video_176x144_3gp_h263_56kbps_25fps_aac_stereo_128kbps_11025hz, 176, 144);
}
public void testLocalVideo_3gp_H263_176x144_300kbps_12fps_AAC_Mono_24kbps_11025Hz()
throws Exception {
playVideoTest(
R.raw.video_176x144_3gp_h263_300kbps_12fps_aac_mono_24kbps_11025hz, 176, 144);
}
public void testLocalVideo_3gp_H263_176x144_300kbps_12fps_AAC_Mono_24kbps_22050Hz()
throws Exception {
playVideoTest(
R.raw.video_176x144_3gp_h263_300kbps_12fps_aac_mono_24kbps_22050hz, 176, 144);
}
public void testLocalVideo_3gp_H263_176x144_300kbps_12fps_AAC_Stereo_24kbps_11025Hz()
throws Exception {
playVideoTest(
R.raw.video_176x144_3gp_h263_300kbps_12fps_aac_stereo_24kbps_11025hz, 176, 144);
}
public void testLocalVideo_3gp_H263_176x144_300kbps_12fps_AAC_Stereo_24kbps_22050Hz()
throws Exception {
playVideoTest(
R.raw.video_176x144_3gp_h263_300kbps_12fps_aac_stereo_24kbps_11025hz, 176, 144);
}
public void testLocalVideo_3gp_H263_176x144_300kbps_12fps_AAC_Stereo_128kbps_11025Hz()
throws Exception {
playVideoTest(
R.raw.video_176x144_3gp_h263_300kbps_12fps_aac_stereo_128kbps_11025hz, 176, 144);
}
public void testLocalVideo_3gp_H263_176x144_300kbps_12fps_AAC_Stereo_128kbps_22050Hz()
throws Exception {
playVideoTest(
R.raw.video_176x144_3gp_h263_300kbps_12fps_aac_stereo_128kbps_11025hz, 176, 144);
}
public void testLocalVideo_3gp_H263_176x144_300kbps_25fps_AAC_Mono_24kbps_11025Hz()
throws Exception {
playVideoTest(
R.raw.video_176x144_3gp_h263_300kbps_25fps_aac_mono_24kbps_11025hz, 176, 144);
}
public void testLocalVideo_3gp_H263_176x144_300kbps_25fps_AAC_Mono_24kbps_22050Hz()
throws Exception {
playVideoTest(
R.raw.video_176x144_3gp_h263_300kbps_25fps_aac_mono_24kbps_22050hz, 176, 144);
}
public void testLocalVideo_3gp_H263_176x144_300kbps_25fps_AAC_Stereo_24kbps_11025Hz()
throws Exception {
playVideoTest(
R.raw.video_176x144_3gp_h263_300kbps_25fps_aac_stereo_24kbps_11025hz, 176, 144);
}
public void testLocalVideo_3gp_H263_176x144_300kbps_25fps_AAC_Stereo_24kbps_22050Hz()
throws Exception {
playVideoTest(
R.raw.video_176x144_3gp_h263_300kbps_25fps_aac_stereo_24kbps_11025hz, 176, 144);
}
public void testLocalVideo_3gp_H263_176x144_300kbps_25fps_AAC_Stereo_128kbps_11025Hz()
throws Exception {
playVideoTest(
R.raw.video_176x144_3gp_h263_300kbps_25fps_aac_stereo_128kbps_11025hz, 176, 144);
}
public void testLocalVideo_3gp_H263_176x144_300kbps_25fps_AAC_Stereo_128kbps_22050Hz()
throws Exception {
playVideoTest(
R.raw.video_176x144_3gp_h263_300kbps_25fps_aac_stereo_128kbps_22050hz, 176, 144);
}
private void readTimedTextTracks() throws Exception {
mTimedTextTrackIndex.clear();
MediaPlayer.TrackInfo[] trackInfos = mMediaPlayer.getTrackInfo();
if (trackInfos == null || trackInfos.length == 0) {
return;
}
Vector<Integer> externalTrackIndex = new Vector<>();
for (int i = 0; i < trackInfos.length; ++i) {
assertTrue(trackInfos[i] != null);
if (trackInfos[i].getTrackType() == MediaPlayer.TrackInfo.MEDIA_TRACK_TYPE_TIMEDTEXT) {
MediaFormat format = trackInfos[i].getFormat();
String mime = format.getString(MediaFormat.KEY_MIME);
if (MediaPlayer.MEDIA_MIMETYPE_TEXT_SUBRIP.equals(mime)) {
externalTrackIndex.add(i);
} else {
mTimedTextTrackIndex.add(i);
}
}
}
mTimedTextTrackIndex.addAll(externalTrackIndex);
}
private int getTimedTextTrackCount() {
return mTimedTextTrackIndex.size();
}
private void selectSubtitleTrack(int index) throws Exception {
int trackIndex = mTimedTextTrackIndex.get(index);
mMediaPlayer.selectTrack(trackIndex);
mSelectedTimedTextIndex = index;
}
private void deselectSubtitleTrack(int index) throws Exception {
int trackIndex = mTimedTextTrackIndex.get(index);
mMediaPlayer.deselectTrack(trackIndex);
if (mSelectedTimedTextIndex == index) {
mSelectedTimedTextIndex = -1;
}
}
public void testDeselectTrack() throws Throwable {
if (!checkLoadResource(R.raw.testvideo_with_2_subtitles)) {
return; // skip;
}
runTestOnUiThread(new Runnable() {
public void run() {
try {
loadSubtitleSource(R.raw.test_subtitle1_srt);
} catch (Exception e) {
throw new AssertionFailedError(e.getMessage());
}
}
});
getInstrumentation().waitForIdleSync();
mMediaPlayer.setDisplay(getActivity().getSurfaceHolder());
mMediaPlayer.setScreenOnWhilePlaying(true);
mMediaPlayer.setWakeMode(mContext, PowerManager.PARTIAL_WAKE_LOCK);
mMediaPlayer.setOnTimedTextListener(new MediaPlayer.OnTimedTextListener() {
@Override
public void onTimedText(MediaPlayer mp, TimedText text) {
if (text != null) {
String plainText = text.getText();
if (plainText != null) {
mOnTimedTextCalled.signal();
Log.d(LOG_TAG, "text: " + plainText.trim());
}
}
}
});
mMediaPlayer.prepare();
readTimedTextTracks();
assertEquals(getTimedTextTrackCount(), 3);
mMediaPlayer.start();
assertTrue(mMediaPlayer.isPlaying());
// Run twice to check if repeated selection-deselection on the same track works well.
for (int i = 0; i < 2; i++) {
// Waits until at least one subtitle is fired. Timeout is 1 sec.
selectSubtitleTrack(0);
mOnTimedTextCalled.reset();
assertTrue(mOnTimedTextCalled.waitForSignal(1500));
// Try deselecting track.
deselectSubtitleTrack(0);
mOnTimedTextCalled.reset();
assertFalse(mOnTimedTextCalled.waitForSignal(1500));
}
// Run the same test for external subtitle track.
for (int i = 0; i < 2; i++) {
selectSubtitleTrack(2);
mOnTimedTextCalled.reset();
assertTrue(mOnTimedTextCalled.waitForSignal(1500));
// Try deselecting track.
deselectSubtitleTrack(2);
mOnTimedTextCalled.reset();
assertFalse(mOnTimedTextCalled.waitForSignal(1500));
}
try {
deselectSubtitleTrack(0);
fail("Deselecting unselected track: expected RuntimeException, " +
"but no exception has been triggered.");
} catch (RuntimeException e) {
// expected
}
mMediaPlayer.stop();
}
public void testChangeSubtitleTrack() throws Throwable {
if (!checkLoadResource(R.raw.testvideo_with_2_subtitles)) {
return; // skip;
}
mMediaPlayer.setDisplay(getActivity().getSurfaceHolder());
mMediaPlayer.setScreenOnWhilePlaying(true);
mMediaPlayer.setWakeMode(mContext, PowerManager.PARTIAL_WAKE_LOCK);
mMediaPlayer.setOnTimedTextListener(new MediaPlayer.OnTimedTextListener() {
@Override
public void onTimedText(MediaPlayer mp, TimedText text) {
final int toleranceMs = 500;
final int durationMs = 500;
int posMs = mMediaPlayer.getCurrentPosition();
if (text != null) {
String plainText = text.getText();
if (plainText != null) {
StringTokenizer tokens = new StringTokenizer(plainText.trim(), ":");
int subtitleTrackIndex = Integer.parseInt(tokens.nextToken());
int startMs = Integer.parseInt(tokens.nextToken());
Log.d(LOG_TAG, "text: " + plainText.trim() +
", trackId: " + subtitleTrackIndex + ", posMs: " + posMs);
assertTrue("The diff between subtitle's start time " + startMs +
" and current time " + posMs +
" is over tolerance " + toleranceMs,
(posMs >= startMs - toleranceMs) &&
(posMs < startMs + durationMs + toleranceMs) );
assertEquals("Expected track: " + mSelectedTimedTextIndex +
", actual track: " + subtitleTrackIndex,
mSelectedTimedTextIndex, subtitleTrackIndex);
mOnTimedTextCalled.signal();
}
}
}
});
mMediaPlayer.prepare();
assertFalse(mMediaPlayer.isPlaying());
runTestOnUiThread(new Runnable() {
public void run() {
try {
readTimedTextTracks();
} catch (Exception e) {
throw new AssertionFailedError(e.getMessage());
}
}
});
getInstrumentation().waitForIdleSync();
assertEquals(getTimedTextTrackCount(), 2);
runTestOnUiThread(new Runnable() {
public void run() {
try {
// Adds two more external subtitle files.
loadSubtitleSource(R.raw.test_subtitle1_srt);
loadSubtitleSource(R.raw.test_subtitle2_srt);
readTimedTextTracks();
} catch (Exception e) {
throw new AssertionFailedError(e.getMessage());
}
}
});
getInstrumentation().waitForIdleSync();
assertEquals(getTimedTextTrackCount(), 4);
selectSubtitleTrack(0);
mOnTimedTextCalled.reset();
mMediaPlayer.start();
assertTrue(mMediaPlayer.isPlaying());
// Waits until at least two subtitles are fired. Timeout is 2 sec.
// Please refer the test srt files:
// test_subtitle1_srt.3gp and test_subtitle2_srt.3gp
assertTrue(mOnTimedTextCalled.waitForCountedSignals(2, 2500) >= 2);
selectSubtitleTrack(1);
mOnTimedTextCalled.reset();
assertTrue(mOnTimedTextCalled.waitForCountedSignals(2, 2500) >= 2);
selectSubtitleTrack(2);
mOnTimedTextCalled.reset();
assertTrue(mOnTimedTextCalled.waitForCountedSignals(2, 2500) >= 2);
selectSubtitleTrack(3);
mOnTimedTextCalled.reset();
assertTrue(mOnTimedTextCalled.waitForCountedSignals(2, 2500) >= 2);
mMediaPlayer.stop();
}
public void testGetTrackInfo() throws Throwable {
if (!checkLoadResource(R.raw.testvideo_with_2_subtitles)) {
return; // skip;
}
runTestOnUiThread(new Runnable() {
public void run() {
try {
loadSubtitleSource(R.raw.test_subtitle1_srt);
loadSubtitleSource(R.raw.test_subtitle2_srt);
} catch (Exception e) {
throw new AssertionFailedError(e.getMessage());
}
}
});
getInstrumentation().waitForIdleSync();
mMediaPlayer.prepare();
mMediaPlayer.start();
readTimedTextTracks();
selectSubtitleTrack(2);
int count = 0;
MediaPlayer.TrackInfo[] trackInfos = mMediaPlayer.getTrackInfo();
assertTrue(trackInfos != null && trackInfos.length != 0);
for (int i = 0; i < trackInfos.length; ++i) {
assertTrue(trackInfos[i] != null);
if (trackInfos[i].getTrackType() == MediaPlayer.TrackInfo.MEDIA_TRACK_TYPE_TIMEDTEXT) {
String trackLanguage = trackInfos[i].getLanguage();
assertTrue(trackLanguage != null);
trackLanguage = trackLanguage.trim();
Log.d(LOG_TAG, "track info lang: " + trackLanguage);
assertTrue("Should not see empty track language with our test data.",
trackLanguage.length() > 0);
count++;
}
}
// There are 4 subtitle tracks in total in our test data.
assertEquals(4, count);
}
/*
* This test assumes the resources being tested are between 8 and 14 seconds long
* The ones being used here are 10 seconds long.
*/
public void testResumeAtEnd() throws Throwable {
int testsRun =
testResumeAtEnd(R.raw.loudsoftmp3) +
testResumeAtEnd(R.raw.loudsoftwav) +
testResumeAtEnd(R.raw.loudsoftogg) +
testResumeAtEnd(R.raw.loudsoftitunes) +
testResumeAtEnd(R.raw.loudsoftfaac) +
testResumeAtEnd(R.raw.loudsoftaac);
if (testsRun == 0) {
MediaUtils.skipTest("no decoder found");
}
}
// returns 1 if test was run, 0 otherwise
private int testResumeAtEnd(int res) throws Throwable {
if (!loadResource(res)) {
return 0; // skip
}
mMediaPlayer.prepare();
mOnCompletionCalled.reset();
mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
mOnCompletionCalled.signal();
mMediaPlayer.start();
}
});
// skip the first part of the file so we reach EOF sooner
mMediaPlayer.seekTo(5000);
mMediaPlayer.start();
// sleep long enough that we restart playback at least once, but no more
Thread.sleep(10000);
assertTrue("MediaPlayer should still be playing", mMediaPlayer.isPlaying());
mMediaPlayer.reset();
assertEquals("wrong number of repetitions", 1, mOnCompletionCalled.getNumSignal());
return 1;
}
public void testCallback() throws Throwable {
final int mp4Duration = 8484;
if (!checkLoadResource(R.raw.testvideo)) {
return; // skip;
}
mMediaPlayer.setDisplay(getActivity().getSurfaceHolder());
mMediaPlayer.setScreenOnWhilePlaying(true);
mMediaPlayer.setOnVideoSizeChangedListener(new MediaPlayer.OnVideoSizeChangedListener() {
@Override
public void onVideoSizeChanged(MediaPlayer mp, int width, int height) {
mOnVideoSizeChangedCalled.signal();
}
});
mMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
mOnPrepareCalled.signal();
}
});
mMediaPlayer.setOnSeekCompleteListener(new MediaPlayer.OnSeekCompleteListener() {
@Override
public void onSeekComplete(MediaPlayer mp) {
mOnSeekCompleteCalled.signal();
}
});
mOnCompletionCalled.reset();
mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
mOnCompletionCalled.signal();
}
});
mMediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
@Override
public boolean onError(MediaPlayer mp, int what, int extra) {
mOnErrorCalled.signal();
return false;
}
});
mMediaPlayer.setOnInfoListener(new MediaPlayer.OnInfoListener() {
@Override
public boolean onInfo(MediaPlayer mp, int what, int extra) {
mOnInfoCalled.signal();
return false;
}
});
assertFalse(mOnPrepareCalled.isSignalled());
assertFalse(mOnVideoSizeChangedCalled.isSignalled());
mMediaPlayer.prepare();
mOnPrepareCalled.waitForSignal();
mOnVideoSizeChangedCalled.waitForSignal();
mOnSeekCompleteCalled.reset();
mMediaPlayer.seekTo(mp4Duration >> 1);
mOnSeekCompleteCalled.waitForSignal();
assertFalse(mOnCompletionCalled.isSignalled());
mMediaPlayer.start();
while(mMediaPlayer.isPlaying()) {
Thread.sleep(SLEEP_TIME);
}
assertFalse(mMediaPlayer.isPlaying());
mOnCompletionCalled.waitForSignal();
assertFalse(mOnErrorCalled.isSignalled());
mMediaPlayer.stop();
mMediaPlayer.start();
mOnErrorCalled.waitForSignal();
}
public void testRecordAndPlay() throws Exception {
if (!hasMicrophone()) {
MediaUtils.skipTest(LOG_TAG, "no microphone");
return;
}
if (!MediaUtils.checkDecoder(MediaFormat.MIMETYPE_AUDIO_AMR_NB)
|| !MediaUtils.checkEncoder(MediaFormat.MIMETYPE_AUDIO_AMR_NB)) {
return; // skip
}
File outputFile = new File(Environment.getExternalStorageDirectory(),
"record_and_play.3gp");
String outputFileLocation = outputFile.getAbsolutePath();
try {
recordMedia(outputFileLocation);
MediaPlayer mp = new MediaPlayer();
try {
mp.setDataSource(outputFileLocation);
mp.prepareAsync();
Thread.sleep(SLEEP_TIME);
playAndStop(mp);
} finally {
mp.release();
}
Uri uri = Uri.parse(outputFileLocation);
mp = new MediaPlayer();
try {
mp.setDataSource(mContext, uri);
mp.prepareAsync();
Thread.sleep(SLEEP_TIME);
playAndStop(mp);
} finally {
mp.release();
}
try {
mp = MediaPlayer.create(mContext, uri);
playAndStop(mp);
} finally {
if (mp != null) {
mp.release();
}
}
try {
mp = MediaPlayer.create(mContext, uri, getActivity().getSurfaceHolder());
playAndStop(mp);
} finally {
if (mp != null) {
mp.release();
}
}
} finally {
outputFile.delete();
}
}
private void playAndStop(MediaPlayer mp) throws Exception {
mp.start();
Thread.sleep(SLEEP_TIME);
mp.stop();
}
private void recordMedia(String outputFile) throws Exception {
MediaRecorder mr = new MediaRecorder();
try {
mr.setAudioSource(MediaRecorder.AudioSource.MIC);
mr.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
mr.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
mr.setOutputFile(outputFile);
mr.prepare();
mr.start();
Thread.sleep(SLEEP_TIME);
mr.stop();
} finally {
mr.release();
}
}
private boolean hasMicrophone() {
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());
}
}