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