summaryrefslogtreecommitdiff
path: root/LoopbackApp/app/src/main/java/org/drrickorang/loopback/NativeAudioThread.java
diff options
context:
space:
mode:
Diffstat (limited to 'LoopbackApp/app/src/main/java/org/drrickorang/loopback/NativeAudioThread.java')
-rw-r--r--LoopbackApp/app/src/main/java/org/drrickorang/loopback/NativeAudioThread.java108
1 files changed, 72 insertions, 36 deletions
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 95d5899..d2ed18b 100644
--- a/LoopbackApp/app/src/main/java/org/drrickorang/loopback/NativeAudioThread.java
+++ b/LoopbackApp/app/src/main/java/org/drrickorang/loopback/NativeAudioThread.java
@@ -19,9 +19,13 @@ package org.drrickorang.loopback;
import java.nio.ByteBuffer;
import java.util.Arrays;
-import android.util.Log;
+import android.content.Context;
+import android.media.AudioManager;
+import android.media.AudioTrack;
+import android.os.Build;
import android.os.Handler;
import android.os.Message;
+import android.util.Log;
/**
@@ -50,6 +54,7 @@ public class NativeAudioThread extends Thread {
public double[] mSamples; // store samples that will be shown on WavePlotView
int mSamplesIndex;
+ private int mThreadType;
private int mTestType;
private int mSamplingRate;
private int mMinPlayerBufferSizeInBytes = 0;
@@ -85,11 +90,36 @@ public class NativeAudioThread extends Thread {
private PipeByteBuffer mPipeByteBuffer;
private GlitchDetectionThread mGlitchDetectionThread;
+ /** Check if it's safe to use getProperty(). */
+ static boolean isSafeToUseGetProperty() {
+ return Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1;
+ }
+
+ public static TestSettings computeDefaultSettings(Context context,
+ int threadType, int performanceMode) {
+ TestSettings nativeResult = nativeComputeDefaultSettings(
+ Constant.BYTES_PER_FRAME, threadType, performanceMode);
+ if (nativeResult != null) {
+ return nativeResult;
+ }
- public NativeAudioThread(int samplingRate, int playerBufferInBytes, int recorderBufferInBytes,
- int micSource, int performanceMode, int testType, int bufferTestDurationInSeconds,
+ int samplingRate = AudioTrack.getNativeOutputSampleRate(AudioManager.STREAM_MUSIC);
+ int minBufferSizeInFrames = 1024;
+ if (isSafeToUseGetProperty()) {
+ AudioManager am = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+ String value = am.getProperty(AudioManager.PROPERTY_OUTPUT_FRAMES_PER_BUFFER);
+ minBufferSizeInFrames = Integer.parseInt(value);
+ }
+ int minBufferSizeInBytes = Constant.BYTES_PER_FRAME * minBufferSizeInFrames;
+ return new TestSettings(samplingRate, minBufferSizeInBytes, minBufferSizeInBytes);
+ }
+
+ public NativeAudioThread(int threadType, int samplingRate, int playerBufferInBytes,
+ int recorderBufferInBytes, int micSource, int performanceMode,
+ int testType, int bufferTestDurationInSeconds,
int bufferTestWavePlotDurationInSeconds, int ignoreFirstFrames,
CaptureHolder captureHolder) {
+ mThreadType = threadType;
mSamplingRate = samplingRate;
mMinPlayerBufferSizeInBytes = playerBufferInBytes;
mMinRecorderBuffSizeInBytes = recorderBufferInBytes;
@@ -104,6 +134,7 @@ public class NativeAudioThread extends Thread {
}
public NativeAudioThread(NativeAudioThread old) {
+ mThreadType = old.mThreadType;
mSamplingRate = old.mSamplingRate;
mMinPlayerBufferSizeInBytes = old.mMinPlayerBufferSizeInBytes;
mMinRecorderBuffSizeInBytes = old.mMinRecorderBuffSizeInBytes;
@@ -130,25 +161,28 @@ public class NativeAudioThread extends Thread {
//jni calls
- public native long slesInit(int samplingRate, int frameCount, int micSource,
+ public static native TestSettings nativeComputeDefaultSettings(
+ int bytesPerFrame, int threadType, int performanceMode);
+ public native long nativeInit(int threadType,
+ int samplingRate, int frameCount, int micSource,
int performanceMode,
int testType, double frequency1, ByteBuffer byteBuffer,
short[] sincTone, int maxRecordedLateCallbacks,
int ignoreFirstFrames);
- public native int slesProcessNext(long sles_data, double[] samples, long offset);
- public native int slesDestroy(long sles_data);
+ public native int nativeProcessNext(long nativeHandle, double[] samples, long offset);
+ public native int nativeDestroy(long nativeHandle);
// to get buffer period data
- public native int[] slesGetRecorderBufferPeriod(long sles_data);
- public native int slesGetRecorderMaxBufferPeriod(long sles_data);
- public native double slesGetRecorderVarianceBufferPeriod(long sles_data);
- public native int[] slesGetPlayerBufferPeriod(long sles_data);
- public native int slesGetPlayerMaxBufferPeriod(long sles_data);
- public native double slesGetPlayerVarianceBufferPeriod(long sles_data);
- public native BufferCallbackTimes slesGetPlayerCallbackTimeStamps(long sles_data);
- public native BufferCallbackTimes slesGetRecorderCallbackTimeStamps(long sles_data);
+ public native int[] nativeGetRecorderBufferPeriod(long nativeHandle);
+ public native int nativeGetRecorderMaxBufferPeriod(long nativeHandle);
+ public native double nativeGetRecorderVarianceBufferPeriod(long nativeHandle);
+ public native int[] nativeGetPlayerBufferPeriod(long nativeHandle);
+ public native int nativeGetPlayerMaxBufferPeriod(long nativeHandle);
+ public native double nativeGetPlayerVarianceBufferPeriod(long nativeHandle);
+ public native BufferCallbackTimes nativeGetPlayerCallbackTimeStamps(long nativeHandle);
+ public native BufferCallbackTimes nativeGetRecorderCallbackTimeStamps(long nativeHandle);
- public native int slesGetCaptureRank(long sles_data);
+ public native int nativeGetCaptureRank(long nativeHandle);
public void run() {
@@ -174,12 +208,13 @@ public class NativeAudioThread extends Thread {
mMessageHandler.sendMessage(msg);
}
- //generate sinc tone use for loopback test
+ // generate windowed tone use for loopback test
short loopbackTone[] = new short[mMinPlayerBufferSizeInBytes / Constant.BYTES_PER_FRAME];
if (mTestType == Constant.LOOPBACK_PLUG_AUDIO_THREAD_TEST_TYPE_LATENCY) {
ToneGeneration sincToneGen = new RampedSineTone(mSamplingRate,
Constant.LOOPBACK_FREQUENCY);
- sincToneGen.generateTone(loopbackTone, loopbackTone.length);
+ int sincLength = Math.min(Constant.LOOPBACK_SAMPLE_FRAMES, loopbackTone.length);
+ sincToneGen.generateTone(loopbackTone, sincLength);
}
log(String.format("about to init, sampling rate: %d, buffer:%d", mSamplingRate,
@@ -188,15 +223,15 @@ public class NativeAudioThread extends Thread {
// mPipeByteBuffer is only used in buffer test
mPipeByteBuffer = new PipeByteBuffer(Constant.MAX_SHORTS);
long startTimeMs = System.currentTimeMillis();
- long sles_data = slesInit(mSamplingRate,
+ long nativeHandle = nativeInit(mThreadType, mSamplingRate,
mMinPlayerBufferSizeInBytes / Constant.BYTES_PER_FRAME, mMicSource,
mPerformanceMode, mTestType,
mFrequency1, mPipeByteBuffer.getByteBuffer(), loopbackTone,
mBufferTestDurationInSeconds * Constant.MAX_RECORDED_LATE_CALLBACKS_PER_SECOND,
mIgnoreFirstFrames);
- log(String.format("sles_data = 0x%X", sles_data));
+ log(String.format("nativeHandle = 0x%X", nativeHandle));
- if (sles_data == 0) {
+ if (nativeHandle == 0) {
//notify error!!
log(" ERROR at JNI initialization");
if (mMessageHandler != null) {
@@ -235,7 +270,7 @@ public class NativeAudioThread extends Thread {
// retrieve native recorder's recorded data
for (int ii = 0; ii < latencyTestDurationInSeconds; ii++) {
log(String.format("block %d...", ii));
- int samplesRead = slesProcessNext(sles_data, mSamples, offset);
+ int samplesRead = nativeProcessNext(nativeHandle, mSamples, offset);
totalSamplesRead += samplesRead;
offset += samplesRead;
log(" [" + ii + "] jni samples read:" + samplesRead +
@@ -253,7 +288,7 @@ public class NativeAudioThread extends Thread {
if (mIsRequestStop) {
break;
} else {
- int rank = slesGetCaptureRank(sles_data);
+ int rank = nativeGetCaptureRank(nativeHandle);
if (rank > 0) {
//log("Late callback detected");
mCaptureHolder.captureState(rank);
@@ -274,15 +309,17 @@ public class NativeAudioThread extends Thread {
}
// collect buffer period data
- mRecorderBufferPeriod = slesGetRecorderBufferPeriod(sles_data);
- mRecorderMaxBufferPeriod = slesGetRecorderMaxBufferPeriod(sles_data);
- mRecorderStdDevBufferPeriod = Math.sqrt(slesGetRecorderVarianceBufferPeriod(sles_data));
- mPlayerBufferPeriod = slesGetPlayerBufferPeriod(sles_data);
- mPlayerMaxBufferPeriod = slesGetPlayerMaxBufferPeriod(sles_data);
- mPlayerStdDevBufferPeriod = Math.sqrt(slesGetPlayerVarianceBufferPeriod(sles_data));
-
- mPlayerCallbackTimes = slesGetPlayerCallbackTimeStamps(sles_data);
- mRecorderCallbackTimes = slesGetRecorderCallbackTimeStamps(sles_data);
+ mRecorderBufferPeriod = nativeGetRecorderBufferPeriod(nativeHandle);
+ mRecorderMaxBufferPeriod = nativeGetRecorderMaxBufferPeriod(nativeHandle);
+ mRecorderStdDevBufferPeriod = Math.sqrt(nativeGetRecorderVarianceBufferPeriod(
+ nativeHandle));
+ mPlayerBufferPeriod = nativeGetPlayerBufferPeriod(nativeHandle);
+ mPlayerMaxBufferPeriod = nativeGetPlayerMaxBufferPeriod(nativeHandle);
+ mPlayerStdDevBufferPeriod = Math.sqrt(nativeGetPlayerVarianceBufferPeriod(
+ nativeHandle));
+
+ mPlayerCallbackTimes = nativeGetPlayerCallbackTimeStamps(nativeHandle);
+ mRecorderCallbackTimes = nativeGetRecorderCallbackTimeStamps(nativeHandle);
// get glitches data only for buffer test
if (mTestType == Constant.LOOPBACK_PLUG_AUDIO_THREAD_TEST_TYPE_BUFFER_PERIOD) {
@@ -296,7 +333,7 @@ public class NativeAudioThread extends Thread {
mCaptureHolder.captureState(0);
}
- runDestroy(sles_data);
+ runDestroy(nativeHandle);
final int maxTry = 20;
int tryCount = 0;
@@ -373,18 +410,17 @@ public class NativeAudioThread extends Thread {
}
- private void runDestroy(final long sles_data) {
+ private void runDestroy(final long localNativeHandle) {
isDestroying = true;
//start thread
- final long local_sles_data = sles_data;
Thread thread = new Thread(new Runnable() {
public void run() {
isDestroying = true;
log("**Start runnable destroy");
- int status = slesDestroy(local_sles_data);
- log(String.format("**End runnable destroy sles delete status: %d", status));
+ int status = nativeDestroy(localNativeHandle);
+ log(String.format("**End runnable destroy native delete status: %d", status));
isDestroying = false;
}
});