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