summaryrefslogtreecommitdiff
path: root/LoopbackApp/app
diff options
context:
space:
mode:
authorRicardo Garcia <rago@google.com>2015-04-02 14:58:29 -0700
committerGlenn Kasten <gkasten@gkasten-macbookpro2.roam.corp.google.com>2015-04-02 16:20:46 -0700
commit7db53f884803677a406c744d4cac7c68a5a57463 (patch)
tree902c26bf415ad69ee69418e1c03f052d9f4a9597 /LoopbackApp/app
parent9fa073a2aafc6cf1af8510ac73f9c7eb5666f16f (diff)
downloaddrrickorang-7db53f884803677a406c744d4cac7c68a5a57463.tar.gz
Bugfixing for older Android versions
Fixing some race conditions that became problematic on older android versions. Instrumented JNI code with debug/log messages. Reduced memory footprint of JNI test by directly using the actual buffer of interest.
Diffstat (limited to 'LoopbackApp/app')
-rw-r--r--LoopbackApp/app/build.gradle2
-rw-r--r--LoopbackApp/app/src/main/java/org/drrickorang/.DS_Storebin0 -> 6148 bytes
-rw-r--r--LoopbackApp/app/src/main/java/org/drrickorang/loopback/LoopbackActivity.java11
-rw-r--r--LoopbackApp/app/src/main/java/org/drrickorang/loopback/NativeAudioThread.java149
-rw-r--r--LoopbackApp/app/src/main/jni/jni_sles.c24
-rw-r--r--LoopbackApp/app/src/main/jni/jni_sles.h2
-rw-r--r--LoopbackApp/app/src/main/jni/sles.cpp72
-rw-r--r--LoopbackApp/app/src/main/jni/sles.h3
8 files changed, 194 insertions, 69 deletions
diff --git a/LoopbackApp/app/build.gradle b/LoopbackApp/app/build.gradle
index f745f4e..a67c80d 100644
--- a/LoopbackApp/app/build.gradle
+++ b/LoopbackApp/app/build.gradle
@@ -11,7 +11,7 @@ android {
ndk {
moduleName "libloopback"
- ldLibs "OpenSLES"
+ ldLibs "OpenSLES", "log"
}
}
diff --git a/LoopbackApp/app/src/main/java/org/drrickorang/.DS_Store b/LoopbackApp/app/src/main/java/org/drrickorang/.DS_Store
new file mode 100644
index 0000000..4a310a6
--- /dev/null
+++ b/LoopbackApp/app/src/main/java/org/drrickorang/.DS_Store
Binary files differ
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 60a5b47..2ecc2e2 100644
--- a/LoopbackApp/app/src/main/java/org/drrickorang/loopback/LoopbackActivity.java
+++ b/LoopbackApp/app/src/main/java/org/drrickorang/loopback/LoopbackActivity.java
@@ -78,8 +78,6 @@ public class LoopbackActivity extends Activity {
case LoopbackAudioThread.FUN_PLUG_AUDIO_THREAD_MESSAGE_REC_STARTED:
log("got message java rec started!!");
showToast("Java Recording Started");
-// Toast.makeText(getApplicationContext(), "Java Recording Started",
-// Toast.LENGTH_SHORT).show();
refreshState();
break;
case LoopbackAudioThread.FUN_PLUG_AUDIO_THREAD_MESSAGE_REC_COMPLETE:
@@ -90,16 +88,17 @@ public class LoopbackActivity extends Activity {
refreshPlots();
refreshState();
showToast("Java Recording Completed");
-// Toast.makeText(getApplicationContext(), "Java Recording Completed",
-// Toast.LENGTH_SHORT).show();
stopAudioThread();
}
break;
case NativeAudioThread.FUN_PLUG_NATIVE_AUDIO_THREAD_MESSAGE_REC_STARTED:
log("got message native rec started!!");
showToast("Native Recording Started");
-// Toast.makeText(getApplicationContext(), "Native Recording Started",
-// Toast.LENGTH_SHORT).show();
+ refreshState();
+ break;
+ case NativeAudioThread.FUN_PLUG_NATIVE_AUDIO_THREAD_MESSAGE_REC_ERROR:
+ log("got message native rec can't start!!");
+ showToast("Native Recording Error. Please try again");
refreshState();
break;
case NativeAudioThread.FUN_PLUG_NATIVE_AUDIO_THREAD_MESSAGE_REC_COMPLETE:
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 469500f..f8760a3 100644
--- a/LoopbackApp/app/src/main/java/org/drrickorang/loopback/NativeAudioThread.java
+++ b/LoopbackApp/app/src/main/java/org/drrickorang/loopback/NativeAudioThread.java
@@ -51,7 +51,7 @@ public class NativeAudioThread extends Thread {
int mMinRecordBuffSizeInBytes = 0;
private int mChannelConfigOut = AudioFormat.CHANNEL_OUT_MONO;
- private double [] samples = new double[50000];
+// private double [] samples = new double[50000];
boolean isPlaying = false;
private Handler mMessageHandler;
@@ -85,7 +85,7 @@ public class NativeAudioThread extends Thread {
//jni calls
public native long slesInit(int samplingRate, int frameCount);
- public native int slesProcessNext(long sles_data, double[] samples);
+ public native int slesProcessNext(long sles_data, double[] samples, long offset);
public native int slesDestroy(long sles_data);
public void run() {
@@ -93,59 +93,116 @@ public class NativeAudioThread extends Thread {
setPriority(Thread.MAX_PRIORITY);
isRunning = true;
+ //erase output buffer
+ if (mvSamples != null)
+ mvSamples = null;
+
+ //resize
+ int nNewSize = (int)(1.1* mSamplingRate * mSecondsToRun ); //10% more just in case
+ mvSamples = new double[nNewSize];
+ mSamplesIndex = 0; //reset index
+
+ //clear samples
+ for(int i=0; i<nNewSize; i++) {
+ mvSamples[i] = 0;
+ }
+
+ //start playing
+ isPlaying = true;
+
+
+ log(" Started capture test");
+ if (mMessageHandler != null) {
+ Message msg = Message.obtain();
+ msg.what = FUN_PLUG_NATIVE_AUDIO_THREAD_MESSAGE_REC_STARTED;
+ mMessageHandler.sendMessage(msg);
+ }
+
+
+
log(String.format("about to init, sampling rate: %d, buffer:%d", mSamplingRate,
mMinPlayBufferSizeInBytes/2 ));
long sles_data = slesInit(mSamplingRate, mMinPlayBufferSizeInBytes/2);
- log(String.format("sles_data = 0x%d",sles_data));
+ log(String.format("sles_data = 0x%X",sles_data));
+ if(sles_data == 0 ) {
+ //notify error!!
- mSamplesIndex = 0;
- int totalSamplesRead = 0;
- for (int ii=0; ii<mSecondsToRun; ii++) {
- log(String.format("block %d...",ii));
- int samplesRead = slesProcessNext(sles_data, samples);
- totalSamplesRead += samplesRead;
- log(" ["+ii+"] jni samples read:" + samplesRead + " currentSampleIndex:"+mSamplesIndex);
- {
- for (int jj=0; jj<samplesRead && mSamplesIndex< mvSamples.length; jj++) {
- mvSamples[mSamplesIndex++] = samples[jj];
- }
+ log(" ERROR at JNI initialization");
+ if (mMessageHandler != null) {
+ Message msg = Message.obtain();
+ msg.what = FUN_PLUG_NATIVE_AUDIO_THREAD_MESSAGE_REC_ERROR;
+ mMessageHandler.sendMessage(msg);
}
- }
+ } else {
+
+ //wait a little bit...
+ try {
+ sleep(10); //just to let it start properly?
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+
- log(String.format(" samplesRead: %d, samplesIndex:%d", totalSamplesRead, mSamplesIndex));
- log(String.format("about to destroy..."));
+
+ mSamplesIndex = 0;
+ int totalSamplesRead = 0;
+ long offset = 0;
+ for (int ii = 0; ii < mSecondsToRun; ii++) {
+ log(String.format("block %d...", ii));
+ int samplesRead = slesProcessNext(sles_data, mvSamples,offset);
+ totalSamplesRead += samplesRead;
+
+ offset += samplesRead;
+ log(" [" + ii + "] jni samples read:" + samplesRead + " currentOffset:" + offset);
+
+// log(" [" + ii + "] jni samples read:" + samplesRead + " currentSampleIndex:" + mSamplesIndex);
+// {
+// for (int jj = 0; jj < samplesRead && mSamplesIndex < mvSamples.length; jj++) {
+// mvSamples[mSamplesIndex++] = samples[jj];
+// }
+// }
+ }
+
+ //log(String.format(" samplesRead: %d, samplesIndex:%d", totalSamplesRead, mSamplesIndex));
+ log(String.format(" samplesRead: %d, sampleOffset:%d", totalSamplesRead, offset));
+ log(String.format("about to destroy..."));
// int status = slesDestroy(sles_data);
// log(String.format("sles delete status: %d", status));
+ runDestroy(sles_data);
- runDestroy(sles_data);
+ int maxTry = 20;
+ int tryCount = 0;
+ //isDestroying = true;
+ while (isDestroying) {
- int maxTry = 100;
- int tryCount=0;
- //isDestroying = true;
- while(isDestroying) {
+ try {
+ sleep(40);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
- try {
- sleep(10);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
+ tryCount++;
- tryCount++;
+ log("destroy try: " + tryCount);
- log("destroy try: "+ tryCount);
+ if (tryCount >= maxTry) {
+ hasDestroyingErrors = true;
+ log("WARNING: waited for max time to properly destroy JNI.");
+ break;
+ }
+ }
+ log(String.format("after destroying. TotalSamplesRead = %d", totalSamplesRead));
- if(tryCount>= maxTry) {
+ if(totalSamplesRead==0)
+ {
hasDestroyingErrors = true;
- log("WARNING: waited for max time to properly destroy JNI.");
- break;
}
- }
- log("after destroying");
- endTest();
+ endTest();
+ }
}
public void setMessageHandler(Handler messageHandler) {
@@ -162,10 +219,10 @@ public class NativeAudioThread extends Thread {
Thread thread = new Thread(new Runnable() {
public void run() {
isDestroying = true;
- log("runnable destroy");
+ log("**Start runnable destroy");
int status = slesDestroy(local_sles_data);
- log(String.format("sles delete status: %d", status));
+ log(String.format("**End runnable destroy sles delete status: %d", status));
isDestroying = false;
}
});
@@ -185,25 +242,7 @@ public class NativeAudioThread extends Thread {
public void runTest() {
- //erase output buffer
- if (mvSamples != null)
- mvSamples = null;
-
- //resize
- int nNewSize = mSamplingRate * mSecondsToRun; //5 seconds!
- mvSamples = new double[nNewSize];
- mSamplesIndex = 0; //reset index
-
- //start playing
- isPlaying = true;
-
- log(" Started capture test");
- if (mMessageHandler != null) {
- Message msg = Message.obtain();
- msg.what = FUN_PLUG_NATIVE_AUDIO_THREAD_MESSAGE_REC_STARTED;
- mMessageHandler.sendMessage(msg);
- }
}
public void endTest() {
diff --git a/LoopbackApp/app/src/main/jni/jni_sles.c b/LoopbackApp/app/src/main/jni/jni_sles.c
index 02e69dc..9d12a1c 100644
--- a/LoopbackApp/app/src/main/jni/jni_sles.c
+++ b/LoopbackApp/app/src/main/jni/jni_sles.c
@@ -24,21 +24,35 @@
JNIEXPORT jlong JNICALL Java_org_drrickorang_loopback_NativeAudioThread_slesInit
(JNIEnv *env __unused, jobject obj __unused, jint samplingRate, jint frameCount) {
- sles_data * pSles;
- slesInit(&pSles, samplingRate, frameCount);
+ sles_data * pSles = NULL;
+
+ if( slesInit(&pSles, samplingRate, frameCount) != SLES_FAIL ) {
+
+ return (long)pSles;
+ }
// FIXME This should be stored as a (long) field in the object,
// so that incorrect Java code could not synthesize a bad sles pointer.
- return (long)pSles;
+ return 0;
}
JNIEXPORT jint JNICALL Java_org_drrickorang_loopback_NativeAudioThread_slesProcessNext
-(JNIEnv *env __unused, jobject obj __unused, jlong sles, jdoubleArray samplesArray) {
+(JNIEnv *env __unused, jobject obj __unused, jlong sles, jdoubleArray samplesArray, jlong offset) {
sles_data * pSles= (sles_data*) sles;
long maxSamples = (*env)->GetArrayLength(env, samplesArray);
double *pSamples = (*env)->GetDoubleArrayElements(env, samplesArray,0);
- int samplesRead = slesProcessNext(pSles, pSamples, maxSamples);
+ long availableSamples = maxSamples-offset;
+ double *pCurrentSample = pSamples+offset;
+
+
+
+ //int samplesRead = slesProcessNext(pSles, pSamples, maxSamples);
+
+ SLES_PRINTF("jni slesProcessNext pSles:%p, currentSample %p, availableSamples %d ", pSles, pCurrentSample, availableSamples);
+
+
+ int samplesRead = slesProcessNext(pSles, pCurrentSample, availableSamples);
return samplesRead;
}
diff --git a/LoopbackApp/app/src/main/jni/jni_sles.h b/LoopbackApp/app/src/main/jni/jni_sles.h
index 56e7bb6..8be992a 100644
--- a/LoopbackApp/app/src/main/jni/jni_sles.h
+++ b/LoopbackApp/app/src/main/jni/jni_sles.h
@@ -29,7 +29,7 @@ JNIEXPORT jlong JNICALL Java_org_drrickorang_loopback_NativeAudioThread_slesInit
(JNIEnv *, jobject, jint, jint );
JNIEXPORT jint JNICALL Java_org_drrickorang_loopback_NativeAudioThread_slesProcessNext
- (JNIEnv *, jobject , jlong, jdoubleArray );
+ (JNIEnv *, jobject , jlong, jdoubleArray, jlong );
JNIEXPORT jint JNICALL Java_org_drrickorang_loopback_NativeAudioThread_slesDestroy
(JNIEnv *, jobject , jlong );
diff --git a/LoopbackApp/app/src/main/jni/sles.cpp b/LoopbackApp/app/src/main/jni/sles.cpp
index 0290099..06efe44 100644
--- a/LoopbackApp/app/src/main/jni/sles.cpp
+++ b/LoopbackApp/app/src/main/jni/sles.cpp
@@ -40,10 +40,15 @@ int slesInit(sles_data ** ppSles, int samplingRate, int frameCount) {
int status = SLES_FAIL;
if (ppSles != NULL) {
sles_data * pSles = (sles_data*)malloc( sizeof (sles_data));
+
+ SLES_PRINTF("malloc %d 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;
if (pSles != NULL)
{
+ SLES_PRINTF("creating server. Sampling rate =%d, frame count = %d",samplingRate, frameCount);
status = slesCreateServer(pSles, samplingRate, frameCount);
+ SLES_PRINTF("slesCreateServer =%d",status);
}
}
return status;
@@ -70,9 +75,11 @@ static void recorderCallback(SLAndroidSimpleBufferQueueItf caller __unused, void
if (pSles != NULL) {
+
SLresult result;
pthread_mutex_lock(&(pSles->mutex));
+ //ee SLES_PRINTF("<R");
// We should only be called when a recording buffer is done
assert(pSles->rxFront <= pSles->rxBufCount);
@@ -118,6 +125,7 @@ static void recorderCallback(SLAndroidSimpleBufferQueueItf caller __unused, void
+ //ee SLES_PRINTF("r>");
pthread_mutex_unlock(&(pSles->mutex));
} //pSles not null
@@ -132,6 +140,7 @@ static void playerCallback(SLBufferQueueItf caller __unused, void *context) {
SLresult result;
pthread_mutex_lock(&(pSles->mutex));
+ //ee SLES_PRINTF("<P");
// Get the buffer that just finished playing
assert(pSles->txFront <= pSles->txBufCount);
@@ -182,7 +191,7 @@ static void playerCallback(SLBufferQueueItf caller __unused, void *context) {
pSles->txRear = txRearNext;
-
+ //ee SLES_PRINTF("p>");
pthread_mutex_unlock(&(pSles->mutex));
} //pSles not null
@@ -363,6 +372,8 @@ int slesCreateServer(sles_data *pSles, int samplingRate, int frameCount) {
if (SL_RESULT_CONTENT_UNSUPPORTED == result) {
fprintf(stderr, "Could not create audio player (result %x), check sample rate\n",
result);
+ SLES_PRINTF("ERROR: Could not create audio player (result %x), check sample rate\n",
+ result);
goto cleanup;
}
ASSERT_EQ(SL_RESULT_SUCCESS, result);
@@ -429,6 +440,9 @@ int slesCreateServer(sles_data *pSles, int samplingRate, int frameCount) {
fprintf(stderr, "Could not create audio recorder (result %x), "
"check sample rate and channel count\n", result);
status = SLES_FAIL;
+
+ SLES_PRINTF("ERROR: Could not create audio recorder (result %x), "
+ "check sample rate and channel count\n", result);
goto cleanup;
}
}
@@ -479,6 +493,8 @@ int slesCreateServer(sles_data *pSles, int samplingRate, int frameCount) {
status = SLES_SUCCESS;
cleanup:
+ SLES_PRINTF("Finished initialization with status: %d", status);
+
int xx =1;
}
@@ -488,6 +504,8 @@ int slesCreateServer(sles_data *pSles, int samplingRate, int frameCount) {
int slesProcessNext(sles_data *pSles, double *pSamples, long maxSamples) {
//int status = SLES_FAIL;
+ SLES_PRINTF("slesProcessNext: pSles = %p, currentSample: %p, maxSamples = %d", pSles, pSamples, maxSamples);
+
int samplesRead = 0;
int currentSample = 0;
@@ -537,32 +555,84 @@ int slesProcessNext(sles_data *pSles, double *pSamples, long maxSamples) {
result = (*(pSles->recorderBufferQueue))->GetState(pSles->recorderBufferQueue,
&recorderBQState);
ASSERT_EQ(SL_RESULT_SUCCESS, result);
+
+ SLES_PRINTF("End of slesProcessNext: pSles = %p, samplesRead = %d, maxSamples= %d", pSles, samplesRead, maxSamples);
}
return samplesRead;
}
int slesDestroyServer(sles_data *pSles) {
int status = SLES_FAIL;
+ SLES_PRINTF("Start slesDestroyServer: pSles = %p", pSles);
+
if (pSles != NULL) {
+
+
+
+ if (NULL != pSles->playerObject) {
+
+ SLES_PRINTF("stopping player...");
+ SLPlayItf playerPlay;
+ SLresult result = (*(pSles->playerObject))->GetInterface(pSles->playerObject, SL_IID_PLAY,
+ &playerPlay);
+
+ ASSERT_EQ(SL_RESULT_SUCCESS, result);
+
+ //stop player and recorder if they exist
+ result = (*playerPlay)->SetPlayState(playerPlay, SL_PLAYSTATE_STOPPED);
+ ASSERT_EQ(SL_RESULT_SUCCESS, result);
+ }
+
+ if (NULL != pSles->recorderObject) {
+
+
+ SLES_PRINTF("stopping recorder...");
+ SLRecordItf recorderRecord;
+ SLresult result = (*(pSles->recorderObject))->GetInterface(pSles->recorderObject, SL_IID_RECORD,
+ &recorderRecord);
+ ASSERT_EQ(SL_RESULT_SUCCESS, result);
+
+
+ result = (*recorderRecord)->SetRecordState(recorderRecord, SL_RECORDSTATE_STOPPED);
+ ASSERT_EQ(SL_RESULT_SUCCESS, result);
+ }
+
+ usleep(1000);
+
+
audio_utils_fifo_deinit(&(pSles->fifo));
delete[] pSles->fifoBuffer;
+ SLES_PRINTF("slesDestroyServer 2");
+
// if (sndfile != NULL) {
audio_utils_fifo_deinit(&(pSles->fifo2));
delete[] pSles->fifo2Buffer;
+
+ SLES_PRINTF("slesDestroyServer 3");
+
// sf_close(sndfile);
// }
if (NULL != pSles->playerObject) {
(*(pSles->playerObject))->Destroy(pSles->playerObject);
}
+
+ SLES_PRINTF("slesDestroyServer 4");
+
if (NULL != pSles->recorderObject) {
(*(pSles->recorderObject))->Destroy(pSles->recorderObject);
}
+
+ SLES_PRINTF("slesDestroyServer 5");
+
(*(pSles->outputmixObject))->Destroy(pSles->outputmixObject);
+ SLES_PRINTF("slesDestroyServer 6");
(*(pSles->engineObject))->Destroy(pSles->engineObject);
+ SLES_PRINTF("slesDestroyServer 7");
}
+ SLES_PRINTF("End slesDestroyServer: status = %d", status);
return status;
}
diff --git a/LoopbackApp/app/src/main/jni/sles.h b/LoopbackApp/app/src/main/jni/sles.h
index 5e41b15..15f6f2e 100644
--- a/LoopbackApp/app/src/main/jni/sles.h
+++ b/LoopbackApp/app/src/main/jni/sles.h
@@ -17,11 +17,14 @@
#include <SLES/OpenSLES.h>
#include <SLES/OpenSLES_Android.h>
#include <pthread.h>
+#include <android/log.h>
#ifndef _Included_org_drrickorang_loopback_sles
#define _Included_org_drrickorang_loopback_sles
//struct audio_utils_fifo;
+#define SLES_PRINTF(...) __android_log_print(ANDROID_LOG_INFO, "sles_jni", __VA_ARGS__);
+
#ifdef __cplusplus
extern "C" {