Home | History | Annotate | Download | only in srec_jni
      1 /*---------------------------------------------------------------------------*
      2  *  android_speech_srec_Recognizer.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 #include <jni.h>
     25 
     26 #define LOG_TAG "srec_jni"
     27 #include "utils/Log.h"
     28 
     29 #include "passert.h"
     30 #include "ESR_CommandLine.h"
     31 #include "ESR_Session.h"
     32 #include "LCHAR.h"
     33 #include "PFile.h"
     34 #include "PFileSystem.h"
     35 #include "PANSIFileSystem.h"
     36 //#include "PMemoryFileSystem.h"
     37 #include "plog.h"
     38 #include "pmemory.h"
     39 #include "ptypes.h"
     40 #include "SR_Grammar.h"
     41 #include "SR_Recognizer.h"
     42 #include "SR_RecognizerImpl.h"
     43 #include "SR_RecognizerResult.h"
     44 #include "SR_Session.h"
     45 #include "SR_Vocabulary.h"
     46 #include "SR_AcousticState.h"
     47 #include "SR_Nametag.h"
     48 #include "PStackSize.h"
     49 
     50 
     51 
     52 //
     53 // helper function to throw an exception
     54 //
     55 static void JNU_ThrowByName(JNIEnv *env, const char* name, const char* msg) {
     56     jclass cls = env->FindClass(name);
     57     if (cls != NULL) {
     58         env->ThrowNew(cls, msg);
     59     }
     60     env->DeleteLocalRef(cls);
     61 }
     62 
     63 static void unimplemented(JNIEnv* env) {
     64     JNU_ThrowByName(env, "java/lang/IllegalStateException", "unimplemented!!!");
     65 }
     66 
     67 static void checkEsrError(JNIEnv* env, ESR_ReturnCode esr_status) {
     68     if (esr_status != ESR_SUCCESS) {
     69         JNU_ThrowByName(env, "java/lang/IllegalStateException", ESR_rc2str(esr_status));
     70     }
     71 }
     72 
     73 
     74 ///////////////////////////////////////////////////////////////////////////
     75 // PMem JNI implementations
     76 ///////////////////////////////////////////////////////////////////////////
     77 
     78 static JNIEXPORT void JNICALL Java_android_speech_srec_Recognizer_PMemInit
     79         (JNIEnv *env, jclass clazz) {
     80     checkEsrError(env, PMemInit());
     81 }
     82 
     83 static JNIEXPORT void JNICALL Java_android_speech_srec_Recognizer_PMemShutdown
     84         (JNIEnv *env, jclass clazz) {
     85     checkEsrError(env, PMemShutdown());
     86 }
     87 
     88 
     89 //////////////////////////////////////////////////////////////////////////
     90 // SR_Session JNI implementations
     91 //////////////////////////////////////////////////////////////////////////
     92 
     93 static JNIEXPORT void JNICALL Java_android_speech_srec_Recognizer_SR_1SessionCreate
     94         (JNIEnv *env, jclass clazz, jstring fileName) {
     95     // TODO: check for fileName NPE
     96     const char* fn = env->GetStringUTFChars(fileName, 0);
     97     checkEsrError(env, SR_SessionCreate(fn));  // TODO: can I post this before freeing the string?
     98     env->ReleaseStringUTFChars(fileName, fn);
     99 }
    100 
    101 static JNIEXPORT void JNICALL Java_android_speech_srec_Recognizer_SR_1SessionDestroy
    102         (JNIEnv *env, jclass clazz) {
    103     checkEsrError(env, SR_SessionDestroy());
    104 }
    105 
    106 
    107 //////////////////////////////////////////////////////////////////////////
    108 // SR_Recognizer JNI implementations
    109 //////////////////////////////////////////////////////////////////////////
    110 
    111 static JNIEXPORT void JNICALL Java_android_speech_srec_Recognizer_SR_1RecognizerStart
    112         (JNIEnv *env, jclass clazz, jlong recognizer) {
    113     checkEsrError(env, SR_RecognizerStart((SR_Recognizer*)recognizer));
    114 }
    115 
    116 static JNIEXPORT void JNICALL Java_android_speech_srec_Recognizer_SR_1RecognizerStop
    117         (JNIEnv *env, jclass clazz, jlong recognizer) {
    118     checkEsrError(env, SR_RecognizerStop((SR_Recognizer*)recognizer));
    119 }
    120 
    121 static JNIEXPORT jlong JNICALL Java_android_speech_srec_Recognizer_SR_1RecognizerCreate
    122         (JNIEnv *env, jclass clazz) {
    123     SR_Recognizer* recognizer = NULL;
    124     // TODO: do we need to clean up the recognizer if this fails?
    125     checkEsrError(env, SR_RecognizerCreate(&recognizer));
    126     return (jlong)recognizer;
    127 }
    128 
    129 static JNIEXPORT void JNICALL Java_android_speech_srec_Recognizer_SR_1RecognizerDestroy
    130         (JNIEnv *env, jclass clazz, jlong recognizer) {
    131     checkEsrError(env, SR_RecognizerDestroy((SR_Recognizer*)recognizer));
    132     return;
    133 }
    134 
    135 static JNIEXPORT void JNICALL Java_android_speech_srec_Recognizer_SR_1RecognizerSetup
    136         (JNIEnv *env, jclass clazz, jlong recognizer) {
    137     checkEsrError(env, SR_RecognizerSetup((SR_Recognizer*)recognizer));
    138     return;
    139 }
    140 
    141 static JNIEXPORT void JNICALL Java_android_speech_srec_Recognizer_SR_1RecognizerUnsetup
    142         (JNIEnv *env, jclass clazz, jlong recognizer) {
    143     checkEsrError(env, SR_RecognizerUnsetup((SR_Recognizer*)recognizer));
    144     return;
    145 }
    146 
    147 static JNIEXPORT jboolean JNICALL Java_android_speech_srec_Recognizer_SR_1RecognizerIsSetup
    148         (JNIEnv *env, jclass clazz, jlong recognizer) {
    149     ESR_BOOL rtn = ESR_FALSE;
    150     checkEsrError(env, SR_RecognizerIsSetup((SR_Recognizer*)recognizer, &rtn));
    151     return rtn;
    152 }
    153 
    154 static JNIEXPORT jstring JNICALL Java_android_speech_srec_Recognizer_SR_1RecognizerGetParameter
    155   (JNIEnv *env, jclass clazz, jlong recognizer, jstring key) {
    156     unimplemented(env);
    157     return 0;
    158 }
    159 
    160 static JNIEXPORT jint JNICALL Java_android_speech_srec_Recognizer_SR_1RecognizerGetSize_1tParameter
    161   (JNIEnv *env, jclass clazz, jlong recognizer, jstring key) {
    162     unimplemented(env);
    163     return 0;
    164 }
    165 
    166 static JNIEXPORT jboolean JNICALL Java_android_speech_srec_Recognizer_SR_1RecognizerGetBoolParameter
    167   (JNIEnv *env, jclass clazz, jlong recognizer, jstring key) {
    168     unimplemented(env);
    169     return JNI_FALSE;
    170 }
    171 
    172 static JNIEXPORT void JNICALL Java_android_speech_srec_Recognizer_SR_1RecognizerSetParameter
    173   (JNIEnv *env, jclass clazz, jlong recognizer, jstring key, jstring value) {
    174     unimplemented(env);
    175     return;
    176 }
    177 
    178 static JNIEXPORT void JNICALL Java_android_speech_srec_Recognizer_SR_1RecognizerSetSize_1tParameter
    179   (JNIEnv *env, jclass clazz, jlong recognizer, jstring key, jint value) {
    180     unimplemented(env);
    181     return;
    182 }
    183 
    184 static JNIEXPORT void JNICALL Java_android_speech_srec_Recognizer_SR_1RecognizerSetBoolParameter
    185   (JNIEnv *env, jclass clazz, jlong recognizer, jstring key , jboolean value) {
    186     unimplemented(env);
    187     return;
    188 }
    189 
    190 static JNIEXPORT void JNICALL Java_android_speech_srec_Recognizer_SR_1RecognizerSetupRule
    191         (JNIEnv *env, jclass clazz, jlong recognizer, jlong grammar, jstring ruleName) {
    192     const char* rn = env->GetStringUTFChars(ruleName, 0);
    193     checkEsrError(env, SR_RecognizerSetupRule((SR_Recognizer*)recognizer, (SR_Grammar*)grammar, rn));
    194     env->ReleaseStringUTFChars(ruleName, rn);
    195 }
    196 
    197 static JNIEXPORT jboolean JNICALL Java_android_speech_srec_Recognizer_SR_1RecognizerHasSetupRules
    198         (JNIEnv *env, jclass clazz, jlong recognizer) {
    199     ESR_BOOL rtn = ESR_FALSE;
    200     checkEsrError(env, SR_RecognizerHasSetupRules((SR_Recognizer*)recognizer, &rtn));
    201     return rtn;
    202 }
    203 
    204 static JNIEXPORT void JNICALL Java_android_speech_srec_Recognizer_SR_1RecognizerActivateRule
    205         (JNIEnv *env, jclass clazz, jlong recognizer, jlong grammar, jstring ruleName, jint weight) {
    206     const char* rn = env->GetStringUTFChars(ruleName, 0);
    207     checkEsrError(env, SR_RecognizerActivateRule((SR_Recognizer*)recognizer, (SR_Grammar*)grammar, rn, weight));
    208     env->ReleaseStringUTFChars(ruleName, rn);
    209 }
    210 
    211 static JNIEXPORT void JNICALL Java_android_speech_srec_Recognizer_SR_1RecognizerDeactivateRule
    212         (JNIEnv *env, jclass clazz, jlong recognizer, jlong grammar, jstring ruleName) {
    213     const char* rn = env->GetStringUTFChars(ruleName, 0);
    214     checkEsrError(env, SR_RecognizerDeactivateRule((SR_Recognizer*)recognizer, (SR_Grammar*)grammar, rn));
    215     env->ReleaseStringUTFChars(ruleName, rn);
    216 }
    217 
    218 static JNIEXPORT void JNICALL Java_android_speech_srec_Recognizer_SR_1RecognizerDeactivateAllRules
    219         (JNIEnv *env, jclass clazz, jlong recognizer) {
    220     checkEsrError(env, SR_RecognizerDeactivateAllRules((SR_Recognizer*)recognizer));
    221 }
    222 
    223 static JNIEXPORT jboolean JNICALL Java_android_speech_srec_Recognizer_SR_1RecognizerIsActiveRule
    224         (JNIEnv *env, jclass clazz, jlong recognizer, jlong grammar, jstring ruleName) {
    225     ESR_BOOL rtn = ESR_FALSE;
    226     const char* rn = env->GetStringUTFChars(ruleName, 0);
    227     checkEsrError(env, SR_RecognizerIsActiveRule((SR_Recognizer*)recognizer, (SR_Grammar*)grammar, rn, &rtn));
    228     env->ReleaseStringUTFChars(ruleName, rn);
    229     return rtn;
    230 }
    231 
    232 static JNIEXPORT jboolean JNICALL Java_android_speech_srec_Recognizer_SR_1RecognizerCheckGrammarConsistency
    233         (JNIEnv *env, jclass clazz, jlong recognizer, jlong grammar) {
    234     ESR_BOOL rtn = ESR_FALSE;
    235     checkEsrError(env, SR_RecognizerCheckGrammarConsistency((SR_Recognizer*)recognizer, (SR_Grammar*)grammar, &rtn));
    236     return rtn;
    237 }
    238 
    239 static JNIEXPORT jint JNICALL Java_android_speech_srec_Recognizer_SR_1RecognizerPutAudio
    240         (JNIEnv *env, jclass clazz, jlong recognizer, jbyteArray audio, jint offset, jint length, jboolean isLast) {
    241     // set the length
    242     jbyte buffer[1024];
    243     if (length > (int)sizeof(buffer)) length = sizeof(buffer);
    244     size_t samples = length / sizeof(asr_int16_t);
    245     length = samples * sizeof(asr_int16_t);
    246 
    247     // fetch data from java
    248     env->GetByteArrayRegion(audio, offset, length, buffer);
    249 
    250     // put the samples into the recognizer
    251     checkEsrError(env, SR_RecognizerPutAudio((SR_Recognizer*)recognizer,
    252             (asr_int16_t*)buffer, &samples, isLast ? ESR_TRUE : ESR_FALSE));
    253     if (samples != length / sizeof(asr_int16_t)) {
    254         checkEsrError(env, ESR_READ_ERROR);
    255         return 0;
    256     }
    257 
    258     return samples * sizeof(asr_int16_t);
    259 }
    260 
    261 static JNIEXPORT jint JNICALL Java_android_speech_srec_Recognizer_SR_1RecognizerAdvance
    262         (JNIEnv *env, jclass clazz, jlong recognizer) {
    263     SR_RecognizerStatus status = SR_RECOGNIZER_EVENT_INVALID;
    264     SR_RecognizerResultType type = SR_RECOGNIZER_RESULT_TYPE_INVALID;
    265     SR_RecognizerResult* recognizerResult = NULL;
    266     checkEsrError(env, SR_RecognizerAdvance((SR_Recognizer*)recognizer, &status, &type, &recognizerResult));
    267     return status;
    268 }
    269 
    270 static JNIEXPORT jboolean JNICALL Java_android_speech_srec_Recognizer_SR_1RecognizerIsSignalClipping
    271         (JNIEnv *env, jclass clazz, jlong recognizer) {
    272     ESR_BOOL rtn = ESR_FALSE;
    273     checkEsrError(env, SR_RecognizerIsSignalClipping((SR_Recognizer*)recognizer, &rtn));
    274     return rtn;
    275 }
    276 
    277 static JNIEXPORT jboolean JNICALL Java_android_speech_srec_Recognizer_SR_1RecognizerIsSignalDCOffset
    278         (JNIEnv *env, jclass clazz, jlong recognizer) {
    279     ESR_BOOL rtn = ESR_FALSE;
    280     checkEsrError(env, SR_RecognizerIsSignalDCOffset((SR_Recognizer*)recognizer, &rtn));
    281     return rtn;
    282 }
    283 
    284 static JNIEXPORT jboolean JNICALL Java_android_speech_srec_Recognizer_SR_1RecognizerIsSignalNoisy
    285         (JNIEnv *env, jclass clazz, jlong recognizer) {
    286     ESR_BOOL rtn = ESR_FALSE;
    287     checkEsrError(env, SR_RecognizerIsSignalNoisy((SR_Recognizer*)recognizer, &rtn));
    288     return rtn;
    289 }
    290 
    291 static JNIEXPORT jboolean JNICALL Java_android_speech_srec_Recognizer_SR_1RecognizerIsSignalTooQuiet
    292         (JNIEnv *env, jclass clazz, jlong recognizer) {
    293     ESR_BOOL rtn = ESR_FALSE;
    294     checkEsrError(env, SR_RecognizerIsSignalTooQuiet((SR_Recognizer*)recognizer, &rtn));
    295     return rtn;
    296 }
    297 
    298 static JNIEXPORT jboolean JNICALL Java_android_speech_srec_Recognizer_SR_1RecognizerIsSignalTooFewSamples
    299         (JNIEnv *env, jclass clazz, jlong recognizer) {
    300     ESR_BOOL rtn = ESR_FALSE;
    301     checkEsrError(env, SR_RecognizerIsSignalTooFewSamples((SR_Recognizer*)recognizer, &rtn));
    302     return rtn;
    303 }
    304 
    305 static JNIEXPORT jboolean JNICALL Java_android_speech_srec_Recognizer_SR_1RecognizerIsSignalTooManySamples
    306         (JNIEnv *env, jclass clazz, jlong recognizer) {
    307     ESR_BOOL rtn = ESR_FALSE;
    308     checkEsrError(env, SR_RecognizerIsSignalTooManySamples((SR_Recognizer*)recognizer, &rtn));
    309     return rtn;
    310 }
    311 
    312 
    313 //////////////////////////////////////////////////////////////////////////
    314 // SR_AcousticState JNI implementations
    315 //////////////////////////////////////////////////////////////////////////
    316 
    317 static JNIEXPORT void JNICALL Java_android_speech_srec_Recognizer_SR_1AcousticStateReset
    318         (JNIEnv *env, jclass clazz, jlong recognizer) {
    319     checkEsrError(env, SR_AcousticStateReset((SR_Recognizer*)recognizer));
    320 }
    321 
    322 static JNIEXPORT void JNICALL Java_android_speech_srec_Recognizer_SR_1AcousticStateSet
    323         (JNIEnv *env, jclass clazz, jlong recognizer, jstring state) {
    324     const char* st = env->GetStringUTFChars(state, 0);
    325     checkEsrError(env, SR_AcousticStateSet((SR_Recognizer*)recognizer, st));
    326     env->ReleaseStringUTFChars(state, st);
    327 }
    328 
    329 static JNIEXPORT jstring JNICALL Java_android_speech_srec_Recognizer_SR_1AcousticStateGet
    330         (JNIEnv *env, jclass clazz, jlong recognizer) {
    331     char rtn[1000];
    332     size_t rtnLength = sizeof(rtn) - 1;
    333     ESR_ReturnCode esr_status = SR_AcousticStateGet((SR_Recognizer*)recognizer, rtn, &rtnLength);
    334     if (esr_status) {
    335         checkEsrError(env, esr_status);
    336         return NULL;
    337     }
    338     rtn[rtnLength] = 0;
    339     return env->NewStringUTF(rtn);
    340 }
    341 
    342 
    343 //////////////////////////////////////////////////////////////////////////
    344 // SR_Grammar JNI implementations
    345 //////////////////////////////////////////////////////////////////////////
    346 
    347 static JNIEXPORT void JNICALL Java_android_speech_srec_Recognizer_SR_1GrammarCompile
    348         (JNIEnv *env, jclass clazz, jlong grammar) {
    349     checkEsrError(env, SR_GrammarCompile((SR_Grammar*)grammar));
    350 }
    351 
    352 static JNIEXPORT void JNICALL Java_android_speech_srec_Recognizer_SR_1GrammarAddWordToSlot
    353         (JNIEnv *env, jclass clazz, jlong grammar, jstring slot, jstring word, jstring pronunciation, jint weight, jstring tag) {
    354     const char* sl = 0;
    355     const char* wo = 0;
    356     const char* pr = 0;
    357     const char* ta = 0;
    358     if ((sl = env->GetStringUTFChars(slot, 0)) &&
    359             (wo = env->GetStringUTFChars(word, 0)) &&
    360             (!pronunciation || (pr = env->GetStringUTFChars(pronunciation, 0))) &&
    361             (ta = env->GetStringUTFChars(tag, 0))) {
    362         checkEsrError(env, SR_GrammarAddWordToSlot((SR_Grammar*)grammar, sl, wo, pr, weight, ta));
    363     }
    364     if (ta) env->ReleaseStringUTFChars(tag, ta);
    365     if (pr) env->ReleaseStringUTFChars(pronunciation, pr);
    366     if (wo) env->ReleaseStringUTFChars(word, wo);
    367     if (sl) env->ReleaseStringUTFChars(slot, sl);
    368 }
    369 
    370 static JNIEXPORT void JNICALL Java_android_speech_srec_Recognizer_SR_1GrammarResetAllSlots
    371         (JNIEnv *env, jclass clazz, jlong grammar) {
    372     checkEsrError(env, SR_GrammarResetAllSlots((SR_Grammar*)grammar));
    373 }
    374 
    375 static JNIEXPORT void JNICALL Java_android_speech_srec_Recognizer_SR_1GrammarSetupVocabulary
    376         (JNIEnv *env, jclass clazz, jlong grammar, jlong vocabulary) {
    377     checkEsrError(env, SR_GrammarSetupVocabulary((SR_Grammar*)grammar, (SR_Vocabulary*)vocabulary));
    378 }
    379 
    380 static JNIEXPORT void JNICALL Java_android_speech_srec_Recognizer_SR_1GrammarSetupRecognizer
    381         (JNIEnv *env, jclass clazz, jlong grammar, jlong recognizer) {
    382     checkEsrError(env, SR_GrammarSetupRecognizer((SR_Grammar*)grammar, (SR_Recognizer*)recognizer));
    383 }
    384 
    385 static JNIEXPORT void JNICALL Java_android_speech_srec_Recognizer_SR_1GrammarUnsetupRecognizer
    386         (JNIEnv *env, jclass clazz, jlong grammar) {
    387     checkEsrError(env, SR_GrammarUnsetupRecognizer((SR_Grammar*)grammar));
    388 }
    389 
    390 static JNIEXPORT jlong JNICALL Java_android_speech_srec_Recognizer_SR_1GrammarCreate
    391         (JNIEnv *env, jclass clazz) {
    392     SR_Grammar* grammar = 0;
    393     checkEsrError(env, SR_GrammarCreate(&grammar));
    394     return (jlong)grammar;
    395 }
    396 
    397 static JNIEXPORT void JNICALL Java_android_speech_srec_Recognizer_SR_1GrammarDestroy
    398         (JNIEnv *env, jclass clazz, jlong grammar) {
    399     checkEsrError(env, SR_GrammarDestroy((SR_Grammar*)grammar));
    400 }
    401 
    402 static JNIEXPORT jlong JNICALL Java_android_speech_srec_Recognizer_SR_1GrammarLoad
    403         (JNIEnv *env, jclass clazz, jstring fileName) {
    404     // TODO: check for fileName NPE
    405     SR_Grammar* grammar = 0;
    406     const char* fn = env->GetStringUTFChars(fileName, 0);
    407     checkEsrError(env, SR_GrammarLoad(fn, &grammar));
    408     env->ReleaseStringUTFChars(fileName, fn);
    409     return (jlong)grammar;
    410 }
    411 
    412 static JNIEXPORT void JNICALL Java_android_speech_srec_Recognizer_SR_1GrammarSave
    413         (JNIEnv *env, jclass clazz, jlong grammar, jstring fileName) {
    414     const char* fn = env->GetStringUTFChars(fileName, 0);
    415     checkEsrError(env, SR_GrammarSave((SR_Grammar*)grammar, fn));
    416     env->ReleaseStringUTFChars(fileName, fn);
    417 }
    418 
    419 static JNIEXPORT void JNICALL Java_android_speech_srec_Recognizer_SR_1GrammarAllowOnly
    420         (JNIEnv *env, jclass clazz, jlong grammar, jstring transcription) {
    421     const char* tr = env->GetStringUTFChars(transcription, 0);
    422     checkEsrError(env, SR_GrammarSave((SR_Grammar*)grammar, tr));
    423     env->ReleaseStringUTFChars(transcription, tr);
    424 }
    425 
    426 static JNIEXPORT void JNICALL Java_android_speech_srec_Recognizer_SR_1GrammarAllowAll
    427         (JNIEnv *env, jclass clazz, jlong grammar) {
    428     checkEsrError(env, SR_GrammarAllowAll((SR_Grammar*)grammar));
    429 }
    430 
    431 
    432 //////////////////////////////////////////////////////////////////////////
    433 // SR_Vocabulary JNI implementations
    434 //////////////////////////////////////////////////////////////////////////
    435 
    436 static JNIEXPORT jlong JNICALL Java_android_speech_srec_Recognizer_SR_1VocabularyLoad
    437         (JNIEnv *env, jclass clazz) {
    438     char filename[P_PATH_MAX];
    439     size_t flen = sizeof(filename) - 1;
    440     checkEsrError(env, ESR_SessionGetLCHAR ( L("cmdline.vocabulary"), filename, &flen ));
    441     filename[sizeof(filename) - 1] = 0;
    442     // TODO: do we need to clean up the recognizer if this fails?
    443     SR_Vocabulary* vocabulary = NULL;
    444     checkEsrError(env, SR_VocabularyLoad(filename, &vocabulary));
    445     return (jlong)vocabulary;
    446 }
    447 
    448 static JNIEXPORT void JNICALL Java_android_speech_srec_Recognizer_SR_1VocabularyDestroy
    449         (JNIEnv *env, jclass clazz, jlong vocabulary) {
    450     // TODO: do we need to clean up the recognizer if this fails?
    451     checkEsrError(env, SR_VocabularyDestroy((SR_Vocabulary*)vocabulary));
    452 }
    453 
    454 static JNIEXPORT jstring JNICALL Java_android_speech_srec_Recognizer_SR_1VocabularyGetPronunciation
    455         (JNIEnv *env, jclass clazz, jlong vocabulary, jstring word) {
    456     char rtn[1000];
    457     size_t rtnLength = sizeof(rtn) - 1;
    458     const char* wo = env->GetStringUTFChars(word, 0);
    459     ESR_ReturnCode esr_status = SR_VocabularyGetPronunciation((SR_Vocabulary*)vocabulary, wo, rtn, &rtnLength);
    460     env->ReleaseStringUTFChars(word, wo);
    461     if (esr_status) {
    462         checkEsrError(env, esr_status);
    463         return NULL;
    464     }
    465     rtn[rtnLength] = 0;
    466     return env->NewStringUTF(rtn);
    467 }
    468 
    469 
    470 //////////////////////////////////////////////////////////////////////////
    471 // SR_RecognizerResult JNI implementations
    472 //////////////////////////////////////////////////////////////////////////
    473 
    474 static JNIEXPORT jbyteArray JNICALL Java_android_speech_srec_Recognizer_SR_1RecognizerResultGetWaveform
    475         (JNIEnv *env, jclass clazz, jlong recognizer) {
    476     unimplemented(env);
    477     return 0;
    478 }
    479 
    480 static JNIEXPORT jint JNICALL Java_android_speech_srec_Recognizer_SR_1RecognizerResultGetSize
    481         (JNIEnv *env, jclass clazz, jlong recognizer) {
    482     size_t size = 0;
    483     checkEsrError(env, SR_RecognizerResultGetSize(((SR_RecognizerImpl*)recognizer)->result, &size));
    484     return size;
    485 }
    486 
    487 static JNIEXPORT jint JNICALL Java_android_speech_srec_Recognizer_SR_1RecognizerResultGetKeyCount
    488         (JNIEnv *env, jclass clazz, jlong recognizer, jint nbest) {
    489     size_t size = 0;
    490     checkEsrError(env, SR_RecognizerResultGetKeyCount(((SR_RecognizerImpl*)recognizer)->result, nbest, &size));
    491     return size;
    492 }
    493 
    494 static JNIEXPORT jobjectArray JNICALL Java_android_speech_srec_Recognizer_SR_1RecognizerResultGetKeyList
    495         (JNIEnv *env, jclass clazz, jlong recognizer, jint nbest) {
    496     // fetch list
    497     LCHAR* list[200];
    498     size_t listSize = sizeof(list) / sizeof(list[0]);
    499     ESR_ReturnCode esr_status = SR_RecognizerResultGetKeyList(((SR_RecognizerImpl*)recognizer)->result, nbest, list, &listSize);
    500     if (esr_status) {
    501         checkEsrError(env, esr_status);
    502         return NULL;
    503     }
    504 
    505     // create String[] of keys
    506     jclass stringClass = env->FindClass("java/lang/String");
    507     if (!stringClass) return NULL;
    508     jobjectArray array = env->NewObjectArray(listSize, stringClass, NULL);
    509     if (!array) return NULL;
    510 
    511     // fill it
    512     for (size_t i = 0; i < listSize; i++) {
    513         // generate new String for key
    514         jstring key = env->NewStringUTF(list[i]);
    515         if (!key) return NULL;
    516         // set the array
    517         env->SetObjectArrayElement(array, i, key);
    518         env->DeleteLocalRef(key);
    519     }
    520 
    521     return array;
    522 }
    523 
    524 static JNIEXPORT jstring JNICALL Java_android_speech_srec_Recognizer_SR_1RecognizerResultGetValue
    525         (JNIEnv *env, jclass clazz, jlong recognizer, jint nbest, jstring key) {
    526     char rtn[1000];
    527     size_t rtnLength = sizeof(rtn) - 1;
    528     const char* ke = env->GetStringUTFChars(key, 0);
    529     ESR_ReturnCode esr_status = SR_RecognizerResultGetValue(((SR_RecognizerImpl*)recognizer)->result, nbest, ke, rtn, &rtnLength);
    530     env->ReleaseStringUTFChars(key, ke);
    531     if (esr_status) {
    532         checkEsrError(env, esr_status);
    533         return NULL;
    534     }
    535     rtn[rtnLength] = 0;
    536     return env->NewStringUTF(rtn);
    537 }
    538 
    539 
    540 /*
    541  * Table of methods associated with a single class.
    542  */
    543 static JNINativeMethod gMethods[] = {
    544     /* name, signature, funcPtr */
    545     // PMem
    546     {"PMemInit",                           "()V",                     (void*)Java_android_speech_srec_Recognizer_PMemInit},
    547     {"PMemShutdown",                       "()V",                     (void*)Java_android_speech_srec_Recognizer_PMemShutdown},
    548     // SR_Session
    549     {"SR_SessionCreate",                   "(Ljava/lang/String;)V",   (void*)Java_android_speech_srec_Recognizer_SR_1SessionCreate},
    550     {"SR_SessionDestroy",                  "()V",                     (void*)Java_android_speech_srec_Recognizer_SR_1SessionDestroy},
    551     // SR_Recognizer
    552     {"SR_RecognizerStart",                 "(J)V",                    (void*)Java_android_speech_srec_Recognizer_SR_1RecognizerStart},
    553     {"SR_RecognizerStop",                  "(J)V",                    (void*)Java_android_speech_srec_Recognizer_SR_1RecognizerStop},
    554     {"SR_RecognizerCreate",                "()J",                     (void*)Java_android_speech_srec_Recognizer_SR_1RecognizerCreate},
    555     {"SR_RecognizerDestroy",               "(J)V",                    (void*)Java_android_speech_srec_Recognizer_SR_1RecognizerDestroy},
    556     {"SR_RecognizerSetup",                 "(J)V",                    (void*)Java_android_speech_srec_Recognizer_SR_1RecognizerSetup},
    557     {"SR_RecognizerUnsetup",               "(J)V",                    (void*)Java_android_speech_srec_Recognizer_SR_1RecognizerUnsetup},
    558     {"SR_RecognizerIsSetup",               "(J)Z",                    (void*)Java_android_speech_srec_Recognizer_SR_1RecognizerIsSetup},
    559     {"SR_RecognizerGetParameter",          "(JLjava/lang/String;)Ljava/lang/String;", (void*)Java_android_speech_srec_Recognizer_SR_1RecognizerGetParameter},
    560     {"SR_RecognizerGetSize_tParameter",    "(JLjava/lang/String;)I",  (void*)Java_android_speech_srec_Recognizer_SR_1RecognizerGetSize_1tParameter},
    561     {"SR_RecognizerGetBoolParameter",      "(JLjava/lang/String;)Z",  (void*)Java_android_speech_srec_Recognizer_SR_1RecognizerGetBoolParameter},
    562     {"SR_RecognizerSetParameter",          "(JLjava/lang/String;Ljava/lang/String;)V", (void*)Java_android_speech_srec_Recognizer_SR_1RecognizerSetParameter},
    563     {"SR_RecognizerSetSize_tParameter",    "(JLjava/lang/String;I)V", (void*)Java_android_speech_srec_Recognizer_SR_1RecognizerSetSize_1tParameter},
    564     {"SR_RecognizerSetBoolParameter",      "(JLjava/lang/String;Z)V", (void*)Java_android_speech_srec_Recognizer_SR_1RecognizerSetBoolParameter},
    565     {"SR_RecognizerSetupRule",             "(JJLjava/lang/String;)V", (void*)Java_android_speech_srec_Recognizer_SR_1RecognizerSetupRule},
    566     {"SR_RecognizerHasSetupRules",         "(J)Z",                    (void*)Java_android_speech_srec_Recognizer_SR_1RecognizerHasSetupRules},
    567     {"SR_RecognizerActivateRule",          "(JJLjava/lang/String;I)V", (void*)Java_android_speech_srec_Recognizer_SR_1RecognizerActivateRule},
    568     {"SR_RecognizerDeactivateRule",        "(JJLjava/lang/String;)V", (void*)Java_android_speech_srec_Recognizer_SR_1RecognizerDeactivateRule},
    569     {"SR_RecognizerDeactivateAllRules",    "(J)V",                    (void*)Java_android_speech_srec_Recognizer_SR_1RecognizerDeactivateAllRules},
    570     {"SR_RecognizerIsActiveRule",          "(JJLjava/lang/String;)Z", (void*)Java_android_speech_srec_Recognizer_SR_1RecognizerIsActiveRule},
    571     {"SR_RecognizerCheckGrammarConsistency", "(JJ)Z",                 (void*)Java_android_speech_srec_Recognizer_SR_1RecognizerCheckGrammarConsistency},
    572     {"SR_RecognizerPutAudio",              "(J[BIIZ)I",               (void*)Java_android_speech_srec_Recognizer_SR_1RecognizerPutAudio},
    573     {"SR_RecognizerAdvance",               "(J)I",                    (void*)Java_android_speech_srec_Recognizer_SR_1RecognizerAdvance},
    574     {"SR_RecognizerIsSignalClipping",      "(J)Z",                    (void*)Java_android_speech_srec_Recognizer_SR_1RecognizerIsSignalClipping},
    575     {"SR_RecognizerIsSignalDCOffset",      "(J)Z",                    (void*)Java_android_speech_srec_Recognizer_SR_1RecognizerIsSignalDCOffset},
    576     {"SR_RecognizerIsSignalNoisy",         "(J)Z",                    (void*)Java_android_speech_srec_Recognizer_SR_1RecognizerIsSignalNoisy},
    577     {"SR_RecognizerIsSignalTooQuiet",      "(J)Z",                    (void*)Java_android_speech_srec_Recognizer_SR_1RecognizerIsSignalTooQuiet},
    578     {"SR_RecognizerIsSignalTooFewSamples", "(J)Z",                    (void*)Java_android_speech_srec_Recognizer_SR_1RecognizerIsSignalTooFewSamples},
    579     {"SR_RecognizerIsSignalTooManySamples", "(J)Z",                   (void*)Java_android_speech_srec_Recognizer_SR_1RecognizerIsSignalTooManySamples},
    580     // SR_AcousticState
    581     {"SR_AcousticStateReset",               "(J)V",                   (void*)Java_android_speech_srec_Recognizer_SR_1AcousticStateReset},
    582     {"SR_AcousticStateSet",                 "(JLjava/lang/String;)V", (void*)Java_android_speech_srec_Recognizer_SR_1AcousticStateSet},
    583     {"SR_AcousticStateGet",                 "(J)Ljava/lang/String;",  (void*)Java_android_speech_srec_Recognizer_SR_1AcousticStateGet},
    584     // SR_Grammar
    585     {"SR_GrammarCompile",                  "(J)V",                    (void*)Java_android_speech_srec_Recognizer_SR_1GrammarCompile},
    586     {"SR_GrammarAddWordToSlot",            "(JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;ILjava/lang/String;)V", (void*)Java_android_speech_srec_Recognizer_SR_1GrammarAddWordToSlot},
    587     {"SR_GrammarResetAllSlots",            "(J)V",                    (void*)Java_android_speech_srec_Recognizer_SR_1GrammarResetAllSlots},
    588     {"SR_GrammarSetupVocabulary",          "(JJ)V",                   (void*)Java_android_speech_srec_Recognizer_SR_1GrammarSetupVocabulary},
    589     {"SR_GrammarSetupRecognizer",          "(JJ)V",                   (void*)Java_android_speech_srec_Recognizer_SR_1GrammarSetupRecognizer},
    590     {"SR_GrammarUnsetupRecognizer",        "(J)V",                    (void*)Java_android_speech_srec_Recognizer_SR_1GrammarUnsetupRecognizer},
    591     {"SR_GrammarCreate",                   "()J",                     (void*)Java_android_speech_srec_Recognizer_SR_1GrammarCreate},
    592     {"SR_GrammarDestroy",                  "(J)V",                    (void*)Java_android_speech_srec_Recognizer_SR_1GrammarDestroy},
    593     {"SR_GrammarLoad",                     "(Ljava/lang/String;)J",   (void*)Java_android_speech_srec_Recognizer_SR_1GrammarLoad},
    594     {"SR_GrammarSave",                     "(JLjava/lang/String;)V",  (void*)Java_android_speech_srec_Recognizer_SR_1GrammarSave},
    595     {"SR_GrammarAllowOnly",                "(JLjava/lang/String;)V",  (void*)Java_android_speech_srec_Recognizer_SR_1GrammarAllowOnly},
    596     {"SR_GrammarAllowAll",                 "(J)V",                    (void*)Java_android_speech_srec_Recognizer_SR_1GrammarAllowAll},
    597     // SR_Vocabulary
    598     {"SR_VocabularyLoad",                  "()J",                     (void*)Java_android_speech_srec_Recognizer_SR_1VocabularyLoad},
    599     {"SR_VocabularyDestroy",               "(J)V",                    (void*)Java_android_speech_srec_Recognizer_SR_1VocabularyDestroy},
    600     {"SR_VocabularyGetPronunciation",      "(JLjava/lang/String;)Ljava/lang/String;",  (void*)Java_android_speech_srec_Recognizer_SR_1VocabularyGetPronunciation},
    601     // SR_RecognizerResult
    602     {"SR_RecognizerResultGetWaveform",     "(J)[B",                   (void*)Java_android_speech_srec_Recognizer_SR_1RecognizerResultGetWaveform},
    603     {"SR_RecognizerResultGetSize",         "(J)I",                    (void*)Java_android_speech_srec_Recognizer_SR_1RecognizerResultGetSize},
    604     {"SR_RecognizerResultGetKeyCount",     "(JI)I",                   (void*)Java_android_speech_srec_Recognizer_SR_1RecognizerResultGetKeyCount},
    605     {"SR_RecognizerResultGetKeyList",      "(JI)[Ljava/lang/String;", (void*)Java_android_speech_srec_Recognizer_SR_1RecognizerResultGetKeyList},
    606     {"SR_RecognizerResultGetValue",        "(JILjava/lang/String;)Ljava/lang/String;", (void*)Java_android_speech_srec_Recognizer_SR_1RecognizerResultGetValue},
    607 };
    608 
    609 /*
    610  * Returns the JNI version on success, -1 on failure.
    611  */
    612 jint register_android_speech_srec_Recognizer(JavaVM* vm, void* reserved)
    613 {
    614     JNIEnv* env = NULL;
    615     jclass clazz = NULL;
    616     const char* className = "android/speech/srec/Recognizer";
    617 
    618     if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
    619         ALOGE("ERROR: GetEnv failed\n");
    620         return -1;
    621     }
    622     assert(env != NULL);
    623 
    624     clazz = env->FindClass(className);
    625     if (clazz == NULL) {
    626         ALOGE("Native registration unable to find class '%s'\n", className);
    627         return -1;
    628     }
    629     if (env->RegisterNatives(clazz, gMethods,
    630             sizeof(gMethods) / sizeof(gMethods[0])) < 0) {
    631         ALOGE("RegisterNatives failed for '%s'\n", className);
    632         return -1;
    633     }
    634 
    635     /* success -- return valid version number */
    636     return JNI_VERSION_1_4;
    637 }
    638 
    639 
    640 extern jint register_android_speech_srec_MicrophoneInputStream(JavaVM* vm, void* reserved);
    641 
    642 jint JNI_OnLoad(JavaVM* vm, void* reserved)
    643 {
    644     if (register_android_speech_srec_MicrophoneInputStream(vm, reserved) != JNI_VERSION_1_4 ||
    645         register_android_speech_srec_Recognizer(vm, reserved) != JNI_VERSION_1_4) return -1;
    646     return JNI_VERSION_1_4;
    647 }
    648