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