Home | History | Annotate | Download | only in jni
      1 /*
      2  * Copyright (C) 2008 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 //#define LOG_NDEBUG 0
     18 
     19 #define LOG_TAG "AudioRecord-JNI"
     20 
     21 #include <inttypes.h>
     22 #include <jni.h>
     23 #include <nativehelper/JNIHelp.h>
     24 #include "core_jni_helpers.h"
     25 
     26 #include <utils/Log.h>
     27 #include <media/AudioRecord.h>
     28 #include <media/MicrophoneInfo.h>
     29 #include <vector>
     30 
     31 #include <nativehelper/ScopedUtfChars.h>
     32 
     33 #include "android_media_AudioFormat.h"
     34 #include "android_media_AudioErrors.h"
     35 #include "android_media_DeviceCallback.h"
     36 #include "android_media_MediaMetricsJNI.h"
     37 #include "android_media_MicrophoneInfo.h"
     38 
     39 // ----------------------------------------------------------------------------
     40 
     41 using namespace android;
     42 
     43 // ----------------------------------------------------------------------------
     44 static const char* const kClassPathName = "android/media/AudioRecord";
     45 static const char* const kAudioAttributesClassPathName = "android/media/AudioAttributes";
     46 
     47 static jclass gArrayListClass;
     48 static struct {
     49     jmethodID add;
     50 } gArrayListMethods;
     51 
     52 struct audio_record_fields_t {
     53     // these fields provide access from C++ to the...
     54     jmethodID postNativeEventInJava; //... event post callback method
     55     jfieldID  nativeRecorderInJavaObj; // provides access to the C++ AudioRecord object
     56     jfieldID  nativeCallbackCookie;    // provides access to the AudioRecord callback data
     57     jfieldID  nativeDeviceCallback;    // provides access to the JNIDeviceCallback instance
     58 };
     59 struct audio_attributes_fields_t {
     60     jfieldID  fieldRecSource;    // AudioAttributes.mSource
     61     jfieldID  fieldFlags;        // AudioAttributes.mFlags
     62     jfieldID  fieldFormattedTags;// AudioAttributes.mFormattedTags
     63 };
     64 static audio_attributes_fields_t javaAudioAttrFields;
     65 static audio_record_fields_t     javaAudioRecordFields;
     66 static struct {
     67     jfieldID  fieldFramePosition;     // AudioTimestamp.framePosition
     68     jfieldID  fieldNanoTime;          // AudioTimestamp.nanoTime
     69 } javaAudioTimestampFields;
     70 
     71 struct audiorecord_callback_cookie {
     72     jclass      audioRecord_class;
     73     jobject     audioRecord_ref;
     74     bool        busy;
     75     Condition   cond;
     76 };
     77 
     78 static Mutex sLock;
     79 static SortedVector <audiorecord_callback_cookie *> sAudioRecordCallBackCookies;
     80 
     81 // ----------------------------------------------------------------------------
     82 
     83 #define AUDIORECORD_ERROR_SETUP_ZEROFRAMECOUNT      (-16)
     84 #define AUDIORECORD_ERROR_SETUP_INVALIDCHANNELMASK  (-17)
     85 #define AUDIORECORD_ERROR_SETUP_INVALIDFORMAT       (-18)
     86 #define AUDIORECORD_ERROR_SETUP_INVALIDSOURCE       (-19)
     87 #define AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED    (-20)
     88 
     89 // ----------------------------------------------------------------------------
     90 static void recorderCallback(int event, void* user, void *info) {
     91 
     92     audiorecord_callback_cookie *callbackInfo = (audiorecord_callback_cookie *)user;
     93     {
     94         Mutex::Autolock l(sLock);
     95         if (sAudioRecordCallBackCookies.indexOf(callbackInfo) < 0) {
     96             return;
     97         }
     98         callbackInfo->busy = true;
     99     }
    100 
    101     switch (event) {
    102     case AudioRecord::EVENT_MARKER: {
    103         JNIEnv *env = AndroidRuntime::getJNIEnv();
    104         if (user != NULL && env != NULL) {
    105             env->CallStaticVoidMethod(
    106                 callbackInfo->audioRecord_class,
    107                 javaAudioRecordFields.postNativeEventInJava,
    108                 callbackInfo->audioRecord_ref, event, 0,0, NULL);
    109             if (env->ExceptionCheck()) {
    110                 env->ExceptionDescribe();
    111                 env->ExceptionClear();
    112             }
    113         }
    114         } break;
    115 
    116     case AudioRecord::EVENT_NEW_POS: {
    117         JNIEnv *env = AndroidRuntime::getJNIEnv();
    118         if (user != NULL && env != NULL) {
    119             env->CallStaticVoidMethod(
    120                 callbackInfo->audioRecord_class,
    121                 javaAudioRecordFields.postNativeEventInJava,
    122                 callbackInfo->audioRecord_ref, event, 0,0, NULL);
    123             if (env->ExceptionCheck()) {
    124                 env->ExceptionDescribe();
    125                 env->ExceptionClear();
    126             }
    127         }
    128         } break;
    129     }
    130 
    131     {
    132         Mutex::Autolock l(sLock);
    133         callbackInfo->busy = false;
    134         callbackInfo->cond.broadcast();
    135     }
    136 }
    137 
    138 static sp<JNIDeviceCallback> getJniDeviceCallback(JNIEnv* env, jobject thiz)
    139 {
    140     Mutex::Autolock l(sLock);
    141     JNIDeviceCallback* const cb =
    142             (JNIDeviceCallback*)env->GetLongField(thiz,
    143                                                   javaAudioRecordFields.nativeDeviceCallback);
    144     return sp<JNIDeviceCallback>(cb);
    145 }
    146 
    147 static sp<JNIDeviceCallback> setJniDeviceCallback(JNIEnv* env,
    148                                                   jobject thiz,
    149                                                   const sp<JNIDeviceCallback>& cb)
    150 {
    151     Mutex::Autolock l(sLock);
    152     sp<JNIDeviceCallback> old =
    153             (JNIDeviceCallback*)env->GetLongField(thiz,
    154                                                   javaAudioRecordFields.nativeDeviceCallback);
    155     if (cb.get()) {
    156         cb->incStrong((void*)setJniDeviceCallback);
    157     }
    158     if (old != 0) {
    159         old->decStrong((void*)setJniDeviceCallback);
    160     }
    161     env->SetLongField(thiz, javaAudioRecordFields.nativeDeviceCallback, (jlong)cb.get());
    162     return old;
    163 }
    164 
    165 // ----------------------------------------------------------------------------
    166 static sp<AudioRecord> getAudioRecord(JNIEnv* env, jobject thiz)
    167 {
    168     Mutex::Autolock l(sLock);
    169     AudioRecord* const ar =
    170             (AudioRecord*)env->GetLongField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj);
    171     return sp<AudioRecord>(ar);
    172 }
    173 
    174 static sp<AudioRecord> setAudioRecord(JNIEnv* env, jobject thiz, const sp<AudioRecord>& ar)
    175 {
    176     Mutex::Autolock l(sLock);
    177     sp<AudioRecord> old =
    178             (AudioRecord*)env->GetLongField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj);
    179     if (ar.get()) {
    180         ar->incStrong((void*)setAudioRecord);
    181     }
    182     if (old != 0) {
    183         old->decStrong((void*)setAudioRecord);
    184     }
    185     env->SetLongField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj, (jlong)ar.get());
    186     return old;
    187 }
    188 
    189 // ----------------------------------------------------------------------------
    190 static jint
    191 android_media_AudioRecord_setup(JNIEnv *env, jobject thiz, jobject weak_this,
    192         jobject jaa, jintArray jSampleRate, jint channelMask, jint channelIndexMask,
    193         jint audioFormat, jint buffSizeInBytes, jintArray jSession, jstring opPackageName,
    194         jlong nativeRecordInJavaObj)
    195 {
    196     //ALOGV(">> Entering android_media_AudioRecord_setup");
    197     //ALOGV("sampleRate=%d, audioFormat=%d, channel mask=%x, buffSizeInBytes=%d "
    198     //     "nativeRecordInJavaObj=0x%llX",
    199     //     sampleRateInHertz, audioFormat, channelMask, buffSizeInBytes, nativeRecordInJavaObj);
    200     audio_channel_mask_t localChanMask = inChannelMaskToNative(channelMask);
    201 
    202     if (jSession == NULL) {
    203         ALOGE("Error creating AudioRecord: invalid session ID pointer");
    204         return (jint) AUDIO_JAVA_ERROR;
    205     }
    206 
    207     jint* nSession = (jint *) env->GetPrimitiveArrayCritical(jSession, NULL);
    208     if (nSession == NULL) {
    209         ALOGE("Error creating AudioRecord: Error retrieving session id pointer");
    210         return (jint) AUDIO_JAVA_ERROR;
    211     }
    212     audio_session_t sessionId = (audio_session_t) nSession[0];
    213     env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
    214     nSession = NULL;
    215 
    216     audio_attributes_t *paa = NULL;
    217     sp<AudioRecord> lpRecorder = 0;
    218     audiorecord_callback_cookie *lpCallbackData = NULL;
    219 
    220     jclass clazz = env->GetObjectClass(thiz);
    221     if (clazz == NULL) {
    222         ALOGE("Can't find %s when setting up callback.", kClassPathName);
    223         return (jint) AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED;
    224     }
    225 
    226     // if we pass in an existing *Native* AudioRecord, we don't need to create/initialize one.
    227     if (nativeRecordInJavaObj == 0) {
    228         if (jaa == 0) {
    229             ALOGE("Error creating AudioRecord: invalid audio attributes");
    230             return (jint) AUDIO_JAVA_ERROR;
    231         }
    232 
    233         if (jSampleRate == 0) {
    234             ALOGE("Error creating AudioRecord: invalid sample rates");
    235             return (jint) AUDIO_JAVA_ERROR;
    236         }
    237         jint elements[1];
    238         env->GetIntArrayRegion(jSampleRate, 0, 1, elements);
    239         int sampleRateInHertz = elements[0];
    240 
    241         // channel index mask takes priority over channel position masks.
    242         if (channelIndexMask) {
    243             // Java channel index masks need the representation bits set.
    244             localChanMask = audio_channel_mask_from_representation_and_bits(
    245                     AUDIO_CHANNEL_REPRESENTATION_INDEX,
    246                     channelIndexMask);
    247         }
    248         // Java channel position masks map directly to the native definition
    249 
    250         if (!audio_is_input_channel(localChanMask)) {
    251             ALOGE("Error creating AudioRecord: channel mask %#x is not valid.", localChanMask);
    252             return (jint) AUDIORECORD_ERROR_SETUP_INVALIDCHANNELMASK;
    253         }
    254         uint32_t channelCount = audio_channel_count_from_in_mask(localChanMask);
    255 
    256         // compare the format against the Java constants
    257         audio_format_t format = audioFormatToNative(audioFormat);
    258         if (format == AUDIO_FORMAT_INVALID) {
    259             ALOGE("Error creating AudioRecord: unsupported audio format %d.", audioFormat);
    260             return (jint) AUDIORECORD_ERROR_SETUP_INVALIDFORMAT;
    261         }
    262 
    263         size_t bytesPerSample = audio_bytes_per_sample(format);
    264 
    265         if (buffSizeInBytes == 0) {
    266              ALOGE("Error creating AudioRecord: frameCount is 0.");
    267             return (jint) AUDIORECORD_ERROR_SETUP_ZEROFRAMECOUNT;
    268         }
    269         size_t frameSize = channelCount * bytesPerSample;
    270         size_t frameCount = buffSizeInBytes / frameSize;
    271 
    272         ScopedUtfChars opPackageNameStr(env, opPackageName);
    273 
    274         // create an uninitialized AudioRecord object
    275         lpRecorder = new AudioRecord(String16(opPackageNameStr.c_str()));
    276 
    277         // read the AudioAttributes values
    278         paa = (audio_attributes_t *) calloc(1, sizeof(audio_attributes_t));
    279         const jstring jtags =
    280                 (jstring) env->GetObjectField(jaa, javaAudioAttrFields.fieldFormattedTags);
    281         const char* tags = env->GetStringUTFChars(jtags, NULL);
    282         // copying array size -1, char array for tags was calloc'd, no need to NULL-terminate it
    283         strncpy(paa->tags, tags, AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1);
    284         env->ReleaseStringUTFChars(jtags, tags);
    285         paa->source = (audio_source_t) env->GetIntField(jaa, javaAudioAttrFields.fieldRecSource);
    286         paa->flags = (audio_flags_mask_t)env->GetIntField(jaa, javaAudioAttrFields.fieldFlags);
    287         ALOGV("AudioRecord_setup for source=%d tags=%s flags=%08x", paa->source, paa->tags, paa->flags);
    288 
    289         audio_input_flags_t flags = AUDIO_INPUT_FLAG_NONE;
    290         if (paa->flags & AUDIO_FLAG_HW_HOTWORD) {
    291             flags = AUDIO_INPUT_FLAG_HW_HOTWORD;
    292         }
    293         // create the callback information:
    294         // this data will be passed with every AudioRecord callback
    295         lpCallbackData = new audiorecord_callback_cookie;
    296         lpCallbackData->audioRecord_class = (jclass)env->NewGlobalRef(clazz);
    297         // we use a weak reference so the AudioRecord object can be garbage collected.
    298         lpCallbackData->audioRecord_ref = env->NewGlobalRef(weak_this);
    299         lpCallbackData->busy = false;
    300 
    301         const status_t status = lpRecorder->set(paa->source,
    302             sampleRateInHertz,
    303             format,        // word length, PCM
    304             localChanMask,
    305             frameCount,
    306             recorderCallback,// callback_t
    307             lpCallbackData,// void* user
    308             0,             // notificationFrames,
    309             true,          // threadCanCallJava
    310             sessionId,
    311             AudioRecord::TRANSFER_DEFAULT,
    312             flags,
    313             -1, -1,        // default uid, pid
    314             paa);
    315 
    316         if (status != NO_ERROR) {
    317             ALOGE("Error creating AudioRecord instance: initialization check failed with status %d.",
    318                     status);
    319             goto native_init_failure;
    320         }
    321     } else { // end if nativeRecordInJavaObj == 0)
    322         lpRecorder = (AudioRecord*)nativeRecordInJavaObj;
    323         // TODO: We need to find out which members of the Java AudioRecord might need to be
    324         // initialized from the Native AudioRecord
    325         // these are directly returned from getters:
    326         //  mSampleRate
    327         //  mRecordSource
    328         //  mAudioFormat
    329         //  mChannelMask
    330         //  mChannelCount
    331         //  mState (?)
    332         //  mRecordingState (?)
    333         //  mPreferredDevice
    334 
    335         // create the callback information:
    336         // this data will be passed with every AudioRecord callback
    337         lpCallbackData = new audiorecord_callback_cookie;
    338         lpCallbackData->audioRecord_class = (jclass)env->NewGlobalRef(clazz);
    339         // we use a weak reference so the AudioRecord object can be garbage collected.
    340         lpCallbackData->audioRecord_ref = env->NewGlobalRef(weak_this);
    341         lpCallbackData->busy = false;
    342     }
    343 
    344     nSession = (jint *) env->GetPrimitiveArrayCritical(jSession, NULL);
    345     if (nSession == NULL) {
    346         ALOGE("Error creating AudioRecord: Error retrieving session id pointer");
    347         goto native_init_failure;
    348     }
    349     // read the audio session ID back from AudioRecord in case a new session was created during set()
    350     nSession[0] = lpRecorder->getSessionId();
    351     env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
    352     nSession = NULL;
    353 
    354     {
    355         const jint elements[1] = { (jint) lpRecorder->getSampleRate() };
    356         env->SetIntArrayRegion(jSampleRate, 0, 1, elements);
    357     }
    358 
    359     {   // scope for the lock
    360         Mutex::Autolock l(sLock);
    361         sAudioRecordCallBackCookies.add(lpCallbackData);
    362     }
    363     // save our newly created C++ AudioRecord in the "nativeRecorderInJavaObj" field
    364     // of the Java object
    365     setAudioRecord(env, thiz, lpRecorder);
    366 
    367     // save our newly created callback information in the "nativeCallbackCookie" field
    368     // of the Java object (in mNativeCallbackCookie) so we can free the memory in finalize()
    369     env->SetLongField(thiz, javaAudioRecordFields.nativeCallbackCookie, (jlong)lpCallbackData);
    370 
    371     if (paa != NULL) {
    372         // audio attributes were copied in AudioRecord creation
    373         free(paa);
    374         paa = NULL;
    375     }
    376 
    377     return (jint) AUDIO_JAVA_SUCCESS;
    378 
    379     // failure:
    380 native_init_failure:
    381     if (paa != NULL) {
    382         free(paa);
    383     }
    384     env->DeleteGlobalRef(lpCallbackData->audioRecord_class);
    385     env->DeleteGlobalRef(lpCallbackData->audioRecord_ref);
    386     delete lpCallbackData;
    387     env->SetLongField(thiz, javaAudioRecordFields.nativeCallbackCookie, 0);
    388 
    389     // lpRecorder goes out of scope, so reference count drops to zero
    390     return (jint) AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED;
    391 }
    392 
    393 
    394 
    395 // ----------------------------------------------------------------------------
    396 static jint
    397 android_media_AudioRecord_start(JNIEnv *env, jobject thiz, jint event, jint triggerSession)
    398 {
    399     sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
    400     if (lpRecorder == NULL ) {
    401         jniThrowException(env, "java/lang/IllegalStateException", NULL);
    402         return (jint) AUDIO_JAVA_ERROR;
    403     }
    404 
    405     return nativeToJavaStatus(
    406             lpRecorder->start((AudioSystem::sync_event_t)event, (audio_session_t) triggerSession));
    407 }
    408 
    409 
    410 // ----------------------------------------------------------------------------
    411 static void
    412 android_media_AudioRecord_stop(JNIEnv *env, jobject thiz)
    413 {
    414     sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
    415     if (lpRecorder == NULL ) {
    416         jniThrowException(env, "java/lang/IllegalStateException", NULL);
    417         return;
    418     }
    419 
    420     lpRecorder->stop();
    421     //ALOGV("Called lpRecorder->stop()");
    422 }
    423 
    424 
    425 // ----------------------------------------------------------------------------
    426 
    427 #define CALLBACK_COND_WAIT_TIMEOUT_MS 1000
    428 static void android_media_AudioRecord_release(JNIEnv *env,  jobject thiz) {
    429     sp<AudioRecord> lpRecorder = setAudioRecord(env, thiz, 0);
    430     if (lpRecorder == NULL) {
    431         return;
    432     }
    433     ALOGV("About to delete lpRecorder: %p", lpRecorder.get());
    434     lpRecorder->stop();
    435 
    436     audiorecord_callback_cookie *lpCookie = (audiorecord_callback_cookie *)env->GetLongField(
    437         thiz, javaAudioRecordFields.nativeCallbackCookie);
    438 
    439     // reset the native resources in the Java object so any attempt to access
    440     // them after a call to release fails.
    441     env->SetLongField(thiz, javaAudioRecordFields.nativeCallbackCookie, 0);
    442 
    443     // delete the callback information
    444     if (lpCookie) {
    445         Mutex::Autolock l(sLock);
    446         ALOGV("deleting lpCookie: %p", lpCookie);
    447         while (lpCookie->busy) {
    448             if (lpCookie->cond.waitRelative(sLock,
    449                                             milliseconds(CALLBACK_COND_WAIT_TIMEOUT_MS)) !=
    450                                                     NO_ERROR) {
    451                 break;
    452             }
    453         }
    454         sAudioRecordCallBackCookies.remove(lpCookie);
    455         env->DeleteGlobalRef(lpCookie->audioRecord_class);
    456         env->DeleteGlobalRef(lpCookie->audioRecord_ref);
    457         delete lpCookie;
    458     }
    459 }
    460 
    461 
    462 // ----------------------------------------------------------------------------
    463 static void android_media_AudioRecord_finalize(JNIEnv *env,  jobject thiz) {
    464     android_media_AudioRecord_release(env, thiz);
    465 }
    466 
    467 // overloaded JNI array helper functions
    468 static inline
    469 jbyte *envGetArrayElements(JNIEnv *env, jbyteArray array, jboolean *isCopy) {
    470     return env->GetByteArrayElements(array, isCopy);
    471 }
    472 
    473 static inline
    474 void envReleaseArrayElements(JNIEnv *env, jbyteArray array, jbyte *elems, jint mode) {
    475     env->ReleaseByteArrayElements(array, elems, mode);
    476 }
    477 
    478 static inline
    479 jshort *envGetArrayElements(JNIEnv *env, jshortArray array, jboolean *isCopy) {
    480     return env->GetShortArrayElements(array, isCopy);
    481 }
    482 
    483 static inline
    484 void envReleaseArrayElements(JNIEnv *env, jshortArray array, jshort *elems, jint mode) {
    485     env->ReleaseShortArrayElements(array, elems, mode);
    486 }
    487 
    488 static inline
    489 jfloat *envGetArrayElements(JNIEnv *env, jfloatArray array, jboolean *isCopy) {
    490     return env->GetFloatArrayElements(array, isCopy);
    491 }
    492 
    493 static inline
    494 void envReleaseArrayElements(JNIEnv *env, jfloatArray array, jfloat *elems, jint mode) {
    495     env->ReleaseFloatArrayElements(array, elems, mode);
    496 }
    497 
    498 static inline
    499 jint interpretReadSizeError(ssize_t readSize) {
    500     if (readSize == WOULD_BLOCK) {
    501         return (jint)0;
    502     } else if (readSize == NO_INIT) {
    503         return AUDIO_JAVA_DEAD_OBJECT;
    504     } else {
    505         ALOGE("Error %zd during AudioRecord native read", readSize);
    506         return nativeToJavaStatus(readSize);
    507     }
    508 }
    509 
    510 template <typename T>
    511 static jint android_media_AudioRecord_readInArray(JNIEnv *env,  jobject thiz,
    512                                                   T javaAudioData,
    513                                                   jint offsetInSamples, jint sizeInSamples,
    514                                                   jboolean isReadBlocking) {
    515     // get the audio recorder from which we'll read new audio samples
    516     sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
    517     if (lpRecorder == NULL) {
    518         ALOGE("Unable to retrieve AudioRecord object");
    519         return (jint)AUDIO_JAVA_INVALID_OPERATION;
    520     }
    521 
    522     if (javaAudioData == NULL) {
    523         ALOGE("Invalid Java array to store recorded audio");
    524         return (jint)AUDIO_JAVA_BAD_VALUE;
    525     }
    526 
    527     // NOTE: We may use GetPrimitiveArrayCritical() when the JNI implementation changes in such
    528     // a way that it becomes much more efficient. When doing so, we will have to prevent the
    529     // AudioSystem callback to be called while in critical section (in case of media server
    530     // process crash for instance)
    531 
    532     // get the pointer to where we'll record the audio
    533     auto *recordBuff = envGetArrayElements(env, javaAudioData, NULL);
    534     if (recordBuff == NULL) {
    535         ALOGE("Error retrieving destination for recorded audio data");
    536         return (jint)AUDIO_JAVA_BAD_VALUE;
    537     }
    538 
    539     // read the new audio data from the native AudioRecord object
    540     const size_t sizeInBytes = sizeInSamples * sizeof(*recordBuff);
    541     ssize_t readSize = lpRecorder->read(
    542             recordBuff + offsetInSamples, sizeInBytes, isReadBlocking == JNI_TRUE /* blocking */);
    543 
    544     envReleaseArrayElements(env, javaAudioData, recordBuff, 0);
    545 
    546     if (readSize < 0) {
    547         return interpretReadSizeError(readSize);
    548     }
    549     return (jint)(readSize / sizeof(*recordBuff));
    550 }
    551 
    552 // ----------------------------------------------------------------------------
    553 static jint android_media_AudioRecord_readInDirectBuffer(JNIEnv *env,  jobject thiz,
    554                                                          jobject jBuffer, jint sizeInBytes,
    555                                                          jboolean isReadBlocking) {
    556     // get the audio recorder from which we'll read new audio samples
    557     sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
    558     if (lpRecorder==NULL)
    559         return (jint)AUDIO_JAVA_INVALID_OPERATION;
    560 
    561     // direct buffer and direct access supported?
    562     long capacity = env->GetDirectBufferCapacity(jBuffer);
    563     if (capacity == -1) {
    564         // buffer direct access is not supported
    565         ALOGE("Buffer direct access is not supported, can't record");
    566         return (jint)AUDIO_JAVA_BAD_VALUE;
    567     }
    568     //ALOGV("capacity = %ld", capacity);
    569     jbyte* nativeFromJavaBuf = (jbyte*) env->GetDirectBufferAddress(jBuffer);
    570     if (nativeFromJavaBuf==NULL) {
    571         ALOGE("Buffer direct access is not supported, can't record");
    572         return (jint)AUDIO_JAVA_BAD_VALUE;
    573     }
    574 
    575     // read new data from the recorder
    576     ssize_t readSize = lpRecorder->read(nativeFromJavaBuf,
    577                                         capacity < sizeInBytes ? capacity : sizeInBytes,
    578                                         isReadBlocking == JNI_TRUE /* blocking */);
    579     if (readSize < 0) {
    580         return interpretReadSizeError(readSize);
    581     }
    582     return (jint)readSize;
    583 }
    584 
    585 // ----------------------------------------------------------------------------
    586 static jint android_media_AudioRecord_get_buffer_size_in_frames(JNIEnv *env,  jobject thiz) {
    587     sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
    588     if (lpRecorder == NULL) {
    589         jniThrowException(env, "java/lang/IllegalStateException",
    590             "Unable to retrieve AudioRecord pointer for frameCount()");
    591         return (jint)AUDIO_JAVA_ERROR;
    592     }
    593     return lpRecorder->frameCount();
    594 }
    595 
    596 // ----------------------------------------------------------------------------
    597 static jint android_media_AudioRecord_set_marker_pos(JNIEnv *env,  jobject thiz,
    598         jint markerPos) {
    599 
    600     sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
    601     if (lpRecorder == NULL) {
    602         jniThrowException(env, "java/lang/IllegalStateException",
    603             "Unable to retrieve AudioRecord pointer for setMarkerPosition()");
    604         return (jint)AUDIO_JAVA_ERROR;
    605     }
    606     return nativeToJavaStatus( lpRecorder->setMarkerPosition(markerPos) );
    607 }
    608 
    609 
    610 // ----------------------------------------------------------------------------
    611 static jint android_media_AudioRecord_get_marker_pos(JNIEnv *env,  jobject thiz) {
    612 
    613     sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
    614     uint32_t markerPos = 0;
    615 
    616     if (lpRecorder == NULL) {
    617         jniThrowException(env, "java/lang/IllegalStateException",
    618             "Unable to retrieve AudioRecord pointer for getMarkerPosition()");
    619         return (jint)AUDIO_JAVA_ERROR;
    620     }
    621     lpRecorder->getMarkerPosition(&markerPos);
    622     return (jint)markerPos;
    623 }
    624 
    625 
    626 // ----------------------------------------------------------------------------
    627 static jint android_media_AudioRecord_set_pos_update_period(JNIEnv *env,  jobject thiz,
    628         jint period) {
    629 
    630     sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
    631 
    632     if (lpRecorder == NULL) {
    633         jniThrowException(env, "java/lang/IllegalStateException",
    634             "Unable to retrieve AudioRecord pointer for setPositionUpdatePeriod()");
    635         return (jint)AUDIO_JAVA_ERROR;
    636     }
    637     return nativeToJavaStatus( lpRecorder->setPositionUpdatePeriod(period) );
    638 }
    639 
    640 
    641 // ----------------------------------------------------------------------------
    642 static jint android_media_AudioRecord_get_pos_update_period(JNIEnv *env,  jobject thiz) {
    643 
    644     sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
    645     uint32_t period = 0;
    646 
    647     if (lpRecorder == NULL) {
    648         jniThrowException(env, "java/lang/IllegalStateException",
    649             "Unable to retrieve AudioRecord pointer for getPositionUpdatePeriod()");
    650         return (jint)AUDIO_JAVA_ERROR;
    651     }
    652     lpRecorder->getPositionUpdatePeriod(&period);
    653     return (jint)period;
    654 }
    655 
    656 
    657 // ----------------------------------------------------------------------------
    658 // returns the minimum required size for the successful creation of an AudioRecord instance.
    659 // returns 0 if the parameter combination is not supported.
    660 // return -1 if there was an error querying the buffer size.
    661 static jint android_media_AudioRecord_get_min_buff_size(JNIEnv *env,  jobject thiz,
    662     jint sampleRateInHertz, jint channelCount, jint audioFormat) {
    663 
    664     ALOGV(">> android_media_AudioRecord_get_min_buff_size(%d, %d, %d)",
    665           sampleRateInHertz, channelCount, audioFormat);
    666 
    667     size_t frameCount = 0;
    668     audio_format_t format = audioFormatToNative(audioFormat);
    669     status_t result = AudioRecord::getMinFrameCount(&frameCount,
    670             sampleRateInHertz,
    671             format,
    672             audio_channel_in_mask_from_count(channelCount));
    673 
    674     if (result == BAD_VALUE) {
    675         return 0;
    676     }
    677     if (result != NO_ERROR) {
    678         return -1;
    679     }
    680     return frameCount * channelCount * audio_bytes_per_sample(format);
    681 }
    682 
    683 static jboolean android_media_AudioRecord_setInputDevice(
    684         JNIEnv *env,  jobject thiz, jint device_id) {
    685 
    686     sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
    687     if (lpRecorder == 0) {
    688         return false;
    689     }
    690     return lpRecorder->setInputDevice(device_id) == NO_ERROR;
    691 }
    692 
    693 static jint android_media_AudioRecord_getRoutedDeviceId(
    694                 JNIEnv *env,  jobject thiz) {
    695 
    696     sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
    697     if (lpRecorder == 0) {
    698         return 0;
    699     }
    700     return (jint)lpRecorder->getRoutedDeviceId();
    701 }
    702 
    703 static void android_media_AudioRecord_enableDeviceCallback(
    704                 JNIEnv *env,  jobject thiz) {
    705 
    706     sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
    707     if (lpRecorder == 0) {
    708         return;
    709     }
    710     sp<JNIDeviceCallback> cb = getJniDeviceCallback(env, thiz);
    711     if (cb != 0) {
    712         return;
    713     }
    714     audiorecord_callback_cookie *cookie =
    715             (audiorecord_callback_cookie *)env->GetLongField(thiz,
    716                                                      javaAudioRecordFields.nativeCallbackCookie);
    717     if (cookie == NULL) {
    718         return;
    719     }
    720 
    721     cb = new JNIDeviceCallback(env, thiz, cookie->audioRecord_ref,
    722                                javaAudioRecordFields.postNativeEventInJava);
    723     status_t status = lpRecorder->addAudioDeviceCallback(cb);
    724     if (status == NO_ERROR) {
    725         setJniDeviceCallback(env, thiz, cb);
    726     }
    727 }
    728 
    729 static void android_media_AudioRecord_disableDeviceCallback(
    730                 JNIEnv *env,  jobject thiz) {
    731 
    732     sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
    733     if (lpRecorder == 0) {
    734         return;
    735     }
    736     sp<JNIDeviceCallback> cb = setJniDeviceCallback(env, thiz, 0);
    737     if (cb != 0) {
    738         lpRecorder->removeAudioDeviceCallback(cb);
    739     }
    740 }
    741 
    742 // ----------------------------------------------------------------------------
    743 static jint android_media_AudioRecord_get_timestamp(JNIEnv *env, jobject thiz,
    744         jobject timestamp, jint timebase) {
    745     sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
    746 
    747     if (lpRecorder == NULL) {
    748         jniThrowException(env, "java/lang/IllegalStateException",
    749             "Unable to retrieve AudioRecord pointer for getTimestamp()");
    750         return (jint)AUDIO_JAVA_ERROR;
    751     }
    752 
    753     ExtendedTimestamp ts;
    754     jint status = nativeToJavaStatus(lpRecorder->getTimestamp(&ts));
    755 
    756     if (status == AUDIO_JAVA_SUCCESS) {
    757         // set the data
    758         int64_t position, time;
    759 
    760         status = nativeToJavaStatus(ts.getBestTimestamp(&position, &time, timebase));
    761         if (status == AUDIO_JAVA_SUCCESS) {
    762             env->SetLongField(
    763                     timestamp, javaAudioTimestampFields.fieldFramePosition, position);
    764             env->SetLongField(
    765                     timestamp, javaAudioTimestampFields.fieldNanoTime, time);
    766         }
    767     }
    768     return status;
    769 }
    770 
    771 // ----------------------------------------------------------------------------
    772 static jobject
    773 android_media_AudioRecord_native_getMetrics(JNIEnv *env, jobject thiz)
    774 {
    775     ALOGV("android_media_AudioRecord_native_getMetrics");
    776 
    777     sp<AudioRecord> lpRecord = getAudioRecord(env, thiz);
    778 
    779     if (lpRecord == NULL) {
    780         ALOGE("Unable to retrieve AudioRecord pointer for getMetrics()");
    781         jniThrowException(env, "java/lang/IllegalStateException", NULL);
    782         return (jobject) NULL;
    783     }
    784 
    785     // get what we have for the metrics from the record session
    786     MediaAnalyticsItem *item = NULL;
    787 
    788     status_t err = lpRecord->getMetrics(item);
    789     if (err != OK) {
    790         ALOGE("getMetrics failed");
    791         jniThrowException(env, "java/lang/IllegalStateException", NULL);
    792         return (jobject) NULL;
    793     }
    794 
    795     jobject mybundle = MediaMetricsJNI::writeMetricsToBundle(env, item, NULL /* mybundle */);
    796 
    797     // housekeeping
    798     delete item;
    799     item = NULL;
    800 
    801     return mybundle;
    802 }
    803 
    804 // ----------------------------------------------------------------------------
    805 static jint android_media_AudioRecord_get_active_microphones(JNIEnv *env,
    806         jobject thiz, jobject jActiveMicrophones) {
    807     if (jActiveMicrophones == NULL) {
    808         ALOGE("jActiveMicrophones is null");
    809         return (jint)AUDIO_JAVA_BAD_VALUE;
    810     }
    811     if (!env->IsInstanceOf(jActiveMicrophones, gArrayListClass)) {
    812         ALOGE("getActiveMicrophones not an arraylist");
    813         return (jint)AUDIO_JAVA_BAD_VALUE;
    814     }
    815 
    816     sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
    817     if (lpRecorder == NULL) {
    818         jniThrowException(env, "java/lang/IllegalStateException",
    819             "Unable to retrieve AudioRecord pointer for getActiveMicrophones()");
    820         return (jint)AUDIO_JAVA_ERROR;
    821     }
    822 
    823     jint jStatus = AUDIO_JAVA_SUCCESS;
    824     std::vector<media::MicrophoneInfo> activeMicrophones;
    825     status_t status = lpRecorder->getActiveMicrophones(&activeMicrophones);
    826     if (status != NO_ERROR) {
    827         ALOGE_IF(status != NO_ERROR, "AudioRecord::getActiveMicrophones error %d", status);
    828         jStatus = nativeToJavaStatus(status);
    829         return jStatus;
    830     }
    831 
    832     for (size_t i = 0; i < activeMicrophones.size(); i++) {
    833         jobject jMicrophoneInfo;
    834         jStatus = convertMicrophoneInfoFromNative(env, &jMicrophoneInfo, &activeMicrophones[i]);
    835         if (jStatus != AUDIO_JAVA_SUCCESS) {
    836             return jStatus;
    837         }
    838         env->CallBooleanMethod(jActiveMicrophones, gArrayListMethods.add, jMicrophoneInfo);
    839         env->DeleteLocalRef(jMicrophoneInfo);
    840     }
    841     return jStatus;
    842 }
    843 
    844 // ----------------------------------------------------------------------------
    845 // ----------------------------------------------------------------------------
    846 static const JNINativeMethod gMethods[] = {
    847     // name,               signature,  funcPtr
    848     {"native_start",         "(II)I",    (void *)android_media_AudioRecord_start},
    849     {"native_stop",          "()V",    (void *)android_media_AudioRecord_stop},
    850     {"native_setup",         "(Ljava/lang/Object;Ljava/lang/Object;[IIIII[ILjava/lang/String;J)I",
    851                                       (void *)android_media_AudioRecord_setup},
    852     {"native_finalize",      "()V",    (void *)android_media_AudioRecord_finalize},
    853     {"native_release",       "()V",    (void *)android_media_AudioRecord_release},
    854     {"native_read_in_byte_array",
    855                              "([BIIZ)I",
    856                                      (void *)android_media_AudioRecord_readInArray<jbyteArray>},
    857     {"native_read_in_short_array",
    858                              "([SIIZ)I",
    859                                      (void *)android_media_AudioRecord_readInArray<jshortArray>},
    860     {"native_read_in_float_array",
    861                              "([FIIZ)I",
    862                                      (void *)android_media_AudioRecord_readInArray<jfloatArray>},
    863     {"native_read_in_direct_buffer","(Ljava/lang/Object;IZ)I",
    864                                        (void *)android_media_AudioRecord_readInDirectBuffer},
    865     {"native_get_buffer_size_in_frames",
    866                              "()I", (void *)android_media_AudioRecord_get_buffer_size_in_frames},
    867     {"native_set_marker_pos","(I)I",   (void *)android_media_AudioRecord_set_marker_pos},
    868     {"native_get_marker_pos","()I",    (void *)android_media_AudioRecord_get_marker_pos},
    869     {"native_set_pos_update_period",
    870                              "(I)I",   (void *)android_media_AudioRecord_set_pos_update_period},
    871     {"native_get_pos_update_period",
    872                              "()I",    (void *)android_media_AudioRecord_get_pos_update_period},
    873     {"native_get_min_buff_size",
    874                              "(III)I",   (void *)android_media_AudioRecord_get_min_buff_size},
    875     {"native_getMetrics",    "()Landroid/os/PersistableBundle;",
    876                                          (void *)android_media_AudioRecord_native_getMetrics},
    877     {"native_setInputDevice", "(I)Z", (void *)android_media_AudioRecord_setInputDevice},
    878     {"native_getRoutedDeviceId", "()I", (void *)android_media_AudioRecord_getRoutedDeviceId},
    879     {"native_enableDeviceCallback", "()V", (void *)android_media_AudioRecord_enableDeviceCallback},
    880     {"native_disableDeviceCallback", "()V",
    881                                         (void *)android_media_AudioRecord_disableDeviceCallback},
    882     {"native_get_timestamp", "(Landroid/media/AudioTimestamp;I)I",
    883                                        (void *)android_media_AudioRecord_get_timestamp},
    884     {"native_get_active_microphones", "(Ljava/util/ArrayList;)I",
    885                                         (void *)android_media_AudioRecord_get_active_microphones},
    886 };
    887 
    888 // field names found in android/media/AudioRecord.java
    889 #define JAVA_POSTEVENT_CALLBACK_NAME  "postEventFromNative"
    890 #define JAVA_NATIVERECORDERINJAVAOBJ_FIELD_NAME  "mNativeRecorderInJavaObj"
    891 #define JAVA_NATIVECALLBACKINFO_FIELD_NAME       "mNativeCallbackCookie"
    892 #define JAVA_NATIVEDEVICECALLBACK_FIELD_NAME       "mNativeDeviceCallback"
    893 
    894 // ----------------------------------------------------------------------------
    895 int register_android_media_AudioRecord(JNIEnv *env)
    896 {
    897     javaAudioRecordFields.postNativeEventInJava = NULL;
    898     javaAudioRecordFields.nativeRecorderInJavaObj = NULL;
    899     javaAudioRecordFields.nativeCallbackCookie = NULL;
    900     javaAudioRecordFields.nativeDeviceCallback = NULL;
    901 
    902 
    903     // Get the AudioRecord class
    904     jclass audioRecordClass = FindClassOrDie(env, kClassPathName);
    905     // Get the postEvent method
    906     javaAudioRecordFields.postNativeEventInJava = GetStaticMethodIDOrDie(env,
    907             audioRecordClass, JAVA_POSTEVENT_CALLBACK_NAME,
    908             "(Ljava/lang/Object;IIILjava/lang/Object;)V");
    909 
    910     // Get the variables
    911     //    mNativeRecorderInJavaObj
    912     javaAudioRecordFields.nativeRecorderInJavaObj = GetFieldIDOrDie(env,
    913             audioRecordClass, JAVA_NATIVERECORDERINJAVAOBJ_FIELD_NAME, "J");
    914     //     mNativeCallbackCookie
    915     javaAudioRecordFields.nativeCallbackCookie = GetFieldIDOrDie(env,
    916             audioRecordClass, JAVA_NATIVECALLBACKINFO_FIELD_NAME, "J");
    917 
    918     javaAudioRecordFields.nativeDeviceCallback = GetFieldIDOrDie(env,
    919             audioRecordClass, JAVA_NATIVEDEVICECALLBACK_FIELD_NAME, "J");
    920 
    921     // Get the AudioAttributes class and fields
    922     jclass audioAttrClass = FindClassOrDie(env, kAudioAttributesClassPathName);
    923     javaAudioAttrFields.fieldRecSource = GetFieldIDOrDie(env, audioAttrClass, "mSource", "I");
    924     javaAudioAttrFields.fieldFlags = GetFieldIDOrDie(env, audioAttrClass, "mFlags", "I");
    925     javaAudioAttrFields.fieldFormattedTags = GetFieldIDOrDie(env,
    926             audioAttrClass, "mFormattedTags", "Ljava/lang/String;");
    927 
    928     // Get the RecordTimestamp class and fields
    929     jclass audioTimestampClass = FindClassOrDie(env, "android/media/AudioTimestamp");
    930     javaAudioTimestampFields.fieldFramePosition =
    931             GetFieldIDOrDie(env, audioTimestampClass, "framePosition", "J");
    932     javaAudioTimestampFields.fieldNanoTime =
    933             GetFieldIDOrDie(env, audioTimestampClass, "nanoTime", "J");
    934 
    935     jclass arrayListClass = FindClassOrDie(env, "java/util/ArrayList");
    936     gArrayListClass = MakeGlobalRefOrDie(env, arrayListClass);
    937     gArrayListMethods.add = GetMethodIDOrDie(env, arrayListClass, "add", "(Ljava/lang/Object;)Z");
    938 
    939     return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
    940 }
    941 
    942 // ----------------------------------------------------------------------------
    943