android_hardware_SoundTrigger.cpp revision 013f66b92db609fceeff9c8171daca13d057cc95
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 users;
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
87static const char* const kRecognitionConfigClassPathName =
88                                     "android/hardware/soundtrigger/SoundTrigger$RecognitionConfig";
89static jclass gRecognitionConfigClass;
90static struct {
91    jfieldID captureRequested;
92    jfieldID keyphrases;
93    jfieldID data;
94} gRecognitionConfigFields;
95
96static const char* const kRecognitionEventClassPathName =
97                                     "android/hardware/soundtrigger/SoundTrigger$RecognitionEvent";
98static jclass gRecognitionEventClass;
99static jmethodID   gRecognitionEventCstor;
100
101static const char* const kKeyphraseRecognitionEventClassPathName =
102                             "android/hardware/soundtrigger/SoundTrigger$KeyphraseRecognitionEvent";
103static jclass gKeyphraseRecognitionEventClass;
104static jmethodID   gKeyphraseRecognitionEventCstor;
105
106static const char* const kKeyphraseRecognitionExtraClassPathName =
107                             "android/hardware/soundtrigger/SoundTrigger$KeyphraseRecognitionExtra";
108static jclass gKeyphraseRecognitionExtraClass;
109static jmethodID   gKeyphraseRecognitionExtraCstor;
110static struct {
111    jfieldID id;
112    jfieldID recognitionModes;
113    jfieldID confidenceLevels;
114} gKeyphraseRecognitionExtraFields;
115
116static const char* const kConfidenceLevelClassPathName =
117                             "android/hardware/soundtrigger/SoundTrigger$ConfidenceLevel";
118static jclass gConfidenceLevelClass;
119static jmethodID   gConfidenceLevelCstor;
120static struct {
121    jfieldID userId;
122    jfieldID confidenceLevel;
123} gConfidenceLevelFields;
124
125static Mutex gLock;
126
127enum {
128    SOUNDTRIGGER_STATUS_OK = 0,
129    SOUNDTRIGGER_STATUS_ERROR = INT_MIN,
130    SOUNDTRIGGER_PERMISSION_DENIED = -1,
131    SOUNDTRIGGER_STATUS_NO_INIT = -19,
132    SOUNDTRIGGER_STATUS_BAD_VALUE = -22,
133    SOUNDTRIGGER_STATUS_DEAD_OBJECT = -32,
134    SOUNDTRIGGER_INVALID_OPERATION = -38,
135};
136
137enum  {
138    SOUNDTRIGGER_EVENT_RECOGNITION = 1,
139    SOUNDTRIGGER_EVENT_SERVICE_DIED = 2,
140};
141
142// ----------------------------------------------------------------------------
143// ref-counted object for callbacks
144class JNISoundTriggerCallback: public SoundTriggerCallback
145{
146public:
147    JNISoundTriggerCallback(JNIEnv* env, jobject thiz, jobject weak_thiz);
148    ~JNISoundTriggerCallback();
149
150    virtual void onRecognitionEvent(struct sound_trigger_recognition_event *event);
151    virtual void onServiceDied();
152
153private:
154    jclass      mClass;     // Reference to SoundTrigger class
155    jobject     mObject;    // Weak ref to SoundTrigger Java object to call on
156};
157
158JNISoundTriggerCallback::JNISoundTriggerCallback(JNIEnv* env, jobject thiz, jobject weak_thiz)
159{
160
161    // Hold onto the SoundTriggerModule class for use in calling the static method
162    // that posts events to the application thread.
163    jclass clazz = env->GetObjectClass(thiz);
164    if (clazz == NULL) {
165        ALOGE("Can't find class %s", kModuleClassPathName);
166        return;
167    }
168    mClass = (jclass)env->NewGlobalRef(clazz);
169
170    // We use a weak reference so the SoundTriggerModule object can be garbage collected.
171    // The reference is only used as a proxy for callbacks.
172    mObject  = env->NewGlobalRef(weak_thiz);
173}
174
175JNISoundTriggerCallback::~JNISoundTriggerCallback()
176{
177    // remove global references
178    JNIEnv *env = AndroidRuntime::getJNIEnv();
179    env->DeleteGlobalRef(mObject);
180    env->DeleteGlobalRef(mClass);
181}
182
183void JNISoundTriggerCallback::onRecognitionEvent(struct sound_trigger_recognition_event *event)
184{
185    JNIEnv *env = AndroidRuntime::getJNIEnv();
186
187    jobject jEvent;
188
189    jbyteArray jData = NULL;
190    if (event->data_size) {
191        jData = env->NewByteArray(event->data_size);
192        jbyte *nData = env->GetByteArrayElements(jData, NULL);
193        memcpy(nData, (char *)event + event->data_offset, event->data_size);
194        env->ReleaseByteArrayElements(jData, nData, 0);
195    }
196
197    if (event->type == SOUND_MODEL_TYPE_KEYPHRASE) {
198        struct sound_trigger_phrase_recognition_event *phraseEvent =
199                (struct sound_trigger_phrase_recognition_event *)event;
200
201        jobjectArray jExtras = env->NewObjectArray(phraseEvent->num_phrases,
202                                                  gKeyphraseRecognitionExtraClass, NULL);
203        if (jExtras == NULL) {
204            return;
205        }
206
207        for (size_t i = 0; i < phraseEvent->num_phrases; i++) {
208            jobjectArray jConfidenceLevels = env->NewObjectArray(
209                                                        phraseEvent->phrase_extras[i].num_levels,
210                                                        gConfidenceLevelClass, NULL);
211
212            if (jConfidenceLevels == NULL) {
213                return;
214            }
215            for (size_t j = 0; j < phraseEvent->phrase_extras[i].num_levels; j++) {
216                jobject jConfidenceLevel = env->NewObject(gConfidenceLevelClass,
217                                                  gConfidenceLevelCstor,
218                                                  phraseEvent->phrase_extras[i].levels[j].user_id,
219                                                  phraseEvent->phrase_extras[i].levels[j].level);
220                env->SetObjectArrayElement(jConfidenceLevels, j, jConfidenceLevel);
221                env->DeleteLocalRef(jConfidenceLevel);
222            }
223
224            jobject jNewExtra = env->NewObject(gKeyphraseRecognitionExtraClass,
225                                               gKeyphraseRecognitionExtraCstor,
226                                               phraseEvent->phrase_extras[i].id,
227                                               phraseEvent->phrase_extras[i].recognition_modes,
228                                               jConfidenceLevels);
229
230            if (jNewExtra == NULL) {
231                return;
232            }
233            env->SetObjectArrayElement(jExtras, i, jNewExtra);
234            env->DeleteLocalRef(jNewExtra);
235            env->DeleteLocalRef(jConfidenceLevels);
236        }
237        jEvent = env->NewObject(gKeyphraseRecognitionEventClass, gKeyphraseRecognitionEventCstor,
238                                event->status, event->model, event->capture_available,
239                               event->capture_session, event->capture_delay_ms,
240                               event->capture_preamble_ms, jData,
241                               phraseEvent->key_phrase_in_capture, jExtras);
242    } else {
243        jEvent = env->NewObject(gRecognitionEventClass, gRecognitionEventCstor,
244                                event->status, event->model, event->capture_available,
245                                event->capture_session, event->capture_delay_ms,
246                                event->capture_preamble_ms, jData);
247    }
248
249
250    env->CallStaticVoidMethod(mClass, gPostEventFromNative, mObject,
251                              SOUNDTRIGGER_EVENT_RECOGNITION, 0, 0, jEvent);
252    if (env->ExceptionCheck()) {
253        ALOGW("An exception occurred while notifying an event.");
254        env->ExceptionClear();
255    }
256}
257
258void JNISoundTriggerCallback::onServiceDied()
259{
260    JNIEnv *env = AndroidRuntime::getJNIEnv();
261
262    env->CallStaticVoidMethod(mClass, gPostEventFromNative, mObject,
263                              SOUNDTRIGGER_EVENT_SERVICE_DIED, 0, 0, NULL);
264    if (env->ExceptionCheck()) {
265        ALOGW("An exception occurred while notifying an event.");
266        env->ExceptionClear();
267    }
268}
269
270// ----------------------------------------------------------------------------
271
272static sp<SoundTrigger> getSoundTrigger(JNIEnv* env, jobject thiz)
273{
274    Mutex::Autolock l(gLock);
275    SoundTrigger* const st = (SoundTrigger*)env->GetLongField(thiz,
276                                                         gModuleFields.mNativeContext);
277    return sp<SoundTrigger>(st);
278}
279
280static sp<SoundTrigger> setSoundTrigger(JNIEnv* env, jobject thiz, const sp<SoundTrigger>& module)
281{
282    Mutex::Autolock l(gLock);
283    sp<SoundTrigger> old = (SoundTrigger*)env->GetLongField(thiz,
284                                                         gModuleFields.mNativeContext);
285    if (module.get()) {
286        module->incStrong((void*)setSoundTrigger);
287    }
288    if (old != 0) {
289        old->decStrong((void*)setSoundTrigger);
290    }
291    env->SetLongField(thiz, gModuleFields.mNativeContext, (jlong)module.get());
292    return old;
293}
294
295
296static jint
297android_hardware_SoundTrigger_listModules(JNIEnv *env, jobject clazz,
298                                          jobject jModules)
299{
300    ALOGV("listModules");
301
302    if (jModules == NULL) {
303        ALOGE("listModules NULL AudioPatch ArrayList");
304        return SOUNDTRIGGER_STATUS_BAD_VALUE;
305    }
306    if (!env->IsInstanceOf(jModules, gArrayListClass)) {
307        ALOGE("listModules not an arraylist");
308        return SOUNDTRIGGER_STATUS_BAD_VALUE;
309    }
310
311    unsigned int numModules = 0;
312    struct sound_trigger_module_descriptor *nModules = NULL;
313
314    status_t status = SoundTrigger::listModules(nModules, &numModules);
315    if (status != NO_ERROR || numModules == 0) {
316        return (jint)status;
317    }
318
319    nModules = (struct sound_trigger_module_descriptor *)
320                            calloc(numModules, sizeof(struct sound_trigger_module_descriptor));
321
322    status = SoundTrigger::listModules(nModules, &numModules);
323    ALOGV("listModules SoundTrigger::listModules status %d numModules %d", status, numModules);
324
325    if (status != NO_ERROR) {
326        numModules = 0;
327    }
328
329    for (size_t i = 0; i < numModules; i++) {
330        char str[SOUND_TRIGGER_MAX_STRING_LEN];
331
332        jstring implementor = env->NewStringUTF(nModules[i].properties.implementor);
333        jstring description = env->NewStringUTF(nModules[i].properties.description);
334        SoundTrigger::guidToString(&nModules[i].properties.uuid,
335                                   str,
336                                   SOUND_TRIGGER_MAX_STRING_LEN);
337        jstring uuid = env->NewStringUTF(str);
338
339        ALOGV("listModules module %d id %d description %s maxSoundModels %d",
340              i, nModules[i].handle, nModules[i].properties.description,
341              nModules[i].properties.max_sound_models);
342
343        jobject newModuleDesc = env->NewObject(gModulePropertiesClass, gModulePropertiesCstor,
344                                               nModules[i].handle,
345                                               implementor, description, uuid,
346                                               nModules[i].properties.version,
347                                               nModules[i].properties.max_sound_models,
348                                               nModules[i].properties.max_key_phrases,
349                                               nModules[i].properties.max_users,
350                                               nModules[i].properties.recognition_modes,
351                                               nModules[i].properties.capture_transition,
352                                               nModules[i].properties.max_buffer_ms,
353                                               nModules[i].properties.concurrent_capture,
354                                               nModules[i].properties.power_consumption_mw);
355
356        env->DeleteLocalRef(implementor);
357        env->DeleteLocalRef(description);
358        env->DeleteLocalRef(uuid);
359        if (newModuleDesc == NULL) {
360            status = SOUNDTRIGGER_STATUS_ERROR;
361            goto exit;
362        }
363        env->CallBooleanMethod(jModules, gArrayListMethods.add, newModuleDesc);
364    }
365
366exit:
367    free(nModules);
368    return (jint) status;
369}
370
371static void
372android_hardware_SoundTrigger_setup(JNIEnv *env, jobject thiz, jobject weak_this)
373{
374    ALOGV("setup");
375
376    sp<JNISoundTriggerCallback> callback = new JNISoundTriggerCallback(env, thiz, weak_this);
377
378    sound_trigger_module_handle_t handle =
379            (sound_trigger_module_handle_t)env->GetIntField(thiz, gModuleFields.mId);
380
381    sp<SoundTrigger> module = SoundTrigger::attach(handle, callback);
382    if (module == 0) {
383        return;
384    }
385
386    setSoundTrigger(env, thiz, module);
387}
388
389static void
390android_hardware_SoundTrigger_detach(JNIEnv *env, jobject thiz)
391{
392    ALOGV("detach");
393    sp<SoundTrigger> module = setSoundTrigger(env, thiz, 0);
394    ALOGV("detach module %p", module.get());
395    if (module != 0) {
396        ALOGV("detach module->detach()");
397        module->detach();
398    }
399}
400
401static void
402android_hardware_SoundTrigger_finalize(JNIEnv *env, jobject thiz)
403{
404    ALOGV("finalize");
405    sp<SoundTrigger> module = getSoundTrigger(env, thiz);
406    if (module != 0) {
407        ALOGW("SoundTrigger finalized without being detached");
408    }
409    android_hardware_SoundTrigger_detach(env, thiz);
410}
411
412static jint
413android_hardware_SoundTrigger_loadSoundModel(JNIEnv *env, jobject thiz,
414                                             jobject jSoundModel, jintArray jHandle)
415{
416    jint status = SOUNDTRIGGER_STATUS_OK;
417    jbyte *nData = NULL;
418    struct sound_trigger_sound_model *nSoundModel;
419    jbyteArray jData;
420    sp<MemoryDealer> memoryDealer;
421    sp<IMemory> memory;
422    size_t size;
423    sound_model_handle_t handle;
424    jobject jUuid;
425    jstring jUuidString;
426    const char *nUuidString;
427
428    ALOGV("loadSoundModel");
429    sp<SoundTrigger> module = getSoundTrigger(env, thiz);
430    if (module == NULL) {
431        return SOUNDTRIGGER_STATUS_ERROR;
432    }
433    if (jHandle == NULL) {
434        return SOUNDTRIGGER_STATUS_BAD_VALUE;
435    }
436    jsize jHandleLen = env->GetArrayLength(jHandle);
437    if (jHandleLen == 0) {
438        return SOUNDTRIGGER_STATUS_BAD_VALUE;
439    }
440    jint *nHandle = env->GetIntArrayElements(jHandle, NULL);
441    if (nHandle == NULL) {
442        return SOUNDTRIGGER_STATUS_ERROR;
443    }
444    if (!env->IsInstanceOf(jSoundModel, gSoundModelClass)) {
445        status = SOUNDTRIGGER_STATUS_BAD_VALUE;
446        goto exit;
447    }
448    size_t offset;
449    sound_trigger_sound_model_type_t type;
450    if (env->IsInstanceOf(jSoundModel, gKeyphraseSoundModelClass)) {
451        offset = sizeof(struct sound_trigger_phrase_sound_model);
452        type = SOUND_MODEL_TYPE_KEYPHRASE;
453    } else {
454        offset = sizeof(struct sound_trigger_sound_model);
455        type = SOUND_MODEL_TYPE_UNKNOWN;
456    }
457
458    jUuid = env->GetObjectField(jSoundModel, gSoundModelFields.uuid);
459    jUuidString = (jstring)env->CallObjectMethod(jUuid, gUUIDMethods.toString);
460    nUuidString = env->GetStringUTFChars(jUuidString, NULL);
461    sound_trigger_uuid_t nUuid;
462    SoundTrigger::stringToGuid(nUuidString, &nUuid);
463    env->ReleaseStringUTFChars(jUuidString, nUuidString);
464    env->DeleteLocalRef(jUuidString);
465
466    jData = (jbyteArray)env->GetObjectField(jSoundModel, gSoundModelFields.data);
467    if (jData == NULL) {
468        status = SOUNDTRIGGER_STATUS_BAD_VALUE;
469        goto exit;
470    }
471    size = env->GetArrayLength(jData);
472
473    nData = env->GetByteArrayElements(jData, NULL);
474    if (jData == NULL) {
475        status = SOUNDTRIGGER_STATUS_ERROR;
476        goto exit;
477    }
478
479    memoryDealer = new MemoryDealer(offset + size, "SoundTrigge-JNI::LoadModel");
480    if (memoryDealer == 0) {
481        status = SOUNDTRIGGER_STATUS_ERROR;
482        goto exit;
483    }
484    memory = memoryDealer->allocate(offset + size);
485    if (memory == 0 || memory->pointer() == NULL) {
486        status = SOUNDTRIGGER_STATUS_ERROR;
487        goto exit;
488    }
489
490    nSoundModel = (struct sound_trigger_sound_model *)memory->pointer();
491
492    nSoundModel->type = type;
493    nSoundModel->uuid = nUuid;
494    nSoundModel->data_size = size;
495    nSoundModel->data_offset = offset;
496    memcpy((char *)nSoundModel + offset, nData, size);
497    if (type == SOUND_MODEL_TYPE_KEYPHRASE) {
498        struct sound_trigger_phrase_sound_model *phraseModel =
499                (struct sound_trigger_phrase_sound_model *)nSoundModel;
500
501        jobjectArray jPhrases =
502            (jobjectArray)env->GetObjectField(jSoundModel, gKeyphraseSoundModelFields.keyphrases);
503        if (jPhrases == NULL) {
504            status = SOUNDTRIGGER_STATUS_BAD_VALUE;
505            goto exit;
506        }
507
508        size_t numPhrases = env->GetArrayLength(jPhrases);
509        phraseModel->num_phrases = numPhrases;
510        ALOGV("loadSoundModel numPhrases %d", numPhrases);
511        for (size_t i = 0; i < numPhrases; i++) {
512            jobject jPhrase = env->GetObjectArrayElement(jPhrases, i);
513            phraseModel->phrases[i].id =
514                                    env->GetIntField(jPhrase,gKeyphraseFields.id);
515            phraseModel->phrases[i].recognition_mode =
516                                    env->GetIntField(jPhrase,gKeyphraseFields.recognitionModes);
517
518            jintArray jUsers = (jintArray)env->GetObjectField(jPhrase, gKeyphraseFields.users);
519            phraseModel->phrases[i].num_users = env->GetArrayLength(jUsers);
520            jint *nUsers = env->GetIntArrayElements(jUsers, NULL);
521            memcpy(phraseModel->phrases[i].users,
522                   nUsers,
523                   phraseModel->phrases[i].num_users * sizeof(int));
524            env->ReleaseIntArrayElements(jUsers, nUsers, 0);
525            env->DeleteLocalRef(jUsers);
526
527            jstring jLocale = (jstring)env->GetObjectField(jPhrase, gKeyphraseFields.locale);
528            const char *nLocale = env->GetStringUTFChars(jLocale, NULL);
529            strncpy(phraseModel->phrases[i].locale,
530                    nLocale,
531                    SOUND_TRIGGER_MAX_LOCALE_LEN);
532            jstring jText = (jstring)env->GetObjectField(jPhrase, gKeyphraseFields.text);
533            const char *nText = env->GetStringUTFChars(jText, NULL);
534            strncpy(phraseModel->phrases[i].text,
535                    nText,
536                    SOUND_TRIGGER_MAX_STRING_LEN);
537
538            env->ReleaseStringUTFChars(jLocale, nLocale);
539            env->DeleteLocalRef(jLocale);
540            env->ReleaseStringUTFChars(jText, nText);
541            env->DeleteLocalRef(jText);
542            ALOGV("loadSoundModel phrases %d text %s locale %s",
543                  i, phraseModel->phrases[i].text, phraseModel->phrases[i].locale);
544            env->DeleteLocalRef(jPhrase);
545        }
546        env->DeleteLocalRef(jPhrases);
547    }
548    status = module->loadSoundModel(memory, &handle);
549    ALOGV("loadSoundModel status %d handle %d", status, handle);
550
551exit:
552    if (nHandle != NULL) {
553        nHandle[0] = (jint)handle;
554        env->ReleaseIntArrayElements(jHandle, nHandle, NULL);
555    }
556    if (nData != NULL) {
557        env->ReleaseByteArrayElements(jData, nData, NULL);
558    }
559    return status;
560}
561
562static jint
563android_hardware_SoundTrigger_unloadSoundModel(JNIEnv *env, jobject thiz,
564                                               jint jHandle)
565{
566    jint status = SOUNDTRIGGER_STATUS_OK;
567    ALOGV("unloadSoundModel");
568    sp<SoundTrigger> module = getSoundTrigger(env, thiz);
569    if (module == NULL) {
570        return SOUNDTRIGGER_STATUS_ERROR;
571    }
572    status = module->unloadSoundModel((sound_model_handle_t)jHandle);
573
574    return status;
575}
576
577static jint
578android_hardware_SoundTrigger_startRecognition(JNIEnv *env, jobject thiz,
579                                               jint jHandle, jobject jConfig)
580{
581    jint status = SOUNDTRIGGER_STATUS_OK;
582    ALOGV("startRecognition");
583    sp<SoundTrigger> module = getSoundTrigger(env, thiz);
584    if (module == NULL) {
585        return SOUNDTRIGGER_STATUS_ERROR;
586    }
587
588    if (!env->IsInstanceOf(jConfig, gRecognitionConfigClass)) {
589        return SOUNDTRIGGER_STATUS_BAD_VALUE;
590    }
591
592    jbyteArray jData = (jbyteArray)env->GetObjectField(jConfig, gRecognitionConfigFields.data);
593    jsize dataSize = 0;
594    jbyte *nData = NULL;
595    if (jData != NULL) {
596        dataSize = env->GetArrayLength(jData);
597        if (dataSize == 0) {
598            return SOUNDTRIGGER_STATUS_BAD_VALUE;
599        }
600        nData = env->GetByteArrayElements(jData, NULL);
601        if (nData == NULL) {
602            return SOUNDTRIGGER_STATUS_ERROR;
603        }
604    }
605
606    size_t totalSize = sizeof(struct sound_trigger_recognition_config) + dataSize;
607    sp<MemoryDealer> memoryDealer =
608            new MemoryDealer(totalSize, "SoundTrigge-JNI::StartRecognition");
609    if (memoryDealer == 0) {
610        return SOUNDTRIGGER_STATUS_ERROR;
611    }
612    sp<IMemory> memory = memoryDealer->allocate(totalSize);
613    if (memory == 0 || memory->pointer() == NULL) {
614        return SOUNDTRIGGER_STATUS_ERROR;
615    }
616    if (dataSize != 0) {
617        memcpy((char *)memory->pointer() + sizeof(struct sound_trigger_recognition_config),
618                nData,
619                dataSize);
620        env->ReleaseByteArrayElements(jData, nData, 0);
621    }
622    env->DeleteLocalRef(jData);
623    struct sound_trigger_recognition_config *config =
624                                    (struct sound_trigger_recognition_config *)memory->pointer();
625    config->data_size = dataSize;
626    config->data_offset = sizeof(struct sound_trigger_recognition_config);
627    config->capture_requested = env->GetIntField(jConfig,
628                                                 gRecognitionConfigFields.captureRequested);
629
630    config->num_phrases = 0;
631    jobjectArray jPhrases =
632        (jobjectArray)env->GetObjectField(jConfig, gRecognitionConfigFields.keyphrases);
633    if (jPhrases != NULL) {
634        config->num_phrases = env->GetArrayLength(jPhrases);
635    }
636    ALOGV("startRecognition num phrases %d", config->num_phrases);
637    for (size_t i = 0; i < config->num_phrases; i++) {
638        jobject jPhrase = env->GetObjectArrayElement(jPhrases, i);
639        config->phrases[i].id = env->GetIntField(jPhrase,
640                                                gKeyphraseRecognitionExtraFields.id);
641        config->phrases[i].recognition_modes = env->GetIntField(jPhrase,
642                                                gKeyphraseRecognitionExtraFields.recognitionModes);
643        config->phrases[i].num_levels = 0;
644        jobjectArray jConfidenceLevels = (jobjectArray)env->GetObjectField(jPhrase,
645                                                gKeyphraseRecognitionExtraFields.confidenceLevels);
646        if (jConfidenceLevels != NULL) {
647            config->phrases[i].num_levels = env->GetArrayLength(jConfidenceLevels);
648        }
649        ALOGV("startRecognition phrase %d num_levels %d", i, config->phrases[i].num_levels);
650        for (size_t j = 0; j < config->phrases[i].num_levels; j++) {
651            jobject jConfidenceLevel = env->GetObjectArrayElement(jConfidenceLevels, j);
652            config->phrases[i].levels[j].user_id = env->GetIntField(jConfidenceLevel,
653                                                                    gConfidenceLevelFields.userId);
654            config->phrases[i].levels[j].level = env->GetIntField(jConfidenceLevel,
655                                                          gConfidenceLevelFields.confidenceLevel);
656            env->DeleteLocalRef(jConfidenceLevel);
657        }
658        ALOGV("startRecognition phrases %d", i);
659        env->DeleteLocalRef(jConfidenceLevels);
660        env->DeleteLocalRef(jPhrase);
661    }
662    env->DeleteLocalRef(jPhrases);
663
664    status = module->startRecognition(jHandle, memory);
665    return status;
666}
667
668static jint
669android_hardware_SoundTrigger_stopRecognition(JNIEnv *env, jobject thiz,
670                                               jint jHandle)
671{
672    jint status = SOUNDTRIGGER_STATUS_OK;
673    ALOGV("stopRecognition");
674    sp<SoundTrigger> module = getSoundTrigger(env, thiz);
675    if (module == NULL) {
676        return SOUNDTRIGGER_STATUS_ERROR;
677    }
678    status = module->stopRecognition(jHandle);
679    return status;
680}
681
682static JNINativeMethod gMethods[] = {
683    {"listModules",
684        "(Ljava/util/ArrayList;)I",
685        (void *)android_hardware_SoundTrigger_listModules},
686};
687
688
689static JNINativeMethod gModuleMethods[] = {
690    {"native_setup",
691        "(Ljava/lang/Object;)V",
692        (void *)android_hardware_SoundTrigger_setup},
693    {"native_finalize",
694        "()V",
695        (void *)android_hardware_SoundTrigger_finalize},
696    {"detach",
697        "()V",
698        (void *)android_hardware_SoundTrigger_detach},
699    {"loadSoundModel",
700        "(Landroid/hardware/soundtrigger/SoundTrigger$SoundModel;[I)I",
701        (void *)android_hardware_SoundTrigger_loadSoundModel},
702    {"unloadSoundModel",
703        "(I)I",
704        (void *)android_hardware_SoundTrigger_unloadSoundModel},
705    {"startRecognition",
706        "(ILandroid/hardware/soundtrigger/SoundTrigger$RecognitionConfig;)I",
707        (void *)android_hardware_SoundTrigger_startRecognition},
708    {"stopRecognition",
709        "(I)I",
710        (void *)android_hardware_SoundTrigger_stopRecognition},
711};
712
713int register_android_hardware_SoundTrigger(JNIEnv *env)
714{
715    jclass arrayListClass = env->FindClass("java/util/ArrayList");
716    gArrayListClass = (jclass) env->NewGlobalRef(arrayListClass);
717    gArrayListMethods.add = env->GetMethodID(arrayListClass, "add", "(Ljava/lang/Object;)Z");
718
719    jclass uuidClass = env->FindClass("java/util/UUID");
720    gUUIDClass = (jclass) env->NewGlobalRef(uuidClass);
721    gUUIDMethods.toString = env->GetMethodID(uuidClass, "toString", "()Ljava/lang/String;");
722
723    jclass lClass = env->FindClass(kSoundTriggerClassPathName);
724    gSoundTriggerClass = (jclass) env->NewGlobalRef(lClass);
725
726    jclass moduleClass = env->FindClass(kModuleClassPathName);
727    gModuleClass = (jclass) env->NewGlobalRef(moduleClass);
728    gPostEventFromNative = env->GetStaticMethodID(moduleClass, "postEventFromNative",
729                                            "(Ljava/lang/Object;IIILjava/lang/Object;)V");
730    gModuleFields.mNativeContext = env->GetFieldID(moduleClass, "mNativeContext", "J");
731    gModuleFields.mId = env->GetFieldID(moduleClass, "mId", "I");
732
733
734    jclass modulePropertiesClass = env->FindClass(kModulePropertiesClassPathName);
735    gModulePropertiesClass = (jclass) env->NewGlobalRef(modulePropertiesClass);
736    gModulePropertiesCstor = env->GetMethodID(modulePropertiesClass, "<init>",
737                              "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;IIIIIZIZI)V");
738
739    jclass soundModelClass = env->FindClass(kSoundModelClassPathName);
740    gSoundModelClass = (jclass) env->NewGlobalRef(soundModelClass);
741    gSoundModelFields.uuid = env->GetFieldID(soundModelClass, "uuid", "Ljava/util/UUID;");
742    gSoundModelFields.data = env->GetFieldID(soundModelClass, "data", "[B");
743
744    jclass keyphraseClass = env->FindClass(kKeyphraseClassPathName);
745    gKeyphraseClass = (jclass) env->NewGlobalRef(keyphraseClass);
746    gKeyphraseFields.id = env->GetFieldID(keyphraseClass, "id", "I");
747    gKeyphraseFields.recognitionModes = env->GetFieldID(keyphraseClass, "recognitionModes", "I");
748    gKeyphraseFields.locale = env->GetFieldID(keyphraseClass, "locale", "Ljava/lang/String;");
749    gKeyphraseFields.text = env->GetFieldID(keyphraseClass, "text", "Ljava/lang/String;");
750    gKeyphraseFields.users = env->GetFieldID(keyphraseClass, "users", "[I");
751
752    jclass keyphraseSoundModelClass = env->FindClass(kKeyphraseSoundModelClassPathName);
753    gKeyphraseSoundModelClass = (jclass) env->NewGlobalRef(keyphraseSoundModelClass);
754    gKeyphraseSoundModelFields.keyphrases = env->GetFieldID(keyphraseSoundModelClass,
755                                         "keyphrases",
756                                         "[Landroid/hardware/soundtrigger/SoundTrigger$Keyphrase;");
757
758
759    jclass recognitionEventClass = env->FindClass(kRecognitionEventClassPathName);
760    gRecognitionEventClass = (jclass) env->NewGlobalRef(recognitionEventClass);
761    gRecognitionEventCstor = env->GetMethodID(recognitionEventClass, "<init>",
762                                              "(IIZIII[B)V");
763
764    jclass keyphraseRecognitionEventClass = env->FindClass(kKeyphraseRecognitionEventClassPathName);
765    gKeyphraseRecognitionEventClass = (jclass) env->NewGlobalRef(keyphraseRecognitionEventClass);
766    gKeyphraseRecognitionEventCstor = env->GetMethodID(keyphraseRecognitionEventClass, "<init>",
767              "(IIZIII[BZ[Landroid/hardware/soundtrigger/SoundTrigger$KeyphraseRecognitionExtra;)V");
768
769
770    jclass keyRecognitionConfigClass = env->FindClass(kRecognitionConfigClassPathName);
771    gRecognitionConfigClass = (jclass) env->NewGlobalRef(keyRecognitionConfigClass);
772    gRecognitionConfigFields.captureRequested = env->GetFieldID(keyRecognitionConfigClass,
773                                                              "captureRequested",
774                                                              "Z");
775    gRecognitionConfigFields.keyphrases = env->GetFieldID(keyRecognitionConfigClass,
776                        "keyphrases",
777                        "[Landroid/hardware/soundtrigger/SoundTrigger$KeyphraseRecognitionExtra;");
778    gRecognitionConfigFields.data = env->GetFieldID(keyRecognitionConfigClass,
779                                                              "data",
780                                                              "[B");
781
782    jclass keyphraseRecognitionExtraClass = env->FindClass(kKeyphraseRecognitionExtraClassPathName);
783    gKeyphraseRecognitionExtraClass = (jclass) env->NewGlobalRef(keyphraseRecognitionExtraClass);
784    gKeyphraseRecognitionExtraCstor = env->GetMethodID(keyphraseRecognitionExtraClass, "<init>",
785                           "(II[Landroid/hardware/soundtrigger/SoundTrigger$ConfidenceLevel;)V");
786    gKeyphraseRecognitionExtraFields.id = env->GetFieldID(gKeyphraseRecognitionExtraClass, "id", "I");
787    gKeyphraseRecognitionExtraFields.recognitionModes = env->GetFieldID(gKeyphraseRecognitionExtraClass, "recognitionModes", "I");
788    gKeyphraseRecognitionExtraFields.confidenceLevels = env->GetFieldID(gKeyphraseRecognitionExtraClass,
789                                             "confidenceLevels",
790                                             "[Landroid/hardware/soundtrigger/SoundTrigger$ConfidenceLevel;");
791
792    jclass confidenceLevelClass = env->FindClass(kConfidenceLevelClassPathName);
793    gConfidenceLevelClass = (jclass) env->NewGlobalRef(confidenceLevelClass);
794    gConfidenceLevelCstor = env->GetMethodID(confidenceLevelClass, "<init>", "(II)V");
795    gConfidenceLevelFields.userId = env->GetFieldID(confidenceLevelClass, "userId", "I");
796    gConfidenceLevelFields.confidenceLevel = env->GetFieldID(confidenceLevelClass,
797                                                             "confidenceLevel", "I");
798
799    int status = AndroidRuntime::registerNativeMethods(env,
800                kSoundTriggerClassPathName, gMethods, NELEM(gMethods));
801
802    if (status == 0) {
803        status = AndroidRuntime::registerNativeMethods(env,
804                kModuleClassPathName, gModuleMethods, NELEM(gModuleMethods));
805    }
806
807
808    return status;
809}
810