summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--LoopbackApp/app/build.gradle2
-rw-r--r--LoopbackApp/app/src/main/AndroidManifest.xml4
-rw-r--r--LoopbackApp/app/src/main/java/org/drrickorang/loopback/CaptureHolder.java30
-rw-r--r--LoopbackApp/app/src/main/java/org/drrickorang/loopback/Correlation.java9
-rw-r--r--LoopbackApp/app/src/main/java/org/drrickorang/loopback/LoopbackActivity.java116
-rw-r--r--LoopbackApp/app/src/main/java/org/drrickorang/loopback/LoopbackAudioThread.java6
-rw-r--r--LoopbackApp/app/src/main/java/org/drrickorang/loopback/NativeAudioThread.java4
-rw-r--r--LoopbackApp/app/src/main/java/org/drrickorang/loopback/SoundLevelCalibration.java56
-rw-r--r--LoopbackApp/app/src/main/jni/sles.cpp40
-rw-r--r--LoopbackApp/app/src/main/res/raw/loopback_listener7
-rw-r--r--LoopbackApp/build.gradle2
-rw-r--r--LoopbackApp/gradle/wrapper/gradle-wrapper.properties4
12 files changed, 202 insertions, 78 deletions
diff --git a/LoopbackApp/app/build.gradle b/LoopbackApp/app/build.gradle
index b1e114a..ff69f81 100644
--- a/LoopbackApp/app/build.gradle
+++ b/LoopbackApp/app/build.gradle
@@ -3,7 +3,7 @@ apply plugin: 'com.android.model.application'
model {
android {
compileSdkVersion = 23
- buildToolsVersion = "23.0.1"
+ buildToolsVersion = "25.0"
defaultConfig.with {
applicationId = "org.drrickorang.loopback"
diff --git a/LoopbackApp/app/src/main/AndroidManifest.xml b/LoopbackApp/app/src/main/AndroidManifest.xml
index 508f37f..a057e02 100644
--- a/LoopbackApp/app/src/main/AndroidManifest.xml
+++ b/LoopbackApp/app/src/main/AndroidManifest.xml
@@ -23,8 +23,8 @@
xmlns:android="http://schemas.android.com/apk/res/android"
package="org.drrickorang.loopback"
- android:versionCode="17"
- android:versionName="0.9.74">
+ android:versionCode="19"
+ android:versionName="0.9.75">
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
diff --git a/LoopbackApp/app/src/main/java/org/drrickorang/loopback/CaptureHolder.java b/LoopbackApp/app/src/main/java/org/drrickorang/loopback/CaptureHolder.java
index 774310b..99143f2 100644
--- a/LoopbackApp/app/src/main/java/org/drrickorang/loopback/CaptureHolder.java
+++ b/LoopbackApp/app/src/main/java/org/drrickorang/loopback/CaptureHolder.java
@@ -140,7 +140,14 @@ public class CaptureHolder {
/**
* Send signal to listener script to terminate and stop atrace
**/
- public static void stopLoopbackListenerScript() {
+ public void stopLoopbackListenerScript() {
+ if (mCaptureThread == null || !mCaptureThread.stopLoopbackListenerScript()) {
+ // The capture thread is unable to execute this operation.
+ stopLoopbackListenerScriptImpl();
+ }
+ }
+
+ static void stopLoopbackListenerScriptImpl() {
try {
OutputStream outputStream = new FileOutputStream(SIGNAL_FILE);
outputStream.write(TERMINATE_SIGNAL.getBytes());
@@ -204,6 +211,8 @@ public class CaptureHolder {
private CapturedState mNewCapturedState;
private int mIndexToPlace;
+ private boolean mIsRunning;
+ private boolean mSignalScriptToQuit;
/**
* Create new thread with capture state struct for captured systrace, bugreport and wav
@@ -217,6 +226,9 @@ public class CaptureHolder {
@Override
public void run() {
+ synchronized (this) {
+ mIsRunning = true;
+ }
// Write names of desired captures to signal file, signalling
// the listener script to write systrace and/or bugreport to those files
@@ -287,6 +299,13 @@ public class CaptureHolder {
for (CapturedState cs:mCapturedStates) log += "\n...." + cs;
Log.d(TAG, log);
+ synchronized (this) {
+ if (mSignalScriptToQuit) {
+ CaptureHolder.stopLoopbackListenerScriptImpl();
+ mSignalScriptToQuit = false;
+ }
+ mIsRunning = false;
+ }
Log.d(TAG, "Completed capture thread terminating");
}
@@ -294,5 +313,14 @@ public class CaptureHolder {
public synchronized void updateRank(int rank) {
mNewCapturedState.rank = Math.max(mNewCapturedState.rank, rank);
}
+
+ public synchronized boolean stopLoopbackListenerScript() {
+ if (mIsRunning) {
+ mSignalScriptToQuit = true;
+ return true;
+ } else {
+ return false;
+ }
+ }
}
}
diff --git a/LoopbackApp/app/src/main/java/org/drrickorang/loopback/Correlation.java b/LoopbackApp/app/src/main/java/org/drrickorang/loopback/Correlation.java
index d12cd7b..6c59bd9 100644
--- a/LoopbackApp/app/src/main/java/org/drrickorang/loopback/Correlation.java
+++ b/LoopbackApp/app/src/main/java/org/drrickorang/loopback/Correlation.java
@@ -37,6 +37,8 @@ public class Correlation implements Parcelable {
public double mEstimatedLatencySamples = 0;
public double mEstimatedLatencyMs = 0;
public double mEstimatedLatencyConfidence = 0.0;
+ public double mAverage = 0.0;
+ public double mRms = 0.0;
private double mAmplitudeThreshold = 0.001; // 0.001 = -60 dB noise
@@ -90,6 +92,9 @@ public class Correlation implements Parcelable {
mDataAutocorrelated.length, data.length, minIndex));
log(String.format(" average : %.3f rms: %.3f", average, rms));
+ mAverage = average;
+ mRms = rms;
+
mEstimatedLatencyConfidence = 0.0;
if (average > 0) {
double factor = 3.0;
@@ -199,6 +204,8 @@ public class Correlation implements Parcelable {
bundle.putDouble("mEstimatedLatencySamples", mEstimatedLatencySamples);
bundle.putDouble("mEstimatedLatencyMs", mEstimatedLatencyMs);
bundle.putDouble("mEstimatedLatencyConfidence", mEstimatedLatencyConfidence);
+ bundle.putDouble("mAverage", mAverage);
+ bundle.putDouble("mRms", mRms);
}
dest.writeBundle(bundle);
}
@@ -211,6 +218,8 @@ public class Correlation implements Parcelable {
mEstimatedLatencySamples = bundle.getDouble("mEstimatedLatencySamples");
mEstimatedLatencyMs = bundle.getDouble("mEstimatedLatencyMs");
mEstimatedLatencyConfidence = bundle.getDouble("mEstimatedLatencyConfidence");
+ mAverage = bundle.getDouble("mAverage");
+ mRms = bundle.getDouble("mRms");
}
}
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 9cfa768..d3acd03 100644
--- a/LoopbackApp/app/src/main/java/org/drrickorang/loopback/LoopbackActivity.java
+++ b/LoopbackApp/app/src/main/java/org/drrickorang/loopback/LoopbackActivity.java
@@ -93,6 +93,8 @@ public class LoopbackActivity extends Activity
private static final int LATENCY_TEST_ENDED = 301;
private static final int BUFFER_TEST_STARTED = 302;
private static final int BUFFER_TEST_ENDED = 303;
+ private static final int CALIBRATION_STARTED = 304;
+ private static final int CALIBRATION_ENDED = 305;
// 0-100 controls compression rate, currently ignore because PNG format is being used
private static final int EXPORTED_IMAGE_QUALITY = 100;
@@ -163,6 +165,7 @@ public class LoopbackActivity extends Activity
private int mPlayerBufferSizeInBytes;
private int mRecorderBufferSizeInBytes;
private int mIgnoreFirstFrames; // TODO: this only applies to native mode
+ private CaptureHolder mCaptureHolder;
// for buffer test
private int[] mGlitchesData;
@@ -280,7 +283,7 @@ public class LoopbackActivity extends Activity
break;
}
if (getApp().isCaptureEnabled()) {
- CaptureHolder.stopLoopbackListenerScript();
+ mCaptureHolder.stopLoopbackListenerScript();
}
stopAudioTestThreads();
if (mIntentRunning && mIntentFileName != null && mIntentFileName.length() > 0) {
@@ -379,11 +382,10 @@ public class LoopbackActivity extends Activity
}
mIntentRunning = false;
-
- }
- if (getApp().isCaptureEnabled()) {
- CaptureHolder.stopLoopbackListenerScript();
- }
+ if (getApp().isCaptureEnabled()) {
+ mCaptureHolder.stopLoopbackListenerScript();
+ }
+ } // mNativeAudioThread != null
refreshSoundLevelBar();
break;
default:
@@ -428,6 +430,16 @@ public class LoopbackActivity extends Activity
LOOPBACK_NATIVE_AUDIO_THREAD_MESSAGE_BUFFER_REC_COMPLETE_ERRORS:
setTransportButtonsState(BUFFER_TEST_ENDED);
break;
+
+ // Sound Calibration started
+ case CALIBRATION_STARTED:
+ setTransportButtonsState(CALIBRATION_STARTED);
+ break;
+
+ // Sound Calibration ended
+ case CALIBRATION_ENDED:
+ setTransportButtonsState(CALIBRATION_ENDED);
+ break;
}
}
};
@@ -803,7 +815,7 @@ public class LoopbackActivity extends Activity
mBufferTestDurationInSeconds = getApp().getBufferTestDuration();
mBufferTestWavePlotDurationInSeconds = getApp().getBufferTestWavePlotDuration();
- CaptureHolder captureHolder = new CaptureHolder(getApp().getNumStateCaptures(),
+ mCaptureHolder = new CaptureHolder(getApp().getNumStateCaptures(),
getFileNamePrefix(), getApp().isCaptureWavSnippetsEnabled(),
getApp().isCaptureSysTraceEnabled(), getApp().isCaptureBugreportEnabled(),
this, mSamplingRate);
@@ -822,20 +834,20 @@ public class LoopbackActivity extends Activity
/ (Constant.BYTES_PER_FRAME * mSamplingRate));
mRecorderBufferPeriod.prepareMemberObjects(
Constant.MAX_RECORDED_LATE_CALLBACKS_PER_SECOND * mBufferTestDurationInSeconds,
- expectedRecorderBufferPeriod, captureHolder);
+ expectedRecorderBufferPeriod, mCaptureHolder);
int expectedPlayerBufferPeriod = Math.round(
(float) (mPlayerBufferSizeInBytes * Constant.MILLIS_PER_SECOND)
/ (Constant.BYTES_PER_FRAME * mSamplingRate));
mPlayerBufferPeriod.prepareMemberObjects(
Constant.MAX_RECORDED_LATE_CALLBACKS_PER_SECOND * mBufferTestDurationInSeconds,
- expectedPlayerBufferPeriod, captureHolder);
+ expectedPlayerBufferPeriod, mCaptureHolder);
mAudioThread = new LoopbackAudioThread(mSamplingRate, mPlayerBufferSizeInBytes,
mRecorderBufferSizeInBytes, micSourceMapped, /* no performance mode */ mRecorderBufferPeriod,
mPlayerBufferPeriod, mTestType, mBufferTestDurationInSeconds,
mBufferTestWavePlotDurationInSeconds, getApplicationContext(),
- mChannelIndex, captureHolder);
+ mChannelIndex, mCaptureHolder);
mAudioThread.setMessageHandler(mMessageHandler);
mAudioThread.mSessionId = sessionId;
mAudioThread.start();
@@ -848,7 +860,7 @@ public class LoopbackActivity extends Activity
mNativeAudioThread = new NativeAudioThread(mSamplingRate, mPlayerBufferSizeInBytes,
mRecorderBufferSizeInBytes, micSourceMapped, performanceModeMapped, mTestType,
mBufferTestDurationInSeconds, mBufferTestWavePlotDurationInSeconds,
- mIgnoreFirstFrames, captureHolder);
+ mIgnoreFirstFrames, mCaptureHolder);
mNativeAudioThread.setMessageHandler(mMessageHandler);
mNativeAudioThread.mSessionId = sessionId;
mNativeAudioThread.start();
@@ -910,6 +922,7 @@ public class LoopbackActivity extends Activity
private void setTransportButtonsState(int state){
Button latencyStart = (Button) findViewById(R.id.buttonStartLatencyTest);
Button bufferStart = (Button) findViewById(R.id.buttonStartBufferTest);
+ Button calibrationStart = (Button) findViewById(R.id.buttonCalibrateSoundLevel);
switch (state) {
case LATENCY_TEST_STARTED:
@@ -919,6 +932,7 @@ public class LoopbackActivity extends Activity
latencyStart.setCompoundDrawablesWithIntrinsicBounds(
R.drawable.ic_stop, 0, 0, 0);
bufferStart.setEnabled(false);
+ calibrationStart.setEnabled(false);
break;
case LATENCY_TEST_ENDED:
@@ -926,6 +940,7 @@ public class LoopbackActivity extends Activity
latencyStart.setCompoundDrawablesWithIntrinsicBounds(
R.drawable.ic_play_arrow, 0, 0, 0);
bufferStart.setEnabled(true);
+ calibrationStart.setEnabled(true);
break;
case BUFFER_TEST_STARTED:
@@ -935,14 +950,39 @@ public class LoopbackActivity extends Activity
bufferStart.setCompoundDrawablesWithIntrinsicBounds(
R.drawable.ic_stop, 0, 0, 0);
latencyStart.setEnabled(false);
+ calibrationStart.setEnabled(false);
break;
case BUFFER_TEST_ENDED:
findViewById(R.id.zoomAndSaveControlPanel).setVisibility(View.VISIBLE);
+ findViewById(R.id.resultSummary).setVisibility(View.VISIBLE);
+ findViewById(R.id.glitchReportPanel).setVisibility(View.VISIBLE);
bufferStart.setCompoundDrawablesWithIntrinsicBounds(
R.drawable.ic_play_arrow, 0, 0, 0);
latencyStart.setEnabled(true);
+ calibrationStart.setEnabled(true);
+ break;
+
+ case CALIBRATION_STARTED:
+ findViewById(R.id.zoomAndSaveControlPanel).setVisibility(View.INVISIBLE);
+ findViewById(R.id.resultSummary).setVisibility(View.INVISIBLE);
+ findViewById(R.id.glitchReportPanel).setVisibility(View.INVISIBLE);
+ bufferStart.setCompoundDrawablesWithIntrinsicBounds(
+ R.drawable.ic_stop, 0, 0, 0);
+ latencyStart.setEnabled(false);
+ bufferStart.setEnabled(false);
+ calibrationStart.setEnabled(false);
+ break;
+
+ case CALIBRATION_ENDED:
+ findViewById(R.id.zoomAndSaveControlPanel).setVisibility(View.VISIBLE);
+ findViewById(R.id.resultSummary).setVisibility(View.VISIBLE);
findViewById(R.id.glitchReportPanel).setVisibility(View.VISIBLE);
+ bufferStart.setCompoundDrawablesWithIntrinsicBounds(
+ R.drawable.ic_play_arrow, 0, 0, 0);
+ latencyStart.setEnabled(true);
+ bufferStart.setEnabled(true);
+ calibrationStart.setEnabled(true);
break;
}
}
@@ -1134,16 +1174,15 @@ public class LoopbackActivity extends Activity
}
public void onButtonCalibrateSoundLevel(final View view) {
- view.setEnabled(false);
+ Message m = Message.obtain();
+ m.what = CALIBRATION_STARTED;
+ mMessageHandler.sendMessage(m);
Runnable onComplete = new Runnable() {
@Override
public void run() {
- view.post(new Runnable() {
- @Override
- public void run() {
- view.setEnabled(true);
- }
- });
+ Message m = Message.obtain();
+ m.what = CALIBRATION_ENDED;
+ mMessageHandler.sendMessage(m);
}
};
doCalibration(onComplete);
@@ -1649,16 +1688,16 @@ public class LoopbackActivity extends Activity
s.append(mTestStartTimeString);
s.append("):\n");
- s.append("SR: " + mSamplingRate + " Hz");
- s.append(" ChannelIndex: " + (mChannelIndex < 0 ? "MONO" : mChannelIndex));
+ s.append("SR: ").append(mSamplingRate).append(" Hz");
+ s.append(" ChannelIndex: ").append(mChannelIndex < 0 ? "MONO" : mChannelIndex);
switch (mAudioThreadType) {
case Constant.AUDIO_THREAD_TYPE_JAVA:
- s.append(" Play Frames: " + playerFrames);
- s.append(" Record Frames: " + recorderFrames);
+ s.append(" Play Frames: " ).append(playerFrames);
+ s.append(" Record Frames: ").append(recorderFrames);
s.append(" Audio: JAVA");
break;
case Constant.AUDIO_THREAD_TYPE_NATIVE:
- s.append(" Frames: " + playerFrames);
+ s.append(" Frames: ").append(playerFrames);
s.append(" Audio: NATIVE");
break;
}
@@ -1666,36 +1705,41 @@ public class LoopbackActivity extends Activity
// mic source
String micSourceName = getApp().getMicSourceString(mMicSource);
if (micSourceName != null) {
- s.append(String.format(" Mic: %s", micSourceName));
+ s.append(" Mic: ").append(micSourceName);
}
// performance mode
String performanceModeName = getApp().getPerformanceModeString(mPerformanceMode);
if (performanceModeName != null) {
- s.append(String.format(" Performance Mode: %s", performanceModeName));
+ s.append(" Performance Mode: ").append(performanceModeName);
}
// sound level at start of test
- s.append(String.format(" Sound Level: %d/%d", mSoundLevel,
- mBarMasterLevel.getMax()));
+ s.append(" Sound Level: ").append(mSoundLevel).append("/").append(mBarMasterLevel.getMax());
+
+ // load threads
+ s.append(" Simulated Load Threads: ").append(getApp().getNumberOfLoadThreads());
// Show short summary of results, round trip latency or number of glitches
if (mTestType == Constant.LOOPBACK_PLUG_AUDIO_THREAD_TEST_TYPE_LATENCY) {
if (mIgnoreFirstFrames > 0) {
- s.append(" First Frames Ignored: " + mIgnoreFirstFrames);
+ s.append(" First Frames Ignored: ").append(mIgnoreFirstFrames);
}
if (mCorrelation.isValid()) {
- mTextViewResultSummary.setText(String.format("Latency: %.2f ms Confidence: %.2f",
- mCorrelation.mEstimatedLatencyMs, mCorrelation.mEstimatedLatencyConfidence));
+ mTextViewResultSummary.setText(String.format("Latency: %.2f ms Confidence: %.2f" +
+ " Average = %.4f RMS = %.4f",
+ mCorrelation.mEstimatedLatencyMs, mCorrelation.mEstimatedLatencyConfidence,
+ mCorrelation.mAverage, mCorrelation.mRms));
}
} else if (mTestType == Constant.LOOPBACK_PLUG_AUDIO_THREAD_TEST_TYPE_BUFFER_PERIOD &&
mGlitchesData != null) {
// show buffer test duration
- s.append("\nBuffer Test Duration: " + mBufferTestDurationInSeconds + " s");
+ s.append("\nBuffer Test Duration: ").append(mBufferTestDurationInSeconds).append(" s");
// show buffer test wave plot duration
- s.append(" Buffer Test Wave Plot Duration: last " +
- mBufferTestWavePlotDurationInSeconds + " s");
+ s.append(" Buffer Test Wave Plot Duration: last ");
+ s.append(mBufferTestWavePlotDurationInSeconds);
+ s.append(" s");
mTextViewResultSummary.setText(getResources().getString(R.string.numGlitches) + " " +
estimateNumberOfGlitches(mGlitchesData));
@@ -1704,7 +1748,7 @@ public class LoopbackActivity extends Activity
}
String info = getApp().getSystemInfo();
- s.append(" " + info);
+ s.append(" ").append(info);
mTextInfo.setText(s.toString());
}
@@ -1922,7 +1966,6 @@ public class LoopbackActivity extends Activity
log("Error closing ParcelFile Descriptor");
}
}
-
}
private StringBuilder getReport() {
@@ -1966,6 +2009,9 @@ public class LoopbackActivity extends Activity
sb.append(String.format("LatencyConfidence = %.2f",
mCorrelation.mEstimatedLatencyConfidence) + endline);
+
+ sb.append(String.format("Average = %.4f", mCorrelation.mAverage) + endline);
+ sb.append(String.format("RMS = %.4f", mCorrelation.mRms) + endline);
break;
case Constant.LOOPBACK_PLUG_AUDIO_THREAD_TEST_TYPE_BUFFER_PERIOD:
sb.append("Buffer Test Duration (s) = " + mBufferTestDurationInSeconds + endline);
diff --git a/LoopbackApp/app/src/main/java/org/drrickorang/loopback/LoopbackAudioThread.java b/LoopbackApp/app/src/main/java/org/drrickorang/loopback/LoopbackAudioThread.java
index ba68780..b4c3b3a 100644
--- a/LoopbackApp/app/src/main/java/org/drrickorang/loopback/LoopbackAudioThread.java
+++ b/LoopbackApp/app/src/main/java/org/drrickorang/loopback/LoopbackAudioThread.java
@@ -27,7 +27,6 @@ import android.util.Log;
import android.os.Handler;
import android.os.Message;
-
/**
* A thread/audio track based audio synth.
*/
@@ -172,9 +171,8 @@ public class LoopbackAudioThread extends Thread {
// read from the pipe and plays it out
int samplesAvailable = mLatencyTestPipe.availableToRead();
if (samplesAvailable > 0) {
- int samplesOfInterest = samplesAvailable;
- if (mMinPlayerBufferSizeSamples < samplesOfInterest)
- samplesOfInterest = mMinPlayerBufferSizeSamples;
+ int samplesOfInterest = Math.min(samplesAvailable,
+ mMinPlayerBufferSizeSamples);
int samplesRead = mLatencyTestPipe.read(audioShortArrayOut, 0,
samplesOfInterest);
diff --git a/LoopbackApp/app/src/main/java/org/drrickorang/loopback/NativeAudioThread.java b/LoopbackApp/app/src/main/java/org/drrickorang/loopback/NativeAudioThread.java
index 5a6735f..95d5899 100644
--- a/LoopbackApp/app/src/main/java/org/drrickorang/loopback/NativeAudioThread.java
+++ b/LoopbackApp/app/src/main/java/org/drrickorang/loopback/NativeAudioThread.java
@@ -292,6 +292,10 @@ public class NativeAudioThread extends Thread {
endDetecting();
}
+ if (mTestType == Constant.LOOPBACK_PLUG_AUDIO_THREAD_TEST_TYPE_LATENCY) {
+ mCaptureHolder.captureState(0);
+ }
+
runDestroy(sles_data);
final int maxTry = 20;
diff --git a/LoopbackApp/app/src/main/java/org/drrickorang/loopback/SoundLevelCalibration.java b/LoopbackApp/app/src/main/java/org/drrickorang/loopback/SoundLevelCalibration.java
index eca9a82..ed70a09 100644
--- a/LoopbackApp/app/src/main/java/org/drrickorang/loopback/SoundLevelCalibration.java
+++ b/LoopbackApp/app/src/main/java/org/drrickorang/loopback/SoundLevelCalibration.java
@@ -25,7 +25,7 @@ import android.util.Log;
class SoundLevelCalibration {
private static final int SECONDS_PER_LEVEL = 1;
private static final int MAX_STEPS = 15; // The maximum number of levels that should be tried
- private static final double CRITICAL_RATIO = 0.4; // Ratio of input over output amplitude at
+ private static final double CRITICAL_RATIO = 0.41; // Ratio of input over output amplitude at
// which the feedback loop neither decays nor
// grows (determined experimentally)
private static final String TAG = "SoundLevelCalibration";
@@ -68,34 +68,39 @@ class SoundLevelCalibration {
// TODO: Allow stopping in the middle of calibration
int calibrate() {
final int maxLevel = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
- int delta = (maxLevel + MAX_STEPS - 1) / MAX_STEPS; // round up
- int level;
- // TODO: Use a better algorithm such as binary search.
- for(level = maxLevel; level >= 0; level -= delta) {
- mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, level, 0);
- if (mChangeListener != null) {
- mChangeListener.go(level);
- }
-
- mNativeAudioThread.start();
- try {
- mNativeAudioThread.join();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- double[] data = mNativeAudioThread.getWaveData();
+ int levelBottom = 0;
+ int levelTop = maxLevel + 1;
+ while(levelTop - levelBottom > 1) {
+ int level = (levelBottom + levelTop) / 2;
+ Log.d(TAG, "setting level to " + level);
+ setVolume(level);
+
+ double amplitude = runAudioThread(mNativeAudioThread);
mNativeAudioThread = new NativeAudioThread(mNativeAudioThread); // generate fresh thread
- double amplitude = averageAmplitude(data);
Log.d(TAG, "calibrate: at sound level " + level + " volume was " + amplitude);
if (amplitude < Constant.SINE_WAVE_AMPLITUDE * CRITICAL_RATIO) {
- Log.d(TAG, "calibrate: chose sound level " + level);
- break;
+ levelBottom = level;
+ } else {
+ levelTop = level;
}
}
+ // At this point, levelBottom has the highest proper value, if there is one (0 otherwise)
+ Log.d(TAG, "Final level: " + levelBottom);
+ setVolume(levelBottom);
+ return levelBottom;
+ }
- // Return the maximum level if we can't find a proper one
- return level != 0 ? level : maxLevel;
+ private double runAudioThread(NativeAudioThread thread) {
+ // runs the native audio thread and returns the average amplitude
+ thread.start();
+ try {
+ thread.join();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ double[] data = thread.getWaveData();
+ return averageAmplitude(data);
}
// TODO: Only gives accurate results for an undistorted sine wave. Check for distortion.
@@ -110,6 +115,13 @@ class SoundLevelCalibration {
return Math.sqrt(2.0 * sumSquare / data.length); // amplitude of the sine wave
}
+ private void setVolume(int level) {
+ mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, level, 0);
+ if (mChangeListener != null) {
+ mChangeListener.go(level);
+ }
+ }
+
void setChangeListener(SoundLevelChangeListener changeListener) {
mChangeListener = changeListener;
}
diff --git a/LoopbackApp/app/src/main/jni/sles.cpp b/LoopbackApp/app/src/main/jni/sles.cpp
index 36a096c..159269b 100644
--- a/LoopbackApp/app/src/main/jni/sles.cpp
+++ b/LoopbackApp/app/src/main/jni/sles.cpp
@@ -45,7 +45,7 @@ int slesInit(sles_data ** ppSles, int samplingRate, int frameCount, int micSourc
memset(pSles, 0, sizeof(sles_data));
- SLES_PRINTF("malloc %zu bytes at %p", sizeof(sles_data), pSles);
+ SLES_PRINTF("pSles malloc %zu bytes at %p", sizeof(sles_data), pSles);
//__android_log_print(ANDROID_LOG_INFO, "sles_jni",
//"malloc %d bytes at %p", sizeof(sles_data), pSles);//Or ANDROID_LOG_INFO, ...
*ppSles = pSles;
@@ -70,6 +70,7 @@ int slesDestroy(sles_data ** ppSles) {
if (*ppSles != NULL)
{
+ SLES_PRINTF("free memory at %p",*ppSles);
free(*ppSles);
*ppSles = 0;
}
@@ -533,9 +534,13 @@ int slesCreateServer(sles_data *pSles, int samplingRate, int frameCount, int mic
// Initialize free buffers
pSles->freeBuffers = (char **) calloc(pSles->freeBufCount + 1, sizeof(char *));
+ SLES_PRINTF(" calloc freeBuffers %zu bytes at %p",pSles->freeBufCount + 1,
+ pSles->freeBuffers);
unsigned j;
for (j = 0; j < pSles->freeBufCount; ++j) {
pSles->freeBuffers[j] = (char *) malloc(pSles->bufSizeInBytes);
+ SLES_PRINTF(" buff%d malloc %zu bytes at %p",j, pSles->bufSizeInBytes,
+ pSles->freeBuffers[j]);
}
pSles->freeFront = 0;
pSles->freeRear = pSles->freeBufCount;
@@ -543,11 +548,13 @@ int slesCreateServer(sles_data *pSles, int samplingRate, int frameCount, int mic
// Initialize record queue
pSles->rxBuffers = (char **) calloc(pSles->rxBufCount + 1, sizeof(char *));
+ SLES_PRINTF(" calloc rxBuffers %zu bytes at %p",pSles->rxBufCount + 1, pSles->rxBuffers);
pSles->rxFront = 0;
pSles->rxRear = 0;
// Initialize play queue
pSles->txBuffers = (char **) calloc(pSles->txBufCount + 1, sizeof(char *));
+ SLES_PRINTF(" calloc txBuffers %zu bytes at %p",pSles->txBufCount + 1, pSles->txBuffers);
pSles->txFront = 0;
pSles->txRear = 0;
@@ -970,8 +977,35 @@ int slesDestroyServer(sles_data *pSles) {
(*(pSles->engineObject))->Destroy(pSles->engineObject);
SLES_PRINTF("slesDestroyServer 7");
-// free(pSles);
-// pSles = NULL;
+ //free buffers
+ if (NULL != pSles->freeBuffers) {
+ for (unsigned j = 0; j < pSles->freeBufCount; ++j) {
+ if (NULL != pSles->freeBuffers[j]) {
+ SLES_PRINTF(" free buff%d at %p",j, pSles->freeBuffers[j]);
+ free (pSles->freeBuffers[j]);
+ }
+ }
+ SLES_PRINTF(" free freeBuffers at %p", pSles->freeBuffers);
+ free(pSles->freeBuffers);
+ } else {
+ SLES_PRINTF(" freeBuffers NULL, no need to free");
+ }
+
+
+ if (NULL != pSles->rxBuffers) {
+ SLES_PRINTF(" free rxBuffers at %p", pSles->rxBuffers);
+ free(pSles->rxBuffers);
+ } else {
+ SLES_PRINTF(" rxBuffers NULL, no need to free");
+ }
+
+ if (NULL != pSles->txBuffers) {
+ SLES_PRINTF(" free txBuffers at %p", pSles->txBuffers);
+ free(pSles->txBuffers);
+ } else {
+ SLES_PRINTF(" txBuffers NULL, no need to free");
+ }
+
status = SLES_SUCCESS;
}
diff --git a/LoopbackApp/app/src/main/res/raw/loopback_listener b/LoopbackApp/app/src/main/res/raw/loopback_listener
index bcbce2c..a29b0c9 100644
--- a/LoopbackApp/app/src/main/res/raw/loopback_listener
+++ b/LoopbackApp/app/src/main/res/raw/loopback_listener
@@ -63,13 +63,6 @@ do
echo "LOOPBACK LISTENER: Finished capture"
- # Check for case that test has ended while capturing state and exit
- if [ -e "$SIGNAL_FILE" ] && [ -s "$SIGNAL_FILE" ] \
- && [ $(cat $SIGNAL_FILE) == $TERMINATE_SIGNAL ]
- then
- exitListener
- fi
-
rm $SIGNAL_FILE
fi
fi
diff --git a/LoopbackApp/build.gradle b/LoopbackApp/build.gradle
index 9d5a7a8..f1cc249 100644
--- a/LoopbackApp/build.gradle
+++ b/LoopbackApp/build.gradle
@@ -4,7 +4,7 @@ buildscript {
jcenter()
}
dependencies {
- classpath 'com.android.tools.build:gradle-experimental:0.6.0'
+ classpath 'com.android.tools.build:gradle-experimental:0.9.0'
}
}
diff --git a/LoopbackApp/gradle/wrapper/gradle-wrapper.properties b/LoopbackApp/gradle/wrapper/gradle-wrapper.properties
index 23b4dd3..dde259e 100644
--- a/LoopbackApp/gradle/wrapper/gradle-wrapper.properties
+++ b/LoopbackApp/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Tue Apr 19 06:51:07 PDT 2016
+#Tue Mar 21 12:29:44 PDT 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip