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//
55static 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
63static void unimplemented(JNIEnv* env) {
64    JNU_ThrowByName(env, "java/lang/IllegalStateException", "unimplemented!!!");
65}
66
67static 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
78static JNIEXPORT void JNICALL Java_android_speech_srec_Recognizer_PMemInit
79        (JNIEnv *env, jclass clazz) {
80    checkEsrError(env, PMemInit());
81}
82
83static 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
93static 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
101static 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
111static 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
116static 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
121static 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
129static 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
135static 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
141static 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
147static 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
154static 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
160static 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
166static 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
172static 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
178static 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
184static 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
190static 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
197static 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
204static 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
211static 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
218static 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
223static 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
232static 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
239static 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
261static 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
270static 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
277static 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
284static 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
291static 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
298static 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
305static 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
317static 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
322static 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
329static 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
347static 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
352static 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
370static 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
375static 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
380static 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
385static 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
390static 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
397static 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
402static 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
412static 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
419static 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
426static 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
436static 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
448static 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
454static 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
474static 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
480static 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
487static 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
494static 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
524static 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 */
543static 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 */
612jint 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
640extern jint register_android_speech_srec_MicrophoneInputStream(JavaVM* vm, void* reserved);
641
642jint 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