summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/jni/android_media_AudioRecord.cpp168
-rw-r--r--core/jni/android_media_AudioTrack.cpp306
2 files changed, 248 insertions, 226 deletions
diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp
index 2fe0b9e..0f04e6f 100644
--- a/core/jni/android_media_AudioRecord.cpp
+++ b/core/jni/android_media_AudioRecord.cpp
@@ -28,6 +28,8 @@
#include <android_runtime/AndroidRuntime.h>
#include <utils/Log.h>
+#include <utils/SortedVector.h>
+#include <utils/threads.h>
#include <media/AudioRecord.h>
#include <media/mediarecorder.h>
@@ -55,9 +57,12 @@ static fields_t javaAudioRecordFields;
struct audiorecord_callback_cookie {
jclass audioRecord_class;
jobject audioRecord_ref;
- };
+ bool busy;
+ Condition cond;
+};
-Mutex sLock;
+static Mutex sLock;
+static SortedVector <audiorecord_callback_cookie *> sAudioRecordCallBackCookies;
// ----------------------------------------------------------------------------
@@ -87,13 +92,21 @@ jint android_media_translateRecorderErrorCode(int code) {
// ----------------------------------------------------------------------------
static void recorderCallback(int event, void* user, void *info) {
+
+ audiorecord_callback_cookie *callbackInfo = (audiorecord_callback_cookie *)user;
+ {
+ Mutex::Autolock l(sLock);
+ if (sAudioRecordCallBackCookies.indexOf(callbackInfo) < 0) {
+ return;
+ }
+ callbackInfo->busy = true;
+ }
if (event == AudioRecord::EVENT_MORE_DATA) {
// set size to 0 to signal we're not using the callback to read more data
AudioRecord::Buffer* pBuff = (AudioRecord::Buffer*)info;
pBuff->size = 0;
} else if (event == AudioRecord::EVENT_MARKER) {
- audiorecord_callback_cookie *callbackInfo = (audiorecord_callback_cookie *)user;
JNIEnv *env = AndroidRuntime::getJNIEnv();
if (user && env) {
env->CallStaticVoidMethod(
@@ -107,7 +120,6 @@ static void recorderCallback(int event, void* user, void *info) {
}
} else if (event == AudioRecord::EVENT_NEW_POS) {
- audiorecord_callback_cookie *callbackInfo = (audiorecord_callback_cookie *)user;
JNIEnv *env = AndroidRuntime::getJNIEnv();
if (user && env) {
env->CallStaticVoidMethod(
@@ -120,8 +132,36 @@ static void recorderCallback(int event, void* user, void *info) {
}
}
}
+ {
+ Mutex::Autolock l(sLock);
+ callbackInfo->busy = false;
+ callbackInfo->cond.broadcast();
+ }
}
+// ----------------------------------------------------------------------------
+static sp<AudioRecord> getAudioRecord(JNIEnv* env, jobject thiz)
+{
+ Mutex::Autolock l(sLock);
+ AudioRecord* const ar =
+ (AudioRecord*)env->GetIntField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj);
+ return sp<AudioRecord>(ar);
+}
+
+static sp<AudioRecord> setAudioRecord(JNIEnv* env, jobject thiz, const sp<AudioRecord>& ar)
+{
+ Mutex::Autolock l(sLock);
+ sp<AudioRecord> old =
+ (AudioRecord*)env->GetIntField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj);
+ if (ar.get()) {
+ ar->incStrong(thiz);
+ }
+ if (old != 0) {
+ old->decStrong(thiz);
+ }
+ env->SetIntField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj, (int)ar.get());
+ return old;
+}
// ----------------------------------------------------------------------------
static int
@@ -162,6 +202,12 @@ android_media_AudioRecord_setup(JNIEnv *env, jobject thiz, jobject weak_this,
return AUDIORECORD_ERROR_SETUP_INVALIDSOURCE;
}
+ jclass clazz = env->GetObjectClass(thiz);
+ if (clazz == NULL) {
+ ALOGE("Can't find %s when setting up callback.", kClassPathName);
+ return AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED;
+ }
+
if (jSession == NULL) {
ALOGE("Error creating AudioRecord: invalid session ID pointer");
return AUDIORECORD_ERROR;
@@ -176,27 +222,20 @@ android_media_AudioRecord_setup(JNIEnv *env, jobject thiz, jobject weak_this,
env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
nSession = NULL;
- audiorecord_callback_cookie *lpCallbackData = NULL;
- AudioRecord* lpRecorder = NULL;
-
// create an uninitialized AudioRecord object
- lpRecorder = new AudioRecord();
- if (lpRecorder == NULL) {
+ sp<AudioRecord> lpRecorder = new AudioRecord();
+ if (lpRecorder == NULL) {
ALOGE("Error creating AudioRecord instance.");
return AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED;
}
// create the callback information:
// this data will be passed with every AudioRecord callback
- jclass clazz = env->GetObjectClass(thiz);
- if (clazz == NULL) {
- ALOGE("Can't find %s when setting up callback.", kClassPathName);
- goto native_track_failure;
- }
- lpCallbackData = new audiorecord_callback_cookie;
+ audiorecord_callback_cookie *lpCallbackData = new audiorecord_callback_cookie;
lpCallbackData->audioRecord_class = (jclass)env->NewGlobalRef(clazz);
// we use a weak reference so the AudioRecord object can be garbage collected.
lpCallbackData->audioRecord_ref = env->NewGlobalRef(weak_this);
+ lpCallbackData->busy = false;
lpRecorder->set((audio_source_t) source,
sampleRateInHertz,
@@ -225,9 +264,13 @@ android_media_AudioRecord_setup(JNIEnv *env, jobject thiz, jobject weak_this,
env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
nSession = NULL;
+ { // scope for the lock
+ Mutex::Autolock l(sLock);
+ sAudioRecordCallBackCookies.add(lpCallbackData);
+ }
// save our newly created C++ AudioRecord in the "nativeRecorderInJavaObj" field
// of the Java object
- env->SetIntField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj, (int)lpRecorder);
+ setAudioRecord(env, thiz, lpRecorder);
// save our newly created callback information in the "nativeCallbackCookie" field
// of the Java object (in mNativeCallbackCookie) so we can free the memory in finalize()
@@ -240,11 +283,6 @@ native_init_failure:
env->DeleteGlobalRef(lpCallbackData->audioRecord_class);
env->DeleteGlobalRef(lpCallbackData->audioRecord_ref);
delete lpCallbackData;
-
-native_track_failure:
- delete lpRecorder;
-
- env->SetIntField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj, 0);
env->SetIntField(thiz, javaAudioRecordFields.nativeCallbackCookie, 0);
return AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED;
@@ -256,8 +294,7 @@ native_track_failure:
static int
android_media_AudioRecord_start(JNIEnv *env, jobject thiz, jint event, jint triggerSession)
{
- AudioRecord *lpRecorder =
- (AudioRecord *)env->GetIntField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj);
+ sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
if (lpRecorder == NULL ) {
jniThrowException(env, "java/lang/IllegalStateException", NULL);
return AUDIORECORD_ERROR;
@@ -272,8 +309,7 @@ android_media_AudioRecord_start(JNIEnv *env, jobject thiz, jint event, jint trig
static void
android_media_AudioRecord_stop(JNIEnv *env, jobject thiz)
{
- AudioRecord *lpRecorder =
- (AudioRecord *)env->GetIntField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj);
+ sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
if (lpRecorder == NULL ) {
jniThrowException(env, "java/lang/IllegalStateException", NULL);
return;
@@ -285,30 +321,35 @@ android_media_AudioRecord_stop(JNIEnv *env, jobject thiz)
// ----------------------------------------------------------------------------
+
+#define CALLBACK_COND_WAIT_TIMEOUT_MS 1000
static void android_media_AudioRecord_release(JNIEnv *env, jobject thiz) {
+ sp<AudioRecord> lpRecorder = setAudioRecord(env, thiz, 0);
+ if (lpRecorder == NULL) {
+ return;
+ }
+ ALOGV("About to delete lpRecorder: %x\n", (int)lpRecorder.get());
+ lpRecorder->stop();
- // serialize access. Ugly, but functional.
- Mutex::Autolock lock(&sLock);
- AudioRecord *lpRecorder =
- (AudioRecord *)env->GetIntField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj);
audiorecord_callback_cookie *lpCookie = (audiorecord_callback_cookie *)env->GetIntField(
thiz, javaAudioRecordFields.nativeCallbackCookie);
// reset the native resources in the Java object so any attempt to access
// them after a call to release fails.
- env->SetIntField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj, 0);
env->SetIntField(thiz, javaAudioRecordFields.nativeCallbackCookie, 0);
- // delete the AudioRecord object
- if (lpRecorder) {
- ALOGV("About to delete lpRecorder: %x\n", (int)lpRecorder);
- lpRecorder->stop();
- delete lpRecorder;
- }
-
// delete the callback information
if (lpCookie) {
+ Mutex::Autolock l(sLock);
ALOGV("deleting lpCookie: %x\n", (int)lpCookie);
+ while (lpCookie->busy) {
+ if (lpCookie->cond.waitRelative(sLock,
+ milliseconds(CALLBACK_COND_WAIT_TIMEOUT_MS)) !=
+ NO_ERROR) {
+ break;
+ }
+ }
+ sAudioRecordCallBackCookies.remove(lpCookie);
env->DeleteGlobalRef(lpCookie->audioRecord_class);
env->DeleteGlobalRef(lpCookie->audioRecord_ref);
delete lpCookie;
@@ -327,11 +368,8 @@ static jint android_media_AudioRecord_readInByteArray(JNIEnv *env, jobject thiz
jbyteArray javaAudioData,
jint offsetInBytes, jint sizeInBytes) {
jbyte* recordBuff = NULL;
- AudioRecord *lpRecorder = NULL;
-
// get the audio recorder from which we'll read new audio samples
- lpRecorder =
- (AudioRecord *)env->GetIntField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj);
+ sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
if (lpRecorder == NULL) {
ALOGE("Unable to retrieve AudioRecord object, can't record");
return 0;
@@ -378,12 +416,8 @@ static jint android_media_AudioRecord_readInShortArray(JNIEnv *env, jobject thi
// ----------------------------------------------------------------------------
static jint android_media_AudioRecord_readInDirectBuffer(JNIEnv *env, jobject thiz,
jobject jBuffer, jint sizeInBytes) {
- AudioRecord *lpRecorder = NULL;
- //ALOGV("Entering android_media_AudioRecord_readInBuffer");
-
// get the audio recorder from which we'll read new audio samples
- lpRecorder =
- (AudioRecord *)env->GetIntField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj);
+ sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
if (lpRecorder==NULL)
return 0;
@@ -411,35 +445,29 @@ static jint android_media_AudioRecord_readInDirectBuffer(JNIEnv *env, jobject t
static jint android_media_AudioRecord_set_marker_pos(JNIEnv *env, jobject thiz,
jint markerPos) {
- AudioRecord *lpRecorder = (AudioRecord *)env->GetIntField(
- thiz, javaAudioRecordFields.nativeRecorderInJavaObj);
-
- if (lpRecorder) {
- return
- android_media_translateRecorderErrorCode( lpRecorder->setMarkerPosition(markerPos) );
- } else {
+ sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
+ if (lpRecorder == NULL) {
jniThrowException(env, "java/lang/IllegalStateException",
"Unable to retrieve AudioRecord pointer for setMarkerPosition()");
return AUDIORECORD_ERROR;
}
+ return android_media_translateRecorderErrorCode( lpRecorder->setMarkerPosition(markerPos) );
}
// ----------------------------------------------------------------------------
static jint android_media_AudioRecord_get_marker_pos(JNIEnv *env, jobject thiz) {
- AudioRecord *lpRecorder = (AudioRecord *)env->GetIntField(
- thiz, javaAudioRecordFields.nativeRecorderInJavaObj);
+ sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
uint32_t markerPos = 0;
- if (lpRecorder) {
- lpRecorder->getMarkerPosition(&markerPos);
- return (jint)markerPos;
- } else {
+ if (lpRecorder == NULL) {
jniThrowException(env, "java/lang/IllegalStateException",
"Unable to retrieve AudioRecord pointer for getMarkerPosition()");
return AUDIORECORD_ERROR;
}
+ lpRecorder->getMarkerPosition(&markerPos);
+ return (jint)markerPos;
}
@@ -447,35 +475,30 @@ static jint android_media_AudioRecord_get_marker_pos(JNIEnv *env, jobject thiz)
static jint android_media_AudioRecord_set_pos_update_period(JNIEnv *env, jobject thiz,
jint period) {
- AudioRecord *lpRecorder = (AudioRecord *)env->GetIntField(
- thiz, javaAudioRecordFields.nativeRecorderInJavaObj);
+ sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
- if (lpRecorder) {
- return
- android_media_translateRecorderErrorCode( lpRecorder->setPositionUpdatePeriod(period) );
- } else {
+ if (lpRecorder == NULL) {
jniThrowException(env, "java/lang/IllegalStateException",
"Unable to retrieve AudioRecord pointer for setPositionUpdatePeriod()");
return AUDIORECORD_ERROR;
}
+ return android_media_translateRecorderErrorCode( lpRecorder->setPositionUpdatePeriod(period) );
}
// ----------------------------------------------------------------------------
static jint android_media_AudioRecord_get_pos_update_period(JNIEnv *env, jobject thiz) {
- AudioRecord *lpRecorder = (AudioRecord *)env->GetIntField(
- thiz, javaAudioRecordFields.nativeRecorderInJavaObj);
+ sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
uint32_t period = 0;
- if (lpRecorder) {
- lpRecorder->getPositionUpdatePeriod(&period);
- return (jint)period;
- } else {
+ if (lpRecorder == NULL) {
jniThrowException(env, "java/lang/IllegalStateException",
"Unable to retrieve AudioRecord pointer for getPositionUpdatePeriod()");
return AUDIORECORD_ERROR;
}
+ lpRecorder->getPositionUpdatePeriod(&period);
+ return (jint)period;
}
@@ -486,7 +509,8 @@ static jint android_media_AudioRecord_get_pos_update_period(JNIEnv *env, jobjec
static jint android_media_AudioRecord_get_min_buff_size(JNIEnv *env, jobject thiz,
jint sampleRateInHertz, jint nbChannels, jint audioFormat) {
- ALOGV(">> android_media_AudioRecord_get_min_buff_size(%d, %d, %d)", sampleRateInHertz, nbChannels, audioFormat);
+ ALOGV(">> android_media_AudioRecord_get_min_buff_size(%d, %d, %d)",
+ sampleRateInHertz, nbChannels, audioFormat);
int frameCount = 0;
status_t result = AudioRecord::getMinFrameCount(&frameCount,
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index a46714e..7e5263d 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -59,7 +59,9 @@ static fields_t javaAudioTrackFields;
struct audiotrack_callback_cookie {
jclass audioTrack_class;
jobject audioTrack_ref;
- };
+ bool busy;
+ Condition cond;
+};
// ----------------------------------------------------------------------------
class AudioTrackJniStorage {
@@ -90,6 +92,9 @@ class AudioTrackJniStorage {
}
};
+static Mutex sLock;
+static SortedVector <audiotrack_callback_cookie *> sAudioTrackCallBackCookies;
+
// ----------------------------------------------------------------------------
#define DEFAULT_OUTPUT_SAMPLE_RATE 44100
@@ -120,13 +125,22 @@ jint android_media_translateErrorCode(int code) {
// ----------------------------------------------------------------------------
static void audioCallback(int event, void* user, void *info) {
+
+ audiotrack_callback_cookie *callbackInfo = (audiotrack_callback_cookie *)user;
+ {
+ Mutex::Autolock l(sLock);
+ if (sAudioTrackCallBackCookies.indexOf(callbackInfo) < 0) {
+ return;
+ }
+ callbackInfo->busy = true;
+ }
+
if (event == AudioTrack::EVENT_MORE_DATA) {
// set size to 0 to signal we're not using the callback to write more data
AudioTrack::Buffer* pBuff = (AudioTrack::Buffer*)info;
pBuff->size = 0;
} else if (event == AudioTrack::EVENT_MARKER) {
- audiotrack_callback_cookie *callbackInfo = (audiotrack_callback_cookie *)user;
JNIEnv *env = AndroidRuntime::getJNIEnv();
if (user && env) {
env->CallStaticVoidMethod(
@@ -140,7 +154,6 @@ static void audioCallback(int event, void* user, void *info) {
}
} else if (event == AudioTrack::EVENT_NEW_POS) {
- audiotrack_callback_cookie *callbackInfo = (audiotrack_callback_cookie *)user;
JNIEnv *env = AndroidRuntime::getJNIEnv();
if (user && env) {
env->CallStaticVoidMethod(
@@ -153,10 +166,39 @@ static void audioCallback(int event, void* user, void *info) {
}
}
}
+ {
+ Mutex::Autolock l(sLock);
+ callbackInfo->busy = false;
+ callbackInfo->cond.broadcast();
+ }
}
// ----------------------------------------------------------------------------
+static sp<AudioTrack> getAudioTrack(JNIEnv* env, jobject thiz)
+{
+ Mutex::Autolock l(sLock);
+ AudioTrack* const at =
+ (AudioTrack*)env->GetIntField(thiz, javaAudioTrackFields.nativeTrackInJavaObj);
+ return sp<AudioTrack>(at);
+}
+
+static sp<AudioTrack> setAudioTrack(JNIEnv* env, jobject thiz, const sp<AudioTrack>& at)
+{
+ Mutex::Autolock l(sLock);
+ sp<AudioTrack> old =
+ (AudioTrack*)env->GetIntField(thiz, javaAudioTrackFields.nativeTrackInJavaObj);
+ if (at.get()) {
+ at->incStrong(thiz);
+ }
+ if (old != 0) {
+ old->decStrong(thiz);
+ }
+ env->SetIntField(thiz, javaAudioTrackFields.nativeTrackInJavaObj, (int)at.get());
+ return old;
+}
+
+// ----------------------------------------------------------------------------
static int
android_media_AudioTrack_native_setup(JNIEnv *env, jobject thiz, jobject weak_this,
jint streamType, jint sampleRateInHertz, jint javaChannelMask,
@@ -231,32 +273,20 @@ android_media_AudioTrack_native_setup(JNIEnv *env, jobject thiz, jobject weak_th
AUDIO_FORMAT_PCM_16_BIT : AUDIO_FORMAT_PCM_8_BIT;
int frameCount = buffSizeInBytes / (nbChannels * bytesPerSample);
- AudioTrackJniStorage* lpJniStorage = new AudioTrackJniStorage();
-
- // initialize the callback information:
- // this data will be passed with every AudioTrack callback
jclass clazz = env->GetObjectClass(thiz);
if (clazz == NULL) {
ALOGE("Can't find %s when setting up callback.", kClassPathName);
- delete lpJniStorage;
return AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED;
}
- lpJniStorage->mCallbackData.audioTrack_class = (jclass)env->NewGlobalRef(clazz);
- // we use a weak reference so the AudioTrack object can be garbage collected.
- lpJniStorage->mCallbackData.audioTrack_ref = env->NewGlobalRef(weak_this);
-
- lpJniStorage->mStreamType = atStreamType;
if (jSession == NULL) {
ALOGE("Error creating AudioTrack: invalid session ID pointer");
- delete lpJniStorage;
return AUDIOTRACK_ERROR;
}
jint* nSession = (jint *) env->GetPrimitiveArrayCritical(jSession, NULL);
if (nSession == NULL) {
ALOGE("Error creating AudioTrack: Error retrieving session id pointer");
- delete lpJniStorage;
return AUDIOTRACK_ERROR;
}
int sessionId = nSession[0];
@@ -264,12 +294,21 @@ android_media_AudioTrack_native_setup(JNIEnv *env, jobject thiz, jobject weak_th
nSession = NULL;
// create the native AudioTrack object
- AudioTrack* lpTrack = new AudioTrack();
+ sp<AudioTrack> lpTrack = new AudioTrack();
if (lpTrack == NULL) {
ALOGE("Error creating uninitialized AudioTrack");
- goto native_track_failure;
+ return AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED;
}
+ // initialize the callback information:
+ // this data will be passed with every AudioTrack callback
+ AudioTrackJniStorage* lpJniStorage = new AudioTrackJniStorage();
+ lpJniStorage->mStreamType = atStreamType;
+ lpJniStorage->mCallbackData.audioTrack_class = (jclass)env->NewGlobalRef(clazz);
+ // we use a weak reference so the AudioTrack object can be garbage collected.
+ lpJniStorage->mCallbackData.audioTrack_ref = env->NewGlobalRef(weak_this);
+ lpJniStorage->mCallbackData.busy = false;
+
// initialize the native AudioTrack object
if (memoryMode == javaAudioTrackFields.MODE_STREAM) {
@@ -323,9 +362,13 @@ android_media_AudioTrack_native_setup(JNIEnv *env, jobject thiz, jobject weak_th
env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
nSession = NULL;
+ { // scope for the lock
+ Mutex::Autolock l(sLock);
+ sAudioTrackCallBackCookies.add(&lpJniStorage->mCallbackData);
+ }
// save our newly created C++ AudioTrack in the "nativeTrackInJavaObj" field
// of the Java object (in mNativeTrackInJavaObj)
- env->SetIntField(thiz, javaAudioTrackFields.nativeTrackInJavaObj, (int)lpTrack);
+ setAudioTrack(env, thiz, lpTrack);
// save the JNI resources so we can free them later
//ALOGV("storing lpJniStorage: %x\n", (int)lpJniStorage);
@@ -335,10 +378,6 @@ android_media_AudioTrack_native_setup(JNIEnv *env, jobject thiz, jobject weak_th
// failures:
native_init_failure:
- delete lpTrack;
- env->SetIntField(thiz, javaAudioTrackFields.nativeTrackInJavaObj, 0);
-
-native_track_failure:
if (nSession != NULL) {
env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
}
@@ -346,8 +385,8 @@ native_track_failure:
env->DeleteGlobalRef(lpJniStorage->mCallbackData.audioTrack_ref);
delete lpJniStorage;
env->SetIntField(thiz, javaAudioTrackFields.jniData, 0);
- return AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED;
+ return AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED;
}
@@ -355,9 +394,8 @@ native_track_failure:
static void
android_media_AudioTrack_start(JNIEnv *env, jobject thiz)
{
- AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
- thiz, javaAudioTrackFields.nativeTrackInJavaObj);
- if (lpTrack == NULL ) {
+ sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
+ if (lpTrack == NULL) {
jniThrowException(env, "java/lang/IllegalStateException",
"Unable to retrieve AudioTrack pointer for start()");
return;
@@ -371,9 +409,8 @@ android_media_AudioTrack_start(JNIEnv *env, jobject thiz)
static void
android_media_AudioTrack_stop(JNIEnv *env, jobject thiz)
{
- AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
- thiz, javaAudioTrackFields.nativeTrackInJavaObj);
- if (lpTrack == NULL ) {
+ sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
+ if (lpTrack == NULL) {
jniThrowException(env, "java/lang/IllegalStateException",
"Unable to retrieve AudioTrack pointer for stop()");
return;
@@ -387,9 +424,8 @@ android_media_AudioTrack_stop(JNIEnv *env, jobject thiz)
static void
android_media_AudioTrack_pause(JNIEnv *env, jobject thiz)
{
- AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
- thiz, javaAudioTrackFields.nativeTrackInJavaObj);
- if (lpTrack == NULL ) {
+ sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
+ if (lpTrack == NULL) {
jniThrowException(env, "java/lang/IllegalStateException",
"Unable to retrieve AudioTrack pointer for pause()");
return;
@@ -403,9 +439,8 @@ android_media_AudioTrack_pause(JNIEnv *env, jobject thiz)
static void
android_media_AudioTrack_flush(JNIEnv *env, jobject thiz)
{
- AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
- thiz, javaAudioTrackFields.nativeTrackInJavaObj);
- if (lpTrack == NULL ) {
+ sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
+ if (lpTrack == NULL) {
jniThrowException(env, "java/lang/IllegalStateException",
"Unable to retrieve AudioTrack pointer for flush()");
return;
@@ -418,9 +453,8 @@ android_media_AudioTrack_flush(JNIEnv *env, jobject thiz)
static void
android_media_AudioTrack_set_volume(JNIEnv *env, jobject thiz, jfloat leftVol, jfloat rightVol )
{
- AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
- thiz, javaAudioTrackFields.nativeTrackInJavaObj);
- if (lpTrack == NULL ) {
+ sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
+ if (lpTrack == NULL) {
jniThrowException(env, "java/lang/IllegalStateException",
"Unable to retrieve AudioTrack pointer for setVolume()");
return;
@@ -430,68 +464,75 @@ android_media_AudioTrack_set_volume(JNIEnv *env, jobject thiz, jfloat leftVol, j
}
// ----------------------------------------------------------------------------
-static void android_media_AudioTrack_native_finalize(JNIEnv *env, jobject thiz) {
- //ALOGV("android_media_AudioTrack_native_finalize jobject: %x\n", (int)thiz);
- // delete the AudioTrack object
- AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
- thiz, javaAudioTrackFields.nativeTrackInJavaObj);
- if (lpTrack) {
- //ALOGV("deleting lpTrack: %x\n", (int)lpTrack);
- lpTrack->stop();
- delete lpTrack;
+#define CALLBACK_COND_WAIT_TIMEOUT_MS 1000
+static void android_media_AudioTrack_native_release(JNIEnv *env, jobject thiz) {
+ sp<AudioTrack> lpTrack = setAudioTrack(env, thiz, 0);
+ if (lpTrack == NULL) {
+ return;
}
+ //ALOGV("deleting lpTrack: %x\n", (int)lpTrack);
+ lpTrack->stop();
// delete the JNI data
AudioTrackJniStorage* pJniStorage = (AudioTrackJniStorage *)env->GetIntField(
thiz, javaAudioTrackFields.jniData);
+ // reset the native resources in the Java object so any attempt to access
+ // them after a call to release fails.
+ env->SetIntField(thiz, javaAudioTrackFields.jniData, 0);
+
if (pJniStorage) {
- // delete global refs created in native_setup
- env->DeleteGlobalRef(pJniStorage->mCallbackData.audioTrack_class);
- env->DeleteGlobalRef(pJniStorage->mCallbackData.audioTrack_ref);
+ Mutex::Autolock l(sLock);
+ audiotrack_callback_cookie *lpCookie = &pJniStorage->mCallbackData;
//ALOGV("deleting pJniStorage: %x\n", (int)pJniStorage);
+ while (lpCookie->busy) {
+ if (lpCookie->cond.waitRelative(sLock,
+ milliseconds(CALLBACK_COND_WAIT_TIMEOUT_MS)) !=
+ NO_ERROR) {
+ break;
+ }
+ }
+ sAudioTrackCallBackCookies.remove(lpCookie);
+ // delete global refs created in native_setup
+ env->DeleteGlobalRef(lpCookie->audioTrack_class);
+ env->DeleteGlobalRef(lpCookie->audioTrack_ref);
delete pJniStorage;
}
}
-// ----------------------------------------------------------------------------
-static void android_media_AudioTrack_native_release(JNIEnv *env, jobject thiz) {
- // do everything a call to finalize would
- android_media_AudioTrack_native_finalize(env, thiz);
- // + reset the native resources in the Java object so any attempt to access
- // them after a call to release fails.
- env->SetIntField(thiz, javaAudioTrackFields.nativeTrackInJavaObj, 0);
- env->SetIntField(thiz, javaAudioTrackFields.jniData, 0);
+// ----------------------------------------------------------------------------
+static void android_media_AudioTrack_native_finalize(JNIEnv *env, jobject thiz) {
+ //ALOGV("android_media_AudioTrack_native_finalize jobject: %x\n", (int)thiz);
+ android_media_AudioTrack_native_release(env, thiz);
}
-
// ----------------------------------------------------------------------------
-jint writeToTrack(AudioTrack* pTrack, jint audioFormat, jbyte* data,
+jint writeToTrack(const sp<AudioTrack>& track, jint audioFormat, jbyte* data,
jint offsetInBytes, jint sizeInBytes) {
// give the data to the native AudioTrack object (the data starts at the offset)
ssize_t written = 0;
// regular write() or copy the data to the AudioTrack's shared memory?
- if (pTrack->sharedBuffer() == 0) {
- written = pTrack->write(data + offsetInBytes, sizeInBytes);
+ if (track->sharedBuffer() == 0) {
+ written = track->write(data + offsetInBytes, sizeInBytes);
} else {
if (audioFormat == javaAudioTrackFields.PCM16) {
// writing to shared memory, check for capacity
- if ((size_t)sizeInBytes > pTrack->sharedBuffer()->size()) {
- sizeInBytes = pTrack->sharedBuffer()->size();
+ if ((size_t)sizeInBytes > track->sharedBuffer()->size()) {
+ sizeInBytes = track->sharedBuffer()->size();
}
- memcpy(pTrack->sharedBuffer()->pointer(), data + offsetInBytes, sizeInBytes);
+ memcpy(track->sharedBuffer()->pointer(), data + offsetInBytes, sizeInBytes);
written = sizeInBytes;
} else if (audioFormat == javaAudioTrackFields.PCM8) {
// data contains 8bit data we need to expand to 16bit before copying
// to the shared memory
// writing to shared memory, check for capacity,
// note that input data will occupy 2X the input space due to 8 to 16bit conversion
- if (((size_t)sizeInBytes)*2 > pTrack->sharedBuffer()->size()) {
- sizeInBytes = pTrack->sharedBuffer()->size() / 2;
+ if (((size_t)sizeInBytes)*2 > track->sharedBuffer()->size()) {
+ sizeInBytes = track->sharedBuffer()->size() / 2;
}
int count = sizeInBytes;
- int16_t *dst = (int16_t *)pTrack->sharedBuffer()->pointer();
+ int16_t *dst = (int16_t *)track->sharedBuffer()->pointer();
const int8_t *src = (const int8_t *)(data + offsetInBytes);
while (count--) {
*dst++ = (int16_t)(*src++^0x80) << 8;
@@ -510,13 +551,9 @@ static jint android_media_AudioTrack_native_write_byte(JNIEnv *env, jobject thi
jbyteArray javaAudioData,
jint offsetInBytes, jint sizeInBytes,
jint javaAudioFormat) {
- jbyte* cAudioData = NULL;
- AudioTrack *lpTrack = NULL;
//ALOGV("android_media_AudioTrack_native_write_byte(offset=%d, sizeInBytes=%d) called",
// offsetInBytes, sizeInBytes);
-
- // get the audio track to load with samples
- lpTrack = (AudioTrack *)env->GetIntField(thiz, javaAudioTrackFields.nativeTrackInJavaObj);
+ sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
if (lpTrack == NULL) {
jniThrowException(env, "java/lang/IllegalStateException",
"Unable to retrieve AudioTrack pointer for write()");
@@ -528,6 +565,7 @@ static jint android_media_AudioTrack_native_write_byte(JNIEnv *env, jobject thi
// a way that it becomes much more efficient. When doing so, we will have to prevent the
// AudioSystem callback to be called while in critical section (in case of media server
// process crash for instance)
+ jbyte* cAudioData = NULL;
if (javaAudioData) {
cAudioData = (jbyte *)env->GetByteArrayElements(javaAudioData, NULL);
if (cAudioData == NULL) {
@@ -564,183 +602,148 @@ static jint android_media_AudioTrack_native_write_short(JNIEnv *env, jobject th
// ----------------------------------------------------------------------------
static jint android_media_AudioTrack_get_native_frame_count(JNIEnv *env, jobject thiz) {
- AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
- thiz, javaAudioTrackFields.nativeTrackInJavaObj);
-
- if (lpTrack) {
- return lpTrack->frameCount();
- } else {
+ sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
+ if (lpTrack == NULL) {
jniThrowException(env, "java/lang/IllegalStateException",
"Unable to retrieve AudioTrack pointer for frameCount()");
return AUDIOTRACK_ERROR;
}
+
+ return lpTrack->frameCount();
}
// ----------------------------------------------------------------------------
static jint android_media_AudioTrack_set_playback_rate(JNIEnv *env, jobject thiz,
jint sampleRateInHz) {
- AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
- thiz, javaAudioTrackFields.nativeTrackInJavaObj);
-
- if (lpTrack) {
- return android_media_translateErrorCode(lpTrack->setSampleRate(sampleRateInHz));
- } else {
+ sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
+ if (lpTrack == NULL) {
jniThrowException(env, "java/lang/IllegalStateException",
"Unable to retrieve AudioTrack pointer for setSampleRate()");
return AUDIOTRACK_ERROR;
}
+ return android_media_translateErrorCode(lpTrack->setSampleRate(sampleRateInHz));
}
// ----------------------------------------------------------------------------
static jint android_media_AudioTrack_get_playback_rate(JNIEnv *env, jobject thiz) {
- AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
- thiz, javaAudioTrackFields.nativeTrackInJavaObj);
-
- if (lpTrack) {
- return (jint) lpTrack->getSampleRate();
- } else {
+ sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
+ if (lpTrack == NULL) {
jniThrowException(env, "java/lang/IllegalStateException",
"Unable to retrieve AudioTrack pointer for getSampleRate()");
return AUDIOTRACK_ERROR;
}
+ return (jint) lpTrack->getSampleRate();
}
// ----------------------------------------------------------------------------
static jint android_media_AudioTrack_set_marker_pos(JNIEnv *env, jobject thiz,
jint markerPos) {
-
- AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
- thiz, javaAudioTrackFields.nativeTrackInJavaObj);
-
- if (lpTrack) {
- return android_media_translateErrorCode( lpTrack->setMarkerPosition(markerPos) );
- } else {
+ sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
+ if (lpTrack == NULL) {
jniThrowException(env, "java/lang/IllegalStateException",
"Unable to retrieve AudioTrack pointer for setMarkerPosition()");
return AUDIOTRACK_ERROR;
}
+ return android_media_translateErrorCode( lpTrack->setMarkerPosition(markerPos) );
}
// ----------------------------------------------------------------------------
static jint android_media_AudioTrack_get_marker_pos(JNIEnv *env, jobject thiz) {
-
- AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
- thiz, javaAudioTrackFields.nativeTrackInJavaObj);
+ sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
uint32_t markerPos = 0;
- if (lpTrack) {
- lpTrack->getMarkerPosition(&markerPos);
- return (jint)markerPos;
- } else {
+ if (lpTrack == NULL) {
jniThrowException(env, "java/lang/IllegalStateException",
"Unable to retrieve AudioTrack pointer for getMarkerPosition()");
return AUDIOTRACK_ERROR;
}
+ lpTrack->getMarkerPosition(&markerPos);
+ return (jint)markerPos;
}
// ----------------------------------------------------------------------------
static jint android_media_AudioTrack_set_pos_update_period(JNIEnv *env, jobject thiz,
jint period) {
-
- AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
- thiz, javaAudioTrackFields.nativeTrackInJavaObj);
-
- if (lpTrack) {
- return android_media_translateErrorCode( lpTrack->setPositionUpdatePeriod(period) );
- } else {
+ sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
+ if (lpTrack == NULL) {
jniThrowException(env, "java/lang/IllegalStateException",
"Unable to retrieve AudioTrack pointer for setPositionUpdatePeriod()");
return AUDIOTRACK_ERROR;
}
+ return android_media_translateErrorCode( lpTrack->setPositionUpdatePeriod(period) );
}
// ----------------------------------------------------------------------------
static jint android_media_AudioTrack_get_pos_update_period(JNIEnv *env, jobject thiz) {
-
- AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
- thiz, javaAudioTrackFields.nativeTrackInJavaObj);
+ sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
uint32_t period = 0;
- if (lpTrack) {
- lpTrack->getPositionUpdatePeriod(&period);
- return (jint)period;
- } else {
+ if (lpTrack == NULL) {
jniThrowException(env, "java/lang/IllegalStateException",
"Unable to retrieve AudioTrack pointer for getPositionUpdatePeriod()");
return AUDIOTRACK_ERROR;
}
+ lpTrack->getPositionUpdatePeriod(&period);
+ return (jint)period;
}
// ----------------------------------------------------------------------------
static jint android_media_AudioTrack_set_position(JNIEnv *env, jobject thiz,
jint position) {
-
- AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
- thiz, javaAudioTrackFields.nativeTrackInJavaObj);
-
- if (lpTrack) {
- return android_media_translateErrorCode( lpTrack->setPosition(position) );
- } else {
+ sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
+ if (lpTrack == NULL) {
jniThrowException(env, "java/lang/IllegalStateException",
"Unable to retrieve AudioTrack pointer for setPosition()");
return AUDIOTRACK_ERROR;
}
+ return android_media_translateErrorCode( lpTrack->setPosition(position) );
}
// ----------------------------------------------------------------------------
static jint android_media_AudioTrack_get_position(JNIEnv *env, jobject thiz) {
-
- AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
- thiz, javaAudioTrackFields.nativeTrackInJavaObj);
+ sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
uint32_t position = 0;
- if (lpTrack) {
- lpTrack->getPosition(&position);
- return (jint)position;
- } else {
+ if (lpTrack == NULL) {
jniThrowException(env, "java/lang/IllegalStateException",
"Unable to retrieve AudioTrack pointer for getPosition()");
return AUDIOTRACK_ERROR;
}
+ lpTrack->getPosition(&position);
+ return (jint)position;
}
// ----------------------------------------------------------------------------
static jint android_media_AudioTrack_set_loop(JNIEnv *env, jobject thiz,
jint loopStart, jint loopEnd, jint loopCount) {
-
- AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
- thiz, javaAudioTrackFields.nativeTrackInJavaObj);
- if (lpTrack) {
- return android_media_translateErrorCode( lpTrack->setLoop(loopStart, loopEnd, loopCount) );
- } else {
+ sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
+ if (lpTrack == NULL) {
jniThrowException(env, "java/lang/IllegalStateException",
"Unable to retrieve AudioTrack pointer for setLoop()");
return AUDIOTRACK_ERROR;
}
+ return android_media_translateErrorCode( lpTrack->setLoop(loopStart, loopEnd, loopCount) );
}
// ----------------------------------------------------------------------------
static jint android_media_AudioTrack_reload(JNIEnv *env, jobject thiz) {
-
- AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
- thiz, javaAudioTrackFields.nativeTrackInJavaObj);
- if (lpTrack) {
- return android_media_translateErrorCode( lpTrack->reload() );
- } else {
+ sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
+ if (lpTrack == NULL) {
jniThrowException(env, "java/lang/IllegalStateException",
"Unable to retrieve AudioTrack pointer for reload()");
return AUDIOTRACK_ERROR;
}
+ return android_media_translateErrorCode( lpTrack->reload() );
}
@@ -795,8 +798,7 @@ static jint android_media_AudioTrack_get_min_buff_size(JNIEnv *env, jobject thi
static void
android_media_AudioTrack_setAuxEffectSendLevel(JNIEnv *env, jobject thiz, jfloat level )
{
- AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
- thiz, javaAudioTrackFields.nativeTrackInJavaObj);
+ sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
if (lpTrack == NULL ) {
jniThrowException(env, "java/lang/IllegalStateException",
"Unable to retrieve AudioTrack pointer for setAuxEffectSendLevel()");
@@ -809,17 +811,13 @@ android_media_AudioTrack_setAuxEffectSendLevel(JNIEnv *env, jobject thiz, jfloat
// ----------------------------------------------------------------------------
static jint android_media_AudioTrack_attachAuxEffect(JNIEnv *env, jobject thiz,
jint effectId) {
-
- AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
- thiz, javaAudioTrackFields.nativeTrackInJavaObj);
-
- if (lpTrack) {
- return android_media_translateErrorCode( lpTrack->attachAuxEffect(effectId) );
- } else {
+ sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
+ if (lpTrack == NULL) {
jniThrowException(env, "java/lang/IllegalStateException",
"Unable to retrieve AudioTrack pointer for attachAuxEffect()");
return AUDIOTRACK_ERROR;
}
+ return android_media_translateErrorCode( lpTrack->attachAuxEffect(effectId) );
}
// ----------------------------------------------------------------------------