android_speech_srec_MicrophoneInputStream.cpp revision b3adea6f471d03c5bd728725adc7ca1cea89edfd
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 35using namespace android; 36 37 38 39// 40// helper function to throw an exception 41// 42static 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. 59class AudioRecordWrapper { 60public: 61 AudioRecordWrapper(AudioRecord *audioRecord) : mAudioRecord(audioRecord) { } 62 ~AudioRecordWrapper() { } 63 AudioRecord* get() const { return mAudioRecord.get(); } 64private: 65 const sp<AudioRecord> mAudioRecord; 66}; 67 68static 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 84static 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 89static 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 102static JNIEXPORT void JNICALL Java_android_speech_srec_Recognizer_AudioRecordStop 103 (JNIEnv *env, jclass clazz, jlong audioRecord) { 104 ((AudioRecordWrapper*)audioRecord)->get()->stop(); 105} 106 107static 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 */ 116static 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 */ 130jint 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