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 "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 #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(jAudioFormat);
    269         env->DeleteLocalRef(jData);
    270     } else {
    271         jEvent = env->NewObject(gRecognitionEventClass, gRecognitionEventCstor,
    272                                 event->status, event->model, event->capture_available,
    273                                 event->capture_session, event->capture_delay_ms,
    274                                 event->capture_preamble_ms, event->trigger_in_data,
    275                                 jAudioFormat, jData);
    276         env->DeleteLocalRef(jAudioFormat);
    277         env->DeleteLocalRef(jData);
    278     }
    279 
    280 
    281     env->CallStaticVoidMethod(mClass, gPostEventFromNative, mObject,
    282                               SOUNDTRIGGER_EVENT_RECOGNITION, 0, 0, jEvent);
    283 
    284     env->DeleteLocalRef(jEvent);
    285     if (env->ExceptionCheck()) {
    286         ALOGW("An exception occurred while notifying an event.");
    287         env->ExceptionClear();
    288     }
    289 }
    290 
    291 void JNISoundTriggerCallback::onSoundModelEvent(struct sound_trigger_model_event *event)
    292 {
    293     JNIEnv *env = AndroidRuntime::getJNIEnv();
    294     jobject jEvent = NULL;
    295     jbyteArray jData = NULL;
    296 
    297     if (event->data_size) {
    298         jData = env->NewByteArray(event->data_size);
    299         jbyte *nData = env->GetByteArrayElements(jData, NULL);
    300         memcpy(nData, (char *)event + event->data_offset, event->data_size);
    301         env->ReleaseByteArrayElements(jData, nData, 0);
    302     }
    303 
    304     jEvent = env->NewObject(gSoundModelEventClass, gSoundModelEventCstor,
    305                             event->status, event->model, jData);
    306 
    307     env->DeleteLocalRef(jData);
    308     env->CallStaticVoidMethod(mClass, gPostEventFromNative, mObject,
    309                               SOUNDTRIGGER_EVENT_SOUNDMODEL, 0, 0, jEvent);
    310     env->DeleteLocalRef(jEvent);
    311     if (env->ExceptionCheck()) {
    312         ALOGW("An exception occurred while notifying an event.");
    313         env->ExceptionClear();
    314     }
    315 }
    316 
    317 void JNISoundTriggerCallback::onServiceStateChange(sound_trigger_service_state_t state)
    318 {
    319     JNIEnv *env = AndroidRuntime::getJNIEnv();
    320     env->CallStaticVoidMethod(mClass, gPostEventFromNative, mObject,
    321                                         SOUNDTRIGGER_EVENT_SERVICE_STATE_CHANGE, state, 0, NULL);
    322     if (env->ExceptionCheck()) {
    323         ALOGW("An exception occurred while notifying an event.");
    324         env->ExceptionClear();
    325     }
    326 }
    327 
    328 void JNISoundTriggerCallback::onServiceDied()
    329 {
    330     JNIEnv *env = AndroidRuntime::getJNIEnv();
    331 
    332     env->CallStaticVoidMethod(mClass, gPostEventFromNative, mObject,
    333                               SOUNDTRIGGER_EVENT_SERVICE_DIED, 0, 0, NULL);
    334     if (env->ExceptionCheck()) {
    335         ALOGW("An exception occurred while notifying an event.");
    336         env->ExceptionClear();
    337     }
    338 }
    339 
    340 // ----------------------------------------------------------------------------
    341 
    342 static sp<SoundTrigger> getSoundTrigger(JNIEnv* env, jobject thiz)
    343 {
    344     Mutex::Autolock l(gLock);
    345     SoundTrigger* const st = (SoundTrigger*)env->GetLongField(thiz,
    346                                                          gModuleFields.mNativeContext);
    347     return sp<SoundTrigger>(st);
    348 }
    349 
    350 static sp<SoundTrigger> setSoundTrigger(JNIEnv* env, jobject thiz, const sp<SoundTrigger>& module)
    351 {
    352     Mutex::Autolock l(gLock);
    353     sp<SoundTrigger> old = (SoundTrigger*)env->GetLongField(thiz,
    354                                                          gModuleFields.mNativeContext);
    355     if (module.get()) {
    356         module->incStrong((void*)setSoundTrigger);
    357     }
    358     if (old != 0) {
    359         old->decStrong((void*)setSoundTrigger);
    360     }
    361     env->SetLongField(thiz, gModuleFields.mNativeContext, (jlong)module.get());
    362     return old;
    363 }
    364 
    365 
    366 static jint
    367 android_hardware_SoundTrigger_listModules(JNIEnv *env, jobject clazz,
    368                                           jobject jModules)
    369 {
    370     ALOGV("listModules");
    371 
    372     if (jModules == NULL) {
    373         ALOGE("listModules NULL AudioPatch ArrayList");
    374         return SOUNDTRIGGER_STATUS_BAD_VALUE;
    375     }
    376     if (!env->IsInstanceOf(jModules, gArrayListClass)) {
    377         ALOGE("listModules not an arraylist");
    378         return SOUNDTRIGGER_STATUS_BAD_VALUE;
    379     }
    380 
    381     unsigned int numModules = 0;
    382     struct sound_trigger_module_descriptor *nModules = NULL;
    383 
    384     status_t status = SoundTrigger::listModules(nModules, &numModules);
    385     if (status != NO_ERROR || numModules == 0) {
    386         return (jint)status;
    387     }
    388 
    389     nModules = (struct sound_trigger_module_descriptor *)
    390                             calloc(numModules, sizeof(struct sound_trigger_module_descriptor));
    391 
    392     status = SoundTrigger::listModules(nModules, &numModules);
    393     ALOGV("listModules SoundTrigger::listModules status %d numModules %d", status, numModules);
    394 
    395     if (status != NO_ERROR) {
    396         numModules = 0;
    397     }
    398 
    399     for (size_t i = 0; i < numModules; i++) {
    400         char str[SOUND_TRIGGER_MAX_STRING_LEN];
    401 
    402         jstring implementor = env->NewStringUTF(nModules[i].properties.implementor);
    403         jstring description = env->NewStringUTF(nModules[i].properties.description);
    404         SoundTrigger::guidToString(&nModules[i].properties.uuid,
    405                                    str,
    406                                    SOUND_TRIGGER_MAX_STRING_LEN);
    407         jstring uuid = env->NewStringUTF(str);
    408 
    409         ALOGV("listModules module %zu id %d description %s maxSoundModels %d",
    410               i, nModules[i].handle, nModules[i].properties.description,
    411               nModules[i].properties.max_sound_models);
    412 
    413         jobject newModuleDesc = env->NewObject(gModulePropertiesClass, gModulePropertiesCstor,
    414                                                nModules[i].handle,
    415                                                implementor, description, uuid,
    416                                                nModules[i].properties.version,
    417                                                nModules[i].properties.max_sound_models,
    418                                                nModules[i].properties.max_key_phrases,
    419                                                nModules[i].properties.max_users,
    420                                                nModules[i].properties.recognition_modes,
    421                                                nModules[i].properties.capture_transition,
    422                                                nModules[i].properties.max_buffer_ms,
    423                                                nModules[i].properties.concurrent_capture,
    424                                                nModules[i].properties.power_consumption_mw,
    425                                                nModules[i].properties.trigger_in_event);
    426 
    427         env->DeleteLocalRef(implementor);
    428         env->DeleteLocalRef(description);
    429         env->DeleteLocalRef(uuid);
    430         if (newModuleDesc == NULL) {
    431             status = SOUNDTRIGGER_STATUS_ERROR;
    432             goto exit;
    433         }
    434         env->CallBooleanMethod(jModules, gArrayListMethods.add, newModuleDesc);
    435     }
    436 
    437 exit:
    438     free(nModules);
    439     return (jint) status;
    440 }
    441 
    442 static void
    443 android_hardware_SoundTrigger_setup(JNIEnv *env, jobject thiz, jobject weak_this)
    444 {
    445     ALOGV("setup");
    446 
    447     sp<JNISoundTriggerCallback> callback = new JNISoundTriggerCallback(env, thiz, weak_this);
    448 
    449     sound_trigger_module_handle_t handle =
    450             (sound_trigger_module_handle_t)env->GetIntField(thiz, gModuleFields.mId);
    451 
    452     sp<SoundTrigger> module = SoundTrigger::attach(handle, callback);
    453     if (module == 0) {
    454         return;
    455     }
    456 
    457     setSoundTrigger(env, thiz, module);
    458 }
    459 
    460 static void
    461 android_hardware_SoundTrigger_detach(JNIEnv *env, jobject thiz)
    462 {
    463     ALOGV("detach");
    464     sp<SoundTrigger> module = setSoundTrigger(env, thiz, 0);
    465     ALOGV("detach module %p", module.get());
    466     if (module != 0) {
    467         ALOGV("detach module->detach()");
    468         module->detach();
    469     }
    470 }
    471 
    472 static void
    473 android_hardware_SoundTrigger_finalize(JNIEnv *env, jobject thiz)
    474 {
    475     ALOGV("finalize");
    476     sp<SoundTrigger> module = getSoundTrigger(env, thiz);
    477     if (module != 0) {
    478         ALOGW("SoundTrigger finalized without being detached");
    479     }
    480     android_hardware_SoundTrigger_detach(env, thiz);
    481 }
    482 
    483 static jint
    484 android_hardware_SoundTrigger_loadSoundModel(JNIEnv *env, jobject thiz,
    485                                              jobject jSoundModel, jintArray jHandle)
    486 {
    487     jint status = SOUNDTRIGGER_STATUS_OK;
    488     jbyte *nData = NULL;
    489     struct sound_trigger_sound_model *nSoundModel;
    490     jbyteArray jData;
    491     sp<MemoryDealer> memoryDealer;
    492     sp<IMemory> memory;
    493     size_t size;
    494     sound_model_handle_t handle;
    495     jobject jUuid;
    496     jstring jUuidString;
    497     const char *nUuidString;
    498 
    499     ALOGV("loadSoundModel");
    500     sp<SoundTrigger> module = getSoundTrigger(env, thiz);
    501     if (module == NULL) {
    502         return SOUNDTRIGGER_STATUS_ERROR;
    503     }
    504     if (jHandle == NULL) {
    505         return SOUNDTRIGGER_STATUS_BAD_VALUE;
    506     }
    507     jsize jHandleLen = env->GetArrayLength(jHandle);
    508     if (jHandleLen == 0) {
    509         return SOUNDTRIGGER_STATUS_BAD_VALUE;
    510     }
    511     jint *nHandle = env->GetIntArrayElements(jHandle, NULL);
    512     if (nHandle == NULL) {
    513         return SOUNDTRIGGER_STATUS_ERROR;
    514     }
    515     if (!env->IsInstanceOf(jSoundModel, gSoundModelClass)) {
    516         status = SOUNDTRIGGER_STATUS_BAD_VALUE;
    517         goto exit;
    518     }
    519     size_t offset;
    520     sound_trigger_sound_model_type_t type;
    521     if (env->IsInstanceOf(jSoundModel, gKeyphraseSoundModelClass)) {
    522         offset = sizeof(struct sound_trigger_phrase_sound_model);
    523         type = SOUND_MODEL_TYPE_KEYPHRASE;
    524     } else {
    525         offset = sizeof(struct sound_trigger_sound_model);
    526         type = SOUND_MODEL_TYPE_UNKNOWN;
    527     }
    528 
    529     jUuid = env->GetObjectField(jSoundModel, gSoundModelFields.uuid);
    530     jUuidString = (jstring)env->CallObjectMethod(jUuid, gUUIDMethods.toString);
    531     nUuidString = env->GetStringUTFChars(jUuidString, NULL);
    532     sound_trigger_uuid_t nUuid;
    533     SoundTrigger::stringToGuid(nUuidString, &nUuid);
    534     env->ReleaseStringUTFChars(jUuidString, nUuidString);
    535     env->DeleteLocalRef(jUuidString);
    536 
    537     sound_trigger_uuid_t nVendorUuid;
    538     jUuid = env->GetObjectField(jSoundModel, gSoundModelFields.vendorUuid);
    539     if (jUuid != NULL) {
    540         jUuidString = (jstring)env->CallObjectMethod(jUuid, gUUIDMethods.toString);
    541         nUuidString = env->GetStringUTFChars(jUuidString, NULL);
    542         SoundTrigger::stringToGuid(nUuidString, &nVendorUuid);
    543         env->ReleaseStringUTFChars(jUuidString, nUuidString);
    544         env->DeleteLocalRef(jUuidString);
    545     } else {
    546         SoundTrigger::stringToGuid("00000000-0000-0000-0000-000000000000", &nVendorUuid);
    547     }
    548 
    549     jData = (jbyteArray)env->GetObjectField(jSoundModel, gSoundModelFields.data);
    550     if (jData == NULL) {
    551         status = SOUNDTRIGGER_STATUS_BAD_VALUE;
    552         goto exit;
    553     }
    554     size = env->GetArrayLength(jData);
    555 
    556     nData = env->GetByteArrayElements(jData, NULL);
    557     if (jData == NULL) {
    558         status = SOUNDTRIGGER_STATUS_ERROR;
    559         goto exit;
    560     }
    561 
    562     memoryDealer = new MemoryDealer(offset + size, "SoundTrigge-JNI::LoadModel");
    563     if (memoryDealer == 0) {
    564         status = SOUNDTRIGGER_STATUS_ERROR;
    565         goto exit;
    566     }
    567     memory = memoryDealer->allocate(offset + size);
    568     if (memory == 0 || memory->pointer() == NULL) {
    569         status = SOUNDTRIGGER_STATUS_ERROR;
    570         goto exit;
    571     }
    572 
    573     nSoundModel = (struct sound_trigger_sound_model *)memory->pointer();
    574 
    575     nSoundModel->type = type;
    576     nSoundModel->uuid = nUuid;
    577     nSoundModel->vendor_uuid = nVendorUuid;
    578     nSoundModel->data_size = size;
    579     nSoundModel->data_offset = offset;
    580     memcpy((char *)nSoundModel + offset, nData, size);
    581     if (type == SOUND_MODEL_TYPE_KEYPHRASE) {
    582         struct sound_trigger_phrase_sound_model *phraseModel =
    583                 (struct sound_trigger_phrase_sound_model *)nSoundModel;
    584 
    585         jobjectArray jPhrases =
    586             (jobjectArray)env->GetObjectField(jSoundModel, gKeyphraseSoundModelFields.keyphrases);
    587         if (jPhrases == NULL) {
    588             status = SOUNDTRIGGER_STATUS_BAD_VALUE;
    589             goto exit;
    590         }
    591 
    592         size_t numPhrases = env->GetArrayLength(jPhrases);
    593         phraseModel->num_phrases = numPhrases;
    594         ALOGV("loadSoundModel numPhrases %zu", numPhrases);
    595         for (size_t i = 0; i < numPhrases; i++) {
    596             jobject jPhrase = env->GetObjectArrayElement(jPhrases, i);
    597             phraseModel->phrases[i].id =
    598                                     env->GetIntField(jPhrase,gKeyphraseFields.id);
    599             phraseModel->phrases[i].recognition_mode =
    600                                     env->GetIntField(jPhrase,gKeyphraseFields.recognitionModes);
    601 
    602             jintArray jUsers = (jintArray)env->GetObjectField(jPhrase, gKeyphraseFields.users);
    603             phraseModel->phrases[i].num_users = env->GetArrayLength(jUsers);
    604             jint *nUsers = env->GetIntArrayElements(jUsers, NULL);
    605             memcpy(phraseModel->phrases[i].users,
    606                    nUsers,
    607                    phraseModel->phrases[i].num_users * sizeof(int));
    608             env->ReleaseIntArrayElements(jUsers, nUsers, 0);
    609             env->DeleteLocalRef(jUsers);
    610 
    611             jstring jLocale = (jstring)env->GetObjectField(jPhrase, gKeyphraseFields.locale);
    612             const char *nLocale = env->GetStringUTFChars(jLocale, NULL);
    613             strncpy(phraseModel->phrases[i].locale,
    614                     nLocale,
    615                     SOUND_TRIGGER_MAX_LOCALE_LEN);
    616             jstring jText = (jstring)env->GetObjectField(jPhrase, gKeyphraseFields.text);
    617             const char *nText = env->GetStringUTFChars(jText, NULL);
    618             strncpy(phraseModel->phrases[i].text,
    619                     nText,
    620                     SOUND_TRIGGER_MAX_STRING_LEN);
    621 
    622             env->ReleaseStringUTFChars(jLocale, nLocale);
    623             env->DeleteLocalRef(jLocale);
    624             env->ReleaseStringUTFChars(jText, nText);
    625             env->DeleteLocalRef(jText);
    626             ALOGV("loadSoundModel phrases %zu text %s locale %s",
    627                   i, phraseModel->phrases[i].text, phraseModel->phrases[i].locale);
    628             env->DeleteLocalRef(jPhrase);
    629         }
    630         env->DeleteLocalRef(jPhrases);
    631     }
    632     status = module->loadSoundModel(memory, &handle);
    633     ALOGV("loadSoundModel status %d handle %d", status, handle);
    634 
    635 exit:
    636     if (nHandle != NULL) {
    637         nHandle[0] = (jint)handle;
    638         env->ReleaseIntArrayElements(jHandle, nHandle, NULL);
    639     }
    640     if (nData != NULL) {
    641         env->ReleaseByteArrayElements(jData, nData, NULL);
    642     }
    643     return status;
    644 }
    645 
    646 static jint
    647 android_hardware_SoundTrigger_unloadSoundModel(JNIEnv *env, jobject thiz,
    648                                                jint jHandle)
    649 {
    650     jint status = SOUNDTRIGGER_STATUS_OK;
    651     ALOGV("unloadSoundModel");
    652     sp<SoundTrigger> module = getSoundTrigger(env, thiz);
    653     if (module == NULL) {
    654         return SOUNDTRIGGER_STATUS_ERROR;
    655     }
    656     status = module->unloadSoundModel((sound_model_handle_t)jHandle);
    657 
    658     return status;
    659 }
    660 
    661 static jint
    662 android_hardware_SoundTrigger_startRecognition(JNIEnv *env, jobject thiz,
    663                                                jint jHandle, jobject jConfig)
    664 {
    665     jint status = SOUNDTRIGGER_STATUS_OK;
    666     ALOGV("startRecognition");
    667     sp<SoundTrigger> module = getSoundTrigger(env, thiz);
    668     if (module == NULL) {
    669         return SOUNDTRIGGER_STATUS_ERROR;
    670     }
    671 
    672     if (!env->IsInstanceOf(jConfig, gRecognitionConfigClass)) {
    673         return SOUNDTRIGGER_STATUS_BAD_VALUE;
    674     }
    675 
    676     jbyteArray jData = (jbyteArray)env->GetObjectField(jConfig, gRecognitionConfigFields.data);
    677     jsize dataSize = 0;
    678     jbyte *nData = NULL;
    679     if (jData != NULL) {
    680         dataSize = env->GetArrayLength(jData);
    681         if (dataSize == 0) {
    682             return SOUNDTRIGGER_STATUS_BAD_VALUE;
    683         }
    684         nData = env->GetByteArrayElements(jData, NULL);
    685         if (nData == NULL) {
    686             return SOUNDTRIGGER_STATUS_ERROR;
    687         }
    688     }
    689 
    690     size_t totalSize = sizeof(struct sound_trigger_recognition_config) + dataSize;
    691     sp<MemoryDealer> memoryDealer =
    692             new MemoryDealer(totalSize, "SoundTrigge-JNI::StartRecognition");
    693     if (memoryDealer == 0) {
    694         return SOUNDTRIGGER_STATUS_ERROR;
    695     }
    696     sp<IMemory> memory = memoryDealer->allocate(totalSize);
    697     if (memory == 0 || memory->pointer() == NULL) {
    698         return SOUNDTRIGGER_STATUS_ERROR;
    699     }
    700     if (dataSize != 0) {
    701         memcpy((char *)memory->pointer() + sizeof(struct sound_trigger_recognition_config),
    702                 nData,
    703                 dataSize);
    704         env->ReleaseByteArrayElements(jData, nData, 0);
    705     }
    706     env->DeleteLocalRef(jData);
    707     struct sound_trigger_recognition_config *config =
    708                                     (struct sound_trigger_recognition_config *)memory->pointer();
    709     config->data_size = dataSize;
    710     config->data_offset = sizeof(struct sound_trigger_recognition_config);
    711     config->capture_requested = env->GetIntField(jConfig,
    712                                                  gRecognitionConfigFields.captureRequested);
    713 
    714     config->num_phrases = 0;
    715     jobjectArray jPhrases =
    716         (jobjectArray)env->GetObjectField(jConfig, gRecognitionConfigFields.keyphrases);
    717     if (jPhrases != NULL) {
    718         config->num_phrases = env->GetArrayLength(jPhrases);
    719     }
    720     ALOGV("startRecognition num phrases %d", config->num_phrases);
    721     for (size_t i = 0; i < config->num_phrases; i++) {
    722         jobject jPhrase = env->GetObjectArrayElement(jPhrases, i);
    723         config->phrases[i].id = env->GetIntField(jPhrase,
    724                                                 gKeyphraseRecognitionExtraFields.id);
    725         config->phrases[i].recognition_modes = env->GetIntField(jPhrase,
    726                                                 gKeyphraseRecognitionExtraFields.recognitionModes);
    727         config->phrases[i].confidence_level = env->GetIntField(jPhrase,
    728                                             gKeyphraseRecognitionExtraFields.coarseConfidenceLevel);
    729         config->phrases[i].num_levels = 0;
    730         jobjectArray jConfidenceLevels = (jobjectArray)env->GetObjectField(jPhrase,
    731                                                 gKeyphraseRecognitionExtraFields.confidenceLevels);
    732         if (jConfidenceLevels != NULL) {
    733             config->phrases[i].num_levels = env->GetArrayLength(jConfidenceLevels);
    734         }
    735         ALOGV("startRecognition phrase %zu num_levels %d", i, config->phrases[i].num_levels);
    736         for (size_t j = 0; j < config->phrases[i].num_levels; j++) {
    737             jobject jConfidenceLevel = env->GetObjectArrayElement(jConfidenceLevels, j);
    738             config->phrases[i].levels[j].user_id = env->GetIntField(jConfidenceLevel,
    739                                                                     gConfidenceLevelFields.userId);
    740             config->phrases[i].levels[j].level = env->GetIntField(jConfidenceLevel,
    741                                                           gConfidenceLevelFields.confidenceLevel);
    742             env->DeleteLocalRef(jConfidenceLevel);
    743         }
    744         ALOGV("startRecognition phrases %zu", i);
    745         env->DeleteLocalRef(jConfidenceLevels);
    746         env->DeleteLocalRef(jPhrase);
    747     }
    748     env->DeleteLocalRef(jPhrases);
    749 
    750     status = module->startRecognition(jHandle, memory);
    751     return status;
    752 }
    753 
    754 static jint
    755 android_hardware_SoundTrigger_stopRecognition(JNIEnv *env, jobject thiz,
    756                                                jint jHandle)
    757 {
    758     jint status = SOUNDTRIGGER_STATUS_OK;
    759     ALOGV("stopRecognition");
    760     sp<SoundTrigger> module = getSoundTrigger(env, thiz);
    761     if (module == NULL) {
    762         return SOUNDTRIGGER_STATUS_ERROR;
    763     }
    764     status = module->stopRecognition(jHandle);
    765     return status;
    766 }
    767 
    768 static JNINativeMethod gMethods[] = {
    769     {"listModules",
    770         "(Ljava/util/ArrayList;)I",
    771         (void *)android_hardware_SoundTrigger_listModules},
    772 };
    773 
    774 
    775 static JNINativeMethod gModuleMethods[] = {
    776     {"native_setup",
    777         "(Ljava/lang/Object;)V",
    778         (void *)android_hardware_SoundTrigger_setup},
    779     {"native_finalize",
    780         "()V",
    781         (void *)android_hardware_SoundTrigger_finalize},
    782     {"detach",
    783         "()V",
    784         (void *)android_hardware_SoundTrigger_detach},
    785     {"loadSoundModel",
    786         "(Landroid/hardware/soundtrigger/SoundTrigger$SoundModel;[I)I",
    787         (void *)android_hardware_SoundTrigger_loadSoundModel},
    788     {"unloadSoundModel",
    789         "(I)I",
    790         (void *)android_hardware_SoundTrigger_unloadSoundModel},
    791     {"startRecognition",
    792         "(ILandroid/hardware/soundtrigger/SoundTrigger$RecognitionConfig;)I",
    793         (void *)android_hardware_SoundTrigger_startRecognition},
    794     {"stopRecognition",
    795         "(I)I",
    796         (void *)android_hardware_SoundTrigger_stopRecognition},
    797 };
    798 
    799 int register_android_hardware_SoundTrigger(JNIEnv *env)
    800 {
    801     jclass arrayListClass = env->FindClass("java/util/ArrayList");
    802     gArrayListClass = (jclass) env->NewGlobalRef(arrayListClass);
    803     gArrayListMethods.add = env->GetMethodID(arrayListClass, "add", "(Ljava/lang/Object;)Z");
    804 
    805     jclass uuidClass = env->FindClass("java/util/UUID");
    806     gUUIDClass = (jclass) env->NewGlobalRef(uuidClass);
    807     gUUIDMethods.toString = env->GetMethodID(uuidClass, "toString", "()Ljava/lang/String;");
    808 
    809     jclass lClass = env->FindClass(kSoundTriggerClassPathName);
    810     gSoundTriggerClass = (jclass) env->NewGlobalRef(lClass);
    811 
    812     jclass moduleClass = env->FindClass(kModuleClassPathName);
    813     gModuleClass = (jclass) env->NewGlobalRef(moduleClass);
    814     gPostEventFromNative = env->GetStaticMethodID(moduleClass, "postEventFromNative",
    815                                             "(Ljava/lang/Object;IIILjava/lang/Object;)V");
    816     gModuleFields.mNativeContext = env->GetFieldID(moduleClass, "mNativeContext", "J");
    817     gModuleFields.mId = env->GetFieldID(moduleClass, "mId", "I");
    818 
    819 
    820     jclass modulePropertiesClass = env->FindClass(kModulePropertiesClassPathName);
    821     gModulePropertiesClass = (jclass) env->NewGlobalRef(modulePropertiesClass);
    822     gModulePropertiesCstor = env->GetMethodID(modulePropertiesClass, "<init>",
    823                               "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;IIIIIZIZIZ)V");
    824 
    825     jclass soundModelClass = env->FindClass(kSoundModelClassPathName);
    826     gSoundModelClass = (jclass) env->NewGlobalRef(soundModelClass);
    827     gSoundModelFields.uuid = env->GetFieldID(soundModelClass, "uuid", "Ljava/util/UUID;");
    828     gSoundModelFields.vendorUuid = env->GetFieldID(soundModelClass, "vendorUuid", "Ljava/util/UUID;");
    829     gSoundModelFields.data = env->GetFieldID(soundModelClass, "data", "[B");
    830 
    831     jclass keyphraseClass = env->FindClass(kKeyphraseClassPathName);
    832     gKeyphraseClass = (jclass) env->NewGlobalRef(keyphraseClass);
    833     gKeyphraseFields.id = env->GetFieldID(keyphraseClass, "id", "I");
    834     gKeyphraseFields.recognitionModes = env->GetFieldID(keyphraseClass, "recognitionModes", "I");
    835     gKeyphraseFields.locale = env->GetFieldID(keyphraseClass, "locale", "Ljava/lang/String;");
    836     gKeyphraseFields.text = env->GetFieldID(keyphraseClass, "text", "Ljava/lang/String;");
    837     gKeyphraseFields.users = env->GetFieldID(keyphraseClass, "users", "[I");
    838 
    839     jclass keyphraseSoundModelClass = env->FindClass(kKeyphraseSoundModelClassPathName);
    840     gKeyphraseSoundModelClass = (jclass) env->NewGlobalRef(keyphraseSoundModelClass);
    841     gKeyphraseSoundModelFields.keyphrases = env->GetFieldID(keyphraseSoundModelClass,
    842                                          "keyphrases",
    843                                          "[Landroid/hardware/soundtrigger/SoundTrigger$Keyphrase;");
    844 
    845 
    846     jclass recognitionEventClass = env->FindClass(kRecognitionEventClassPathName);
    847     gRecognitionEventClass = (jclass) env->NewGlobalRef(recognitionEventClass);
    848     gRecognitionEventCstor = env->GetMethodID(recognitionEventClass, "<init>",
    849                                               "(IIZIIIZLandroid/media/AudioFormat;[B)V");
    850 
    851     jclass keyphraseRecognitionEventClass = env->FindClass(kKeyphraseRecognitionEventClassPathName);
    852     gKeyphraseRecognitionEventClass = (jclass) env->NewGlobalRef(keyphraseRecognitionEventClass);
    853     gKeyphraseRecognitionEventCstor = env->GetMethodID(keyphraseRecognitionEventClass, "<init>",
    854               "(IIZIIIZLandroid/media/AudioFormat;[B[Landroid/hardware/soundtrigger/SoundTrigger$KeyphraseRecognitionExtra;)V");
    855 
    856 
    857     jclass keyRecognitionConfigClass = env->FindClass(kRecognitionConfigClassPathName);
    858     gRecognitionConfigClass = (jclass) env->NewGlobalRef(keyRecognitionConfigClass);
    859     gRecognitionConfigFields.captureRequested = env->GetFieldID(keyRecognitionConfigClass,
    860                                                               "captureRequested",
    861                                                               "Z");
    862     gRecognitionConfigFields.keyphrases = env->GetFieldID(keyRecognitionConfigClass,
    863                         "keyphrases",
    864                         "[Landroid/hardware/soundtrigger/SoundTrigger$KeyphraseRecognitionExtra;");
    865     gRecognitionConfigFields.data = env->GetFieldID(keyRecognitionConfigClass,
    866                                                               "data",
    867                                                               "[B");
    868 
    869     jclass keyphraseRecognitionExtraClass = env->FindClass(kKeyphraseRecognitionExtraClassPathName);
    870     gKeyphraseRecognitionExtraClass = (jclass) env->NewGlobalRef(keyphraseRecognitionExtraClass);
    871     gKeyphraseRecognitionExtraCstor = env->GetMethodID(keyphraseRecognitionExtraClass, "<init>",
    872                            "(III[Landroid/hardware/soundtrigger/SoundTrigger$ConfidenceLevel;)V");
    873     gKeyphraseRecognitionExtraFields.id = env->GetFieldID(gKeyphraseRecognitionExtraClass, "id", "I");
    874     gKeyphraseRecognitionExtraFields.recognitionModes = env->GetFieldID(gKeyphraseRecognitionExtraClass,
    875                                                                         "recognitionModes", "I");
    876     gKeyphraseRecognitionExtraFields.coarseConfidenceLevel = env->GetFieldID(gKeyphraseRecognitionExtraClass,
    877                                                                         "coarseConfidenceLevel", "I");
    878     gKeyphraseRecognitionExtraFields.confidenceLevels = env->GetFieldID(gKeyphraseRecognitionExtraClass,
    879                                              "confidenceLevels",
    880                                              "[Landroid/hardware/soundtrigger/SoundTrigger$ConfidenceLevel;");
    881 
    882     jclass confidenceLevelClass = env->FindClass(kConfidenceLevelClassPathName);
    883     gConfidenceLevelClass = (jclass) env->NewGlobalRef(confidenceLevelClass);
    884     gConfidenceLevelCstor = env->GetMethodID(confidenceLevelClass, "<init>", "(II)V");
    885     gConfidenceLevelFields.userId = env->GetFieldID(confidenceLevelClass, "userId", "I");
    886     gConfidenceLevelFields.confidenceLevel = env->GetFieldID(confidenceLevelClass,
    887                                                              "confidenceLevel", "I");
    888 
    889     jclass audioFormatClass = env->FindClass(kAudioFormatClassPathName);
    890     gAudioFormatClass = (jclass) env->NewGlobalRef(audioFormatClass);
    891     gAudioFormatCstor = env->GetMethodID(audioFormatClass, "<init>", "(III)V");
    892 
    893     jclass soundModelEventClass = env->FindClass(kSoundModelEventClassPathName);
    894     gSoundModelEventClass = (jclass) env->NewGlobalRef(soundModelEventClass);
    895     gSoundModelEventCstor = env->GetMethodID(soundModelEventClass, "<init>",
    896                                               "(II[B)V");
    897 
    898 
    899     int status = AndroidRuntime::registerNativeMethods(env,
    900                 kSoundTriggerClassPathName, gMethods, NELEM(gMethods));
    901 
    902     if (status == 0) {
    903         status = AndroidRuntime::registerNativeMethods(env,
    904                 kModuleClassPathName, gModuleMethods, NELEM(gModuleMethods));
    905     }
    906 
    907 
    908     return status;
    909 }
    910