diff options
author | Ricardo Garcia <rago@google.com> | 2015-04-02 14:58:29 -0700 |
---|---|---|
committer | Ricardo Garcia <rago@google.com> | 2015-04-02 15:04:24 -0700 |
commit | e1b0d76f5597f735509e48e732e3efa26ea9fe0b (patch) | |
tree | 7108e4c96aa47b7cb72466cd8097bf234bf28e49 /LoopbackApp/app | |
parent | 6c27b1100b1db706d824c78f8ad1311f08ef23f2 (diff) | |
download | drrickorang-e1b0d76f5597f735509e48e732e3efa26ea9fe0b.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.gradle | 2 | ||||
-rw-r--r-- | LoopbackApp/app/src/main/java/org/drrickorang/.DS_Store | bin | 6148 -> 6148 bytes | |||
-rw-r--r-- | LoopbackApp/app/src/main/java/org/drrickorang/loopback/LoopbackActivity.java | 11 | ||||
-rw-r--r-- | LoopbackApp/app/src/main/java/org/drrickorang/loopback/NativeAudioThread.java | 149 | ||||
-rw-r--r-- | LoopbackApp/app/src/main/jni/jni_sles.c | 24 | ||||
-rw-r--r-- | LoopbackApp/app/src/main/jni/jni_sles.h | 2 | ||||
-rw-r--r-- | LoopbackApp/app/src/main/jni/sles.cpp | 72 | ||||
-rw-r--r-- | LoopbackApp/app/src/main/jni/sles.h | 3 |
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 Binary files differindex ba55215..4a310a6 100644 --- a/LoopbackApp/app/src/main/java/org/drrickorang/.DS_Store +++ b/LoopbackApp/app/src/main/java/org/drrickorang/.DS_Store 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" { |