summaryrefslogtreecommitdiff
path: root/LoopbackApp/app/src/main/java/org/drrickorang/loopback/LoopbackActivity.java
diff options
context:
space:
mode:
Diffstat (limited to 'LoopbackApp/app/src/main/java/org/drrickorang/loopback/LoopbackActivity.java')
-rw-r--r--LoopbackApp/app/src/main/java/org/drrickorang/loopback/LoopbackActivity.java339
1 files changed, 244 insertions, 95 deletions
diff --git a/LoopbackApp/app/src/main/java/org/drrickorang/loopback/LoopbackActivity.java b/LoopbackApp/app/src/main/java/org/drrickorang/loopback/LoopbackActivity.java
index 5eb6d7b..36fbe71 100644
--- a/LoopbackApp/app/src/main/java/org/drrickorang/loopback/LoopbackActivity.java
+++ b/LoopbackApp/app/src/main/java/org/drrickorang/loopback/LoopbackActivity.java
@@ -32,9 +32,7 @@ import android.content.pm.PackageManager;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.Canvas;
-import android.media.AudioFormat;
import android.media.AudioManager;
-import android.media.MediaRecorder;
import android.net.Uri;
import android.os.Bundle;
import android.os.Build;
@@ -78,22 +76,35 @@ public class LoopbackActivity extends Activity
private static final int SAVE_PLAYER_BUFFER_PERIOD_TO_TXT_REQUEST = 46;
private static final int SAVE_RECORDER_BUFFER_PERIOD_TO_PNG_REQUEST = 47;
private static final int SAVE_PLAYER_BUFFER_PERIOD_TO_PNG_REQUEST = 48;
- private static final int SAVE_GLITCH_OCCURRENCES_TO_TEXT_REQUEST = 49;
- private static final int SETTINGS_ACTIVITY_REQUEST_CODE = 54;
+ private static final int SAVE_RECORDER_BUFFER_PERIOD_TIMES_TO_TXT_REQUEST = 49;
+ private static final int SAVE_PLAYER_BUFFER_PERIOD_TIMES_TO_TXT_REQUEST = 50;
+ private static final int SAVE_GLITCH_OCCURRENCES_TO_TEXT_REQUEST = 51;
+ private static final int SAVE_GLITCH_AND_CALLBACK_HEATMAP_REQUEST = 52;
+
+ private static final int SETTINGS_ACTIVITY_REQUEST = 54;
+
private static final int THREAD_SLEEP_DURATION_MS = 200;
- private static final int PERMISSIONS_REQUEST_RECORD_AUDIO = 201;
- private static final int PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE = 202;
+ private static final int PERMISSIONS_REQUEST_RECORD_AUDIO_LATENCY = 201;
+ private static final int PERMISSIONS_REQUEST_RECORD_AUDIO_BUFFER = 202;
+ private static final int PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE = 203;
private static final int LATENCY_TEST_STARTED = 300;
private static final int LATENCY_TEST_ENDED = 301;
private static final int BUFFER_TEST_STARTED = 302;
private static final int BUFFER_TEST_ENDED = 303;
+
+ // 0-100 controls compression rate, currently ignore because PNG format is being used
+ private static final int EXPORTED_IMAGE_QUALITY = 100;
+
private static final int HISTOGRAM_EXPORT_WIDTH = 2000;
private static final int HISTOGRAM_EXPORT_HEIGHT = 2000;
+ private static final int HEATMAP_DRAW_WIDTH = 2560;
+ private static final int HEATMAP_DRAW_HEIGHT = 1440;
+ private static final int HEATMAP_EXPORT_DIVISOR = 2;
LoopbackAudioThread mAudioThread = null;
NativeAudioThread mNativeAudioThread = null;
private WavePlotView mWavePlotView;
- private String mCurrentTime = "IncorrectTime"; // The time the plot is acquired
+ private String mTestStartTimeString = "IncorrectTime"; // The time the test begins
private static final String FILE_SAVE_PATH = "file://mnt/sdcard/";
private SeekBar mBarMasterLevel; // drag the volume
@@ -113,6 +124,8 @@ public class LoopbackActivity extends Activity
private int mNativeRecorderMaxBufferPeriod;
private int[] mNativePlayerBufferPeriodArray;
private int mNativePlayerMaxBufferPeriod;
+ private BufferCallbackTimes mRecorderCallbackTimes;
+ private BufferCallbackTimes mPlayerCallbackTimes;
private static final String INTENT_SAMPLING_FREQUENCY = "SF";
private static final String INTENT_CHANNEL_INDEX = "CI";
@@ -125,6 +138,10 @@ public class LoopbackActivity extends Activity
private static final String INTENT_TEST_TYPE = "TestType";
private static final String INTENT_BUFFER_TEST_DURATION = "BufferTestDuration";
private static final String INTENT_NUMBER_LOAD_THREADS = "NumLoadThreads";
+ private static final String INTENT_ENABLE_SYSTRACE = "CaptureSysTrace";
+ private static final String INTENT_ENABLE_WAVCAPTURE = "CaptureWavs";
+ private static final String INTENT_NUM_CAPTURES = "NumCaptures";
+ private static final String INTENT_WAV_DURATION = "WavDuration";
// for running the test using adb command
private boolean mIntentRunning = false; // if it is running triggered by intent with parameters
@@ -186,12 +203,12 @@ public class LoopbackActivity extends Activity
case LoopbackAudioThread.LOOPBACK_AUDIO_THREAD_MESSAGE_LATENCY_REC_COMPLETE:
if (mAudioThread != null) {
mWaveData = mAudioThread.getWaveData();
+ mRecorderCallbackTimes = mRecorderBufferPeriod.getCallbackTimes();
+ mPlayerCallbackTimes = mPlayerBufferPeriod.getCallbackTimes();
mCorrelation.computeCorrelation(mWaveData, mSamplingRate);
log("got message java latency rec complete!!");
refreshPlots();
refreshState();
- mCurrentTime = (String) DateFormat.format("MMddkkmmss",
- System.currentTimeMillis());
switch (msg.what) {
case LoopbackAudioThread.LOOPBACK_AUDIO_THREAD_MESSAGE_LATENCY_REC_STOP:
@@ -234,13 +251,14 @@ public class LoopbackActivity extends Activity
mGlitchingIntervalTooLong = mAudioThread.getGlitchingIntervalTooLong();
mFFTSamplingSize = mAudioThread.getFFTSamplingSize();
mFFTOverlapSamples = mAudioThread.getFFTOverlapSamples();
+ mRecorderCallbackTimes = mRecorderBufferPeriod.getCallbackTimes();
+ mPlayerCallbackTimes = mPlayerBufferPeriod.getCallbackTimes();
refreshPlots(); // only plot that last few seconds
refreshState();
- mCurrentTime = (String) DateFormat.format("MMddkkmmss",
- System.currentTimeMillis());
+ //rounded up number of seconds elapsed
mBufferTestElapsedSeconds =
- (int) ((System.currentTimeMillis() - mBufferTestStartTime)
- / Constant.MILLIS_PER_SECOND);
+ (int) ((System.currentTimeMillis() - mBufferTestStartTime +
+ Constant.MILLIS_PER_SECOND - 1) / Constant.MILLIS_PER_SECOND);
switch (msg.what) {
case LoopbackAudioThread.LOOPBACK_AUDIO_THREAD_MESSAGE_BUFFER_REC_STOP:
showToast("Java Buffer Test Stopped");
@@ -249,7 +267,9 @@ public class LoopbackActivity extends Activity
showToast("Java Buffer Test Completed");
break;
}
-
+ if (getApp().isCaptureSysTraceEnabled()) {
+ CaptureHolder.stopLoopbackListenerScript();
+ }
stopAudioTestThreads();
if (mIntentRunning && mIntentFileName != null && mIntentFileName.length() > 0) {
saveAllTo(mIntentFileName);
@@ -304,6 +324,8 @@ public class LoopbackActivity extends Activity
getRecorderMaxBufferPeriod();
mNativePlayerBufferPeriodArray = mNativeAudioThread.getPlayerBufferPeriod();
mNativePlayerMaxBufferPeriod = mNativeAudioThread.getPlayerMaxBufferPeriod();
+ mRecorderCallbackTimes = mNativeAudioThread.getRecorderCallbackTimes();
+ mPlayerCallbackTimes = mNativeAudioThread.getPlayerCallbackTimes();
if (msg.what != NativeAudioThread.
LOOPBACK_NATIVE_AUDIO_THREAD_MESSAGE_BUFFER_REC_COMPLETE) {
@@ -313,11 +335,10 @@ public class LoopbackActivity extends Activity
log("got message native buffer test rec complete!!");
refreshPlots();
refreshState();
- mCurrentTime = (String) DateFormat.format("MMddkkmmss",
- System.currentTimeMillis());
+ //rounded up number of seconds elapsed
mBufferTestElapsedSeconds =
- (int) ((System.currentTimeMillis() - mBufferTestStartTime)
- / Constant.MILLIS_PER_SECOND);
+ (int) ((System.currentTimeMillis() - mBufferTestStartTime +
+ Constant.MILLIS_PER_SECOND - 1) / Constant.MILLIS_PER_SECOND);
switch (msg.what) {
case NativeAudioThread.
LOOPBACK_NATIVE_AUDIO_THREAD_MESSAGE_BUFFER_REC_COMPLETE_ERRORS:
@@ -344,6 +365,9 @@ public class LoopbackActivity extends Activity
}
+ if (getApp().isCaptureSysTraceEnabled()) {
+ CaptureHolder.stopLoopbackListenerScript();
+ }
refreshSoundLevelBar();
break;
default:
@@ -401,6 +425,11 @@ public class LoopbackActivity extends Activity
View view = getLayoutInflater().inflate(R.layout.main_activity, null);
setContentView(view);
+ boolean successfulWrite = AtraceScriptsWriter.writeScriptsToFile(this);
+ if(!successfulWrite) {
+ showToast("Unable to write loopback_listener script to device");
+ }
+
mTextInfo = (TextView) findViewById(R.id.textInfo);
mBarMasterLevel = (SeekBar) findViewById(R.id.BarMasterLevel);
@@ -484,6 +513,8 @@ public class LoopbackActivity extends Activity
// --ei SF 48000 --es FileName test1 --ei RecorderBuffer 512 --ei PlayerBuffer 512
// --ei AudioThread 1 --ei MicSource 3 --ei AudioLevel 12
// --ei TestType 223 --ei BufferTestDuration 60 --ei NumLoadThreads 4
+ // --ei CI -1 --ez CaptureSysTrace true --ez CaptureWavs false --ei NumCaptures 5
+ // --ei WavDuration 15
// Note: for native mode, player and recorder buffer sizes are the same, and can only be
// set through player buffer size
@@ -547,6 +578,26 @@ public class LoopbackActivity extends Activity
mIntentRunning = true;
}
+ if (b.containsKey(INTENT_ENABLE_SYSTRACE)) {
+ getApp().setCaptureSysTraceEnabled(b.getBoolean(INTENT_ENABLE_SYSTRACE));
+ mIntentRunning = true;
+ }
+
+ if (b.containsKey(INTENT_ENABLE_WAVCAPTURE)) {
+ getApp().setCaptureWavsEnabled(b.getBoolean(INTENT_ENABLE_WAVCAPTURE));
+ mIntentRunning = true;
+ }
+
+ if (b.containsKey(INTENT_NUM_CAPTURES)) {
+ getApp().setNumberOfCaptures(b.getInt(INTENT_NUM_CAPTURES));
+ mIntentRunning = true;
+ }
+
+ if (b.containsKey(INTENT_WAV_DURATION)) {
+ getApp().setBufferTestWavePlotDuration(b.getInt(INTENT_WAV_DURATION));
+ mIntentRunning = true;
+ }
+
if (mIntentRunning || b.containsKey(INTENT_TEST_TYPE)) {
// run tests with provided or default parameters
refreshState();
@@ -648,7 +699,7 @@ public class LoopbackActivity extends Activity
// Launch settings activity
Intent mySettingsIntent = new Intent(this, SettingsActivity.class);
- startActivityForResult(mySettingsIntent, SETTINGS_ACTIVITY_REQUEST_CODE);
+ startActivityForResult(mySettingsIntent, SETTINGS_ACTIVITY_REQUEST);
} else {
showToast("Test in progress... please wait");
}
@@ -686,10 +737,16 @@ public class LoopbackActivity extends Activity
mChannelIndex = getApp().getChannelIndex();
mPlayerBufferSizeInBytes = getApp().getPlayerBufferSizeInBytes();
mRecorderBufferSizeInBytes = getApp().getRecorderBufferSizeInBytes();
+ mTestStartTimeString = (String) DateFormat.format("MMddkkmmss",
+ System.currentTimeMillis());
int micSource = getApp().getMicSource();
int bufferTestDurationInSeconds = getApp().getBufferTestDuration();
int bufferTestWavePlotDurationInSeconds = getApp().getBufferTestWavePlotDuration();
+ CaptureHolder captureHolder = new CaptureHolder(getApp().getNumStateCaptures(),
+ getFileNamePrefix(), getApp().isCaptureWavSnippetsEnabled(),
+ getApp().isCaptureSysTraceEnabled(), this, mSamplingRate);
+
log(" current sampling rate: " + mSamplingRate);
stopAudioTestThreads();
@@ -699,11 +756,25 @@ public class LoopbackActivity extends Activity
case Constant.AUDIO_THREAD_TYPE_JAVA:
micSourceMapped = getApp().mapMicSource(Constant.AUDIO_THREAD_TYPE_JAVA, micSource);
+ int expectedRecorderBufferPeriod = Math.round(
+ (float) (mRecorderBufferSizeInBytes * Constant.MILLIS_PER_SECOND)
+ / (Constant.BYTES_PER_FRAME * mSamplingRate));
+ mRecorderBufferPeriod.prepareMemberObjects(
+ Constant.MAX_RECORDED_LATE_CALLBACKS_PER_SECOND * bufferTestDurationInSeconds,
+ expectedRecorderBufferPeriod, captureHolder);
+
+ int expectedPlayerBufferPeriod = Math.round(
+ (float) (mPlayerBufferSizeInBytes * Constant.MILLIS_PER_SECOND)
+ / (Constant.BYTES_PER_FRAME * mSamplingRate));
+ mPlayerBufferPeriod.prepareMemberObjects(
+ Constant.MAX_RECORDED_LATE_CALLBACKS_PER_SECOND * bufferTestDurationInSeconds,
+ expectedPlayerBufferPeriod, captureHolder);
+
mAudioThread = new LoopbackAudioThread(mSamplingRate, mPlayerBufferSizeInBytes,
mRecorderBufferSizeInBytes, micSourceMapped, mRecorderBufferPeriod,
mPlayerBufferPeriod, mTestType, bufferTestDurationInSeconds,
bufferTestWavePlotDurationInSeconds, getApplicationContext(),
- mChannelIndex);
+ mChannelIndex, captureHolder);
mAudioThread.setMessageHandler(mMessageHandler);
mAudioThread.mSessionId = sessionId;
mAudioThread.start();
@@ -714,7 +785,8 @@ public class LoopbackActivity extends Activity
// size = player buffer size in native mode
mNativeAudioThread = new NativeAudioThread(mSamplingRate, mPlayerBufferSizeInBytes,
mRecorderBufferSizeInBytes, micSourceMapped, mTestType,
- bufferTestDurationInSeconds, bufferTestWavePlotDurationInSeconds);
+ bufferTestDurationInSeconds, bufferTestWavePlotDurationInSeconds,
+ captureHolder);
mNativeAudioThread.setMessageHandler(mMessageHandler);
mNativeAudioThread.mSessionId = sessionId;
mNativeAudioThread.start();
@@ -824,7 +896,7 @@ public class LoopbackActivity extends Activity
if (hasRecordAudioPermission()) {
startLatencyTest();
} else {
- requestRecordAudioPermission();
+ requestRecordAudioPermission(PERMISSIONS_REQUEST_RECORD_AUDIO_LATENCY);
}
}
@@ -869,7 +941,7 @@ public class LoopbackActivity extends Activity
if (hasRecordAudioPermission()) {
startBufferTest();
} else {
- requestRecordAudioPermission();
+ requestRecordAudioPermission(PERMISSIONS_REQUEST_RECORD_AUDIO_BUFFER);
}
}
@@ -946,7 +1018,7 @@ public class LoopbackActivity extends Activity
*/
private void SaveFilesWithDialog() {
- String fileName = "loopback_" + mCurrentTime;
+ String fileName = "loopback_" + mTestStartTimeString;
//Launch filename choosing activities if available, otherwise save without prompting
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
@@ -955,15 +1027,22 @@ public class LoopbackActivity extends Activity
launchFileNameChoosingActivity("audio/wav", fileName, ".wav", SAVE_TO_WAVE_REQUEST);
launchFileNameChoosingActivity("text/plain", fileName, "_recorderBufferPeriod.txt",
SAVE_RECORDER_BUFFER_PERIOD_TO_TXT_REQUEST);
+ launchFileNameChoosingActivity("text/plain", fileName, "_recorderBufferPeriodTimes.txt",
+ SAVE_RECORDER_BUFFER_PERIOD_TIMES_TO_TXT_REQUEST);
launchFileNameChoosingActivity("image/png", fileName, "_recorderBufferPeriod.png",
SAVE_RECORDER_BUFFER_PERIOD_TO_PNG_REQUEST);
launchFileNameChoosingActivity("text/plain", fileName, "_playerBufferPeriod.txt",
SAVE_PLAYER_BUFFER_PERIOD_TO_TXT_REQUEST);
+ launchFileNameChoosingActivity("text/plain", fileName, "_playerBufferPeriodTimes.txt",
+ SAVE_PLAYER_BUFFER_PERIOD_TIMES_TO_TXT_REQUEST);
launchFileNameChoosingActivity("image/png", fileName, "_playerBufferPeriod.png",
SAVE_PLAYER_BUFFER_PERIOD_TO_PNG_REQUEST);
+
if (mGlitchesData != null) {
launchFileNameChoosingActivity("text/plain", fileName, "_glitchMillis.txt",
SAVE_GLITCH_OCCURRENCES_TO_TEXT_REQUEST);
+ launchFileNameChoosingActivity("image/png", fileName, "_heatMap.png",
+ SAVE_GLITCH_AND_CALLBACK_HEATMAP_REQUEST);
}
} else {
saveAllTo(fileName);
@@ -982,6 +1061,13 @@ public class LoopbackActivity extends Activity
startActivityForResult(FilenameIntent, RequestCode);
}
+ private String getFileNamePrefix(){
+ if (mIntentFileName != null && !mIntentFileName.isEmpty()) {
+ return mIntentFileName;
+ } else {
+ return "loopback_" + mTestStartTimeString;
+ }
+ }
/** See the documentation on onButtonSave() */
public void saveAllTo(String fileName) {
@@ -998,7 +1084,7 @@ public class LoopbackActivity extends Activity
saveScreenShot(Uri.parse(FILE_SAVE_PATH + fileName + ".png"));
- saveReport(Uri.parse(FILE_SAVE_PATH + fileName + ".txt"));
+ saveTextToFile(Uri.parse(FILE_SAVE_PATH + fileName + ".txt"), getReport().toString());
int[] bufferPeriodArray = null;
int maxBufferPeriod = Constant.UNKNOWN;
@@ -1016,6 +1102,8 @@ public class LoopbackActivity extends Activity
bufferPeriodArray, maxBufferPeriod);
saveHistogram(Uri.parse(FILE_SAVE_PATH + fileName + "_recorderBufferPeriod.png"),
bufferPeriodArray, maxBufferPeriod);
+ saveTextToFile(Uri.parse(FILE_SAVE_PATH + fileName + "_recorderBufferPeriodTimes.txt"),
+ mRecorderCallbackTimes.toString());
bufferPeriodArray = null;
maxBufferPeriod = Constant.UNKNOWN;
@@ -1029,14 +1117,21 @@ public class LoopbackActivity extends Activity
maxBufferPeriod = mNativePlayerMaxBufferPeriod;
break;
}
- saveBufferPeriod(Uri.parse(FILE_SAVE_PATH + fileName + "_playerBufferPeriod.txt")
+ saveBufferPeriod(Uri.parse(FILE_SAVE_PATH + fileName + "_playerBufferPeriod.txt")
, bufferPeriodArray, maxBufferPeriod);
saveHistogram(Uri.parse(FILE_SAVE_PATH + fileName + "_playerBufferPeriod.png"),
bufferPeriodArray, maxBufferPeriod);
+ saveTextToFile(Uri.parse(FILE_SAVE_PATH + fileName + "_playerBufferPeriodTimes.txt"),
+ mPlayerCallbackTimes.toString());
if (mGlitchesData != null) {
saveGlitchOccurrences(Uri.parse(FILE_SAVE_PATH + fileName + "_glitchMillis.txt"),
mGlitchesData);
+ saveHeatMap(Uri.parse(FILE_SAVE_PATH + fileName + "_heatMap.png"),
+ mRecorderCallbackTimes, mPlayerCallbackTimes,
+ GlitchesStringBuilder.getGlitchMilliseconds(mFFTSamplingSize,
+ mFFTOverlapSamples, mGlitchesData, mSamplingRate),
+ mGlitchingIntervalTooLong, mBufferTestElapsedSeconds, fileName);
}
}
@@ -1062,7 +1157,7 @@ public class LoopbackActivity extends Activity
break;
case SAVE_TO_TXT_REQUEST:
if (resultData != null) {
- saveReport(resultData.getData());
+ saveTextToFile(resultData.getData(), getReport().toString());
}
break;
case SAVE_RECORDER_BUFFER_PERIOD_TO_TXT_REQUEST:
@@ -1133,12 +1228,33 @@ public class LoopbackActivity extends Activity
saveHistogram(resultData.getData(), bufferPeriodArray, maxBufferPeriod);
}
break;
+ case SAVE_PLAYER_BUFFER_PERIOD_TIMES_TO_TXT_REQUEST:
+ if (resultData != null) {
+ saveTextToFile(resultData.getData(),
+ mPlayerCallbackTimes.toString());
+ }
+ break;
+ case SAVE_RECORDER_BUFFER_PERIOD_TIMES_TO_TXT_REQUEST:
+ if (resultData != null) {
+ saveTextToFile(resultData.getData(),
+ mRecorderCallbackTimes.toString());
+ }
+ break;
case SAVE_GLITCH_OCCURRENCES_TO_TEXT_REQUEST:
if (resultData != null) {
saveGlitchOccurrences(resultData.getData(), mGlitchesData);
}
break;
- case SETTINGS_ACTIVITY_REQUEST_CODE:
+ case SAVE_GLITCH_AND_CALLBACK_HEATMAP_REQUEST:
+ if (resultData != null && mGlitchesData != null && mRecorderCallbackTimes != null
+ & mPlayerCallbackTimes != null){
+ saveHeatMap(resultData.getData(), mRecorderCallbackTimes, mPlayerCallbackTimes,
+ GlitchesStringBuilder.getGlitchMilliseconds(mFFTSamplingSize,
+ mFFTOverlapSamples, mGlitchesData, mSamplingRate),
+ mGlitchingIntervalTooLong, mBufferTestElapsedSeconds,
+ resultData.getData().toString());
+ }
+ case SETTINGS_ACTIVITY_REQUEST:
log("return from new settings!");
// here we wipe out all previous results, in order to avoid the condition where
@@ -1167,10 +1283,10 @@ public class LoopbackActivity extends Activity
/** Reset all results gathered from previous round of test (if any). */
private void resetResults() {
mCorrelation.invalidate();
- mRecorderBufferPeriod.resetRecord();
- mPlayerBufferPeriod.resetRecord();
mNativeRecorderBufferPeriodArray = null;
mNativePlayerBufferPeriodArray = null;
+ mPlayerCallbackTimes = null;
+ mRecorderCallbackTimes = null;
mGlitchesData = null;
mWaveData = null;
}
@@ -1228,15 +1344,12 @@ public class LoopbackActivity extends Activity
switch (mAudioThreadType) {
case Constant.AUDIO_THREAD_TYPE_JAVA:
- RecorderBufferPeriodIntent.putExtra("recorderBufferPeriodTimeStampArray",
- mRecorderBufferPeriod.getBufferPeriodTimeStampArray());
RecorderBufferPeriodIntent.putExtra("recorderBufferPeriodArray",
mRecorderBufferPeriod.getBufferPeriodArray());
RecorderBufferPeriodIntent.putExtra("recorderBufferPeriodMax",
mRecorderBufferPeriod.getMaxBufferPeriod());
break;
case Constant.AUDIO_THREAD_TYPE_NATIVE:
- // TODO change code in sles.cpp to collect timeStamp in native mode as well
RecorderBufferPeriodIntent.putExtra("recorderBufferPeriodArray",
mNativeRecorderBufferPeriodArray);
RecorderBufferPeriodIntent.putExtra("recorderBufferPeriodMax",
@@ -1260,15 +1373,12 @@ public class LoopbackActivity extends Activity
switch (mAudioThreadType) {
case Constant.AUDIO_THREAD_TYPE_JAVA:
- PlayerBufferPeriodIntent.putExtra("playerBufferPeriodTimeStampArray",
- mPlayerBufferPeriod.getBufferPeriodTimeStampArray());
PlayerBufferPeriodIntent.putExtra("playerBufferPeriodArray",
mPlayerBufferPeriod.getBufferPeriodArray());
PlayerBufferPeriodIntent.putExtra("playerBufferPeriodMax",
mPlayerBufferPeriod.getMaxBufferPeriod());
break;
case Constant.AUDIO_THREAD_TYPE_NATIVE:
- // TODO change code in sles.cpp to collect timeStamp in native mode as well
PlayerBufferPeriodIntent.putExtra("playerBufferPeriodArray",
mNativePlayerBufferPeriodArray);
PlayerBufferPeriodIntent.putExtra("playerBufferPeriodMax",
@@ -1339,6 +1449,37 @@ public class LoopbackActivity extends Activity
}
}
+ /** Display pop up window of recorded metrics and system information */
+ public void onButtonHeatMap(View view) {
+ if (!isBusy()) {
+ if (mTestType == Constant.LOOPBACK_PLUG_AUDIO_THREAD_TEST_TYPE_BUFFER_PERIOD
+ && mGlitchesData != null && mRecorderCallbackTimes != null
+ && mRecorderCallbackTimes != null) {
+
+ // Create a PopUpWindow with heatMap custom view
+ View puLayout = this.getLayoutInflater().inflate(R.layout.heatmap_window, null);
+ PopupWindow popUp = new PopupWindow(puLayout, ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT, true);
+
+ ((LinearLayout) popUp.getContentView()).addView(
+ new GlitchAndCallbackHeatMapView(this, mRecorderCallbackTimes,
+ mPlayerCallbackTimes,
+ GlitchesStringBuilder.getGlitchMilliseconds(mFFTSamplingSize,
+ mFFTOverlapSamples, mGlitchesData, mSamplingRate),
+ mGlitchingIntervalTooLong, mBufferTestElapsedSeconds,
+ getResources().getString(R.string.heatTitle)));
+
+ popUp.showAtLocation(findViewById(R.id.linearLayoutMain), Gravity.TOP, 0, 0);
+
+ } else {
+ showToast("Please run the tests to get data");
+ }
+
+ } else {
+ showToast("Test in progress... please wait");
+ }
+ }
+
/** Redraw the plot according to mWaveData */
void refreshPlots() {
mWavePlotView.setData(mWaveData);
@@ -1502,8 +1643,35 @@ public class LoopbackActivity extends Activity
}
}
- /** Save a screenshot of the main activity. */
private void saveHistogram(Uri uri, int[] bufferPeriodArray, int maxBufferPeriod) {
+ // Create and histogram view bitmap
+ HistogramView recordHisto = new HistogramView(this,null);
+ recordHisto.setBufferPeriodArray(bufferPeriodArray);
+ recordHisto.setMaxBufferPeriod(maxBufferPeriod);
+
+ // Draw histogram on bitmap canvas
+ Bitmap histoBmp = Bitmap.createBitmap(HISTOGRAM_EXPORT_WIDTH,
+ HISTOGRAM_EXPORT_HEIGHT, Bitmap.Config.ARGB_8888); // creates a MUTABLE bitmap
+ recordHisto.fillCanvas(new Canvas(histoBmp), histoBmp.getWidth(), histoBmp.getHeight());
+
+ saveImage(uri, histoBmp);
+ }
+
+ private void saveHeatMap(Uri uri, BufferCallbackTimes recorderCallbackTimes,
+ BufferCallbackTimes playerCallbackTimes, int[] glitchMilliseconds,
+ boolean glitchesExceeded, int duration, String title) {
+ Bitmap heatBmp = Bitmap.createBitmap(HEATMAP_DRAW_WIDTH, HEATMAP_DRAW_HEIGHT,
+ Bitmap.Config.ARGB_8888);
+ GlitchAndCallbackHeatMapView.fillCanvas(new Canvas(heatBmp), recorderCallbackTimes,
+ playerCallbackTimes, glitchMilliseconds, glitchesExceeded, duration,
+ title);
+ saveImage(uri, Bitmap.createScaledBitmap(heatBmp,
+ HEATMAP_DRAW_WIDTH / HEATMAP_EXPORT_DIVISOR,
+ HEATMAP_DRAW_HEIGHT / HEATMAP_EXPORT_DIVISOR, false));
+ }
+
+ /** Save an image to file. */
+ private void saveImage(Uri uri, Bitmap bmp) {
ParcelFileDescriptor parcelFileDescriptor = null;
FileOutputStream outputStream;
try {
@@ -1515,19 +1683,8 @@ public class LoopbackActivity extends Activity
log("Done creating output stream");
- // Create and save histogram view
- HistogramView recordHisto = new HistogramView(this,null);
- recordHisto.setBufferPeriodArray(bufferPeriodArray);
- recordHisto.setMaxBufferPeriod(maxBufferPeriod);
-
- // Draw histogram on bitmap canvas
- Bitmap histoBmp = Bitmap.createBitmap(HISTOGRAM_EXPORT_WIDTH,
- HISTOGRAM_EXPORT_HEIGHT, Bitmap.Config.ARGB_8888); // creates a MUTABLE bitmap
- Canvas canvas = new Canvas(histoBmp);
- recordHisto.fillCanvas(canvas, histoBmp.getWidth(), histoBmp.getHeight());
-
// Save compressed bitmap to file
- histoBmp.compress(Bitmap.CompressFormat.PNG, 100, outputStream);
+ bmp.compress(Bitmap.CompressFormat.PNG, EXPORTED_IMAGE_QUALITY, outputStream);
parcelFileDescriptor.close();
} catch (Exception e) {
log("Failed to open png file " + e);
@@ -1564,10 +1721,10 @@ public class LoopbackActivity extends Activity
int[] usefulBufferData = Arrays.copyOfRange(bufferPeriodArray, 0, usefulDataRange);
String endline = "\n";
- String tab = "\t";
+ String delimiter = ",";
StringBuilder sb = new StringBuilder();
for (int i = 0; i < usefulBufferData.length; i++) {
- sb.append(i + tab + usefulBufferData[i] + endline);
+ sb.append(i + delimiter + usefulBufferData[i] + endline);
}
outputStream.write(sb.toString().getBytes());
@@ -1589,7 +1746,7 @@ public class LoopbackActivity extends Activity
}
/** Save a .txt file of various test results. */
- void saveReport(Uri uri) {
+ void saveTextToFile(Uri uri, String outputText) {
ParcelFileDescriptor parcelFileDescriptor = null;
FileOutputStream outputStream;
try {
@@ -1600,7 +1757,7 @@ public class LoopbackActivity extends Activity
outputStream = new FileOutputStream(fileDescriptor);
log("Done creating output stream");
- outputStream.write(getReport().toString().getBytes());
+ outputStream.write(outputText.getBytes());
parcelFileDescriptor.close();
} catch (Exception e) {
log("Failed to open text file " + e);
@@ -1621,7 +1778,7 @@ public class LoopbackActivity extends Activity
String endline = "\n";
final int stringLength = 300;
StringBuilder sb = new StringBuilder(stringLength);
- sb.append("DateTime = " + mCurrentTime + endline);
+ sb.append("DateTime = " + mTestStartTimeString + endline);
sb.append(INTENT_SAMPLING_FREQUENCY + " = " + getApp().getSamplingRate() + endline);
sb.append(INTENT_RECORDER_BUFFER + " = " + getApp().getRecorderBufferSizeInBytes() /
Constant.BYTES_PER_FRAME + endline);
@@ -1665,14 +1822,7 @@ public class LoopbackActivity extends Activity
case Constant.LOOPBACK_PLUG_AUDIO_THREAD_TEST_TYPE_BUFFER_PERIOD:
sb.append("Buffer Test Duration (s) = " + mBufferTestElapsedSeconds + endline);
- // report expected recorder buffer period
- int expectedRecorderBufferPeriod = mRecorderBufferSizeInBytes /
- Constant.BYTES_PER_FRAME * Constant.MILLIS_PER_SECOND / mSamplingRate;
- sb.append("Expected Recorder Buffer Period (ms) = " + expectedRecorderBufferPeriod +
- endline);
-
// report recorder results
- int recorderBufferSize = mRecorderBufferSizeInBytes / Constant.BYTES_PER_FRAME;
int[] recorderBufferData = null;
int recorderBufferDataMax = 0;
switch (mAudioThreadType) {
@@ -1685,6 +1835,7 @@ public class LoopbackActivity extends Activity
recorderBufferDataMax = mNativeRecorderMaxBufferPeriod;
break;
}
+ // report expected recorder buffer period
if (recorderBufferData != null) {
// this is the range of data that actually has values
int usefulDataRange = Math.min(recorderBufferDataMax + 1,
@@ -1692,11 +1843,13 @@ public class LoopbackActivity extends Activity
int[] usefulBufferData = Arrays.copyOfRange(recorderBufferData, 0,
usefulDataRange);
PerformanceMeasurement measurement = new PerformanceMeasurement(
- recorderBufferSize, mSamplingRate, usefulBufferData);
+ mRecorderCallbackTimes.getExpectedBufferPeriod(), usefulBufferData);
float recorderPercentAtExpected =
measurement.percentBufferPeriodsAtExpected();
double benchmark = measurement.computeWeightedBenchmark();
int outliers = measurement.countOutliers();
+ sb.append("Expected Recorder Buffer Period (ms) = " +
+ mRecorderCallbackTimes.getExpectedBufferPeriod() + endline);
sb.append("Recorder Buffer Periods At Expected = " +
String.format("%.5f%%", recorderPercentAtExpected * 100) + endline);
@@ -1711,7 +1864,6 @@ public class LoopbackActivity extends Activity
}
// report player results
- int playerBufferSize = mPlayerBufferSizeInBytes / Constant.BYTES_PER_FRAME;
int[] playerBufferData = null;
int playerBufferDataMax = 0;
switch (mAudioThreadType) {
@@ -1724,6 +1876,9 @@ public class LoopbackActivity extends Activity
playerBufferDataMax = mNativePlayerMaxBufferPeriod;
break;
}
+ // report expected player buffer period
+ sb.append("Expected Player Buffer Period (ms) = " +
+ mPlayerCallbackTimes.getExpectedBufferPeriod() + endline);
if (playerBufferData != null) {
// this is the range of data that actually has values
int usefulDataRange = Math.min(playerBufferDataMax + 1,
@@ -1731,7 +1886,7 @@ public class LoopbackActivity extends Activity
int[] usefulBufferData = Arrays.copyOfRange(playerBufferData, 0,
usefulDataRange);
PerformanceMeasurement measurement = new PerformanceMeasurement(
- playerBufferSize, mSamplingRate, usefulBufferData);
+ mPlayerCallbackTimes.getExpectedBufferPeriod(), usefulBufferData);
float playerPercentAtExpected = measurement.percentBufferPeriodsAtExpected();
double benchmark = measurement.computeWeightedBenchmark();
int outliers = measurement.countOutliers();
@@ -1748,18 +1903,6 @@ public class LoopbackActivity extends Activity
} else {
sb.append("Cannot Find Player Buffer Period Data!" + endline);
}
-
- // report expected player buffer period
- int expectedPlayerBufferPeriod = mPlayerBufferSizeInBytes / Constant.BYTES_PER_FRAME
- * Constant.MILLIS_PER_SECOND / mSamplingRate;
- if (audioType.equals("JAVA")) {
- // javaPlayerMultiple depends on the samples written per AudioTrack.write()
- int javaPlayerMultiple = 2;
- expectedPlayerBufferPeriod *= javaPlayerMultiple;
- }
- sb.append("Expected Player Buffer Period (ms) = " + expectedPlayerBufferPeriod +
- endline);
-
// report glitches per hour
int numberOfGlitches = estimateNumberOfGlitches(mGlitchesData);
float testDurationInHours = mBufferTestElapsedSeconds
@@ -1773,8 +1916,18 @@ public class LoopbackActivity extends Activity
sb.append("Total Number of Glitches = " + numberOfGlitches + endline);
// report if the total glitching interval is too long
- sb.append("Total glitching interval too long: " +
- mGlitchingIntervalTooLong + endline);
+ sb.append("Total glitching interval too long = " +
+ mGlitchingIntervalTooLong);
+
+ sb.append("\nLate Player Callbacks = ");
+ sb.append(mPlayerCallbackTimes.getNumLateOrEarlyCallbacks());
+ sb.append("\nLate Player Callbacks Exceeded Capacity = ");
+ sb.append(mPlayerCallbackTimes.isCapacityExceeded());
+ sb.append("\nLate Recorder Callbacks = ");
+ sb.append(mRecorderCallbackTimes.getNumLateOrEarlyCallbacks());
+ sb.append("\nLate Recorder Callbacks Exceeded Capacity = ");
+ sb.append(mRecorderCallbackTimes.isCapacityExceeded());
+ sb.append("\n");
}
@@ -1882,7 +2035,7 @@ public class LoopbackActivity extends Activity
/**
* Requests the RECORD_AUDIO permission from the user
*/
- private void requestRecordAudioPermission(){
+ private void requestRecordAudioPermission(int requestCode){
String requiredPermission = Manifest.permission.RECORD_AUDIO;
@@ -1891,30 +2044,26 @@ public class LoopbackActivity extends Activity
if (ActivityCompat.shouldShowRequestPermissionRationale(this,
requiredPermission)) {
- showToast("This app needs to record audio through the microphone to test the device's performance");
+ showToast("This app needs to record audio through the microphone to test the device's "+
+ "performance");
}
// request the permission.
- ActivityCompat.requestPermissions(this,
- new String[]{requiredPermission},
- PERMISSIONS_REQUEST_RECORD_AUDIO);
+ ActivityCompat.requestPermissions(this, new String[]{requiredPermission}, requestCode);
}
@Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
- // We can ignore this call since we'll check for RECORD_AUDIO each time the
- // user does anything which requires that permission. We can't, however, delete
- // this method as this will cause ActivityCompat.requestPermissions to fail.
-
- // Save all files after being granted permissions
- if (requestCode == PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE && grantResults.length > 0
- && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
- if (mIntentFileName != null && !mIntentFileName.isEmpty()) {
- saveAllTo(mIntentFileName);
- } else {
- saveAllTo("loopback_" + mCurrentTime);
+ // Save all files or run requested test after being granted permissions
+ if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
+ if (requestCode == PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE ) {
+ saveAllTo(getFileNamePrefix());
+ } else if (requestCode == PERMISSIONS_REQUEST_RECORD_AUDIO_BUFFER) {
+ startBufferTest();
+ } else if (requestCode == PERMISSIONS_REQUEST_RECORD_AUDIO_LATENCY) {
+ startLatencyTest();
}
}
}
@@ -1952,7 +2101,7 @@ public class LoopbackActivity extends Activity
@Override
public void onSaveDialogSelect(DialogFragment dialog, boolean saveWithoutDialog) {
if (saveWithoutDialog) {
- saveAllTo("loopback_" + mCurrentTime);
+ saveAllTo("loopback_" + mTestStartTimeString);
} else {
SaveFilesWithDialog();
}