Merge "fix AudioTrack and AudioRecord JNI"
diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp
index ab70f25..3f7df50 100644
--- a/core/jni/android_media_AudioRecord.cpp
+++ b/core/jni/android_media_AudioRecord.cpp
@@ -399,13 +399,46 @@
                                                         jshortArray javaAudioData,
                                                         jint offsetInShorts, jint sizeInShorts) {
 
-    jint read = android_media_AudioRecord_readInByteArray(env, thiz,
-                                                        (jbyteArray) javaAudioData,
-                                                        offsetInShorts*2, sizeInShorts*2);
-    if (read > 0) {
-        read /= 2;
+    jshort* recordBuff = NULL;
+    // get the audio recorder from which we'll read new audio samples
+    sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
+    if (lpRecorder == NULL) {
+        ALOGE("Unable to retrieve AudioRecord object, can't record");
+        return 0;
     }
-    return read;
+
+    if (!javaAudioData) {
+        ALOGE("Invalid Java array to store recorded audio, can't record");
+        return 0;
+    }
+
+    // get the pointer to where we'll record the audio
+    // NOTE: We may use GetPrimitiveArrayCritical() when the JNI implementation changes in such
+    // 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)
+    recordBuff = (jshort *)env->GetShortArrayElements(javaAudioData, NULL);
+
+    if (recordBuff == NULL) {
+        ALOGE("Error retrieving destination for recorded audio data, can't record");
+        return 0;
+    }
+
+    // read the new audio data from the native AudioRecord object
+    const size_t recorderBuffSize = lpRecorder->frameCount()*lpRecorder->frameSize();
+    const size_t sizeInBytes = sizeInShorts * sizeof(short);
+    ssize_t readSize = lpRecorder->read(recordBuff + offsetInShorts * sizeof(short),
+                                        sizeInBytes > recorderBuffSize ?
+                                            recorderBuffSize : sizeInBytes);
+
+    env->ReleaseShortArrayElements(javaAudioData, recordBuff, 0);
+
+    if (readSize < 0) {
+        readSize = AUDIORECORD_ERROR_INVALID_OPERATION;
+    } else {
+        readSize /= sizeof(short);
+    }
+    return (jint) readSize;
 }
 
 // ----------------------------------------------------------------------------
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index dc8d9d8..1bf42e9 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -595,13 +595,39 @@
                                                   jshortArray javaAudioData,
                                                   jint offsetInShorts, jint sizeInShorts,
                                                   jint javaAudioFormat) {
-    jint written = android_media_AudioTrack_native_write_byte(env, thiz,
-                                                 (jbyteArray) javaAudioData,
-                                                 offsetInShorts*2, sizeInShorts*2,
-                                                 javaAudioFormat);
-    if (written > 0) {
-        written /= 2;
+    sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
+    if (lpTrack == NULL) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+            "Unable to retrieve AudioTrack pointer for write()");
+        return 0;
     }
+
+    // get the pointer for the audio data from the java array
+    // NOTE: We may use GetPrimitiveArrayCritical() when the JNI implementation changes in such
+    // 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)
+    jshort* cAudioData = NULL;
+    if (javaAudioData) {
+        cAudioData = (jshort *)env->GetShortArrayElements(javaAudioData, NULL);
+        if (cAudioData == NULL) {
+            ALOGE("Error retrieving source of audio data to play, can't play");
+            return 0; // out of memory or no data to load
+        }
+    } else {
+        ALOGE("NULL java array of audio data to play, can't play");
+        return 0;
+    }
+    jint written = writeToTrack(lpTrack, javaAudioFormat, (jbyte *)cAudioData,
+                                offsetInShorts * sizeof(short), sizeInShorts * sizeof(short));
+    env->ReleaseShortArrayElements(javaAudioData, cAudioData, 0);
+
+    if (written > 0) {
+        written /= sizeof(short);
+    }
+    //ALOGV("write wrote %d (tried %d) shorts in the native AudioTrack with offset %d",
+    //     (int)written, (int)(sizeInShorts), (int)offsetInShorts);
+
     return written;
 }