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