android_hardware_SoundTrigger.cpp revision d4233c68fc17f0909e9e36494db85a634f8e2665
1/*
2**
3** Copyright 2014, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9**     http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18//#define LOG_NDEBUG 0
19#define LOG_TAG "SoundTrigger-JNI"
20#include <utils/Log.h>
21
22#include "jni.h"
23#include "JNIHelp.h"
24#include "android_runtime/AndroidRuntime.h"
25#include <system/sound_trigger.h>
26#include <soundtrigger/SoundTriggerCallback.h>
27#include <soundtrigger/SoundTrigger.h>
28#include <utils/RefBase.h>
29#include <utils/Vector.h>
30#include <binder/IMemory.h>
31#include <binder/MemoryDealer.h>
32
33using namespace android;
34
35static jclass gArrayListClass;
36static struct {
37    jmethodID    add;
38} gArrayListMethods;
39
40static jclass gUUIDClass;
41static struct {
42    jmethodID    toString;
43} gUUIDMethods;
44
45static const char* const kSoundTriggerClassPathName = "android/hardware/soundtrigger/SoundTrigger";
46static jclass gSoundTriggerClass;
47
48static const char* const kModuleClassPathName = "android/hardware/soundtrigger/SoundTriggerModule";
49static jclass gModuleClass;
50static struct {
51    jfieldID    mNativeContext;
52    jfieldID    mId;
53} gModuleFields;
54static jmethodID   gPostEventFromNative;
55
56static const char* const kModulePropertiesClassPathName =
57                                     "android/hardware/soundtrigger/SoundTrigger$ModuleProperties";
58static jclass gModulePropertiesClass;
59static jmethodID   gModulePropertiesCstor;
60
61static const char* const kSoundModelClassPathName =
62                                     "android/hardware/soundtrigger/SoundTrigger$SoundModel";
63static jclass gSoundModelClass;
64static struct {
65    jfieldID    uuid;
66    jfieldID    data;
67} gSoundModelFields;
68
69static const char* const kKeyphraseClassPathName =
70                                     "android/hardware/soundtrigger/SoundTrigger$Keyphrase";
71static jclass gKeyphraseClass;
72static struct {
73    jfieldID id;
74    jfieldID recognitionModes;
75    jfieldID locale;
76    jfieldID text;
77    jfieldID numUsers;
78} gKeyphraseFields;
79
80static const char* const kKeyphraseSoundModelClassPathName =
81                                 "android/hardware/soundtrigger/SoundTrigger$KeyphraseSoundModel";
82static jclass gKeyphraseSoundModelClass;
83static struct {
84    jfieldID    keyphrases;
85} gKeyphraseSoundModelFields;
86
87
88static const char* const kRecognitionEventClassPathName =
89                                     "android/hardware/soundtrigger/SoundTrigger$RecognitionEvent";
90static jclass gRecognitionEventClass;
91static jmethodID   gRecognitionEventCstor;
92
93static const char* const kKeyphraseRecognitionEventClassPathName =
94                             "android/hardware/soundtrigger/SoundTrigger$KeyphraseRecognitionEvent";
95static jclass gKeyphraseRecognitionEventClass;
96static jmethodID   gKeyphraseRecognitionEventCstor;
97
98static const char* const kKeyphraseRecognitionExtraClassPathName =
99                             "android/hardware/soundtrigger/SoundTrigger$KeyphraseRecognitionExtra";
100static jclass gKeyphraseRecognitionExtraClass;
101static jmethodID   gKeyphraseRecognitionExtraCstor;
102
103static Mutex gLock;
104
105enum {
106    SOUNDTRIGGER_STATUS_OK = 0,
107    SOUNDTRIGGER_STATUS_ERROR = INT_MIN,
108    SOUNDTRIGGER_PERMISSION_DENIED = -1,
109    SOUNDTRIGGER_STATUS_NO_INIT = -19,
110    SOUNDTRIGGER_STATUS_BAD_VALUE = -22,
111    SOUNDTRIGGER_STATUS_DEAD_OBJECT = -32,
112    SOUNDTRIGGER_INVALID_OPERATION = -38,
113};
114
115enum  {
116    SOUNDTRIGGER_EVENT_RECOGNITION = 1,
117    SOUNDTRIGGER_EVENT_SERVICE_DIED = 2,
118};
119
120// ----------------------------------------------------------------------------
121// ref-counted object for callbacks
122class JNISoundTriggerCallback: public SoundTriggerCallback
123{
124public:
125    JNISoundTriggerCallback(JNIEnv* env, jobject thiz, jobject weak_thiz);
126    ~JNISoundTriggerCallback();
127
128    virtual void onRecognitionEvent(struct sound_trigger_recognition_event *event);
129    virtual void onServiceDied();
130
131private:
132    jclass      mClass;     // Reference to SoundTrigger class
133    jobject     mObject;    // Weak ref to SoundTrigger Java object to call on
134};
135
136JNISoundTriggerCallback::JNISoundTriggerCallback(JNIEnv* env, jobject thiz, jobject weak_thiz)
137{
138
139    // Hold onto the SoundTriggerModule class for use in calling the static method
140    // that posts events to the application thread.
141    jclass clazz = env->GetObjectClass(thiz);
142    if (clazz == NULL) {
143        ALOGE("Can't find class %s", kModuleClassPathName);
144        return;
145    }
146    mClass = (jclass)env->NewGlobalRef(clazz);
147
148    // We use a weak reference so the SoundTriggerModule object can be garbage collected.
149    // The reference is only used as a proxy for callbacks.
150    mObject  = env->NewGlobalRef(weak_thiz);
151}
152
153JNISoundTriggerCallback::~JNISoundTriggerCallback()
154{
155    // remove global references
156    JNIEnv *env = AndroidRuntime::getJNIEnv();
157    env->DeleteGlobalRef(mObject);
158    env->DeleteGlobalRef(mClass);
159}
160
161void JNISoundTriggerCallback::onRecognitionEvent(struct sound_trigger_recognition_event *event)
162{
163    JNIEnv *env = AndroidRuntime::getJNIEnv();
164
165    jobject jEvent;
166
167    jbyteArray jData = NULL;
168    if (event->data_size) {
169        jData = env->NewByteArray(event->data_size);
170        jbyte *nData = env->GetByteArrayElements(jData, NULL);
171        memcpy(nData, (char *)event + event->data_offset, event->data_size);
172        env->ReleaseByteArrayElements(jData, nData, 0);
173    }
174
175    if (event->type == SOUND_MODEL_TYPE_KEYPHRASE) {
176        struct sound_trigger_phrase_recognition_event *phraseEvent =
177                (struct sound_trigger_phrase_recognition_event *)event;
178
179        jobjectArray jExtras = env->NewObjectArray(phraseEvent->num_phrases,
180                                                  gKeyphraseRecognitionExtraClass, NULL);
181        if (jExtras == NULL) {
182            return;
183        }
184
185        for (size_t i = 0; i < phraseEvent->num_phrases; i++) {
186            jintArray jConfidenceLevels = env->NewIntArray(phraseEvent->phrase_extras[i].num_users);
187            if (jConfidenceLevels == NULL) {
188                return;
189            }
190            jint *nConfidenceLevels = env->GetIntArrayElements(jConfidenceLevels, NULL);
191            memcpy(nConfidenceLevels,
192                   phraseEvent->phrase_extras[i].confidence_levels,
193                   phraseEvent->phrase_extras[i].num_users * sizeof(int));
194            env->ReleaseIntArrayElements(jConfidenceLevels, nConfidenceLevels, 0);
195            jobject jNewExtra = env->NewObject(gKeyphraseRecognitionExtraClass,
196                                               gKeyphraseRecognitionExtraCstor,
197                                               jConfidenceLevels,
198                                               phraseEvent->phrase_extras[i].recognition_modes);
199
200            if (jNewExtra == NULL) {
201                return;
202            }
203            env->SetObjectArrayElement(jExtras, i, jNewExtra);
204
205        }
206        jEvent = env->NewObject(gKeyphraseRecognitionEventClass, gKeyphraseRecognitionEventCstor,
207                                event->status, event->model, event->capture_available,
208                               event->capture_session, event->capture_delay_ms, jData,
209                               phraseEvent->key_phrase_in_capture, jExtras);
210    } else {
211        jEvent = env->NewObject(gRecognitionEventClass, gRecognitionEventCstor,
212                                event->status, event->model, event->capture_available,
213                                event->capture_session, event->capture_delay_ms, jData);
214    }
215
216
217    env->CallStaticVoidMethod(mClass, gPostEventFromNative, mObject,
218                              SOUNDTRIGGER_EVENT_RECOGNITION, 0, 0, jEvent);
219    if (env->ExceptionCheck()) {
220        ALOGW("An exception occurred while notifying an event.");
221        env->ExceptionClear();
222    }
223}
224
225void JNISoundTriggerCallback::onServiceDied()
226{
227    JNIEnv *env = AndroidRuntime::getJNIEnv();
228
229    env->CallStaticVoidMethod(mClass, gPostEventFromNative, mObject,
230                              SOUNDTRIGGER_EVENT_SERVICE_DIED, 0, 0, NULL);
231    if (env->ExceptionCheck()) {
232        ALOGW("An exception occurred while notifying an event.");
233        env->ExceptionClear();
234    }
235}
236
237// ----------------------------------------------------------------------------
238
239static sp<SoundTrigger> getSoundTrigger(JNIEnv* env, jobject thiz)
240{
241    Mutex::Autolock l(gLock);
242    SoundTrigger* const st = (SoundTrigger*)env->GetLongField(thiz,
243                                                         gModuleFields.mNativeContext);
244    return sp<SoundTrigger>(st);
245}
246
247static sp<SoundTrigger> setSoundTrigger(JNIEnv* env, jobject thiz, const sp<SoundTrigger>& module)
248{
249    Mutex::Autolock l(gLock);
250    sp<SoundTrigger> old = (SoundTrigger*)env->GetLongField(thiz,
251                                                         gModuleFields.mNativeContext);
252    if (module.get()) {
253        module->incStrong((void*)setSoundTrigger);
254    }
255    if (old != 0) {
256        old->decStrong((void*)setSoundTrigger);
257    }
258    env->SetLongField(thiz, gModuleFields.mNativeContext, (jlong)module.get());
259    return old;
260}
261
262
263static jint
264android_hardware_SoundTrigger_listModules(JNIEnv *env, jobject clazz,
265                                          jobject jModules)
266{
267    ALOGV("listModules");
268
269    if (jModules == NULL) {
270        ALOGE("listModules NULL AudioPatch ArrayList");
271        return SOUNDTRIGGER_STATUS_BAD_VALUE;
272    }
273    if (!env->IsInstanceOf(jModules, gArrayListClass)) {
274        ALOGE("listModules not an arraylist");
275        return SOUNDTRIGGER_STATUS_BAD_VALUE;
276    }
277
278    unsigned int numModules = 0;
279    struct sound_trigger_module_descriptor *nModules = NULL;
280
281    status_t status = SoundTrigger::listModules(nModules, &numModules);
282    if (status != NO_ERROR || numModules == 0) {
283        return (jint)status;
284    }
285
286    nModules = (struct sound_trigger_module_descriptor *)
287                            calloc(numModules, sizeof(struct sound_trigger_module_descriptor));
288
289    status = SoundTrigger::listModules(nModules, &numModules);
290    ALOGV("listModules SoundTrigger::listModules status %d numModules %d", status, numModules);
291
292    if (status != NO_ERROR) {
293        numModules = 0;
294    }
295
296    for (size_t i = 0; i < numModules; i++) {
297        char str[SOUND_TRIGGER_MAX_STRING_LEN];
298
299        jstring implementor = env->NewStringUTF(nModules[i].properties.implementor);
300        jstring description = env->NewStringUTF(nModules[i].properties.description);
301        SoundTrigger::guidToString(&nModules[i].properties.uuid,
302                                   str,
303                                   SOUND_TRIGGER_MAX_STRING_LEN);
304        jstring uuid = env->NewStringUTF(str);
305
306        ALOGV("listModules module %d id %d description %s maxSoundModels %d",
307              i, nModules[i].handle, nModules[i].properties.description,
308              nModules[i].properties.max_sound_models);
309
310        jobject newModuleDesc = env->NewObject(gModulePropertiesClass, gModulePropertiesCstor,
311                                               nModules[i].handle,
312                                               implementor, description, uuid,
313                                               nModules[i].properties.version,
314                                               nModules[i].properties.max_sound_models,
315                                               nModules[i].properties.max_key_phrases,
316                                               nModules[i].properties.max_users,
317                                               nModules[i].properties.recognition_modes,
318                                               nModules[i].properties.capture_transition,
319                                               nModules[i].properties.max_buffer_ms,
320                                               nModules[i].properties.concurrent_capture,
321                                               nModules[i].properties.power_consumption_mw);
322
323        env->DeleteLocalRef(implementor);
324        env->DeleteLocalRef(description);
325        env->DeleteLocalRef(uuid);
326        if (newModuleDesc == NULL) {
327            status = SOUNDTRIGGER_STATUS_ERROR;
328            goto exit;
329        }
330        env->CallBooleanMethod(jModules, gArrayListMethods.add, newModuleDesc);
331    }
332
333exit:
334    free(nModules);
335    return (jint) status;
336}
337
338static void
339android_hardware_SoundTrigger_setup(JNIEnv *env, jobject thiz, jobject weak_this)
340{
341    ALOGV("setup");
342
343    sp<JNISoundTriggerCallback> callback = new JNISoundTriggerCallback(env, thiz, weak_this);
344
345    sound_trigger_module_handle_t handle =
346            (sound_trigger_module_handle_t)env->GetIntField(thiz, gModuleFields.mId);
347
348    sp<SoundTrigger> module = SoundTrigger::attach(handle, callback);
349    if (module == 0) {
350        return;
351    }
352
353    setSoundTrigger(env, thiz, module);
354}
355
356static void
357android_hardware_SoundTrigger_detach(JNIEnv *env, jobject thiz)
358{
359    ALOGV("detach");
360    sp<SoundTrigger> module = setSoundTrigger(env, thiz, 0);
361    ALOGV("detach module %p", module.get());
362    if (module != 0) {
363        ALOGV("detach module->detach()");
364        module->detach();
365    }
366}
367
368static void
369android_hardware_SoundTrigger_finalize(JNIEnv *env, jobject thiz)
370{
371    ALOGV("finalize");
372    sp<SoundTrigger> module = getSoundTrigger(env, thiz);
373    if (module != 0) {
374        ALOGW("SoundTrigger finalized without being detached");
375    }
376    android_hardware_SoundTrigger_detach(env, thiz);
377}
378
379static jint
380android_hardware_SoundTrigger_loadSoundModel(JNIEnv *env, jobject thiz,
381                                             jobject jSoundModel, jintArray jHandle)
382{
383    jint status = SOUNDTRIGGER_STATUS_OK;
384    char *nData = NULL;
385    struct sound_trigger_sound_model *nSoundModel;
386    jbyteArray jData;
387    sp<MemoryDealer> memoryDealer;
388    sp<IMemory> memory;
389    size_t size;
390    sound_model_handle_t handle;
391    jobject jUuid;
392    jstring jUuidString;
393    const char *nUuidString;
394
395    ALOGV("loadSoundModel");
396    sp<SoundTrigger> module = getSoundTrigger(env, thiz);
397    if (module == NULL) {
398        return SOUNDTRIGGER_STATUS_ERROR;
399    }
400    if (jHandle == NULL) {
401        return SOUNDTRIGGER_STATUS_BAD_VALUE;
402    }
403    jsize jHandleLen = env->GetArrayLength(jHandle);
404    if (jHandleLen == 0) {
405        return SOUNDTRIGGER_STATUS_BAD_VALUE;
406    }
407    jint *nHandle = env->GetIntArrayElements(jHandle, NULL);
408    if (nHandle == NULL) {
409        return SOUNDTRIGGER_STATUS_ERROR;
410    }
411    if (!env->IsInstanceOf(jSoundModel, gSoundModelClass)) {
412        status = SOUNDTRIGGER_STATUS_BAD_VALUE;
413        goto exit;
414    }
415    size_t offset;
416    sound_trigger_sound_model_type_t type;
417    if (env->IsInstanceOf(jSoundModel, gKeyphraseSoundModelClass)) {
418        offset = sizeof(struct sound_trigger_phrase_sound_model);
419        type = SOUND_MODEL_TYPE_KEYPHRASE;
420    } else {
421        offset = sizeof(struct sound_trigger_sound_model);
422        type = SOUND_MODEL_TYPE_UNKNOWN;
423    }
424
425    jUuid = env->GetObjectField(jSoundModel, gSoundModelFields.uuid);
426    jUuidString = (jstring)env->CallObjectMethod(jUuid, gUUIDMethods.toString);
427    nUuidString = env->GetStringUTFChars(jUuidString, NULL);
428    sound_trigger_uuid_t nUuid;
429    SoundTrigger::stringToGuid(nUuidString, &nUuid);
430    env->ReleaseStringUTFChars(jUuidString, nUuidString);
431    env->DeleteLocalRef(jUuidString);
432
433    jData = (jbyteArray)env->GetObjectField(jSoundModel, gSoundModelFields.data);
434    if (jData == NULL) {
435        status = SOUNDTRIGGER_STATUS_BAD_VALUE;
436        goto exit;
437    }
438    size = env->GetArrayLength(jData);
439
440    nData = (char *)env->GetByteArrayElements(jData, NULL);
441    if (jData == NULL) {
442        status = SOUNDTRIGGER_STATUS_ERROR;
443        goto exit;
444    }
445
446    memoryDealer = new MemoryDealer(offset + size, "SoundTrigge-JNI::LoadModel");
447    if (memoryDealer == 0) {
448        status = SOUNDTRIGGER_STATUS_ERROR;
449        goto exit;
450    }
451    memory = memoryDealer->allocate(offset + size);
452    if (memory == 0 || memory->pointer() == NULL) {
453        status = SOUNDTRIGGER_STATUS_ERROR;
454        goto exit;
455    }
456
457    nSoundModel = (struct sound_trigger_sound_model *)memory->pointer();
458
459    nSoundModel->type = type;
460    nSoundModel->uuid = nUuid;
461    nSoundModel->data_size = size;
462    nSoundModel->data_offset = offset;
463    memcpy((char *)nSoundModel + offset, nData, size);
464    if (type == SOUND_MODEL_TYPE_KEYPHRASE) {
465        struct sound_trigger_phrase_sound_model *phraseModel =
466                (struct sound_trigger_phrase_sound_model *)nSoundModel;
467
468        jobjectArray jPhrases =
469            (jobjectArray)env->GetObjectField(jSoundModel, gKeyphraseSoundModelFields.keyphrases);
470        if (jPhrases == NULL) {
471            status = SOUNDTRIGGER_STATUS_BAD_VALUE;
472            goto exit;
473        }
474
475        size_t numPhrases = env->GetArrayLength(jPhrases);
476        phraseModel->num_phrases = numPhrases;
477        ALOGV("loadSoundModel numPhrases %d", numPhrases);
478        for (size_t i = 0; i < numPhrases; i++) {
479            jobject jPhrase = env->GetObjectArrayElement(jPhrases, i);
480            phraseModel->phrases[i].id =
481                                    env->GetIntField(jPhrase,gKeyphraseFields.id);
482            phraseModel->phrases[i].recognition_mode =
483                                    env->GetIntField(jPhrase,gKeyphraseFields.recognitionModes);
484            phraseModel->phrases[i].num_users =
485                                    env->GetIntField(jPhrase, gKeyphraseFields.numUsers);
486            jstring jLocale = (jstring)env->GetObjectField(jPhrase, gKeyphraseFields.locale);
487            const char *nLocale = env->GetStringUTFChars(jLocale, NULL);
488            strncpy(phraseModel->phrases[i].locale,
489                    nLocale,
490                    SOUND_TRIGGER_MAX_LOCALE_LEN);
491            jstring jText = (jstring)env->GetObjectField(jPhrase, gKeyphraseFields.text);
492            const char *nText = env->GetStringUTFChars(jText, NULL);
493            strncpy(phraseModel->phrases[i].text,
494                    nText,
495                    SOUND_TRIGGER_MAX_STRING_LEN);
496
497            env->ReleaseStringUTFChars(jLocale, nLocale);
498            env->DeleteLocalRef(jLocale);
499            env->ReleaseStringUTFChars(jText, nText);
500            env->DeleteLocalRef(jText);
501            ALOGV("loadSoundModel phrases %d text %s locale %s",
502                  i, phraseModel->phrases[i].text, phraseModel->phrases[i].locale);
503        }
504        env->DeleteLocalRef(jPhrases);
505    }
506    status = module->loadSoundModel(memory, &handle);
507    ALOGV("loadSoundModel status %d handle %d", status, handle);
508
509exit:
510    if (nHandle != NULL) {
511        nHandle[0] = (jint)handle;
512        env->ReleaseIntArrayElements(jHandle, nHandle, NULL);
513    }
514    if (nData != NULL) {
515        env->ReleaseByteArrayElements(jData, (jbyte *)nData, NULL);
516    }
517    return status;
518}
519
520static jint
521android_hardware_SoundTrigger_unloadSoundModel(JNIEnv *env, jobject thiz,
522                                               jint jHandle)
523{
524    jint status = SOUNDTRIGGER_STATUS_OK;
525    ALOGV("unloadSoundModel");
526    sp<SoundTrigger> module = getSoundTrigger(env, thiz);
527    if (module == NULL) {
528        return SOUNDTRIGGER_STATUS_ERROR;
529    }
530    status = module->unloadSoundModel((sound_model_handle_t)jHandle);
531
532    return status;
533}
534
535static jint
536android_hardware_SoundTrigger_startRecognition(JNIEnv *env, jobject thiz,
537                                               jint jHandle, jbyteArray jData)
538{
539    jint status = SOUNDTRIGGER_STATUS_OK;
540    ALOGV("startRecognition");
541    sp<SoundTrigger> module = getSoundTrigger(env, thiz);
542    if (module == NULL) {
543        return SOUNDTRIGGER_STATUS_ERROR;
544    }
545    jsize dataSize = 0;
546    char *nData = NULL;
547    sp<IMemory> memory;
548    if (jData != NULL) {
549        dataSize = env->GetArrayLength(jData);
550        if (dataSize == 0) {
551            return SOUNDTRIGGER_STATUS_BAD_VALUE;
552        }
553        nData = (char *)env->GetByteArrayElements(jData, NULL);
554        if (nData == NULL) {
555            return SOUNDTRIGGER_STATUS_ERROR;
556        }
557        sp<MemoryDealer> memoryDealer =
558                new MemoryDealer(dataSize, "SoundTrigge-JNI::StartRecognition");
559        if (memoryDealer == 0) {
560            return SOUNDTRIGGER_STATUS_ERROR;
561        }
562        memory = memoryDealer->allocate(dataSize);
563        if (memory == 0 || memory->pointer() == NULL) {
564            return SOUNDTRIGGER_STATUS_ERROR;
565        }
566        memcpy(memory->pointer(), nData, dataSize);
567    }
568
569    status = module->startRecognition(jHandle, memory);
570    return status;
571}
572
573static jint
574android_hardware_SoundTrigger_stopRecognition(JNIEnv *env, jobject thiz,
575                                               jint jHandle)
576{
577    jint status = SOUNDTRIGGER_STATUS_OK;
578    ALOGV("stopRecognition");
579    sp<SoundTrigger> module = getSoundTrigger(env, thiz);
580    if (module == NULL) {
581        return SOUNDTRIGGER_STATUS_ERROR;
582    }
583    status = module->stopRecognition(jHandle);
584    return status;
585}
586
587static JNINativeMethod gMethods[] = {
588    {"listModules",
589        "(Ljava/util/ArrayList;)I",
590        (void *)android_hardware_SoundTrigger_listModules},
591};
592
593
594static JNINativeMethod gModuleMethods[] = {
595    {"native_setup",
596        "(Ljava/lang/Object;)V",
597        (void *)android_hardware_SoundTrigger_setup},
598    {"native_finalize",
599        "()V",
600        (void *)android_hardware_SoundTrigger_finalize},
601    {"detach",
602        "()V",
603        (void *)android_hardware_SoundTrigger_detach},
604    {"loadSoundModel",
605        "(Landroid/hardware/soundtrigger/SoundTrigger$SoundModel;[I)I",
606        (void *)android_hardware_SoundTrigger_loadSoundModel},
607    {"unloadSoundModel",
608        "(I)I",
609        (void *)android_hardware_SoundTrigger_unloadSoundModel},
610    {"startRecognition",
611        "(I[B)I",
612        (void *)android_hardware_SoundTrigger_startRecognition},
613    {"stopRecognition",
614        "(I)I",
615        (void *)android_hardware_SoundTrigger_stopRecognition},
616};
617
618int register_android_hardware_SoundTrigger(JNIEnv *env)
619{
620    jclass arrayListClass = env->FindClass("java/util/ArrayList");
621    gArrayListClass = (jclass) env->NewGlobalRef(arrayListClass);
622    gArrayListMethods.add = env->GetMethodID(arrayListClass, "add", "(Ljava/lang/Object;)Z");
623
624    jclass uuidClass = env->FindClass("java/util/UUID");
625    gUUIDClass = (jclass) env->NewGlobalRef(uuidClass);
626    gUUIDMethods.toString = env->GetMethodID(uuidClass, "toString", "()Ljava/lang/String;");
627
628    jclass lClass = env->FindClass(kSoundTriggerClassPathName);
629    gSoundTriggerClass = (jclass) env->NewGlobalRef(lClass);
630
631    jclass moduleClass = env->FindClass(kModuleClassPathName);
632    gModuleClass = (jclass) env->NewGlobalRef(moduleClass);
633    gPostEventFromNative = env->GetStaticMethodID(moduleClass, "postEventFromNative",
634                                            "(Ljava/lang/Object;IIILjava/lang/Object;)V");
635    gModuleFields.mNativeContext = env->GetFieldID(moduleClass, "mNativeContext", "J");
636    gModuleFields.mId = env->GetFieldID(moduleClass, "mId", "I");
637
638
639    jclass modulePropertiesClass = env->FindClass(kModulePropertiesClassPathName);
640    gModulePropertiesClass = (jclass) env->NewGlobalRef(modulePropertiesClass);
641    gModulePropertiesCstor = env->GetMethodID(modulePropertiesClass, "<init>",
642                              "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;IIIIIZIZI)V");
643
644    jclass soundModelClass = env->FindClass(kSoundModelClassPathName);
645    gSoundModelClass = (jclass) env->NewGlobalRef(soundModelClass);
646    gSoundModelFields.uuid = env->GetFieldID(soundModelClass, "uuid", "Ljava/util/UUID;");
647    gSoundModelFields.data = env->GetFieldID(soundModelClass, "data", "[B");
648
649    jclass keyphraseClass = env->FindClass(kKeyphraseClassPathName);
650    gKeyphraseClass = (jclass) env->NewGlobalRef(keyphraseClass);
651    gKeyphraseFields.id = env->GetFieldID(keyphraseClass, "id", "I");
652    gKeyphraseFields.recognitionModes = env->GetFieldID(keyphraseClass, "recognitionModes", "I");
653    gKeyphraseFields.locale = env->GetFieldID(keyphraseClass, "locale", "Ljava/lang/String;");
654    gKeyphraseFields.text = env->GetFieldID(keyphraseClass, "text", "Ljava/lang/String;");
655    gKeyphraseFields.numUsers = env->GetFieldID(keyphraseClass, "numUsers", "I");
656
657    jclass keyphraseSoundModelClass = env->FindClass(kKeyphraseSoundModelClassPathName);
658    gKeyphraseSoundModelClass = (jclass) env->NewGlobalRef(keyphraseSoundModelClass);
659    gKeyphraseSoundModelFields.keyphrases = env->GetFieldID(keyphraseSoundModelClass,
660                                         "keyphrases",
661                                         "[Landroid/hardware/soundtrigger/SoundTrigger$Keyphrase;");
662
663
664    jclass recognitionEventClass = env->FindClass(kRecognitionEventClassPathName);
665    gRecognitionEventClass = (jclass) env->NewGlobalRef(recognitionEventClass);
666    gRecognitionEventCstor = env->GetMethodID(recognitionEventClass, "<init>",
667                                              "(IIZII[B)V");
668
669    jclass keyphraseRecognitionEventClass = env->FindClass(kKeyphraseRecognitionEventClassPathName);
670    gKeyphraseRecognitionEventClass = (jclass) env->NewGlobalRef(keyphraseRecognitionEventClass);
671    gKeyphraseRecognitionEventCstor = env->GetMethodID(keyphraseRecognitionEventClass, "<init>",
672              "(IIZII[BZ[Landroid/hardware/soundtrigger/SoundTrigger$KeyphraseRecognitionExtra;)V");
673
674
675    jclass keyphraseRecognitionExtraClass = env->FindClass(kKeyphraseRecognitionExtraClassPathName);
676    gKeyphraseRecognitionExtraClass = (jclass) env->NewGlobalRef(keyphraseRecognitionExtraClass);
677    gKeyphraseRecognitionExtraCstor = env->GetMethodID(keyphraseRecognitionExtraClass, "<init>",
678                                              "([II)V");
679
680    int status = AndroidRuntime::registerNativeMethods(env,
681                kSoundTriggerClassPathName, gMethods, NELEM(gMethods));
682
683    if (status == 0) {
684        status = AndroidRuntime::registerNativeMethods(env,
685                kModuleClassPathName, gModuleMethods, NELEM(gModuleMethods));
686    }
687
688    return status;
689}
690