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 
JNISoundTriggerCallback(JNIEnv * env,jobject thiz,jobject weak_thiz)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 
~JNISoundTriggerCallback()192 JNISoundTriggerCallback::~JNISoundTriggerCallback()
193 {
194     // remove global references
195     JNIEnv *env = AndroidRuntime::getJNIEnv();
196     env->DeleteGlobalRef(mObject);
197     env->DeleteGlobalRef(mClass);
198 }
199 
onRecognitionEvent(struct sound_trigger_recognition_event * event)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 
onSoundModelEvent(struct sound_trigger_model_event * event)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 
onServiceStateChange(sound_trigger_service_state_t state)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 
onServiceDied()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 
getSoundTrigger(JNIEnv * env,jobject thiz)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 
setSoundTrigger(JNIEnv * env,jobject thiz,const sp<SoundTrigger> & module)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
android_hardware_SoundTrigger_listModules(JNIEnv * env,jobject clazz,jobject jModules)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
android_hardware_SoundTrigger_setup(JNIEnv * env,jobject thiz,jobject weak_this)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
android_hardware_SoundTrigger_detach(JNIEnv * env,jobject thiz)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
android_hardware_SoundTrigger_finalize(JNIEnv * env,jobject thiz)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
android_hardware_SoundTrigger_loadSoundModel(JNIEnv * env,jobject thiz,jobject jSoundModel,jintArray jHandle)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
android_hardware_SoundTrigger_unloadSoundModel(JNIEnv * env,jobject thiz,jint jHandle)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
android_hardware_SoundTrigger_startRecognition(JNIEnv * env,jobject thiz,jint jHandle,jobject jConfig)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
android_hardware_SoundTrigger_stopRecognition(JNIEnv * env,jobject thiz,jint jHandle)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 
register_android_hardware_SoundTrigger(JNIEnv * env)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