blob: c9a0b1ed3f0613196df4348d0ce0950d9d71ed8f [file] [log] [blame]
Eric Laurent60b62bc2014-04-18 17:50:49 -07001/*
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
33using namespace android;
34
35static jclass gArrayListClass;
36static struct {
37 jmethodID add;
38} gArrayListMethods;
39
Sandeep Siddharthad4233c62014-06-12 18:31:19 -070040static jclass gUUIDClass;
41static struct {
42 jmethodID toString;
43} gUUIDMethods;
44
Eric Laurent60b62bc2014-04-18 17:50:49 -070045static const char* const kSoundTriggerClassPathName = "android/hardware/soundtrigger/SoundTrigger";
46static jclass gSoundTriggerClass;
47
48static const char* const kModuleClassPathName = "android/hardware/soundtrigger/SoundTriggerModule";
49static jclass gModuleClass;
50static struct {
51 jfieldID mNativeContext;
52 jfieldID mId;
53} gModuleFields;
54static jmethodID gPostEventFromNative;
55
56static const char* const kModulePropertiesClassPathName =
57 "android/hardware/soundtrigger/SoundTrigger$ModuleProperties";
58static jclass gModulePropertiesClass;
59static jmethodID gModulePropertiesCstor;
60
61static const char* const kSoundModelClassPathName =
62 "android/hardware/soundtrigger/SoundTrigger$SoundModel";
63static jclass gSoundModelClass;
64static struct {
Sandeep Siddharthad4233c62014-06-12 18:31:19 -070065 jfieldID uuid;
Eric Laurent60b62bc2014-04-18 17:50:49 -070066 jfieldID data;
67} gSoundModelFields;
68
Sandeep Siddharthad4233c62014-06-12 18:31:19 -070069static const char* const kKeyphraseClassPathName =
70 "android/hardware/soundtrigger/SoundTrigger$Keyphrase";
71static jclass gKeyphraseClass;
Eric Laurent60b62bc2014-04-18 17:50:49 -070072static struct {
Sandeep Siddharthad4233c62014-06-12 18:31:19 -070073 jfieldID id;
Eric Laurent60b62bc2014-04-18 17:50:49 -070074 jfieldID recognitionModes;
75 jfieldID locale;
76 jfieldID text;
Eric Laurent013f66b2014-07-06 16:35:00 -070077 jfieldID users;
Sandeep Siddharthad4233c62014-06-12 18:31:19 -070078} gKeyphraseFields;
Eric Laurent60b62bc2014-04-18 17:50:49 -070079
Sandeep Siddharthad4233c62014-06-12 18:31:19 -070080static const char* const kKeyphraseSoundModelClassPathName =
81 "android/hardware/soundtrigger/SoundTrigger$KeyphraseSoundModel";
82static jclass gKeyphraseSoundModelClass;
Eric Laurent60b62bc2014-04-18 17:50:49 -070083static struct {
Sandeep Siddharthad4233c62014-06-12 18:31:19 -070084 jfieldID keyphrases;
85} gKeyphraseSoundModelFields;
Eric Laurent60b62bc2014-04-18 17:50:49 -070086
Eric Laurent013f66b2014-07-06 16:35:00 -070087static const char* const kRecognitionConfigClassPathName =
88 "android/hardware/soundtrigger/SoundTrigger$RecognitionConfig";
89static jclass gRecognitionConfigClass;
90static struct {
91 jfieldID captureRequested;
92 jfieldID keyphrases;
93 jfieldID data;
94} gRecognitionConfigFields;
Eric Laurent60b62bc2014-04-18 17:50:49 -070095
96static const char* const kRecognitionEventClassPathName =
97 "android/hardware/soundtrigger/SoundTrigger$RecognitionEvent";
98static jclass gRecognitionEventClass;
99static jmethodID gRecognitionEventCstor;
100
Sandeep Siddharthad4233c62014-06-12 18:31:19 -0700101static const char* const kKeyphraseRecognitionEventClassPathName =
102 "android/hardware/soundtrigger/SoundTrigger$KeyphraseRecognitionEvent";
103static jclass gKeyphraseRecognitionEventClass;
104static jmethodID gKeyphraseRecognitionEventCstor;
Eric Laurent60b62bc2014-04-18 17:50:49 -0700105
Sandeep Siddharthad4233c62014-06-12 18:31:19 -0700106static const char* const kKeyphraseRecognitionExtraClassPathName =
107 "android/hardware/soundtrigger/SoundTrigger$KeyphraseRecognitionExtra";
108static jclass gKeyphraseRecognitionExtraClass;
109static jmethodID gKeyphraseRecognitionExtraCstor;
Eric Laurent013f66b2014-07-06 16:35:00 -0700110static struct {
111 jfieldID id;
112 jfieldID recognitionModes;
113 jfieldID confidenceLevels;
114} gKeyphraseRecognitionExtraFields;
115
116static const char* const kConfidenceLevelClassPathName =
117 "android/hardware/soundtrigger/SoundTrigger$ConfidenceLevel";
118static jclass gConfidenceLevelClass;
119static jmethodID gConfidenceLevelCstor;
120static struct {
121 jfieldID userId;
122 jfieldID confidenceLevel;
123} gConfidenceLevelFields;
Eric Laurent60b62bc2014-04-18 17:50:49 -0700124
125static Mutex gLock;
126
127enum {
128 SOUNDTRIGGER_STATUS_OK = 0,
129 SOUNDTRIGGER_STATUS_ERROR = INT_MIN,
130 SOUNDTRIGGER_PERMISSION_DENIED = -1,
131 SOUNDTRIGGER_STATUS_NO_INIT = -19,
132 SOUNDTRIGGER_STATUS_BAD_VALUE = -22,
133 SOUNDTRIGGER_STATUS_DEAD_OBJECT = -32,
134 SOUNDTRIGGER_INVALID_OPERATION = -38,
135};
136
137enum {
138 SOUNDTRIGGER_EVENT_RECOGNITION = 1,
139 SOUNDTRIGGER_EVENT_SERVICE_DIED = 2,
140};
141
142// ----------------------------------------------------------------------------
143// ref-counted object for callbacks
144class JNISoundTriggerCallback: public SoundTriggerCallback
145{
146public:
147 JNISoundTriggerCallback(JNIEnv* env, jobject thiz, jobject weak_thiz);
148 ~JNISoundTriggerCallback();
149
150 virtual void onRecognitionEvent(struct sound_trigger_recognition_event *event);
151 virtual void onServiceDied();
152
153private:
154 jclass mClass; // Reference to SoundTrigger class
155 jobject mObject; // Weak ref to SoundTrigger Java object to call on
156};
157
158JNISoundTriggerCallback::JNISoundTriggerCallback(JNIEnv* env, jobject thiz, jobject weak_thiz)
159{
160
161 // Hold onto the SoundTriggerModule class for use in calling the static method
162 // that posts events to the application thread.
163 jclass clazz = env->GetObjectClass(thiz);
164 if (clazz == NULL) {
165 ALOGE("Can't find class %s", kModuleClassPathName);
166 return;
167 }
168 mClass = (jclass)env->NewGlobalRef(clazz);
169
170 // We use a weak reference so the SoundTriggerModule object can be garbage collected.
171 // The reference is only used as a proxy for callbacks.
172 mObject = env->NewGlobalRef(weak_thiz);
173}
174
175JNISoundTriggerCallback::~JNISoundTriggerCallback()
176{
177 // remove global references
178 JNIEnv *env = AndroidRuntime::getJNIEnv();
179 env->DeleteGlobalRef(mObject);
180 env->DeleteGlobalRef(mClass);
181}
182
183void JNISoundTriggerCallback::onRecognitionEvent(struct sound_trigger_recognition_event *event)
184{
185 JNIEnv *env = AndroidRuntime::getJNIEnv();
186
187 jobject jEvent;
188
189 jbyteArray jData = NULL;
190 if (event->data_size) {
191 jData = env->NewByteArray(event->data_size);
192 jbyte *nData = env->GetByteArrayElements(jData, NULL);
193 memcpy(nData, (char *)event + event->data_offset, event->data_size);
194 env->ReleaseByteArrayElements(jData, nData, 0);
195 }
196
197 if (event->type == SOUND_MODEL_TYPE_KEYPHRASE) {
198 struct sound_trigger_phrase_recognition_event *phraseEvent =
199 (struct sound_trigger_phrase_recognition_event *)event;
200
201 jobjectArray jExtras = env->NewObjectArray(phraseEvent->num_phrases,
Sandeep Siddharthad4233c62014-06-12 18:31:19 -0700202 gKeyphraseRecognitionExtraClass, NULL);
Eric Laurent60b62bc2014-04-18 17:50:49 -0700203 if (jExtras == NULL) {
204 return;
205 }
206
207 for (size_t i = 0; i < phraseEvent->num_phrases; i++) {
Eric Laurent013f66b2014-07-06 16:35:00 -0700208 jobjectArray jConfidenceLevels = env->NewObjectArray(
209 phraseEvent->phrase_extras[i].num_levels,
210 gConfidenceLevelClass, NULL);
211
Eric Laurent60b62bc2014-04-18 17:50:49 -0700212 if (jConfidenceLevels == NULL) {
213 return;
214 }
Eric Laurent013f66b2014-07-06 16:35:00 -0700215 for (size_t j = 0; j < phraseEvent->phrase_extras[i].num_levels; j++) {
216 jobject jConfidenceLevel = env->NewObject(gConfidenceLevelClass,
217 gConfidenceLevelCstor,
218 phraseEvent->phrase_extras[i].levels[j].user_id,
219 phraseEvent->phrase_extras[i].levels[j].level);
220 env->SetObjectArrayElement(jConfidenceLevels, j, jConfidenceLevel);
221 env->DeleteLocalRef(jConfidenceLevel);
222 }
223
Sandeep Siddharthad4233c62014-06-12 18:31:19 -0700224 jobject jNewExtra = env->NewObject(gKeyphraseRecognitionExtraClass,
225 gKeyphraseRecognitionExtraCstor,
Eric Laurent013f66b2014-07-06 16:35:00 -0700226 phraseEvent->phrase_extras[i].id,
227 phraseEvent->phrase_extras[i].recognition_modes,
228 jConfidenceLevels);
Eric Laurent60b62bc2014-04-18 17:50:49 -0700229
230 if (jNewExtra == NULL) {
231 return;
232 }
233 env->SetObjectArrayElement(jExtras, i, jNewExtra);
Eric Laurent013f66b2014-07-06 16:35:00 -0700234 env->DeleteLocalRef(jNewExtra);
235 env->DeleteLocalRef(jConfidenceLevels);
Eric Laurent60b62bc2014-04-18 17:50:49 -0700236 }
Sandeep Siddharthad4233c62014-06-12 18:31:19 -0700237 jEvent = env->NewObject(gKeyphraseRecognitionEventClass, gKeyphraseRecognitionEventCstor,
Eric Laurent60b62bc2014-04-18 17:50:49 -0700238 event->status, event->model, event->capture_available,
Eric Laurent013f66b2014-07-06 16:35:00 -0700239 event->capture_session, event->capture_delay_ms,
240 event->capture_preamble_ms, jData,
Eric Laurent60b62bc2014-04-18 17:50:49 -0700241 phraseEvent->key_phrase_in_capture, jExtras);
242 } else {
243 jEvent = env->NewObject(gRecognitionEventClass, gRecognitionEventCstor,
244 event->status, event->model, event->capture_available,
Eric Laurent013f66b2014-07-06 16:35:00 -0700245 event->capture_session, event->capture_delay_ms,
246 event->capture_preamble_ms, jData);
Eric Laurent60b62bc2014-04-18 17:50:49 -0700247 }
248
249
250 env->CallStaticVoidMethod(mClass, gPostEventFromNative, mObject,
251 SOUNDTRIGGER_EVENT_RECOGNITION, 0, 0, jEvent);
252 if (env->ExceptionCheck()) {
253 ALOGW("An exception occurred while notifying an event.");
254 env->ExceptionClear();
255 }
256}
257
258void JNISoundTriggerCallback::onServiceDied()
259{
260 JNIEnv *env = AndroidRuntime::getJNIEnv();
261
262 env->CallStaticVoidMethod(mClass, gPostEventFromNative, mObject,
263 SOUNDTRIGGER_EVENT_SERVICE_DIED, 0, 0, NULL);
264 if (env->ExceptionCheck()) {
265 ALOGW("An exception occurred while notifying an event.");
266 env->ExceptionClear();
267 }
268}
269
270// ----------------------------------------------------------------------------
271
272static sp<SoundTrigger> getSoundTrigger(JNIEnv* env, jobject thiz)
273{
274 Mutex::Autolock l(gLock);
275 SoundTrigger* const st = (SoundTrigger*)env->GetLongField(thiz,
276 gModuleFields.mNativeContext);
277 return sp<SoundTrigger>(st);
278}
279
280static sp<SoundTrigger> setSoundTrigger(JNIEnv* env, jobject thiz, const sp<SoundTrigger>& module)
281{
282 Mutex::Autolock l(gLock);
283 sp<SoundTrigger> old = (SoundTrigger*)env->GetLongField(thiz,
284 gModuleFields.mNativeContext);
285 if (module.get()) {
286 module->incStrong((void*)setSoundTrigger);
287 }
288 if (old != 0) {
289 old->decStrong((void*)setSoundTrigger);
290 }
291 env->SetLongField(thiz, gModuleFields.mNativeContext, (jlong)module.get());
292 return old;
293}
294
295
296static jint
297android_hardware_SoundTrigger_listModules(JNIEnv *env, jobject clazz,
298 jobject jModules)
299{
300 ALOGV("listModules");
301
302 if (jModules == NULL) {
303 ALOGE("listModules NULL AudioPatch ArrayList");
304 return SOUNDTRIGGER_STATUS_BAD_VALUE;
305 }
306 if (!env->IsInstanceOf(jModules, gArrayListClass)) {
307 ALOGE("listModules not an arraylist");
308 return SOUNDTRIGGER_STATUS_BAD_VALUE;
309 }
310
311 unsigned int numModules = 0;
312 struct sound_trigger_module_descriptor *nModules = NULL;
313
314 status_t status = SoundTrigger::listModules(nModules, &numModules);
315 if (status != NO_ERROR || numModules == 0) {
316 return (jint)status;
317 }
318
319 nModules = (struct sound_trigger_module_descriptor *)
320 calloc(numModules, sizeof(struct sound_trigger_module_descriptor));
321
322 status = SoundTrigger::listModules(nModules, &numModules);
323 ALOGV("listModules SoundTrigger::listModules status %d numModules %d", status, numModules);
324
325 if (status != NO_ERROR) {
326 numModules = 0;
327 }
328
329 for (size_t i = 0; i < numModules; i++) {
330 char str[SOUND_TRIGGER_MAX_STRING_LEN];
331
332 jstring implementor = env->NewStringUTF(nModules[i].properties.implementor);
333 jstring description = env->NewStringUTF(nModules[i].properties.description);
334 SoundTrigger::guidToString(&nModules[i].properties.uuid,
335 str,
336 SOUND_TRIGGER_MAX_STRING_LEN);
337 jstring uuid = env->NewStringUTF(str);
338
339 ALOGV("listModules module %d id %d description %s maxSoundModels %d",
340 i, nModules[i].handle, nModules[i].properties.description,
341 nModules[i].properties.max_sound_models);
342
343 jobject newModuleDesc = env->NewObject(gModulePropertiesClass, gModulePropertiesCstor,
344 nModules[i].handle,
345 implementor, description, uuid,
346 nModules[i].properties.version,
347 nModules[i].properties.max_sound_models,
348 nModules[i].properties.max_key_phrases,
349 nModules[i].properties.max_users,
350 nModules[i].properties.recognition_modes,
351 nModules[i].properties.capture_transition,
352 nModules[i].properties.max_buffer_ms,
353 nModules[i].properties.concurrent_capture,
354 nModules[i].properties.power_consumption_mw);
355
356 env->DeleteLocalRef(implementor);
357 env->DeleteLocalRef(description);
358 env->DeleteLocalRef(uuid);
359 if (newModuleDesc == NULL) {
360 status = SOUNDTRIGGER_STATUS_ERROR;
361 goto exit;
362 }
363 env->CallBooleanMethod(jModules, gArrayListMethods.add, newModuleDesc);
364 }
365
366exit:
367 free(nModules);
368 return (jint) status;
369}
370
371static void
372android_hardware_SoundTrigger_setup(JNIEnv *env, jobject thiz, jobject weak_this)
373{
374 ALOGV("setup");
375
376 sp<JNISoundTriggerCallback> callback = new JNISoundTriggerCallback(env, thiz, weak_this);
377
378 sound_trigger_module_handle_t handle =
379 (sound_trigger_module_handle_t)env->GetIntField(thiz, gModuleFields.mId);
380
381 sp<SoundTrigger> module = SoundTrigger::attach(handle, callback);
382 if (module == 0) {
383 return;
384 }
385
386 setSoundTrigger(env, thiz, module);
387}
388
389static void
390android_hardware_SoundTrigger_detach(JNIEnv *env, jobject thiz)
391{
392 ALOGV("detach");
393 sp<SoundTrigger> module = setSoundTrigger(env, thiz, 0);
394 ALOGV("detach module %p", module.get());
395 if (module != 0) {
396 ALOGV("detach module->detach()");
397 module->detach();
398 }
399}
400
401static void
402android_hardware_SoundTrigger_finalize(JNIEnv *env, jobject thiz)
403{
404 ALOGV("finalize");
405 sp<SoundTrigger> module = getSoundTrigger(env, thiz);
406 if (module != 0) {
407 ALOGW("SoundTrigger finalized without being detached");
408 }
409 android_hardware_SoundTrigger_detach(env, thiz);
410}
411
412static jint
413android_hardware_SoundTrigger_loadSoundModel(JNIEnv *env, jobject thiz,
414 jobject jSoundModel, jintArray jHandle)
415{
416 jint status = SOUNDTRIGGER_STATUS_OK;
Eric Laurent013f66b2014-07-06 16:35:00 -0700417 jbyte *nData = NULL;
Eric Laurent60b62bc2014-04-18 17:50:49 -0700418 struct sound_trigger_sound_model *nSoundModel;
419 jbyteArray jData;
420 sp<MemoryDealer> memoryDealer;
421 sp<IMemory> memory;
422 size_t size;
423 sound_model_handle_t handle;
Sandeep Siddharthad4233c62014-06-12 18:31:19 -0700424 jobject jUuid;
425 jstring jUuidString;
426 const char *nUuidString;
Eric Laurent60b62bc2014-04-18 17:50:49 -0700427
428 ALOGV("loadSoundModel");
429 sp<SoundTrigger> module = getSoundTrigger(env, thiz);
430 if (module == NULL) {
431 return SOUNDTRIGGER_STATUS_ERROR;
432 }
433 if (jHandle == NULL) {
434 return SOUNDTRIGGER_STATUS_BAD_VALUE;
435 }
436 jsize jHandleLen = env->GetArrayLength(jHandle);
437 if (jHandleLen == 0) {
438 return SOUNDTRIGGER_STATUS_BAD_VALUE;
439 }
440 jint *nHandle = env->GetIntArrayElements(jHandle, NULL);
441 if (nHandle == NULL) {
442 return SOUNDTRIGGER_STATUS_ERROR;
443 }
444 if (!env->IsInstanceOf(jSoundModel, gSoundModelClass)) {
445 status = SOUNDTRIGGER_STATUS_BAD_VALUE;
446 goto exit;
447 }
448 size_t offset;
449 sound_trigger_sound_model_type_t type;
Sandeep Siddharthad4233c62014-06-12 18:31:19 -0700450 if (env->IsInstanceOf(jSoundModel, gKeyphraseSoundModelClass)) {
Eric Laurent60b62bc2014-04-18 17:50:49 -0700451 offset = sizeof(struct sound_trigger_phrase_sound_model);
452 type = SOUND_MODEL_TYPE_KEYPHRASE;
453 } else {
454 offset = sizeof(struct sound_trigger_sound_model);
455 type = SOUND_MODEL_TYPE_UNKNOWN;
456 }
Sandeep Siddharthad4233c62014-06-12 18:31:19 -0700457
458 jUuid = env->GetObjectField(jSoundModel, gSoundModelFields.uuid);
459 jUuidString = (jstring)env->CallObjectMethod(jUuid, gUUIDMethods.toString);
460 nUuidString = env->GetStringUTFChars(jUuidString, NULL);
461 sound_trigger_uuid_t nUuid;
462 SoundTrigger::stringToGuid(nUuidString, &nUuid);
463 env->ReleaseStringUTFChars(jUuidString, nUuidString);
464 env->DeleteLocalRef(jUuidString);
465
Eric Laurent60b62bc2014-04-18 17:50:49 -0700466 jData = (jbyteArray)env->GetObjectField(jSoundModel, gSoundModelFields.data);
467 if (jData == NULL) {
468 status = SOUNDTRIGGER_STATUS_BAD_VALUE;
469 goto exit;
470 }
471 size = env->GetArrayLength(jData);
472
Eric Laurent013f66b2014-07-06 16:35:00 -0700473 nData = env->GetByteArrayElements(jData, NULL);
Eric Laurent60b62bc2014-04-18 17:50:49 -0700474 if (jData == NULL) {
475 status = SOUNDTRIGGER_STATUS_ERROR;
476 goto exit;
477 }
478
479 memoryDealer = new MemoryDealer(offset + size, "SoundTrigge-JNI::LoadModel");
480 if (memoryDealer == 0) {
481 status = SOUNDTRIGGER_STATUS_ERROR;
482 goto exit;
483 }
484 memory = memoryDealer->allocate(offset + size);
485 if (memory == 0 || memory->pointer() == NULL) {
486 status = SOUNDTRIGGER_STATUS_ERROR;
487 goto exit;
488 }
489
490 nSoundModel = (struct sound_trigger_sound_model *)memory->pointer();
491
492 nSoundModel->type = type;
Sandeep Siddharthad4233c62014-06-12 18:31:19 -0700493 nSoundModel->uuid = nUuid;
Eric Laurent60b62bc2014-04-18 17:50:49 -0700494 nSoundModel->data_size = size;
495 nSoundModel->data_offset = offset;
496 memcpy((char *)nSoundModel + offset, nData, size);
497 if (type == SOUND_MODEL_TYPE_KEYPHRASE) {
498 struct sound_trigger_phrase_sound_model *phraseModel =
499 (struct sound_trigger_phrase_sound_model *)nSoundModel;
500
501 jobjectArray jPhrases =
Sandeep Siddharthad4233c62014-06-12 18:31:19 -0700502 (jobjectArray)env->GetObjectField(jSoundModel, gKeyphraseSoundModelFields.keyphrases);
Eric Laurent60b62bc2014-04-18 17:50:49 -0700503 if (jPhrases == NULL) {
504 status = SOUNDTRIGGER_STATUS_BAD_VALUE;
505 goto exit;
506 }
507
508 size_t numPhrases = env->GetArrayLength(jPhrases);
509 phraseModel->num_phrases = numPhrases;
510 ALOGV("loadSoundModel numPhrases %d", numPhrases);
511 for (size_t i = 0; i < numPhrases; i++) {
512 jobject jPhrase = env->GetObjectArrayElement(jPhrases, i);
Sandeep Siddharthad4233c62014-06-12 18:31:19 -0700513 phraseModel->phrases[i].id =
514 env->GetIntField(jPhrase,gKeyphraseFields.id);
Eric Laurent60b62bc2014-04-18 17:50:49 -0700515 phraseModel->phrases[i].recognition_mode =
Sandeep Siddharthad4233c62014-06-12 18:31:19 -0700516 env->GetIntField(jPhrase,gKeyphraseFields.recognitionModes);
Eric Laurent013f66b2014-07-06 16:35:00 -0700517
518 jintArray jUsers = (jintArray)env->GetObjectField(jPhrase, gKeyphraseFields.users);
519 phraseModel->phrases[i].num_users = env->GetArrayLength(jUsers);
520 jint *nUsers = env->GetIntArrayElements(jUsers, NULL);
521 memcpy(phraseModel->phrases[i].users,
522 nUsers,
523 phraseModel->phrases[i].num_users * sizeof(int));
524 env->ReleaseIntArrayElements(jUsers, nUsers, 0);
525 env->DeleteLocalRef(jUsers);
526
Sandeep Siddharthad4233c62014-06-12 18:31:19 -0700527 jstring jLocale = (jstring)env->GetObjectField(jPhrase, gKeyphraseFields.locale);
Eric Laurent60b62bc2014-04-18 17:50:49 -0700528 const char *nLocale = env->GetStringUTFChars(jLocale, NULL);
529 strncpy(phraseModel->phrases[i].locale,
530 nLocale,
531 SOUND_TRIGGER_MAX_LOCALE_LEN);
Sandeep Siddharthad4233c62014-06-12 18:31:19 -0700532 jstring jText = (jstring)env->GetObjectField(jPhrase, gKeyphraseFields.text);
Eric Laurent60b62bc2014-04-18 17:50:49 -0700533 const char *nText = env->GetStringUTFChars(jText, NULL);
534 strncpy(phraseModel->phrases[i].text,
535 nText,
536 SOUND_TRIGGER_MAX_STRING_LEN);
537
538 env->ReleaseStringUTFChars(jLocale, nLocale);
539 env->DeleteLocalRef(jLocale);
540 env->ReleaseStringUTFChars(jText, nText);
541 env->DeleteLocalRef(jText);
542 ALOGV("loadSoundModel phrases %d text %s locale %s",
543 i, phraseModel->phrases[i].text, phraseModel->phrases[i].locale);
Eric Laurent013f66b2014-07-06 16:35:00 -0700544 env->DeleteLocalRef(jPhrase);
Eric Laurent60b62bc2014-04-18 17:50:49 -0700545 }
546 env->DeleteLocalRef(jPhrases);
547 }
548 status = module->loadSoundModel(memory, &handle);
549 ALOGV("loadSoundModel status %d handle %d", status, handle);
550
551exit:
552 if (nHandle != NULL) {
553 nHandle[0] = (jint)handle;
554 env->ReleaseIntArrayElements(jHandle, nHandle, NULL);
555 }
556 if (nData != NULL) {
Eric Laurent013f66b2014-07-06 16:35:00 -0700557 env->ReleaseByteArrayElements(jData, nData, NULL);
Eric Laurent60b62bc2014-04-18 17:50:49 -0700558 }
559 return status;
560}
561
562static jint
563android_hardware_SoundTrigger_unloadSoundModel(JNIEnv *env, jobject thiz,
564 jint jHandle)
565{
566 jint status = SOUNDTRIGGER_STATUS_OK;
567 ALOGV("unloadSoundModel");
568 sp<SoundTrigger> module = getSoundTrigger(env, thiz);
569 if (module == NULL) {
570 return SOUNDTRIGGER_STATUS_ERROR;
571 }
572 status = module->unloadSoundModel((sound_model_handle_t)jHandle);
573
574 return status;
575}
576
577static jint
578android_hardware_SoundTrigger_startRecognition(JNIEnv *env, jobject thiz,
Eric Laurent013f66b2014-07-06 16:35:00 -0700579 jint jHandle, jobject jConfig)
Eric Laurent60b62bc2014-04-18 17:50:49 -0700580{
581 jint status = SOUNDTRIGGER_STATUS_OK;
582 ALOGV("startRecognition");
583 sp<SoundTrigger> module = getSoundTrigger(env, thiz);
584 if (module == NULL) {
585 return SOUNDTRIGGER_STATUS_ERROR;
586 }
Eric Laurent013f66b2014-07-06 16:35:00 -0700587
588 if (!env->IsInstanceOf(jConfig, gRecognitionConfigClass)) {
589 return SOUNDTRIGGER_STATUS_BAD_VALUE;
590 }
591
592 jbyteArray jData = (jbyteArray)env->GetObjectField(jConfig, gRecognitionConfigFields.data);
Eric Laurent60b62bc2014-04-18 17:50:49 -0700593 jsize dataSize = 0;
Eric Laurent013f66b2014-07-06 16:35:00 -0700594 jbyte *nData = NULL;
Eric Laurent60b62bc2014-04-18 17:50:49 -0700595 if (jData != NULL) {
596 dataSize = env->GetArrayLength(jData);
597 if (dataSize == 0) {
598 return SOUNDTRIGGER_STATUS_BAD_VALUE;
599 }
Eric Laurent013f66b2014-07-06 16:35:00 -0700600 nData = env->GetByteArrayElements(jData, NULL);
Eric Laurent60b62bc2014-04-18 17:50:49 -0700601 if (nData == NULL) {
602 return SOUNDTRIGGER_STATUS_ERROR;
603 }
Eric Laurent60b62bc2014-04-18 17:50:49 -0700604 }
605
Eric Laurent013f66b2014-07-06 16:35:00 -0700606 size_t totalSize = sizeof(struct sound_trigger_recognition_config) + dataSize;
607 sp<MemoryDealer> memoryDealer =
608 new MemoryDealer(totalSize, "SoundTrigge-JNI::StartRecognition");
609 if (memoryDealer == 0) {
610 return SOUNDTRIGGER_STATUS_ERROR;
611 }
612 sp<IMemory> memory = memoryDealer->allocate(totalSize);
613 if (memory == 0 || memory->pointer() == NULL) {
614 return SOUNDTRIGGER_STATUS_ERROR;
615 }
616 if (dataSize != 0) {
617 memcpy((char *)memory->pointer() + sizeof(struct sound_trigger_recognition_config),
618 nData,
619 dataSize);
620 env->ReleaseByteArrayElements(jData, nData, 0);
621 }
622 env->DeleteLocalRef(jData);
623 struct sound_trigger_recognition_config *config =
624 (struct sound_trigger_recognition_config *)memory->pointer();
625 config->data_size = dataSize;
626 config->data_offset = sizeof(struct sound_trigger_recognition_config);
627 config->capture_requested = env->GetIntField(jConfig,
628 gRecognitionConfigFields.captureRequested);
629
630 config->num_phrases = 0;
631 jobjectArray jPhrases =
632 (jobjectArray)env->GetObjectField(jConfig, gRecognitionConfigFields.keyphrases);
633 if (jPhrases != NULL) {
634 config->num_phrases = env->GetArrayLength(jPhrases);
635 }
636 ALOGV("startRecognition num phrases %d", config->num_phrases);
637 for (size_t i = 0; i < config->num_phrases; i++) {
638 jobject jPhrase = env->GetObjectArrayElement(jPhrases, i);
639 config->phrases[i].id = env->GetIntField(jPhrase,
640 gKeyphraseRecognitionExtraFields.id);
641 config->phrases[i].recognition_modes = env->GetIntField(jPhrase,
642 gKeyphraseRecognitionExtraFields.recognitionModes);
643 config->phrases[i].num_levels = 0;
644 jobjectArray jConfidenceLevels = (jobjectArray)env->GetObjectField(jPhrase,
645 gKeyphraseRecognitionExtraFields.confidenceLevels);
646 if (jConfidenceLevels != NULL) {
647 config->phrases[i].num_levels = env->GetArrayLength(jConfidenceLevels);
648 }
649 ALOGV("startRecognition phrase %d num_levels %d", i, config->phrases[i].num_levels);
650 for (size_t j = 0; j < config->phrases[i].num_levels; j++) {
651 jobject jConfidenceLevel = env->GetObjectArrayElement(jConfidenceLevels, j);
652 config->phrases[i].levels[j].user_id = env->GetIntField(jConfidenceLevel,
653 gConfidenceLevelFields.userId);
654 config->phrases[i].levels[j].level = env->GetIntField(jConfidenceLevel,
655 gConfidenceLevelFields.confidenceLevel);
656 env->DeleteLocalRef(jConfidenceLevel);
657 }
658 ALOGV("startRecognition phrases %d", i);
659 env->DeleteLocalRef(jConfidenceLevels);
660 env->DeleteLocalRef(jPhrase);
661 }
662 env->DeleteLocalRef(jPhrases);
663
Eric Laurent60b62bc2014-04-18 17:50:49 -0700664 status = module->startRecognition(jHandle, memory);
665 return status;
666}
667
668static jint
669android_hardware_SoundTrigger_stopRecognition(JNIEnv *env, jobject thiz,
670 jint jHandle)
671{
672 jint status = SOUNDTRIGGER_STATUS_OK;
673 ALOGV("stopRecognition");
674 sp<SoundTrigger> module = getSoundTrigger(env, thiz);
675 if (module == NULL) {
676 return SOUNDTRIGGER_STATUS_ERROR;
677 }
678 status = module->stopRecognition(jHandle);
679 return status;
680}
681
682static JNINativeMethod gMethods[] = {
683 {"listModules",
684 "(Ljava/util/ArrayList;)I",
685 (void *)android_hardware_SoundTrigger_listModules},
686};
687
688
689static JNINativeMethod gModuleMethods[] = {
690 {"native_setup",
691 "(Ljava/lang/Object;)V",
692 (void *)android_hardware_SoundTrigger_setup},
693 {"native_finalize",
694 "()V",
695 (void *)android_hardware_SoundTrigger_finalize},
696 {"detach",
697 "()V",
698 (void *)android_hardware_SoundTrigger_detach},
699 {"loadSoundModel",
700 "(Landroid/hardware/soundtrigger/SoundTrigger$SoundModel;[I)I",
701 (void *)android_hardware_SoundTrigger_loadSoundModel},
702 {"unloadSoundModel",
703 "(I)I",
704 (void *)android_hardware_SoundTrigger_unloadSoundModel},
705 {"startRecognition",
Eric Laurent013f66b2014-07-06 16:35:00 -0700706 "(ILandroid/hardware/soundtrigger/SoundTrigger$RecognitionConfig;)I",
Eric Laurent60b62bc2014-04-18 17:50:49 -0700707 (void *)android_hardware_SoundTrigger_startRecognition},
708 {"stopRecognition",
709 "(I)I",
710 (void *)android_hardware_SoundTrigger_stopRecognition},
711};
712
713int register_android_hardware_SoundTrigger(JNIEnv *env)
714{
715 jclass arrayListClass = env->FindClass("java/util/ArrayList");
716 gArrayListClass = (jclass) env->NewGlobalRef(arrayListClass);
717 gArrayListMethods.add = env->GetMethodID(arrayListClass, "add", "(Ljava/lang/Object;)Z");
718
Sandeep Siddharthad4233c62014-06-12 18:31:19 -0700719 jclass uuidClass = env->FindClass("java/util/UUID");
720 gUUIDClass = (jclass) env->NewGlobalRef(uuidClass);
721 gUUIDMethods.toString = env->GetMethodID(uuidClass, "toString", "()Ljava/lang/String;");
722
Eric Laurent60b62bc2014-04-18 17:50:49 -0700723 jclass lClass = env->FindClass(kSoundTriggerClassPathName);
724 gSoundTriggerClass = (jclass) env->NewGlobalRef(lClass);
725
726 jclass moduleClass = env->FindClass(kModuleClassPathName);
727 gModuleClass = (jclass) env->NewGlobalRef(moduleClass);
728 gPostEventFromNative = env->GetStaticMethodID(moduleClass, "postEventFromNative",
729 "(Ljava/lang/Object;IIILjava/lang/Object;)V");
730 gModuleFields.mNativeContext = env->GetFieldID(moduleClass, "mNativeContext", "J");
731 gModuleFields.mId = env->GetFieldID(moduleClass, "mId", "I");
732
733
734 jclass modulePropertiesClass = env->FindClass(kModulePropertiesClassPathName);
735 gModulePropertiesClass = (jclass) env->NewGlobalRef(modulePropertiesClass);
736 gModulePropertiesCstor = env->GetMethodID(modulePropertiesClass, "<init>",
737 "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;IIIIIZIZI)V");
738
739 jclass soundModelClass = env->FindClass(kSoundModelClassPathName);
740 gSoundModelClass = (jclass) env->NewGlobalRef(soundModelClass);
Sandeep Siddharthad4233c62014-06-12 18:31:19 -0700741 gSoundModelFields.uuid = env->GetFieldID(soundModelClass, "uuid", "Ljava/util/UUID;");
Eric Laurent60b62bc2014-04-18 17:50:49 -0700742 gSoundModelFields.data = env->GetFieldID(soundModelClass, "data", "[B");
743
Sandeep Siddharthad4233c62014-06-12 18:31:19 -0700744 jclass keyphraseClass = env->FindClass(kKeyphraseClassPathName);
745 gKeyphraseClass = (jclass) env->NewGlobalRef(keyphraseClass);
746 gKeyphraseFields.id = env->GetFieldID(keyphraseClass, "id", "I");
747 gKeyphraseFields.recognitionModes = env->GetFieldID(keyphraseClass, "recognitionModes", "I");
748 gKeyphraseFields.locale = env->GetFieldID(keyphraseClass, "locale", "Ljava/lang/String;");
749 gKeyphraseFields.text = env->GetFieldID(keyphraseClass, "text", "Ljava/lang/String;");
Eric Laurent013f66b2014-07-06 16:35:00 -0700750 gKeyphraseFields.users = env->GetFieldID(keyphraseClass, "users", "[I");
Eric Laurent60b62bc2014-04-18 17:50:49 -0700751
Sandeep Siddharthad4233c62014-06-12 18:31:19 -0700752 jclass keyphraseSoundModelClass = env->FindClass(kKeyphraseSoundModelClassPathName);
753 gKeyphraseSoundModelClass = (jclass) env->NewGlobalRef(keyphraseSoundModelClass);
754 gKeyphraseSoundModelFields.keyphrases = env->GetFieldID(keyphraseSoundModelClass,
755 "keyphrases",
756 "[Landroid/hardware/soundtrigger/SoundTrigger$Keyphrase;");
Eric Laurent60b62bc2014-04-18 17:50:49 -0700757
758
759 jclass recognitionEventClass = env->FindClass(kRecognitionEventClassPathName);
760 gRecognitionEventClass = (jclass) env->NewGlobalRef(recognitionEventClass);
761 gRecognitionEventCstor = env->GetMethodID(recognitionEventClass, "<init>",
Eric Laurent013f66b2014-07-06 16:35:00 -0700762 "(IIZIII[B)V");
Eric Laurent60b62bc2014-04-18 17:50:49 -0700763
Sandeep Siddharthad4233c62014-06-12 18:31:19 -0700764 jclass keyphraseRecognitionEventClass = env->FindClass(kKeyphraseRecognitionEventClassPathName);
765 gKeyphraseRecognitionEventClass = (jclass) env->NewGlobalRef(keyphraseRecognitionEventClass);
766 gKeyphraseRecognitionEventCstor = env->GetMethodID(keyphraseRecognitionEventClass, "<init>",
Eric Laurent013f66b2014-07-06 16:35:00 -0700767 "(IIZIII[BZ[Landroid/hardware/soundtrigger/SoundTrigger$KeyphraseRecognitionExtra;)V");
Eric Laurent60b62bc2014-04-18 17:50:49 -0700768
769
Eric Laurent013f66b2014-07-06 16:35:00 -0700770 jclass keyRecognitionConfigClass = env->FindClass(kRecognitionConfigClassPathName);
771 gRecognitionConfigClass = (jclass) env->NewGlobalRef(keyRecognitionConfigClass);
772 gRecognitionConfigFields.captureRequested = env->GetFieldID(keyRecognitionConfigClass,
773 "captureRequested",
774 "Z");
775 gRecognitionConfigFields.keyphrases = env->GetFieldID(keyRecognitionConfigClass,
776 "keyphrases",
777 "[Landroid/hardware/soundtrigger/SoundTrigger$KeyphraseRecognitionExtra;");
778 gRecognitionConfigFields.data = env->GetFieldID(keyRecognitionConfigClass,
779 "data",
780 "[B");
781
Sandeep Siddharthad4233c62014-06-12 18:31:19 -0700782 jclass keyphraseRecognitionExtraClass = env->FindClass(kKeyphraseRecognitionExtraClassPathName);
783 gKeyphraseRecognitionExtraClass = (jclass) env->NewGlobalRef(keyphraseRecognitionExtraClass);
784 gKeyphraseRecognitionExtraCstor = env->GetMethodID(keyphraseRecognitionExtraClass, "<init>",
Eric Laurent013f66b2014-07-06 16:35:00 -0700785 "(II[Landroid/hardware/soundtrigger/SoundTrigger$ConfidenceLevel;)V");
786 gKeyphraseRecognitionExtraFields.id = env->GetFieldID(gKeyphraseRecognitionExtraClass, "id", "I");
787 gKeyphraseRecognitionExtraFields.recognitionModes = env->GetFieldID(gKeyphraseRecognitionExtraClass, "recognitionModes", "I");
788 gKeyphraseRecognitionExtraFields.confidenceLevels = env->GetFieldID(gKeyphraseRecognitionExtraClass,
789 "confidenceLevels",
790 "[Landroid/hardware/soundtrigger/SoundTrigger$ConfidenceLevel;");
791
792 jclass confidenceLevelClass = env->FindClass(kConfidenceLevelClassPathName);
793 gConfidenceLevelClass = (jclass) env->NewGlobalRef(confidenceLevelClass);
794 gConfidenceLevelCstor = env->GetMethodID(confidenceLevelClass, "<init>", "(II)V");
795 gConfidenceLevelFields.userId = env->GetFieldID(confidenceLevelClass, "userId", "I");
796 gConfidenceLevelFields.confidenceLevel = env->GetFieldID(confidenceLevelClass,
797 "confidenceLevel", "I");
Eric Laurent60b62bc2014-04-18 17:50:49 -0700798
799 int status = AndroidRuntime::registerNativeMethods(env,
800 kSoundTriggerClassPathName, gMethods, NELEM(gMethods));
801
802 if (status == 0) {
803 status = AndroidRuntime::registerNativeMethods(env,
804 kModuleClassPathName, gModuleMethods, NELEM(gModuleMethods));
805 }
806
Eric Laurent013f66b2014-07-06 16:35:00 -0700807
Eric Laurent60b62bc2014-04-18 17:50:49 -0700808 return status;
809}