1 /*---------------------------------------------------------------------------* 2 * android_speech_srec_MicrophoneInputStream.cpp * 3 * * 4 * Copyright 2007 Nuance Communciations, Inc. * 5 * * 6 * Licensed under the Apache License, Version 2.0 (the 'License'); * 7 * you may not use this file except in compliance with the License. * 8 * * 9 * You may obtain a copy of the License at * 10 * http://www.apache.org/licenses/LICENSE-2.0 * 11 * * 12 * Unless required by applicable law or agreed to in writing, software * 13 * distributed under the License is distributed on an 'AS IS' BASIS, * 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 15 * See the License for the specific language governing permissions and * 16 * limitations under the License. * 17 * * 18 *---------------------------------------------------------------------------*/ 19 20 21 #include <string.h> 22 #include <stdio.h> 23 #include <stdlib.h> 24 25 #define LOG_TAG "srec_jni" 26 #include <utils/Log.h> 27 28 #include <media/AudioRecord.h> 29 #include <media/mediarecorder.h> 30 31 #include <system/audio.h> 32 33 #include <jni.h> 34 35 using namespace android; 36 37 38 39 // 40 // helper function to throw an exception 41 // 42 static void throwException(JNIEnv *env, const char* ex, const char* fmt, int data) { 43 if (jclass cls = env->FindClass(ex)) { 44 char msg[1000]; 45 sprintf(msg, fmt, data); 46 env->ThrowNew(cls, msg); 47 env->DeleteLocalRef(cls); 48 } 49 } 50 51 52 /////////////////////////////////////////////////////////////////////////////// 53 // MicrophoneInputStream JNI implememtations 54 /////////////////////////////////////////////////////////////////////////////// 55 56 // Java uses an int to hold a raw pointer, which is already ugly. 57 // But we need to hold an sp<>, which is of unknown size. 58 // So we wrap the sp<> within a class, and give Java the int version of a pointer to this class. 59 class AudioRecordWrapper { 60 public: 61 AudioRecordWrapper(AudioRecord *audioRecord) : mAudioRecord(audioRecord) { } 62 ~AudioRecordWrapper() { } 63 AudioRecord* get() const { return mAudioRecord.get(); } 64 private: 65 const sp<AudioRecord> mAudioRecord; 66 }; 67 68 static JNIEXPORT jlong JNICALL Java_android_speech_srec_Recognizer_AudioRecordNew 69 (JNIEnv *env, jclass clazz, jint sampleRate, jint fifoFrames) { 70 71 AudioRecordWrapper *ar = new AudioRecordWrapper(new AudioRecord( 72 AUDIO_SOURCE_VOICE_RECOGNITION, sampleRate, 73 AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_MONO, 74 fifoFrames)); 75 status_t s = ar->get()->initCheck(); 76 if (s != NO_ERROR) { 77 delete ar; 78 ar = NULL; 79 ALOGE("initCheck error %d ", s); 80 } 81 return (jlong)ar; 82 } 83 84 static JNIEXPORT jint JNICALL Java_android_speech_srec_Recognizer_AudioRecordStart 85 (JNIEnv *env, jclass clazz, jlong audioRecord) { 86 return (jint)(((AudioRecordWrapper*)audioRecord)->get()->start()); 87 } 88 89 static JNIEXPORT jint JNICALL Java_android_speech_srec_Recognizer_AudioRecordRead 90 (JNIEnv *env, jclass clazz, jlong audioRecord, jbyteArray array, jint offset, jint length) { 91 jbyte buffer[4096]; 92 if (length > (int)sizeof(buffer)) length = sizeof(buffer); 93 length = ((AudioRecordWrapper*)audioRecord)->get()->read(buffer, length); 94 if (length < 0) { 95 throwException(env, "java/io/IOException", "AudioRecord::read failed %d", length); 96 return -1; 97 } 98 env->SetByteArrayRegion(array, offset, length, buffer); 99 return length; 100 } 101 102 static JNIEXPORT void JNICALL Java_android_speech_srec_Recognizer_AudioRecordStop 103 (JNIEnv *env, jclass clazz, jlong audioRecord) { 104 ((AudioRecordWrapper*)audioRecord)->get()->stop(); 105 } 106 107 static JNIEXPORT void JNICALL Java_android_speech_srec_Recognizer_AudioRecordDelete 108 (JNIEnv *env, jclass clazz, jlong audioRecord) { 109 delete (AudioRecordWrapper*)audioRecord; 110 } 111 112 113 /* 114 * Table of methods associated with a single class. 115 */ 116 static JNINativeMethod gMethods[] = { 117 /* name, signature, funcPtr */ 118 {"AudioRecordNew", "(II)J", (void*)Java_android_speech_srec_Recognizer_AudioRecordNew}, 119 {"AudioRecordStart", "(J)I", (void*)Java_android_speech_srec_Recognizer_AudioRecordStart}, 120 {"AudioRecordRead", "(J[BII)I", (void*)Java_android_speech_srec_Recognizer_AudioRecordRead}, 121 {"AudioRecordStop", "(J)V", (void*)Java_android_speech_srec_Recognizer_AudioRecordStop}, 122 {"AudioRecordDelete", "(J)V", (void*)Java_android_speech_srec_Recognizer_AudioRecordDelete}, 123 }; 124 125 /* 126 * Set some test stuff up. 127 * 128 * Returns the JNI version on success, -1 on failure. 129 */ 130 jint register_android_speech_srec_MicrophoneInputStream(JavaVM* vm, void* reserved) 131 { 132 JNIEnv* env = NULL; 133 jclass clazz = NULL; 134 const char* className = "android/speech/srec/MicrophoneInputStream"; 135 136 if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { 137 ALOGE("ERROR: GetEnv failed\n"); 138 return -1; 139 } 140 assert(env != NULL); 141 142 clazz = env->FindClass(className); 143 if (clazz == NULL) { 144 ALOGE("Native registration unable to find class '%s'\n", className); 145 return -1; 146 } 147 if (env->RegisterNatives(clazz, gMethods, 148 sizeof(gMethods) / sizeof(gMethods[0])) < 0) { 149 ALOGE("RegisterNatives failed for '%s'\n", className); 150 return -1; 151 } 152 153 /* success -- return valid version number */ 154 return JNI_VERSION_1_4;; 155 } 156