| /*---------------------------------------------------------------------------* |
| * android_speech_srec_MicrophoneInputStream.cpp * |
| * * |
| * Copyright 2007 Nuance Communciations, Inc. * |
| * * |
| * Licensed under the Apache License, Version 2.0 (the 'License'); * |
| * you may not use this file except in compliance with the License. * |
| * * |
| * You may obtain a copy of the License at * |
| * http://www.apache.org/licenses/LICENSE-2.0 * |
| * * |
| * Unless required by applicable law or agreed to in writing, software * |
| * distributed under the License is distributed on an 'AS IS' BASIS, * |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * |
| * See the License for the specific language governing permissions and * |
| * limitations under the License. * |
| * * |
| *---------------------------------------------------------------------------*/ |
| |
| |
| #include <string.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| |
| #define LOG_TAG "srec_jni" |
| #include <utils/Log.h> |
| |
| #include <media/AudioRecord.h> |
| #include <media/mediarecorder.h> |
| |
| #include <system/audio.h> |
| |
| #include <jni.h> |
| |
| using namespace android; |
| |
| |
| |
| // |
| // helper function to throw an exception |
| // |
| static void throwException(JNIEnv *env, const char* ex, const char* fmt, int data) { |
| if (jclass cls = env->FindClass(ex)) { |
| char msg[1000]; |
| sprintf(msg, fmt, data); |
| env->ThrowNew(cls, msg); |
| env->DeleteLocalRef(cls); |
| } |
| } |
| |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // MicrophoneInputStream JNI implememtations |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| // Java uses an int to hold a raw pointer, which is already ugly. |
| // But we need to hold an sp<>, which is of unknown size. |
| // So we wrap the sp<> within a class, and give Java the int version of a pointer to this class. |
| class AudioRecordWrapper { |
| public: |
| AudioRecordWrapper(AudioRecord *audioRecord) : mAudioRecord(audioRecord) { } |
| ~AudioRecordWrapper() { } |
| AudioRecord* get() const { return mAudioRecord.get(); } |
| private: |
| const sp<AudioRecord> mAudioRecord; |
| }; |
| |
| static JNIEXPORT jlong JNICALL Java_android_speech_srec_Recognizer_AudioRecordNew |
| (JNIEnv *env, jclass clazz, jint sampleRate, jint fifoFrames) { |
| |
| AudioRecordWrapper *ar = new AudioRecordWrapper(new AudioRecord( |
| AUDIO_SOURCE_VOICE_RECOGNITION, sampleRate, |
| AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_MONO, |
| fifoFrames)); |
| status_t s = ar->get()->initCheck(); |
| if (s != NO_ERROR) { |
| delete ar; |
| ar = NULL; |
| ALOGE("initCheck error %d ", s); |
| } |
| return (jlong)ar; |
| } |
| |
| static JNIEXPORT jint JNICALL Java_android_speech_srec_Recognizer_AudioRecordStart |
| (JNIEnv *env, jclass clazz, jlong audioRecord) { |
| return (jint)(((AudioRecordWrapper*)audioRecord)->get()->start()); |
| } |
| |
| static JNIEXPORT jint JNICALL Java_android_speech_srec_Recognizer_AudioRecordRead |
| (JNIEnv *env, jclass clazz, jlong audioRecord, jbyteArray array, jint offset, jint length) { |
| jbyte buffer[4096]; |
| if (length > (int)sizeof(buffer)) length = sizeof(buffer); |
| length = ((AudioRecordWrapper*)audioRecord)->get()->read(buffer, length); |
| if (length < 0) { |
| throwException(env, "java/io/IOException", "AudioRecord::read failed %d", length); |
| return -1; |
| } |
| env->SetByteArrayRegion(array, offset, length, buffer); |
| return length; |
| } |
| |
| static JNIEXPORT void JNICALL Java_android_speech_srec_Recognizer_AudioRecordStop |
| (JNIEnv *env, jclass clazz, jlong audioRecord) { |
| ((AudioRecordWrapper*)audioRecord)->get()->stop(); |
| } |
| |
| static JNIEXPORT void JNICALL Java_android_speech_srec_Recognizer_AudioRecordDelete |
| (JNIEnv *env, jclass clazz, jlong audioRecord) { |
| delete (AudioRecordWrapper*)audioRecord; |
| } |
| |
| |
| /* |
| * Table of methods associated with a single class. |
| */ |
| static JNINativeMethod gMethods[] = { |
| /* name, signature, funcPtr */ |
| {"AudioRecordNew", "(II)J", (void*)Java_android_speech_srec_Recognizer_AudioRecordNew}, |
| {"AudioRecordStart", "(J)I", (void*)Java_android_speech_srec_Recognizer_AudioRecordStart}, |
| {"AudioRecordRead", "(J[BII)I", (void*)Java_android_speech_srec_Recognizer_AudioRecordRead}, |
| {"AudioRecordStop", "(J)V", (void*)Java_android_speech_srec_Recognizer_AudioRecordStop}, |
| {"AudioRecordDelete", "(J)V", (void*)Java_android_speech_srec_Recognizer_AudioRecordDelete}, |
| }; |
| |
| /* |
| * Set some test stuff up. |
| * |
| * Returns the JNI version on success, -1 on failure. |
| */ |
| jint register_android_speech_srec_MicrophoneInputStream(JavaVM* vm, void* reserved) |
| { |
| JNIEnv* env = NULL; |
| jclass clazz = NULL; |
| const char* className = "android/speech/srec/MicrophoneInputStream"; |
| |
| if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { |
| ALOGE("ERROR: GetEnv failed\n"); |
| return -1; |
| } |
| assert(env != NULL); |
| |
| clazz = env->FindClass(className); |
| if (clazz == NULL) { |
| ALOGE("Native registration unable to find class '%s'\n", className); |
| return -1; |
| } |
| if (env->RegisterNatives(clazz, gMethods, |
| sizeof(gMethods) / sizeof(gMethods[0])) < 0) { |
| ALOGE("RegisterNatives failed for '%s'\n", className); |
| return -1; |
| } |
| |
| /* success -- return valid version number */ |
| return JNI_VERSION_1_4;; |
| } |