[go: nahoru, domu]

19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project//#define LOG_NDEBUG 0
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#define LOG_TAG "AudioRecord-JNI"
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2195ece35c2f8b86203e88b49d67cef8e80e107a2bKévin PETIT#include <inttypes.h>
22c81d31c3f801ba3d559a22c27b926ace38a7ab49Glenn Kasten#include <jni.h>
23c81d31c3f801ba3d559a22c27b926ace38a7ab49Glenn Kasten#include <JNIHelp.h>
24ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe#include "core_jni_helpers.h"
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
26c81d31c3f801ba3d559a22c27b926ace38a7ab49Glenn Kasten#include <utils/Log.h>
27c81d31c3f801ba3d559a22c27b926ace38a7ab49Glenn Kasten#include <media/AudioRecord.h>
2824fc2fb1c541e954b83fd31ea9f786a5e9b45501Dima Zavin
29fa5ecdc4ac6d7a8db2bb9e4a6a60a3189025df30Svet Ganov#include <ScopedUtfChars.h>
30fa5ecdc4ac6d7a8db2bb9e4a6a60a3189025df30Svet Ganov
31fe834d30f4f3f51b754d55fecb36f11279733948Glenn Kasten#include "android_media_AudioFormat.h"
32bc11a696f6856624de532a6830d5db9dbbe2384cEric Laurent#include "android_media_AudioErrors.h"
334bcdba848449b33d7022de527c526943aff1f5fdEric Laurent#include "android_media_DeviceCallback.h"
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// ----------------------------------------------------------------------------
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectusing namespace android;
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// ----------------------------------------------------------------------------
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic const char* const kClassPathName = "android/media/AudioRecord";
41701d6ff12f36bf5e9de0dafdaced06744fd411ebJean-Michel Trivistatic const char* const kAudioAttributesClassPathName = "android/media/AudioAttributes";
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
43701d6ff12f36bf5e9de0dafdaced06744fd411ebJean-Michel Trivistruct audio_record_fields_t {
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // these fields provide access from C++ to the...
459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    jmethodID postNativeEventInJava; //... event post callback method
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    jfieldID  nativeRecorderInJavaObj; // provides access to the C++ AudioRecord object
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    jfieldID  nativeCallbackCookie;    // provides access to the AudioRecord callback data
484bcdba848449b33d7022de527c526943aff1f5fdEric Laurent    jfieldID  nativeDeviceCallback;    // provides access to the JNIDeviceCallback instance
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project};
50701d6ff12f36bf5e9de0dafdaced06744fd411ebJean-Michel Trivistruct audio_attributes_fields_t {
51701d6ff12f36bf5e9de0dafdaced06744fd411ebJean-Michel Trivi    jfieldID  fieldRecSource;    // AudioAttributes.mSource
52bdad1afa92a6e7cd688061d5432f25a3dd15b64eEric Laurent    jfieldID  fieldFlags;        // AudioAttributes.mFlags
53701d6ff12f36bf5e9de0dafdaced06744fd411ebJean-Michel Trivi    jfieldID  fieldFormattedTags;// AudioAttributes.mFormattedTags
54701d6ff12f36bf5e9de0dafdaced06744fd411ebJean-Michel Trivi};
55701d6ff12f36bf5e9de0dafdaced06744fd411ebJean-Michel Trivistatic audio_attributes_fields_t javaAudioAttrFields;
56701d6ff12f36bf5e9de0dafdaced06744fd411ebJean-Michel Trivistatic audio_record_fields_t     javaAudioRecordFields;
570ad99c059735d6d4a9f9fb5379c8b1b35ce01f38Andy Hungstatic struct {
580ad99c059735d6d4a9f9fb5379c8b1b35ce01f38Andy Hung    jfieldID  fieldFramePosition;     // AudioTimestamp.framePosition
590ad99c059735d6d4a9f9fb5379c8b1b35ce01f38Andy Hung    jfieldID  fieldNanoTime;          // AudioTimestamp.nanoTime
600ad99c059735d6d4a9f9fb5379c8b1b35ce01f38Andy Hung} javaAudioTimestampFields;
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstruct audiorecord_callback_cookie {
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    jclass      audioRecord_class;
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    jobject     audioRecord_ref;
65532bc1cb7da9fdbf34893fa48b2ae11f54cf6a8eEric Laurent    bool        busy;
66532bc1cb7da9fdbf34893fa48b2ae11f54cf6a8eEric Laurent    Condition   cond;
67532bc1cb7da9fdbf34893fa48b2ae11f54cf6a8eEric Laurent};
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
69532bc1cb7da9fdbf34893fa48b2ae11f54cf6a8eEric Laurentstatic Mutex sLock;
70532bc1cb7da9fdbf34893fa48b2ae11f54cf6a8eEric Laurentstatic SortedVector <audiorecord_callback_cookie *> sAudioRecordCallBackCookies;
71e6335c904aafa17795b059a5d83b8b7db6c761c8Dave Sparks
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// ----------------------------------------------------------------------------
739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#define AUDIORECORD_ERROR_SETUP_ZEROFRAMECOUNT      -16
75a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent#define AUDIORECORD_ERROR_SETUP_INVALIDCHANNELMASK -17
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#define AUDIORECORD_ERROR_SETUP_INVALIDFORMAT       -18
774bc035a65cac177be9294e69f110497e3b6e34e6Eric Laurent#define AUDIORECORD_ERROR_SETUP_INVALIDSOURCE       -19
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#define AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED    -20
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// ----------------------------------------------------------------------------
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic void recorderCallback(int event, void* user, void *info) {
82532bc1cb7da9fdbf34893fa48b2ae11f54cf6a8eEric Laurent
83532bc1cb7da9fdbf34893fa48b2ae11f54cf6a8eEric Laurent    audiorecord_callback_cookie *callbackInfo = (audiorecord_callback_cookie *)user;
84532bc1cb7da9fdbf34893fa48b2ae11f54cf6a8eEric Laurent    {
85532bc1cb7da9fdbf34893fa48b2ae11f54cf6a8eEric Laurent        Mutex::Autolock l(sLock);
86532bc1cb7da9fdbf34893fa48b2ae11f54cf6a8eEric Laurent        if (sAudioRecordCallBackCookies.indexOf(callbackInfo) < 0) {
87532bc1cb7da9fdbf34893fa48b2ae11f54cf6a8eEric Laurent            return;
88532bc1cb7da9fdbf34893fa48b2ae11f54cf6a8eEric Laurent        }
89532bc1cb7da9fdbf34893fa48b2ae11f54cf6a8eEric Laurent        callbackInfo->busy = true;
90532bc1cb7da9fdbf34893fa48b2ae11f54cf6a8eEric Laurent    }
9118db49a46259020387c40fff36d92edc1087a366Glenn Kasten
925b1576ccbd9ab43d5e3238589cf5b43a4834447dGlenn Kasten    switch (event) {
935b1576ccbd9ab43d5e3238589cf5b43a4834447dGlenn Kasten    case AudioRecord::EVENT_MARKER: {
949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        JNIEnv *env = AndroidRuntime::getJNIEnv();
95a667ff30e4fb6f741c2a930e7c31ef7e962d3b40Glenn Kasten        if (user != NULL && env != NULL) {
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            env->CallStaticVoidMethod(
9718db49a46259020387c40fff36d92edc1087a366Glenn Kasten                callbackInfo->audioRecord_class,
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                javaAudioRecordFields.postNativeEventInJava,
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                callbackInfo->audioRecord_ref, event, 0,0, NULL);
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (env->ExceptionCheck()) {
1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                env->ExceptionDescribe();
1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                env->ExceptionClear();
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1055b1576ccbd9ab43d5e3238589cf5b43a4834447dGlenn Kasten        } break;
1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1075b1576ccbd9ab43d5e3238589cf5b43a4834447dGlenn Kasten    case AudioRecord::EVENT_NEW_POS: {
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        JNIEnv *env = AndroidRuntime::getJNIEnv();
109a667ff30e4fb6f741c2a930e7c31ef7e962d3b40Glenn Kasten        if (user != NULL && env != NULL) {
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            env->CallStaticVoidMethod(
11118db49a46259020387c40fff36d92edc1087a366Glenn Kasten                callbackInfo->audioRecord_class,
1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                javaAudioRecordFields.postNativeEventInJava,
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                callbackInfo->audioRecord_ref, event, 0,0, NULL);
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (env->ExceptionCheck()) {
1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                env->ExceptionDescribe();
1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                env->ExceptionClear();
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1195b1576ccbd9ab43d5e3238589cf5b43a4834447dGlenn Kasten        } break;
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1215b1576ccbd9ab43d5e3238589cf5b43a4834447dGlenn Kasten
122532bc1cb7da9fdbf34893fa48b2ae11f54cf6a8eEric Laurent    {
123532bc1cb7da9fdbf34893fa48b2ae11f54cf6a8eEric Laurent        Mutex::Autolock l(sLock);
124532bc1cb7da9fdbf34893fa48b2ae11f54cf6a8eEric Laurent        callbackInfo->busy = false;
125532bc1cb7da9fdbf34893fa48b2ae11f54cf6a8eEric Laurent        callbackInfo->cond.broadcast();
126532bc1cb7da9fdbf34893fa48b2ae11f54cf6a8eEric Laurent    }
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1294bcdba848449b33d7022de527c526943aff1f5fdEric Laurentstatic sp<JNIDeviceCallback> getJniDeviceCallback(JNIEnv* env, jobject thiz)
1304bcdba848449b33d7022de527c526943aff1f5fdEric Laurent{
1314bcdba848449b33d7022de527c526943aff1f5fdEric Laurent    Mutex::Autolock l(sLock);
1324bcdba848449b33d7022de527c526943aff1f5fdEric Laurent    JNIDeviceCallback* const cb =
1334bcdba848449b33d7022de527c526943aff1f5fdEric Laurent            (JNIDeviceCallback*)env->GetLongField(thiz,
1344bcdba848449b33d7022de527c526943aff1f5fdEric Laurent                                                  javaAudioRecordFields.nativeDeviceCallback);
1354bcdba848449b33d7022de527c526943aff1f5fdEric Laurent    return sp<JNIDeviceCallback>(cb);
1364bcdba848449b33d7022de527c526943aff1f5fdEric Laurent}
1374bcdba848449b33d7022de527c526943aff1f5fdEric Laurent
1384bcdba848449b33d7022de527c526943aff1f5fdEric Laurentstatic sp<JNIDeviceCallback> setJniDeviceCallback(JNIEnv* env,
1394bcdba848449b33d7022de527c526943aff1f5fdEric Laurent                                                  jobject thiz,
1404bcdba848449b33d7022de527c526943aff1f5fdEric Laurent                                                  const sp<JNIDeviceCallback>& cb)
1414bcdba848449b33d7022de527c526943aff1f5fdEric Laurent{
1424bcdba848449b33d7022de527c526943aff1f5fdEric Laurent    Mutex::Autolock l(sLock);
1434bcdba848449b33d7022de527c526943aff1f5fdEric Laurent    sp<JNIDeviceCallback> old =
1444bcdba848449b33d7022de527c526943aff1f5fdEric Laurent            (JNIDeviceCallback*)env->GetLongField(thiz,
1454bcdba848449b33d7022de527c526943aff1f5fdEric Laurent                                                  javaAudioRecordFields.nativeDeviceCallback);
1464bcdba848449b33d7022de527c526943aff1f5fdEric Laurent    if (cb.get()) {
1474bcdba848449b33d7022de527c526943aff1f5fdEric Laurent        cb->incStrong((void*)setJniDeviceCallback);
1484bcdba848449b33d7022de527c526943aff1f5fdEric Laurent    }
1494bcdba848449b33d7022de527c526943aff1f5fdEric Laurent    if (old != 0) {
1504bcdba848449b33d7022de527c526943aff1f5fdEric Laurent        old->decStrong((void*)setJniDeviceCallback);
1514bcdba848449b33d7022de527c526943aff1f5fdEric Laurent    }
1524bcdba848449b33d7022de527c526943aff1f5fdEric Laurent    env->SetLongField(thiz, javaAudioRecordFields.nativeDeviceCallback, (jlong)cb.get());
1534bcdba848449b33d7022de527c526943aff1f5fdEric Laurent    return old;
1544bcdba848449b33d7022de527c526943aff1f5fdEric Laurent}
1554bcdba848449b33d7022de527c526943aff1f5fdEric Laurent
156532bc1cb7da9fdbf34893fa48b2ae11f54cf6a8eEric Laurent// ----------------------------------------------------------------------------
157532bc1cb7da9fdbf34893fa48b2ae11f54cf6a8eEric Laurentstatic sp<AudioRecord> getAudioRecord(JNIEnv* env, jobject thiz)
158532bc1cb7da9fdbf34893fa48b2ae11f54cf6a8eEric Laurent{
159532bc1cb7da9fdbf34893fa48b2ae11f54cf6a8eEric Laurent    Mutex::Autolock l(sLock);
160532bc1cb7da9fdbf34893fa48b2ae11f54cf6a8eEric Laurent    AudioRecord* const ar =
161075e9a19ce645752f8282bc19c91b25978a7dc52Ashok Bhat            (AudioRecord*)env->GetLongField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj);
162532bc1cb7da9fdbf34893fa48b2ae11f54cf6a8eEric Laurent    return sp<AudioRecord>(ar);
163532bc1cb7da9fdbf34893fa48b2ae11f54cf6a8eEric Laurent}
164532bc1cb7da9fdbf34893fa48b2ae11f54cf6a8eEric Laurent
165532bc1cb7da9fdbf34893fa48b2ae11f54cf6a8eEric Laurentstatic sp<AudioRecord> setAudioRecord(JNIEnv* env, jobject thiz, const sp<AudioRecord>& ar)
166532bc1cb7da9fdbf34893fa48b2ae11f54cf6a8eEric Laurent{
167532bc1cb7da9fdbf34893fa48b2ae11f54cf6a8eEric Laurent    Mutex::Autolock l(sLock);
168532bc1cb7da9fdbf34893fa48b2ae11f54cf6a8eEric Laurent    sp<AudioRecord> old =
169075e9a19ce645752f8282bc19c91b25978a7dc52Ashok Bhat            (AudioRecord*)env->GetLongField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj);
170532bc1cb7da9fdbf34893fa48b2ae11f54cf6a8eEric Laurent    if (ar.get()) {
171b1d90c8f60f71422196c337f1d078b68867f5710Mathias Agopian        ar->incStrong((void*)setAudioRecord);
172532bc1cb7da9fdbf34893fa48b2ae11f54cf6a8eEric Laurent    }
173532bc1cb7da9fdbf34893fa48b2ae11f54cf6a8eEric Laurent    if (old != 0) {
174b1d90c8f60f71422196c337f1d078b68867f5710Mathias Agopian        old->decStrong((void*)setAudioRecord);
175532bc1cb7da9fdbf34893fa48b2ae11f54cf6a8eEric Laurent    }
176075e9a19ce645752f8282bc19c91b25978a7dc52Ashok Bhat    env->SetLongField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj, (jlong)ar.get());
177532bc1cb7da9fdbf34893fa48b2ae11f54cf6a8eEric Laurent    return old;
178532bc1cb7da9fdbf34893fa48b2ae11f54cf6a8eEric Laurent}
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// ----------------------------------------------------------------------------
181075e9a19ce645752f8282bc19c91b25978a7dc52Ashok Bhatstatic jint
1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectandroid_media_AudioRecord_setup(JNIEnv *env, jobject thiz, jobject weak_this,
1831cbf9b3741ec486c3ffce08f145501eb1ca73640Glenn Kasten        jobject jaa, jintArray jSampleRate, jint channelMask, jint channelIndexMask,
1849b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean        jint audioFormat, jint buffSizeInBytes, jintArray jSession, jstring opPackageName,
1859b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean        jlong nativeRecordInJavaObj)
1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
18771f2cf116aab893e224056c38ab146bd1538dd3eSteve Block    //ALOGV(">> Entering android_media_AudioRecord_setup");
1889b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean    //ALOGV("sampleRate=%d, audioFormat=%d, channel mask=%x, buffSizeInBytes=%d "
1899b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean    //     "nativeRecordInJavaObj=0x%llX",
1909b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean    //     sampleRateInHertz, audioFormat, channelMask, buffSizeInBytes, nativeRecordInJavaObj);
1919b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean    audio_channel_mask_t localChanMask = inChannelMaskToNative(channelMask);
192532bc1cb7da9fdbf34893fa48b2ae11f54cf6a8eEric Laurent
19344ff4cd8be50768d5bd471bc6c034acefa0b59caEric Laurent    if (jSession == NULL) {
1943762c311729fe9f3af085c14c5c1fb471d994c03Steve Block        ALOGE("Error creating AudioRecord: invalid session ID pointer");
195bc11a696f6856624de532a6830d5db9dbbe2384cEric Laurent        return (jint) AUDIO_JAVA_ERROR;
19644ff4cd8be50768d5bd471bc6c034acefa0b59caEric Laurent    }
19744ff4cd8be50768d5bd471bc6c034acefa0b59caEric Laurent
19844ff4cd8be50768d5bd471bc6c034acefa0b59caEric Laurent    jint* nSession = (jint *) env->GetPrimitiveArrayCritical(jSession, NULL);
19944ff4cd8be50768d5bd471bc6c034acefa0b59caEric Laurent    if (nSession == NULL) {
2003762c311729fe9f3af085c14c5c1fb471d994c03Steve Block        ALOGE("Error creating AudioRecord: Error retrieving session id pointer");
201bc11a696f6856624de532a6830d5db9dbbe2384cEric Laurent        return (jint) AUDIO_JAVA_ERROR;
20244ff4cd8be50768d5bd471bc6c034acefa0b59caEric Laurent    }
20333b840444f5a481dd31e129079d3c0cf3acdf80eGlenn Kasten    audio_session_t sessionId = (audio_session_t) nSession[0];
20444ff4cd8be50768d5bd471bc6c034acefa0b59caEric Laurent    env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
20544ff4cd8be50768d5bd471bc6c034acefa0b59caEric Laurent    nSession = NULL;
20644ff4cd8be50768d5bd471bc6c034acefa0b59caEric Laurent
2079b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean    audio_attributes_t *paa = NULL;
2089b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean    sp<AudioRecord> lpRecorder = 0;
2099b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean    audiorecord_callback_cookie *lpCallbackData = NULL;
2109b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean
2119b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean    jclass clazz = env->GetObjectClass(thiz);
2129b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean    if (clazz == NULL) {
2139b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean        ALOGE("Can't find %s when setting up callback.", kClassPathName);
2149b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean        return (jint) AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED;
2159b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean    }
216fa5ecdc4ac6d7a8db2bb9e4a6a60a3189025df30Svet Ganov
2179b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean    // if we pass in an existing *Native* AudioRecord, we don't need to create/initialize one.
2189b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean    if (nativeRecordInJavaObj == 0) {
2199b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean        if (jaa == 0) {
2209b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean            ALOGE("Error creating AudioRecord: invalid audio attributes");
2219b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean            return (jint) AUDIO_JAVA_ERROR;
2229b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean        }
22318db49a46259020387c40fff36d92edc1087a366Glenn Kasten
2249b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean        if (jSampleRate == 0) {
2259b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean            ALOGE("Error creating AudioRecord: invalid sample rates");
2269b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean            return (jint) AUDIO_JAVA_ERROR;
2279b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean        }
2289b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean        jint elements[1];
2299b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean        env->GetIntArrayRegion(jSampleRate, 0, 1, elements);
2309b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean        int sampleRateInHertz = elements[0];
2319b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean
2329b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean        // channel index mask takes priority over channel position masks.
2339b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean        if (channelIndexMask) {
2349b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean            // Java channel index masks need the representation bits set.
2359b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean            localChanMask = audio_channel_mask_from_representation_and_bits(
2369b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean                    AUDIO_CHANNEL_REPRESENTATION_INDEX,
2379b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean                    channelIndexMask);
2389b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean        }
2399b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean        // Java channel position masks map directly to the native definition
2409b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean
2419b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean        if (!audio_is_input_channel(localChanMask)) {
2429b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean            ALOGE("Error creating AudioRecord: channel mask %#x is not valid.", localChanMask);
2439b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean            return (jint) AUDIORECORD_ERROR_SETUP_INVALIDCHANNELMASK;
2449b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean        }
2459b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean        uint32_t channelCount = audio_channel_count_from_in_mask(localChanMask);
2469b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean
2479b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean        // compare the format against the Java constants
2489b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean        audio_format_t format = audioFormatToNative(audioFormat);
2499b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean        if (format == AUDIO_FORMAT_INVALID) {
2509b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean            ALOGE("Error creating AudioRecord: unsupported audio format %d.", audioFormat);
2519b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean            return (jint) AUDIORECORD_ERROR_SETUP_INVALIDFORMAT;
2529b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean        }
2539b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean
2549b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean        size_t bytesPerSample = audio_bytes_per_sample(format);
2559b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean
2569b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean        if (buffSizeInBytes == 0) {
2579b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean             ALOGE("Error creating AudioRecord: frameCount is 0.");
2589b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean            return (jint) AUDIORECORD_ERROR_SETUP_ZEROFRAMECOUNT;
2599b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean        }
2609b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean        size_t frameSize = channelCount * bytesPerSample;
2619b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean        size_t frameCount = buffSizeInBytes / frameSize;
2629b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean
2639b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean        ScopedUtfChars opPackageNameStr(env, opPackageName);
2649b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean
2659b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean        // create an uninitialized AudioRecord object
2669b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean        lpRecorder = new AudioRecord(String16(opPackageNameStr.c_str()));
2679b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean
2689b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean        // read the AudioAttributes values
2699b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean        paa = (audio_attributes_t *) calloc(1, sizeof(audio_attributes_t));
2709b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean        const jstring jtags =
2719b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean                (jstring) env->GetObjectField(jaa, javaAudioAttrFields.fieldFormattedTags);
2729b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean        const char* tags = env->GetStringUTFChars(jtags, NULL);
2739b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean        // copying array size -1, char array for tags was calloc'd, no need to NULL-terminate it
2749b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean        strncpy(paa->tags, tags, AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1);
2759b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean        env->ReleaseStringUTFChars(jtags, tags);
2769b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean        paa->source = (audio_source_t) env->GetIntField(jaa, javaAudioAttrFields.fieldRecSource);
2779b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean        paa->flags = (audio_flags_mask_t)env->GetIntField(jaa, javaAudioAttrFields.fieldFlags);
2789b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean        ALOGV("AudioRecord_setup for source=%d tags=%s flags=%08x", paa->source, paa->tags, paa->flags);
2799b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean
2809b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean        audio_input_flags_t flags = AUDIO_INPUT_FLAG_NONE;
2819b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean        if (paa->flags & AUDIO_FLAG_HW_HOTWORD) {
2829b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean            flags = AUDIO_INPUT_FLAG_HW_HOTWORD;
2839b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean        }
2849b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean        // create the callback information:
2859b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean        // this data will be passed with every AudioRecord callback
2869b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean        lpCallbackData = new audiorecord_callback_cookie;
2879b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean        lpCallbackData->audioRecord_class = (jclass)env->NewGlobalRef(clazz);
2889b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean        // we use a weak reference so the AudioRecord object can be garbage collected.
2899b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean        lpCallbackData->audioRecord_ref = env->NewGlobalRef(weak_this);
2909b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean        lpCallbackData->busy = false;
2919b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean
2929b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean        const status_t status = lpRecorder->set(paa->source,
2939b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean            sampleRateInHertz,
2949b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean            format,        // word length, PCM
2959b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean            localChanMask,
2969b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean            frameCount,
2979b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean            recorderCallback,// callback_t
2989b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean            lpCallbackData,// void* user
2999b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean            0,             // notificationFrames,
3009b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean            true,          // threadCanCallJava
3019b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean            sessionId,
3029b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean            AudioRecord::TRANSFER_DEFAULT,
3039b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean            flags,
3049b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean            -1, -1,        // default uid, pid
3059b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean            paa);
3069b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean
3079b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean        if (status != NO_ERROR) {
3089b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean            ALOGE("Error creating AudioRecord instance: initialization check failed with status %d.",
3099b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean                    status);
3109b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean            goto native_init_failure;
3119b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean        }
3129b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean    } else { // end if nativeRecordInJavaObj == 0)
3139b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean        lpRecorder = (AudioRecord*)nativeRecordInJavaObj;
3149b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean        // TODO: We need to find out which members of the Java AudioRecord might need to be
3159b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean        // initialized from the Native AudioRecord
3169b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean        // these are directly returned from getters:
3179b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean        //  mSampleRate
3189b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean        //  mRecordSource
3199b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean        //  mAudioFormat
3209b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean        //  mChannelMask
3219b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean        //  mChannelCount
3229b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean        //  mState (?)
3239b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean        //  mRecordingState (?)
3249b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean        //  mPreferredDevice
3259b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean
3269b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean        // create the callback information:
3279b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean        // this data will be passed with every AudioRecord callback
3289b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean        lpCallbackData = new audiorecord_callback_cookie;
3299b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean        lpCallbackData->audioRecord_class = (jclass)env->NewGlobalRef(clazz);
3309b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean        // we use a weak reference so the AudioRecord object can be garbage collected.
3319b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean        lpCallbackData->audioRecord_ref = env->NewGlobalRef(weak_this);
3329b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean        lpCallbackData->busy = false;
3339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
33544ff4cd8be50768d5bd471bc6c034acefa0b59caEric Laurent    nSession = (jint *) env->GetPrimitiveArrayCritical(jSession, NULL);
33644ff4cd8be50768d5bd471bc6c034acefa0b59caEric Laurent    if (nSession == NULL) {
3373762c311729fe9f3af085c14c5c1fb471d994c03Steve Block        ALOGE("Error creating AudioRecord: Error retrieving session id pointer");
33844ff4cd8be50768d5bd471bc6c034acefa0b59caEric Laurent        goto native_init_failure;
33944ff4cd8be50768d5bd471bc6c034acefa0b59caEric Laurent    }
340b3db213eb55acb661e4b9ea40bcc00af4b76fab9Glenn Kasten    // read the audio session ID back from AudioRecord in case a new session was created during set()
34144ff4cd8be50768d5bd471bc6c034acefa0b59caEric Laurent    nSession[0] = lpRecorder->getSessionId();
34244ff4cd8be50768d5bd471bc6c034acefa0b59caEric Laurent    env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
34344ff4cd8be50768d5bd471bc6c034acefa0b59caEric Laurent    nSession = NULL;
34444ff4cd8be50768d5bd471bc6c034acefa0b59caEric Laurent
3451cbf9b3741ec486c3ffce08f145501eb1ca73640Glenn Kasten    {
3461cbf9b3741ec486c3ffce08f145501eb1ca73640Glenn Kasten        const jint elements[1] = { (jint) lpRecorder->getSampleRate() };
3471cbf9b3741ec486c3ffce08f145501eb1ca73640Glenn Kasten        env->SetIntArrayRegion(jSampleRate, 0, 1, elements);
3481cbf9b3741ec486c3ffce08f145501eb1ca73640Glenn Kasten    }
3491cbf9b3741ec486c3ffce08f145501eb1ca73640Glenn Kasten
350532bc1cb7da9fdbf34893fa48b2ae11f54cf6a8eEric Laurent    {   // scope for the lock
351532bc1cb7da9fdbf34893fa48b2ae11f54cf6a8eEric Laurent        Mutex::Autolock l(sLock);
352532bc1cb7da9fdbf34893fa48b2ae11f54cf6a8eEric Laurent        sAudioRecordCallBackCookies.add(lpCallbackData);
353532bc1cb7da9fdbf34893fa48b2ae11f54cf6a8eEric Laurent    }
35418db49a46259020387c40fff36d92edc1087a366Glenn Kasten    // save our newly created C++ AudioRecord in the "nativeRecorderInJavaObj" field
3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // of the Java object
356532bc1cb7da9fdbf34893fa48b2ae11f54cf6a8eEric Laurent    setAudioRecord(env, thiz, lpRecorder);
35718db49a46259020387c40fff36d92edc1087a366Glenn Kasten
3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // save our newly created callback information in the "nativeCallbackCookie" field
3599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // of the Java object (in mNativeCallbackCookie) so we can free the memory in finalize()
360075e9a19ce645752f8282bc19c91b25978a7dc52Ashok Bhat    env->SetLongField(thiz, javaAudioRecordFields.nativeCallbackCookie, (jlong)lpCallbackData);
36118db49a46259020387c40fff36d92edc1087a366Glenn Kasten
362bc11a696f6856624de532a6830d5db9dbbe2384cEric Laurent    return (jint) AUDIO_JAVA_SUCCESS;
36318db49a46259020387c40fff36d92edc1087a366Glenn Kasten
3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // failure:
3659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectnative_init_failure:
3664bac5a3928d57ac193141eb6d45f3b39200d27deJean-Michel Trivi    env->DeleteGlobalRef(lpCallbackData->audioRecord_class);
3674bac5a3928d57ac193141eb6d45f3b39200d27deJean-Michel Trivi    env->DeleteGlobalRef(lpCallbackData->audioRecord_ref);
3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    delete lpCallbackData;
369075e9a19ce645752f8282bc19c91b25978a7dc52Ashok Bhat    env->SetLongField(thiz, javaAudioRecordFields.nativeCallbackCookie, 0);
37018db49a46259020387c40fff36d92edc1087a366Glenn Kasten
37114d226a2cd7b39e17a3f0bfdab79e645f7146f53Glenn Kasten    // lpRecorder goes out of scope, so reference count drops to zero
372075e9a19ce645752f8282bc19c91b25978a7dc52Ashok Bhat    return (jint) AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED;
3739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
3749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// ----------------------------------------------------------------------------
378075e9a19ce645752f8282bc19c91b25978a7dc52Ashok Bhatstatic jint
379505e5c8859f596ed58489be565d6e029314b2ac8Eric Laurentandroid_media_AudioRecord_start(JNIEnv *env, jobject thiz, jint event, jint triggerSession)
3809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
381532bc1cb7da9fdbf34893fa48b2ae11f54cf6a8eEric Laurent    sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
3829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (lpRecorder == NULL ) {
3839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        jniThrowException(env, "java/lang/IllegalStateException", NULL);
384bc11a696f6856624de532a6830d5db9dbbe2384cEric Laurent        return (jint) AUDIO_JAVA_ERROR;
3859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
38618db49a46259020387c40fff36d92edc1087a366Glenn Kasten
387bc11a696f6856624de532a6830d5db9dbbe2384cEric Laurent    return nativeToJavaStatus(
38833b840444f5a481dd31e129079d3c0cf3acdf80eGlenn Kasten            lpRecorder->start((AudioSystem::sync_event_t)event, (audio_session_t) triggerSession));
3899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
3909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// ----------------------------------------------------------------------------
3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic void
3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectandroid_media_AudioRecord_stop(JNIEnv *env, jobject thiz)
3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
396532bc1cb7da9fdbf34893fa48b2ae11f54cf6a8eEric Laurent    sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (lpRecorder == NULL ) {
3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        jniThrowException(env, "java/lang/IllegalStateException", NULL);
3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return;
4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    lpRecorder->stop();
40371f2cf116aab893e224056c38ab146bd1538dd3eSteve Block    //ALOGV("Called lpRecorder->stop()");
4049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
4059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// ----------------------------------------------------------------------------
408532bc1cb7da9fdbf34893fa48b2ae11f54cf6a8eEric Laurent
409532bc1cb7da9fdbf34893fa48b2ae11f54cf6a8eEric Laurent#define CALLBACK_COND_WAIT_TIMEOUT_MS 1000
410e6335c904aafa17795b059a5d83b8b7db6c761c8Dave Sparksstatic void android_media_AudioRecord_release(JNIEnv *env,  jobject thiz) {
411532bc1cb7da9fdbf34893fa48b2ae11f54cf6a8eEric Laurent    sp<AudioRecord> lpRecorder = setAudioRecord(env, thiz, 0);
412532bc1cb7da9fdbf34893fa48b2ae11f54cf6a8eEric Laurent    if (lpRecorder == NULL) {
413532bc1cb7da9fdbf34893fa48b2ae11f54cf6a8eEric Laurent        return;
414532bc1cb7da9fdbf34893fa48b2ae11f54cf6a8eEric Laurent    }
4152fbf25b50f8534c78f3b9063d35a0b5970ff8f1eGlenn Kasten    ALOGV("About to delete lpRecorder: %p", lpRecorder.get());
416532bc1cb7da9fdbf34893fa48b2ae11f54cf6a8eEric Laurent    lpRecorder->stop();
417e6335c904aafa17795b059a5d83b8b7db6c761c8Dave Sparks
418075e9a19ce645752f8282bc19c91b25978a7dc52Ashok Bhat    audiorecord_callback_cookie *lpCookie = (audiorecord_callback_cookie *)env->GetLongField(
419e6335c904aafa17795b059a5d83b8b7db6c761c8Dave Sparks        thiz, javaAudioRecordFields.nativeCallbackCookie);
4209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
421e6335c904aafa17795b059a5d83b8b7db6c761c8Dave Sparks    // reset the native resources in the Java object so any attempt to access
422e6335c904aafa17795b059a5d83b8b7db6c761c8Dave Sparks    // them after a call to release fails.
423075e9a19ce645752f8282bc19c91b25978a7dc52Ashok Bhat    env->SetLongField(thiz, javaAudioRecordFields.nativeCallbackCookie, 0);
424e6335c904aafa17795b059a5d83b8b7db6c761c8Dave Sparks
4259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // delete the callback information
4269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (lpCookie) {
427532bc1cb7da9fdbf34893fa48b2ae11f54cf6a8eEric Laurent        Mutex::Autolock l(sLock);
4282fbf25b50f8534c78f3b9063d35a0b5970ff8f1eGlenn Kasten        ALOGV("deleting lpCookie: %p", lpCookie);
429532bc1cb7da9fdbf34893fa48b2ae11f54cf6a8eEric Laurent        while (lpCookie->busy) {
430532bc1cb7da9fdbf34893fa48b2ae11f54cf6a8eEric Laurent            if (lpCookie->cond.waitRelative(sLock,
431532bc1cb7da9fdbf34893fa48b2ae11f54cf6a8eEric Laurent                                            milliseconds(CALLBACK_COND_WAIT_TIMEOUT_MS)) !=
432532bc1cb7da9fdbf34893fa48b2ae11f54cf6a8eEric Laurent                                                    NO_ERROR) {
433532bc1cb7da9fdbf34893fa48b2ae11f54cf6a8eEric Laurent                break;
434532bc1cb7da9fdbf34893fa48b2ae11f54cf6a8eEric Laurent            }
435532bc1cb7da9fdbf34893fa48b2ae11f54cf6a8eEric Laurent        }
436532bc1cb7da9fdbf34893fa48b2ae11f54cf6a8eEric Laurent        sAudioRecordCallBackCookies.remove(lpCookie);
4374bac5a3928d57ac193141eb6d45f3b39200d27deJean-Michel Trivi        env->DeleteGlobalRef(lpCookie->audioRecord_class);
4384bac5a3928d57ac193141eb6d45f3b39200d27deJean-Michel Trivi        env->DeleteGlobalRef(lpCookie->audioRecord_ref);
4399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        delete lpCookie;
4409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
4429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// ----------------------------------------------------------------------------
445e6335c904aafa17795b059a5d83b8b7db6c761c8Dave Sparksstatic void android_media_AudioRecord_finalize(JNIEnv *env,  jobject thiz) {
446e6335c904aafa17795b059a5d83b8b7db6c761c8Dave Sparks    android_media_AudioRecord_release(env, thiz);
4479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
4489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4490e9e2f3724b43f86bb7e41a40e665587730ce6aeAndy Hung// overloaded JNI array helper functions
4500e9e2f3724b43f86bb7e41a40e665587730ce6aeAndy Hungstatic inline
4510e9e2f3724b43f86bb7e41a40e665587730ce6aeAndy Hungjbyte *envGetArrayElements(JNIEnv *env, jbyteArray array, jboolean *isCopy) {
4520e9e2f3724b43f86bb7e41a40e665587730ce6aeAndy Hung    return env->GetByteArrayElements(array, isCopy);
4539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
4549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4550e9e2f3724b43f86bb7e41a40e665587730ce6aeAndy Hungstatic inline
4560e9e2f3724b43f86bb7e41a40e665587730ce6aeAndy Hungvoid envReleaseArrayElements(JNIEnv *env, jbyteArray array, jbyte *elems, jint mode) {
4570e9e2f3724b43f86bb7e41a40e665587730ce6aeAndy Hung    env->ReleaseByteArrayElements(array, elems, mode);
4580e9e2f3724b43f86bb7e41a40e665587730ce6aeAndy Hung}
4593d4c64191a181aac0922abbd56f4046d6b7ec31cEric Laurent
4600e9e2f3724b43f86bb7e41a40e665587730ce6aeAndy Hungstatic inline
4610e9e2f3724b43f86bb7e41a40e665587730ce6aeAndy Hungjshort *envGetArrayElements(JNIEnv *env, jshortArray array, jboolean *isCopy) {
4620e9e2f3724b43f86bb7e41a40e665587730ce6aeAndy Hung    return env->GetShortArrayElements(array, isCopy);
4630e9e2f3724b43f86bb7e41a40e665587730ce6aeAndy Hung}
4643d4c64191a181aac0922abbd56f4046d6b7ec31cEric Laurent
4650e9e2f3724b43f86bb7e41a40e665587730ce6aeAndy Hungstatic inline
4660e9e2f3724b43f86bb7e41a40e665587730ce6aeAndy Hungvoid envReleaseArrayElements(JNIEnv *env, jshortArray array, jshort *elems, jint mode) {
4670e9e2f3724b43f86bb7e41a40e665587730ce6aeAndy Hung    env->ReleaseShortArrayElements(array, elems, mode);
4680e9e2f3724b43f86bb7e41a40e665587730ce6aeAndy Hung}
4693d4c64191a181aac0922abbd56f4046d6b7ec31cEric Laurent
4700e9e2f3724b43f86bb7e41a40e665587730ce6aeAndy Hungstatic inline
4710e9e2f3724b43f86bb7e41a40e665587730ce6aeAndy Hungjfloat *envGetArrayElements(JNIEnv *env, jfloatArray array, jboolean *isCopy) {
4720e9e2f3724b43f86bb7e41a40e665587730ce6aeAndy Hung    return env->GetFloatArrayElements(array, isCopy);
4730e9e2f3724b43f86bb7e41a40e665587730ce6aeAndy Hung}
4743d4c64191a181aac0922abbd56f4046d6b7ec31cEric Laurent
4750e9e2f3724b43f86bb7e41a40e665587730ce6aeAndy Hungstatic inline
4760e9e2f3724b43f86bb7e41a40e665587730ce6aeAndy Hungvoid envReleaseArrayElements(JNIEnv *env, jfloatArray array, jfloat *elems, jint mode) {
4770e9e2f3724b43f86bb7e41a40e665587730ce6aeAndy Hung    env->ReleaseFloatArrayElements(array, elems, mode);
4780e9e2f3724b43f86bb7e41a40e665587730ce6aeAndy Hung}
4793d4c64191a181aac0922abbd56f4046d6b7ec31cEric Laurent
4800e9e2f3724b43f86bb7e41a40e665587730ce6aeAndy Hungstatic inline
4810e9e2f3724b43f86bb7e41a40e665587730ce6aeAndy Hungjint interpretReadSizeError(ssize_t readSize) {
482219de73da2a986ddcbfbc593c4e4e01c858ce245Eric Laurent    if (readSize == WOULD_BLOCK) {
4830e9e2f3724b43f86bb7e41a40e665587730ce6aeAndy Hung        return (jint)0;
484219de73da2a986ddcbfbc593c4e4e01c858ce245Eric Laurent    } else if (readSize == NO_INIT) {
485219de73da2a986ddcbfbc593c4e4e01c858ce245Eric Laurent        return AUDIO_JAVA_DEAD_OBJECT;
486219de73da2a986ddcbfbc593c4e4e01c858ce245Eric Laurent    } else {
487219de73da2a986ddcbfbc593c4e4e01c858ce245Eric Laurent        ALOGE("Error %zd during AudioRecord native read", readSize);
488219de73da2a986ddcbfbc593c4e4e01c858ce245Eric Laurent        return nativeToJavaStatus(readSize);
4893d4c64191a181aac0922abbd56f4046d6b7ec31cEric Laurent    }
4909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
4919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4920e9e2f3724b43f86bb7e41a40e665587730ce6aeAndy Hungtemplate <typename T>
4930e9e2f3724b43f86bb7e41a40e665587730ce6aeAndy Hungstatic jint android_media_AudioRecord_readInArray(JNIEnv *env,  jobject thiz,
4940e9e2f3724b43f86bb7e41a40e665587730ce6aeAndy Hung                                                  T javaAudioData,
4950e9e2f3724b43f86bb7e41a40e665587730ce6aeAndy Hung                                                  jint offsetInSamples, jint sizeInSamples,
4960e9e2f3724b43f86bb7e41a40e665587730ce6aeAndy Hung                                                  jboolean isReadBlocking) {
49758b0f3f3324ad04d53b31a75c9ad617957dfbba6Andy Hung    // get the audio recorder from which we'll read new audio samples
49858b0f3f3324ad04d53b31a75c9ad617957dfbba6Andy Hung    sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
49958b0f3f3324ad04d53b31a75c9ad617957dfbba6Andy Hung    if (lpRecorder == NULL) {
50058b0f3f3324ad04d53b31a75c9ad617957dfbba6Andy Hung        ALOGE("Unable to retrieve AudioRecord object");
50158b0f3f3324ad04d53b31a75c9ad617957dfbba6Andy Hung        return (jint)AUDIO_JAVA_INVALID_OPERATION;
50258b0f3f3324ad04d53b31a75c9ad617957dfbba6Andy Hung    }
50358b0f3f3324ad04d53b31a75c9ad617957dfbba6Andy Hung
50458b0f3f3324ad04d53b31a75c9ad617957dfbba6Andy Hung    if (javaAudioData == NULL) {
5050e9e2f3724b43f86bb7e41a40e665587730ce6aeAndy Hung        ALOGE("Invalid Java array to store recorded audio");
5060e9e2f3724b43f86bb7e41a40e665587730ce6aeAndy Hung        return (jint)AUDIO_JAVA_BAD_VALUE;
5070e9e2f3724b43f86bb7e41a40e665587730ce6aeAndy Hung    }
50858b0f3f3324ad04d53b31a75c9ad617957dfbba6Andy Hung
50958b0f3f3324ad04d53b31a75c9ad617957dfbba6Andy Hung    // NOTE: We may use GetPrimitiveArrayCritical() when the JNI implementation changes in such
51058b0f3f3324ad04d53b31a75c9ad617957dfbba6Andy Hung    // a way that it becomes much more efficient. When doing so, we will have to prevent the
51158b0f3f3324ad04d53b31a75c9ad617957dfbba6Andy Hung    // AudioSystem callback to be called while in critical section (in case of media server
51258b0f3f3324ad04d53b31a75c9ad617957dfbba6Andy Hung    // process crash for instance)
5130e9e2f3724b43f86bb7e41a40e665587730ce6aeAndy Hung
5140e9e2f3724b43f86bb7e41a40e665587730ce6aeAndy Hung    // get the pointer to where we'll record the audio
5150e9e2f3724b43f86bb7e41a40e665587730ce6aeAndy Hung    auto *recordBuff = envGetArrayElements(env, javaAudioData, NULL);
51658b0f3f3324ad04d53b31a75c9ad617957dfbba6Andy Hung    if (recordBuff == NULL) {
51758b0f3f3324ad04d53b31a75c9ad617957dfbba6Andy Hung        ALOGE("Error retrieving destination for recorded audio data");
51858b0f3f3324ad04d53b31a75c9ad617957dfbba6Andy Hung        return (jint)AUDIO_JAVA_BAD_VALUE;
51958b0f3f3324ad04d53b31a75c9ad617957dfbba6Andy Hung    }
52058b0f3f3324ad04d53b31a75c9ad617957dfbba6Andy Hung
52158b0f3f3324ad04d53b31a75c9ad617957dfbba6Andy Hung    // read the new audio data from the native AudioRecord object
5220e9e2f3724b43f86bb7e41a40e665587730ce6aeAndy Hung    const size_t sizeInBytes = sizeInSamples * sizeof(*recordBuff);
5230e9e2f3724b43f86bb7e41a40e665587730ce6aeAndy Hung    ssize_t readSize = lpRecorder->read(
5240e9e2f3724b43f86bb7e41a40e665587730ce6aeAndy Hung            recordBuff + offsetInSamples, sizeInBytes, isReadBlocking == JNI_TRUE /* blocking */);
52558b0f3f3324ad04d53b31a75c9ad617957dfbba6Andy Hung
5260e9e2f3724b43f86bb7e41a40e665587730ce6aeAndy Hung    envReleaseArrayElements(env, javaAudioData, recordBuff, 0);
52758b0f3f3324ad04d53b31a75c9ad617957dfbba6Andy Hung
52858b0f3f3324ad04d53b31a75c9ad617957dfbba6Andy Hung    if (readSize < 0) {
5290e9e2f3724b43f86bb7e41a40e665587730ce6aeAndy Hung        return interpretReadSizeError(readSize);
53058b0f3f3324ad04d53b31a75c9ad617957dfbba6Andy Hung    }
5310e9e2f3724b43f86bb7e41a40e665587730ce6aeAndy Hung    return (jint)(readSize / sizeof(*recordBuff));
53258b0f3f3324ad04d53b31a75c9ad617957dfbba6Andy Hung}
53358b0f3f3324ad04d53b31a75c9ad617957dfbba6Andy Hung
53458b0f3f3324ad04d53b31a75c9ad617957dfbba6Andy Hung// ----------------------------------------------------------------------------
5359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic jint android_media_AudioRecord_readInDirectBuffer(JNIEnv *env,  jobject thiz,
5360e9e2f3724b43f86bb7e41a40e665587730ce6aeAndy Hung                                                         jobject jBuffer, jint sizeInBytes,
5370e9e2f3724b43f86bb7e41a40e665587730ce6aeAndy Hung                                                         jboolean isReadBlocking) {
5389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // get the audio recorder from which we'll read new audio samples
539532bc1cb7da9fdbf34893fa48b2ae11f54cf6a8eEric Laurent    sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
54018db49a46259020387c40fff36d92edc1087a366Glenn Kasten    if (lpRecorder==NULL)
5410e9e2f3724b43f86bb7e41a40e665587730ce6aeAndy Hung        return (jint)AUDIO_JAVA_INVALID_OPERATION;
5429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // direct buffer and direct access supported?
5449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    long capacity = env->GetDirectBufferCapacity(jBuffer);
54518db49a46259020387c40fff36d92edc1087a366Glenn Kasten    if (capacity == -1) {
5469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // buffer direct access is not supported
5473762c311729fe9f3af085c14c5c1fb471d994c03Steve Block        ALOGE("Buffer direct access is not supported, can't record");
5480e9e2f3724b43f86bb7e41a40e665587730ce6aeAndy Hung        return (jint)AUDIO_JAVA_BAD_VALUE;
5499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
55071f2cf116aab893e224056c38ab146bd1538dd3eSteve Block    //ALOGV("capacity = %ld", capacity);
5519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    jbyte* nativeFromJavaBuf = (jbyte*) env->GetDirectBufferAddress(jBuffer);
55218db49a46259020387c40fff36d92edc1087a366Glenn Kasten    if (nativeFromJavaBuf==NULL) {
5533762c311729fe9f3af085c14c5c1fb471d994c03Steve Block        ALOGE("Buffer direct access is not supported, can't record");
5540e9e2f3724b43f86bb7e41a40e665587730ce6aeAndy Hung        return (jint)AUDIO_JAVA_BAD_VALUE;
55518db49a46259020387c40fff36d92edc1087a366Glenn Kasten    }
5569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // read new data from the recorder
558357263da0ec2bc2be9d48c1becc3d94288c2f3edEric Laurent    ssize_t readSize = lpRecorder->read(nativeFromJavaBuf,
5590e9e2f3724b43f86bb7e41a40e665587730ce6aeAndy Hung                                        capacity < sizeInBytes ? capacity : sizeInBytes,
5600e9e2f3724b43f86bb7e41a40e665587730ce6aeAndy Hung                                        isReadBlocking == JNI_TRUE /* blocking */);
561357263da0ec2bc2be9d48c1becc3d94288c2f3edEric Laurent    if (readSize < 0) {
5620e9e2f3724b43f86bb7e41a40e665587730ce6aeAndy Hung        return interpretReadSizeError(readSize);
563357263da0ec2bc2be9d48c1becc3d94288c2f3edEric Laurent    }
564357263da0ec2bc2be9d48c1becc3d94288c2f3edEric Laurent    return (jint)readSize;
5659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
5669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// ----------------------------------------------------------------------------
568e90a0a88f4eabdc27c3ef033f38c91ea23362a1eAndy Hungstatic jint android_media_AudioRecord_get_buffer_size_in_frames(JNIEnv *env,  jobject thiz) {
569864ae678521cc26801a1611b3d4eabe90c0a17f7Andy Hung    sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
570864ae678521cc26801a1611b3d4eabe90c0a17f7Andy Hung    if (lpRecorder == NULL) {
571864ae678521cc26801a1611b3d4eabe90c0a17f7Andy Hung        jniThrowException(env, "java/lang/IllegalStateException",
572e90a0a88f4eabdc27c3ef033f38c91ea23362a1eAndy Hung            "Unable to retrieve AudioRecord pointer for frameCount()");
573864ae678521cc26801a1611b3d4eabe90c0a17f7Andy Hung        return (jint)AUDIO_JAVA_ERROR;
574864ae678521cc26801a1611b3d4eabe90c0a17f7Andy Hung    }
575864ae678521cc26801a1611b3d4eabe90c0a17f7Andy Hung    return lpRecorder->frameCount();
576864ae678521cc26801a1611b3d4eabe90c0a17f7Andy Hung}
577864ae678521cc26801a1611b3d4eabe90c0a17f7Andy Hung
578864ae678521cc26801a1611b3d4eabe90c0a17f7Andy Hung// ----------------------------------------------------------------------------
57918db49a46259020387c40fff36d92edc1087a366Glenn Kastenstatic jint android_media_AudioRecord_set_marker_pos(JNIEnv *env,  jobject thiz,
5809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        jint markerPos) {
58118db49a46259020387c40fff36d92edc1087a366Glenn Kasten
582532bc1cb7da9fdbf34893fa48b2ae11f54cf6a8eEric Laurent    sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
583532bc1cb7da9fdbf34893fa48b2ae11f54cf6a8eEric Laurent    if (lpRecorder == NULL) {
5849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        jniThrowException(env, "java/lang/IllegalStateException",
5859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            "Unable to retrieve AudioRecord pointer for setMarkerPosition()");
586bc11a696f6856624de532a6830d5db9dbbe2384cEric Laurent        return (jint)AUDIO_JAVA_ERROR;
5879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
588bc11a696f6856624de532a6830d5db9dbbe2384cEric Laurent    return nativeToJavaStatus( lpRecorder->setMarkerPosition(markerPos) );
5899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
5909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// ----------------------------------------------------------------------------
5939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic jint android_media_AudioRecord_get_marker_pos(JNIEnv *env,  jobject thiz) {
59418db49a46259020387c40fff36d92edc1087a366Glenn Kasten
595532bc1cb7da9fdbf34893fa48b2ae11f54cf6a8eEric Laurent    sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
5969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    uint32_t markerPos = 0;
59718db49a46259020387c40fff36d92edc1087a366Glenn Kasten
598532bc1cb7da9fdbf34893fa48b2ae11f54cf6a8eEric Laurent    if (lpRecorder == NULL) {
5999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        jniThrowException(env, "java/lang/IllegalStateException",
6009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            "Unable to retrieve AudioRecord pointer for getMarkerPosition()");
601bc11a696f6856624de532a6830d5db9dbbe2384cEric Laurent        return (jint)AUDIO_JAVA_ERROR;
6029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
603532bc1cb7da9fdbf34893fa48b2ae11f54cf6a8eEric Laurent    lpRecorder->getMarkerPosition(&markerPos);
604532bc1cb7da9fdbf34893fa48b2ae11f54cf6a8eEric Laurent    return (jint)markerPos;
6059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
6069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// ----------------------------------------------------------------------------
6099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic jint android_media_AudioRecord_set_pos_update_period(JNIEnv *env,  jobject thiz,
6109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        jint period) {
61118db49a46259020387c40fff36d92edc1087a366Glenn Kasten
612532bc1cb7da9fdbf34893fa48b2ae11f54cf6a8eEric Laurent    sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
61318db49a46259020387c40fff36d92edc1087a366Glenn Kasten
614532bc1cb7da9fdbf34893fa48b2ae11f54cf6a8eEric Laurent    if (lpRecorder == NULL) {
6159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        jniThrowException(env, "java/lang/IllegalStateException",
6169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            "Unable to retrieve AudioRecord pointer for setPositionUpdatePeriod()");
617bc11a696f6856624de532a6830d5db9dbbe2384cEric Laurent        return (jint)AUDIO_JAVA_ERROR;
61818db49a46259020387c40fff36d92edc1087a366Glenn Kasten    }
619bc11a696f6856624de532a6830d5db9dbbe2384cEric Laurent    return nativeToJavaStatus( lpRecorder->setPositionUpdatePeriod(period) );
6209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
6219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// ----------------------------------------------------------------------------
6249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic jint android_media_AudioRecord_get_pos_update_period(JNIEnv *env,  jobject thiz) {
62518db49a46259020387c40fff36d92edc1087a366Glenn Kasten
626532bc1cb7da9fdbf34893fa48b2ae11f54cf6a8eEric Laurent    sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
6279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    uint32_t period = 0;
62818db49a46259020387c40fff36d92edc1087a366Glenn Kasten
629532bc1cb7da9fdbf34893fa48b2ae11f54cf6a8eEric Laurent    if (lpRecorder == NULL) {
6309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        jniThrowException(env, "java/lang/IllegalStateException",
6319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            "Unable to retrieve AudioRecord pointer for getPositionUpdatePeriod()");
632bc11a696f6856624de532a6830d5db9dbbe2384cEric Laurent        return (jint)AUDIO_JAVA_ERROR;
6339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
634532bc1cb7da9fdbf34893fa48b2ae11f54cf6a8eEric Laurent    lpRecorder->getPositionUpdatePeriod(&period);
635532bc1cb7da9fdbf34893fa48b2ae11f54cf6a8eEric Laurent    return (jint)period;
6369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
6379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// ----------------------------------------------------------------------------
6409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// returns the minimum required size for the successful creation of an AudioRecord instance.
6419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// returns 0 if the parameter combination is not supported.
6429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// return -1 if there was an error querying the buffer size.
6439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic jint android_media_AudioRecord_get_min_buff_size(JNIEnv *env,  jobject thiz,
6445b8fd44365f03601aaba41879ac18e70ce814a0fGlenn Kasten    jint sampleRateInHertz, jint channelCount, jint audioFormat) {
645c3308074cd6f06bbb35c1999b5260f938742a9e7Chia-chi Yeh
646532bc1cb7da9fdbf34893fa48b2ae11f54cf6a8eEric Laurent    ALOGV(">> android_media_AudioRecord_get_min_buff_size(%d, %d, %d)",
6475b8fd44365f03601aaba41879ac18e70ce814a0fGlenn Kasten          sampleRateInHertz, channelCount, audioFormat);
648c3308074cd6f06bbb35c1999b5260f938742a9e7Chia-chi Yeh
649fd1e3dfde2a70906c50144a7b1b53593ec1f7891Glenn Kasten    size_t frameCount = 0;
650a5a42384367230b8e16cf441d5dcf4225332f9d7Glenn Kasten    audio_format_t format = audioFormatToNative(audioFormat);
651c3308074cd6f06bbb35c1999b5260f938742a9e7Chia-chi Yeh    status_t result = AudioRecord::getMinFrameCount(&frameCount,
652c3308074cd6f06bbb35c1999b5260f938742a9e7Chia-chi Yeh            sampleRateInHertz,
653a5a42384367230b8e16cf441d5dcf4225332f9d7Glenn Kasten            format,
6545b8fd44365f03601aaba41879ac18e70ce814a0fGlenn Kasten            audio_channel_in_mask_from_count(channelCount));
655c3308074cd6f06bbb35c1999b5260f938742a9e7Chia-chi Yeh
656c3308074cd6f06bbb35c1999b5260f938742a9e7Chia-chi Yeh    if (result == BAD_VALUE) {
657c3308074cd6f06bbb35c1999b5260f938742a9e7Chia-chi Yeh        return 0;
658c3308074cd6f06bbb35c1999b5260f938742a9e7Chia-chi Yeh    }
659c3308074cd6f06bbb35c1999b5260f938742a9e7Chia-chi Yeh    if (result != NO_ERROR) {
660c3308074cd6f06bbb35c1999b5260f938742a9e7Chia-chi Yeh        return -1;
6619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6625b8fd44365f03601aaba41879ac18e70ce814a0fGlenn Kasten    return frameCount * channelCount * audio_bytes_per_sample(format);
6639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
6649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6652d6de4c38c899707e0596b7fa4dad9bbb3eb6b60Paul McLeanstatic jboolean android_media_AudioRecord_setInputDevice(
6662d6de4c38c899707e0596b7fa4dad9bbb3eb6b60Paul McLean        JNIEnv *env,  jobject thiz, jint device_id) {
6672d6de4c38c899707e0596b7fa4dad9bbb3eb6b60Paul McLean
6686bd27e1a0c030e0c47d21dd4c99c3133c85685a9Paul McLean    sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
6694bcdba848449b33d7022de527c526943aff1f5fdEric Laurent    if (lpRecorder == 0) {
670cef696e8b464e6479ed352b3b490e41ee677bd91Paul McLean        return false;
6714bcdba848449b33d7022de527c526943aff1f5fdEric Laurent    }
6726bd27e1a0c030e0c47d21dd4c99c3133c85685a9Paul McLean    return lpRecorder->setInputDevice(device_id) == NO_ERROR;
6732d6de4c38c899707e0596b7fa4dad9bbb3eb6b60Paul McLean}
6749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6754bcdba848449b33d7022de527c526943aff1f5fdEric Laurentstatic jint android_media_AudioRecord_getRoutedDeviceId(
6764bcdba848449b33d7022de527c526943aff1f5fdEric Laurent                JNIEnv *env,  jobject thiz) {
6774bcdba848449b33d7022de527c526943aff1f5fdEric Laurent
6784bcdba848449b33d7022de527c526943aff1f5fdEric Laurent    sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
6794bcdba848449b33d7022de527c526943aff1f5fdEric Laurent    if (lpRecorder == 0) {
6804bcdba848449b33d7022de527c526943aff1f5fdEric Laurent        return 0;
6814bcdba848449b33d7022de527c526943aff1f5fdEric Laurent    }
6824bcdba848449b33d7022de527c526943aff1f5fdEric Laurent    return (jint)lpRecorder->getRoutedDeviceId();
6834bcdba848449b33d7022de527c526943aff1f5fdEric Laurent}
6844bcdba848449b33d7022de527c526943aff1f5fdEric Laurent
6854bcdba848449b33d7022de527c526943aff1f5fdEric Laurentstatic void android_media_AudioRecord_enableDeviceCallback(
6864bcdba848449b33d7022de527c526943aff1f5fdEric Laurent                JNIEnv *env,  jobject thiz) {
6874bcdba848449b33d7022de527c526943aff1f5fdEric Laurent
6884bcdba848449b33d7022de527c526943aff1f5fdEric Laurent    sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
6894bcdba848449b33d7022de527c526943aff1f5fdEric Laurent    if (lpRecorder == 0) {
6904bcdba848449b33d7022de527c526943aff1f5fdEric Laurent        return;
6914bcdba848449b33d7022de527c526943aff1f5fdEric Laurent    }
6924bcdba848449b33d7022de527c526943aff1f5fdEric Laurent    sp<JNIDeviceCallback> cb = getJniDeviceCallback(env, thiz);
6934bcdba848449b33d7022de527c526943aff1f5fdEric Laurent    if (cb != 0) {
6944bcdba848449b33d7022de527c526943aff1f5fdEric Laurent        return;
6954bcdba848449b33d7022de527c526943aff1f5fdEric Laurent    }
6964bcdba848449b33d7022de527c526943aff1f5fdEric Laurent    audiorecord_callback_cookie *cookie =
6974bcdba848449b33d7022de527c526943aff1f5fdEric Laurent            (audiorecord_callback_cookie *)env->GetLongField(thiz,
6984bcdba848449b33d7022de527c526943aff1f5fdEric Laurent                                                     javaAudioRecordFields.nativeCallbackCookie);
6994bcdba848449b33d7022de527c526943aff1f5fdEric Laurent    if (cookie == NULL) {
7004bcdba848449b33d7022de527c526943aff1f5fdEric Laurent        return;
7014bcdba848449b33d7022de527c526943aff1f5fdEric Laurent    }
7024bcdba848449b33d7022de527c526943aff1f5fdEric Laurent
7034bcdba848449b33d7022de527c526943aff1f5fdEric Laurent    cb = new JNIDeviceCallback(env, thiz, cookie->audioRecord_ref,
7044bcdba848449b33d7022de527c526943aff1f5fdEric Laurent                               javaAudioRecordFields.postNativeEventInJava);
7054bcdba848449b33d7022de527c526943aff1f5fdEric Laurent    status_t status = lpRecorder->addAudioDeviceCallback(cb);
7064bcdba848449b33d7022de527c526943aff1f5fdEric Laurent    if (status == NO_ERROR) {
7074bcdba848449b33d7022de527c526943aff1f5fdEric Laurent        setJniDeviceCallback(env, thiz, cb);
7084bcdba848449b33d7022de527c526943aff1f5fdEric Laurent    }
7094bcdba848449b33d7022de527c526943aff1f5fdEric Laurent}
7104bcdba848449b33d7022de527c526943aff1f5fdEric Laurent
7114bcdba848449b33d7022de527c526943aff1f5fdEric Laurentstatic void android_media_AudioRecord_disableDeviceCallback(
7124bcdba848449b33d7022de527c526943aff1f5fdEric Laurent                JNIEnv *env,  jobject thiz) {
7134bcdba848449b33d7022de527c526943aff1f5fdEric Laurent
7144bcdba848449b33d7022de527c526943aff1f5fdEric Laurent    sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
7154bcdba848449b33d7022de527c526943aff1f5fdEric Laurent    if (lpRecorder == 0) {
7164bcdba848449b33d7022de527c526943aff1f5fdEric Laurent        return;
7174bcdba848449b33d7022de527c526943aff1f5fdEric Laurent    }
7184bcdba848449b33d7022de527c526943aff1f5fdEric Laurent    sp<JNIDeviceCallback> cb = setJniDeviceCallback(env, thiz, 0);
7194bcdba848449b33d7022de527c526943aff1f5fdEric Laurent    if (cb != 0) {
7204bcdba848449b33d7022de527c526943aff1f5fdEric Laurent        lpRecorder->removeAudioDeviceCallback(cb);
7214bcdba848449b33d7022de527c526943aff1f5fdEric Laurent    }
7224bcdba848449b33d7022de527c526943aff1f5fdEric Laurent}
7234bcdba848449b33d7022de527c526943aff1f5fdEric Laurent
7240ad99c059735d6d4a9f9fb5379c8b1b35ce01f38Andy Hung// ----------------------------------------------------------------------------
7250ad99c059735d6d4a9f9fb5379c8b1b35ce01f38Andy Hungstatic jint android_media_AudioRecord_get_timestamp(JNIEnv *env, jobject thiz,
7260ad99c059735d6d4a9f9fb5379c8b1b35ce01f38Andy Hung        jobject timestamp, jint timebase) {
7270ad99c059735d6d4a9f9fb5379c8b1b35ce01f38Andy Hung    sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
7280ad99c059735d6d4a9f9fb5379c8b1b35ce01f38Andy Hung
7290ad99c059735d6d4a9f9fb5379c8b1b35ce01f38Andy Hung    if (lpRecorder == NULL) {
7300ad99c059735d6d4a9f9fb5379c8b1b35ce01f38Andy Hung        jniThrowException(env, "java/lang/IllegalStateException",
7310ad99c059735d6d4a9f9fb5379c8b1b35ce01f38Andy Hung            "Unable to retrieve AudioRecord pointer for getTimestamp()");
7320ad99c059735d6d4a9f9fb5379c8b1b35ce01f38Andy Hung        return (jint)AUDIO_JAVA_ERROR;
7330ad99c059735d6d4a9f9fb5379c8b1b35ce01f38Andy Hung    }
7344bcdba848449b33d7022de527c526943aff1f5fdEric Laurent
7350ad99c059735d6d4a9f9fb5379c8b1b35ce01f38Andy Hung    ExtendedTimestamp ts;
736f4d81bd865d341c6d71fcd4c40294a2570770879Andy Hung    jint status = nativeToJavaStatus(lpRecorder->getTimestamp(&ts));
7370ad99c059735d6d4a9f9fb5379c8b1b35ce01f38Andy Hung
7380ad99c059735d6d4a9f9fb5379c8b1b35ce01f38Andy Hung    if (status == AUDIO_JAVA_SUCCESS) {
7390ad99c059735d6d4a9f9fb5379c8b1b35ce01f38Andy Hung        // set the data
7400ad99c059735d6d4a9f9fb5379c8b1b35ce01f38Andy Hung        int64_t position, time;
7410ad99c059735d6d4a9f9fb5379c8b1b35ce01f38Andy Hung
7420ad99c059735d6d4a9f9fb5379c8b1b35ce01f38Andy Hung        status = nativeToJavaStatus(ts.getBestTimestamp(&position, &time, timebase));
7430ad99c059735d6d4a9f9fb5379c8b1b35ce01f38Andy Hung        if (status == AUDIO_JAVA_SUCCESS) {
7440ad99c059735d6d4a9f9fb5379c8b1b35ce01f38Andy Hung            env->SetLongField(
7450ad99c059735d6d4a9f9fb5379c8b1b35ce01f38Andy Hung                    timestamp, javaAudioTimestampFields.fieldFramePosition, position);
7460ad99c059735d6d4a9f9fb5379c8b1b35ce01f38Andy Hung            env->SetLongField(
7470ad99c059735d6d4a9f9fb5379c8b1b35ce01f38Andy Hung                    timestamp, javaAudioTimestampFields.fieldNanoTime, time);
7480ad99c059735d6d4a9f9fb5379c8b1b35ce01f38Andy Hung        }
7490ad99c059735d6d4a9f9fb5379c8b1b35ce01f38Andy Hung    }
7500ad99c059735d6d4a9f9fb5379c8b1b35ce01f38Andy Hung    return status;
7510ad99c059735d6d4a9f9fb5379c8b1b35ce01f38Andy Hung}
7524bcdba848449b33d7022de527c526943aff1f5fdEric Laurent
7539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// ----------------------------------------------------------------------------
7549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// ----------------------------------------------------------------------------
75576f6a86de25e1bf74717e047e55fd44b089673f3Daniel Micaystatic const JNINativeMethod gMethods[] = {
7569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // name,               signature,  funcPtr
757505e5c8859f596ed58489be565d6e029314b2ac8Eric Laurent    {"native_start",         "(II)I",    (void *)android_media_AudioRecord_start},
7589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    {"native_stop",          "()V",    (void *)android_media_AudioRecord_stop},
7599b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean    {"native_setup",         "(Ljava/lang/Object;Ljava/lang/Object;[IIIII[ILjava/lang/String;J)I",
7609b09e533ac67d3d25465e3312b4957bc90b0c84fPaul McLean                                      (void *)android_media_AudioRecord_setup},
7619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    {"native_finalize",      "()V",    (void *)android_media_AudioRecord_finalize},
7629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    {"native_release",       "()V",    (void *)android_media_AudioRecord_release},
76318db49a46259020387c40fff36d92edc1087a366Glenn Kasten    {"native_read_in_byte_array",
7640e9e2f3724b43f86bb7e41a40e665587730ce6aeAndy Hung                             "([BIIZ)I",
7650e9e2f3724b43f86bb7e41a40e665587730ce6aeAndy Hung                                     (void *)android_media_AudioRecord_readInArray<jbyteArray>},
7669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    {"native_read_in_short_array",
7670e9e2f3724b43f86bb7e41a40e665587730ce6aeAndy Hung                             "([SIIZ)I",
7680e9e2f3724b43f86bb7e41a40e665587730ce6aeAndy Hung                                     (void *)android_media_AudioRecord_readInArray<jshortArray>},
76958b0f3f3324ad04d53b31a75c9ad617957dfbba6Andy Hung    {"native_read_in_float_array",
7700e9e2f3724b43f86bb7e41a40e665587730ce6aeAndy Hung                             "([FIIZ)I",
7710e9e2f3724b43f86bb7e41a40e665587730ce6aeAndy Hung                                     (void *)android_media_AudioRecord_readInArray<jfloatArray>},
7720e9e2f3724b43f86bb7e41a40e665587730ce6aeAndy Hung    {"native_read_in_direct_buffer","(Ljava/lang/Object;IZ)I",
7739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                       (void *)android_media_AudioRecord_readInDirectBuffer},
774e90a0a88f4eabdc27c3ef033f38c91ea23362a1eAndy Hung    {"native_get_buffer_size_in_frames",
775e90a0a88f4eabdc27c3ef033f38c91ea23362a1eAndy Hung                             "()I", (void *)android_media_AudioRecord_get_buffer_size_in_frames},
7769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    {"native_set_marker_pos","(I)I",   (void *)android_media_AudioRecord_set_marker_pos},
7779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    {"native_get_marker_pos","()I",    (void *)android_media_AudioRecord_get_marker_pos},
7789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    {"native_set_pos_update_period",
7799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                             "(I)I",   (void *)android_media_AudioRecord_set_pos_update_period},
7809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    {"native_get_pos_update_period",
7819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                             "()I",    (void *)android_media_AudioRecord_get_pos_update_period},
7829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    {"native_get_min_buff_size",
7839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                             "(III)I",   (void *)android_media_AudioRecord_get_min_buff_size},
7842d6de4c38c899707e0596b7fa4dad9bbb3eb6b60Paul McLean    {"native_setInputDevice", "(I)Z", (void *)android_media_AudioRecord_setInputDevice},
7854bcdba848449b33d7022de527c526943aff1f5fdEric Laurent    {"native_getRoutedDeviceId", "()I", (void *)android_media_AudioRecord_getRoutedDeviceId},
7864bcdba848449b33d7022de527c526943aff1f5fdEric Laurent    {"native_enableDeviceCallback", "()V", (void *)android_media_AudioRecord_enableDeviceCallback},
7874bcdba848449b33d7022de527c526943aff1f5fdEric Laurent    {"native_disableDeviceCallback", "()V",
7884bcdba848449b33d7022de527c526943aff1f5fdEric Laurent                                        (void *)android_media_AudioRecord_disableDeviceCallback},
7890ad99c059735d6d4a9f9fb5379c8b1b35ce01f38Andy Hung    {"native_get_timestamp", "(Landroid/media/AudioTimestamp;I)I",
7900ad99c059735d6d4a9f9fb5379c8b1b35ce01f38Andy Hung                                       (void *)android_media_AudioRecord_get_timestamp},
7919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project};
7929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// field names found in android/media/AudioRecord.java
7949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#define JAVA_POSTEVENT_CALLBACK_NAME  "postEventFromNative"
7959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#define JAVA_NATIVERECORDERINJAVAOBJ_FIELD_NAME  "mNativeRecorderInJavaObj"
7969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#define JAVA_NATIVECALLBACKINFO_FIELD_NAME       "mNativeCallbackCookie"
7974bcdba848449b33d7022de527c526943aff1f5fdEric Laurent#define JAVA_NATIVEDEVICECALLBACK_FIELD_NAME       "mNativeDeviceCallback"
7989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// ----------------------------------------------------------------------------
8009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectint register_android_media_AudioRecord(JNIEnv *env)
8019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
8029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    javaAudioRecordFields.postNativeEventInJava = NULL;
8039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    javaAudioRecordFields.nativeRecorderInJavaObj = NULL;
8049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    javaAudioRecordFields.nativeCallbackCookie = NULL;
8054bcdba848449b33d7022de527c526943aff1f5fdEric Laurent    javaAudioRecordFields.nativeDeviceCallback = NULL;
80618db49a46259020387c40fff36d92edc1087a366Glenn Kasten
8079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Get the AudioRecord class
809ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe    jclass audioRecordClass = FindClassOrDie(env, kClassPathName);
8109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Get the postEvent method
811ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe    javaAudioRecordFields.postNativeEventInJava = GetStaticMethodIDOrDie(env,
812ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe            audioRecordClass, JAVA_POSTEVENT_CALLBACK_NAME,
813ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe            "(Ljava/lang/Object;IIILjava/lang/Object;)V");
8149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Get the variables
8169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    //    mNativeRecorderInJavaObj
817ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe    javaAudioRecordFields.nativeRecorderInJavaObj = GetFieldIDOrDie(env,
818ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe            audioRecordClass, JAVA_NATIVERECORDERINJAVAOBJ_FIELD_NAME, "J");
8199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    //     mNativeCallbackCookie
820ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe    javaAudioRecordFields.nativeCallbackCookie = GetFieldIDOrDie(env,
821ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe            audioRecordClass, JAVA_NATIVECALLBACKINFO_FIELD_NAME, "J");
8229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8234bcdba848449b33d7022de527c526943aff1f5fdEric Laurent    javaAudioRecordFields.nativeDeviceCallback = GetFieldIDOrDie(env,
8244bcdba848449b33d7022de527c526943aff1f5fdEric Laurent            audioRecordClass, JAVA_NATIVEDEVICECALLBACK_FIELD_NAME, "J");
8254bcdba848449b33d7022de527c526943aff1f5fdEric Laurent
826701d6ff12f36bf5e9de0dafdaced06744fd411ebJean-Michel Trivi    // Get the AudioAttributes class and fields
827ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe    jclass audioAttrClass = FindClassOrDie(env, kAudioAttributesClassPathName);
828ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe    javaAudioAttrFields.fieldRecSource = GetFieldIDOrDie(env, audioAttrClass, "mSource", "I");
829ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe    javaAudioAttrFields.fieldFlags = GetFieldIDOrDie(env, audioAttrClass, "mFlags", "I");
830ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe    javaAudioAttrFields.fieldFormattedTags = GetFieldIDOrDie(env,
831ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe            audioAttrClass, "mFormattedTags", "Ljava/lang/String;");
832701d6ff12f36bf5e9de0dafdaced06744fd411ebJean-Michel Trivi
8330ad99c059735d6d4a9f9fb5379c8b1b35ce01f38Andy Hung    // Get the RecordTimestamp class and fields
8340ad99c059735d6d4a9f9fb5379c8b1b35ce01f38Andy Hung    jclass audioTimestampClass = FindClassOrDie(env, "android/media/AudioTimestamp");
8350ad99c059735d6d4a9f9fb5379c8b1b35ce01f38Andy Hung    javaAudioTimestampFields.fieldFramePosition =
8360ad99c059735d6d4a9f9fb5379c8b1b35ce01f38Andy Hung            GetFieldIDOrDie(env, audioTimestampClass, "framePosition", "J");
8370ad99c059735d6d4a9f9fb5379c8b1b35ce01f38Andy Hung    javaAudioTimestampFields.fieldNanoTime =
8380ad99c059735d6d4a9f9fb5379c8b1b35ce01f38Andy Hung            GetFieldIDOrDie(env, audioTimestampClass, "nanoTime", "J");
8390ad99c059735d6d4a9f9fb5379c8b1b35ce01f38Andy Hung
840ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe    return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
8419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
8429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// ----------------------------------------------------------------------------
844