blob: 3dcb75069a46b83f22b14aa0c34379919e919263 [file] [log] [blame]
package org.linaro.mmtest;
import android.app.Activity;
import android.os.Bundle;
import android.os.Build;
import android.view.Window;
import android.util.Log;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.os.Process;
import android.view.SurfaceView;
import android.app.AlertDialog;
import java.io.RandomAccessFile;
import java.lang.Math;
import java.util.List;
public class MultimediaTest extends Activity implements android.media.MediaPlayer.OnCompletionListener,android.media.MediaPlayer.OnErrorListener,android.media.MediaPlayer.OnInfoListener {
private static final String TAG = "MultimediaTest";
private int currentTest = -1;
private boolean ranAnyTest = false;
private MediaPlayer mp;
private String failure;
private long timestamp;
private long cpuTimestamp;
private int expectedDuration;
private final Test[] tests = {
// Audio Codecs
new Test("test-AAC-Stereo-96k.m4a", "AAC Stereo 96k", false),
new Test("test-AAC-Mono-8k.m4a", "AAC Mono 8k", false),
new Test("test-AMR-NB.3gp", "AMR-NB", false),
new Test("test-flac.flac", "FLAC", false, 12 /*android.os.Build.HONEYCOMB_MR1*/),
new Test("test-MP3.mp3", "MP3", false),
new Test("test-Vorbis.ogg", "Ogg Vorbis", false),
new Test("test-PCM8.wav", "PCM 8-Bit", false),
new Test("test-PCM16.wav", "PCM 16-Bit", false),
// Video Codecs
new Test("test-H.263.3gp", "H.263"),
new Test("test-H.264.m4v", "H.264"),
new Test("test-MPEG4_SP.mp4", "MPEG-4 SP"),
new Test("test-VP8.webm", "VP8"),
// Mixed A/V
new Test("test-H.263-AAC.3gp", "3GP(H.263/AAC)"),
new Test("test-H.264-AAC.mp4", "MP4(H.264/AAC)"),
new Test("test-H.264-AAC-HD.mp4", "HD-MP4(H.264/AAC)"),
new Test("test-MPEG4-MP3.mp4", "MP4(MPEG4/MP3)"),
new Test("test-VP8-Vorbis.webm", "WebM(VP8/Vorbis)", true, 10 /*android.os.Build.GINGERBREAD_MR1*/)
};
class Test {
public String filename;
public String name;
public boolean hasVideo;
public int minVersion;
public Test(String pFilename, String pName, boolean pHasVideo, int pMinVersion) {
filename = pFilename;
name = pName;
hasVideo = pHasVideo;
minVersion = pMinVersion;
}
public Test(String pFilename, String pName, boolean pHasVideo) {
this(pFilename, pName, pHasVideo, 0);
}
public Test(String pFilename, String pName) {
this(pFilename, pName, true, 0);
}
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.v(TAG, "Starting tests");
SurfaceView sv=new SurfaceView(this);
setContentView(sv);
mp=new MediaPlayer();
mp.setOnCompletionListener(this);
mp.setOnErrorListener(this);
mp.setOnInfoListener(this);
mp.setAudioStreamType(android.media.AudioManager.STREAM_MUSIC);
mp.setDisplay(sv.getHolder());
runNextTest();
}
public void runNextTest() {
failure = "";
if(++currentTest > tests.length) {
Log.v(TAG, "Tests completed");
if(!ranAnyTest) {
AlertDialog dlg=new AlertDialog.Builder(this).setTitle("Files not found").setMessage("Multimedia files to be tested could not be found on the SD card. Please put the files (generated by the creator script) into the /mmtest directory of the SD card and try again.").create();
dlg.show();
}
finish();
}
Test t=tests[currentTest];
if(t.minVersion > android.os.Build.VERSION.SDK_INT) {
Log.i(TAG, "SKIP:" + t.name + ":Not expected to pass on this version of Android");
runNextTest();
return;
}
Log.v(TAG, "Running test " + t.name);
mp.reset();
try {
mp.setDataSource("/sdcard/mmtest/" + t.filename);
mp.prepare();
ranAnyTest = true;
} catch(java.io.IOException e) {
Log.e(TAG, "ERR:" + tests[currentTest].name + ":test:IO Error - test file seems to be missing: /sdcard/mmtest/" + t.filename);
runNextTest();
return;
}
if((mp.getVideoHeight() == 0) ^ t.hasVideo)
Log.i(TAG, "PASS:" + tests[currentTest].name + ":sanityCheck:Test and Player agree about whether or not the content has a video part");
else
Log.i(TAG, "FAIL:" + tests[currentTest].name + ":sanityCheck:Test and Player disagree about whether or not the content has a video part");
timestamp = System.currentTimeMillis();
cpuTimestamp = cpuTime();
expectedDuration = mp.getDuration();
if(expectedDuration <= 0)
Log.i(TAG, "WARN:" + tests[currentTest].name + ":Couldn't determine duration");
mp.start();
}
@Override
public void onCompletion(MediaPlayer mp) {
long elapsedTime = System.currentTimeMillis() - timestamp;
long elapsedCpuTime = cpuTime() - cpuTimestamp;
if(failure.length() == 0) {
if(expectedDuration >= 0 && Math.abs(elapsedTime - expectedDuration) > 10000) {
Log.i(TAG, "WARN:" + tests[currentTest].name + ":Actual playing time (" + Long.toString(elapsedTime) + "ms) differs significantly from expected time (" + Integer.toString(expectedDuration) + "ms)");
}
Log.i(TAG, "PASS:" + tests[currentTest].name + ":playback");
} else
Log.i(TAG, "FAIL:" + tests[currentTest].name + ":playback:" + failure);
// FIXME we should find a reasonable threshold to make
// an educated guess on whether or not a codec is hardware
// accelerated.
// Will require some testing on different hardware...
Log.i(TAG, "PERF:" + tests[currentTest].name + Long.toString(elapsedCpuTime) + " jiffies used");
runNextTest();
}
@Override
public boolean onError(MediaPlayer mp, int what, int extra) {
failure = "Got error code " + Integer.toString(what) + "/" + Integer.toString(extra);
return false; // call onCompletion
}
@Override
public boolean onInfo(MediaPlayer mp, int what, int extra) {
Log.i(TAG, "NOTE:" + tests[currentTest].name + ":playback:MediaPlayer sent info " + Integer.toString(what) + "/" + Integer.toString(extra));
return true;
}
public long cpuTime() {
long usedTime = 0;
try {
RandomAccessFile reader = new RandomAccessFile("/proc/" + Integer.toString(Process.myPid()) + "/stat", "r");
String[] toks=reader.readLine().split(" ");
// 13: jiffies in user mode
// 14: jiffies in kernel mode
// 15: jiffies in user mode of child processes (maybe some codecs launch an external decoder...)
// 16: jiffies in kernel mode of child processes
usedTime = Long.parseLong(toks[13]) + Long.parseLong(toks[14]) + Long.parseLong(toks[15]) + Long.parseLong(toks[16]);
reader.close();
} catch(java.io.FileNotFoundException e) {
Log.e(TAG, "ERR:/proc not mounted?");
} catch(java.io.IOException e) {
Log.e(TAG, "ERR:I/O error while reading CPU load");
}
return usedTime;
}
}