blob: afb92a1246041b98f7187db255bdf0fbaef4db4f [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;
77 jfieldID numUsers;
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
87
88static const char* const kRecognitionEventClassPathName =
89 "android/hardware/soundtrigger/SoundTrigger$RecognitionEvent";
90static jclass gRecognitionEventClass;
91static jmethodID gRecognitionEventCstor;
92
Sandeep Siddharthad4233c62014-06-12 18:31:19 -070093static const char* const kKeyphraseRecognitionEventClassPathName =
94 "android/hardware/soundtrigger/SoundTrigger$KeyphraseRecognitionEvent";
95static jclass gKeyphraseRecognitionEventClass;
96static jmethodID gKeyphraseRecognitionEventCstor;
Eric Laurent60b62bc2014-04-18 17:50:49 -070097
Sandeep Siddharthad4233c62014-06-12 18:31:19 -070098static const char* const kKeyphraseRecognitionExtraClassPathName =
99 "android/hardware/soundtrigger/SoundTrigger$KeyphraseRecognitionExtra";
100static jclass gKeyphraseRecognitionExtraClass;
101static jmethodID gKeyphraseRecognitionExtraCstor;
Eric Laurent60b62bc2014-04-18 17:50:49 -0700102
103static Mutex gLock;
104
105enum {
106 SOUNDTRIGGER_STATUS_OK = 0,
107 SOUNDTRIGGER_STATUS_ERROR = INT_MIN,
108 SOUNDTRIGGER_PERMISSION_DENIED = -1,
109 SOUNDTRIGGER_STATUS_NO_INIT = -19,
110 SOUNDTRIGGER_STATUS_BAD_VALUE = -22,
111 SOUNDTRIGGER_STATUS_DEAD_OBJECT = -32,
112 SOUNDTRIGGER_INVALID_OPERATION = -38,
113};
114
115enum {
116 SOUNDTRIGGER_EVENT_RECOGNITION = 1,
117 SOUNDTRIGGER_EVENT_SERVICE_DIED = 2,
118};
119
120// ----------------------------------------------------------------------------
121// ref-counted object for callbacks
122class JNISoundTriggerCallback: public SoundTriggerCallback
123{
124public:
125 JNISoundTriggerCallback(JNIEnv* env, jobject thiz, jobject weak_thiz);
126 ~JNISoundTriggerCallback();
127
128 virtual void onRecognitionEvent(struct sound_trigger_recognition_event *event);
129 virtual void onServiceDied();
130
131private:
132 jclass mClass; // Reference to SoundTrigger class
133 jobject mObject; // Weak ref to SoundTrigger Java object to call on
134};
135
136JNISoundTriggerCallback::JNISoundTriggerCallback(JNIEnv* env, jobject thiz, jobject weak_thiz)
137{
138
139 // Hold onto the SoundTriggerModule class for use in calling the static method
140 // that posts events to the application thread.
141 jclass clazz = env->GetObjectClass(thiz);
142 if (clazz == NULL) {
143 ALOGE("Can't find class %s", kModuleClassPathName);
144 return;
145 }
146 mClass = (jclass)env->NewGlobalRef(clazz);
147
148 // We use a weak reference so the SoundTriggerModule object can be garbage collected.
149 // The reference is only used as a proxy for callbacks.
150 mObject = env->NewGlobalRef(weak_thiz);
151}
152
153JNISoundTriggerCallback::~JNISoundTriggerCallback()
154{
155 // remove global references
156 JNIEnv *env = AndroidRuntime::getJNIEnv();
157 env->DeleteGlobalRef(mObject);
158 env->DeleteGlobalRef(mClass);
159}
160
161void JNISoundTriggerCallback::onRecognitionEvent(struct sound_trigger_recognition_event *event)
162{
163 JNIEnv *env = AndroidRuntime::getJNIEnv();
164
165 jobject jEvent;
166
167 jbyteArray jData = NULL;
168 if (event->data_size) {
169 jData = env->NewByteArray(event->data_size);
170 jbyte *nData = env->GetByteArrayElements(jData, NULL);
171 memcpy(nData, (char *)event + event->data_offset, event->data_size);
172 env->ReleaseByteArrayElements(jData, nData, 0);
173 }
174
175 if (event->type == SOUND_MODEL_TYPE_KEYPHRASE) {
176 struct sound_trigger_phrase_recognition_event *phraseEvent =
177 (struct sound_trigger_phrase_recognition_event *)event;
178
179 jobjectArray jExtras = env->NewObjectArray(phraseEvent->num_phrases,
Sandeep Siddharthad4233c62014-06-12 18:31:19 -0700180 gKeyphraseRecognitionExtraClass, NULL);
Eric Laurent60b62bc2014-04-18 17:50:49 -0700181 if (jExtras == NULL) {
182 return;
183 }
184
185 for (size_t i = 0; i < phraseEvent->num_phrases; i++) {
186 jintArray jConfidenceLevels = env->NewIntArray(phraseEvent->phrase_extras[i].num_users);
187 if (jConfidenceLevels == NULL) {
188 return;
189 }
190 jint *nConfidenceLevels = env->GetIntArrayElements(jConfidenceLevels, NULL);
191 memcpy(nConfidenceLevels,
192 phraseEvent->phrase_extras[i].confidence_levels,
193 phraseEvent->phrase_extras[i].num_users * sizeof(int));
194 env->ReleaseIntArrayElements(jConfidenceLevels, nConfidenceLevels, 0);
Sandeep Siddharthad4233c62014-06-12 18:31:19 -0700195 jobject jNewExtra = env->NewObject(gKeyphraseRecognitionExtraClass,
196 gKeyphraseRecognitionExtraCstor,
Eric Laurent60b62bc2014-04-18 17:50:49 -0700197 jConfidenceLevels,
198 phraseEvent->phrase_extras[i].recognition_modes);
199
200 if (jNewExtra == NULL) {
201 return;
202 }
203 env->SetObjectArrayElement(jExtras, i, jNewExtra);
204
205 }
Sandeep Siddharthad4233c62014-06-12 18:31:19 -0700206 jEvent = env->NewObject(gKeyphraseRecognitionEventClass, gKeyphraseRecognitionEventCstor,
Eric Laurent60b62bc2014-04-18 17:50:49 -0700207 event->status, event->model, event->capture_available,
208 event->capture_session, event->capture_delay_ms, jData,
209 phraseEvent->key_phrase_in_capture, jExtras);
210 } else {
211 jEvent = env->NewObject(gRecognitionEventClass, gRecognitionEventCstor,
212 event->status, event->model, event->capture_available,
213 event->capture_session, event->capture_delay_ms, jData);
214 }
215
216
217 env->CallStaticVoidMethod(mClass, gPostEventFromNative, mObject,
218 SOUNDTRIGGER_EVENT_RECOGNITION, 0, 0, jEvent);
219 if (env->ExceptionCheck()) {
220 ALOGW("An exception occurred while notifying an event.");
221 env->ExceptionClear();
222 }
223}
224
225void JNISoundTriggerCallback::onServiceDied()
226{
227 JNIEnv *env = AndroidRuntime::getJNIEnv();
228
229 env->CallStaticVoidMethod(mClass, gPostEventFromNative, mObject,
230 SOUNDTRIGGER_EVENT_SERVICE_DIED, 0, 0, NULL);
231 if (env->ExceptionCheck()) {
232 ALOGW("An exception occurred while notifying an event.");
233 env->ExceptionClear();
234 }
235}
236
237// ----------------------------------------------------------------------------
238
239static sp<SoundTrigger> getSoundTrigger(JNIEnv* env, jobject thiz)
240{
241 Mutex::Autolock l(gLock);
242 SoundTrigger* const st = (SoundTrigger*)env->GetLongField(thiz,
243 gModuleFields.mNativeContext);
244 return sp<SoundTrigger>(st);
245}
246
247static sp<SoundTrigger> setSoundTrigger(JNIEnv* env, jobject thiz, const sp<SoundTrigger>& module)
248{
249 Mutex::Autolock l(gLock);
250 sp<SoundTrigger> old = (SoundTrigger*)env->GetLongField(thiz,
251 gModuleFields.mNativeContext);
252 if (module.get()) {
253 module->incStrong((void*)setSoundTrigger);
254 }
255 if (old != 0) {
256 old->decStrong((void*)setSoundTrigger);
257 }
258 env->SetLongField(thiz, gModuleFields.mNativeContext, (jlong)module.get());
259 return old;
260}
261
262
263static jint
264android_hardware_SoundTrigger_listModules(JNIEnv *env, jobject clazz,
265 jobject jModules)
266{
267 ALOGV("listModules");
268
269 if (jModules == NULL) {
270 ALOGE("listModules NULL AudioPatch ArrayList");
271 return SOUNDTRIGGER_STATUS_BAD_VALUE;
272 }
273 if (!env->IsInstanceOf(jModules, gArrayListClass)) {
274 ALOGE("listModules not an arraylist");
275 return SOUNDTRIGGER_STATUS_BAD_VALUE;
276 }
277
278 unsigned int numModules = 0;
279 struct sound_trigger_module_descriptor *nModules = NULL;
280
281 status_t status = SoundTrigger::listModules(nModules, &numModules);
282 if (status != NO_ERROR || numModules == 0) {
283 return (jint)status;
284 }
285
286 nModules = (struct sound_trigger_module_descriptor *)
287 calloc(numModules, sizeof(struct sound_trigger_module_descriptor));
288
289 status = SoundTrigger::listModules(nModules, &numModules);
290 ALOGV("listModules SoundTrigger::listModules status %d numModules %d", status, numModules);
291
292 if (status != NO_ERROR) {
293 numModules = 0;
294 }
295
296 for (size_t i = 0; i < numModules; i++) {
297 char str[SOUND_TRIGGER_MAX_STRING_LEN];
298
299 jstring implementor = env->NewStringUTF(nModules[i].properties.implementor);
300 jstring description = env->NewStringUTF(nModules[i].properties.description);
301 SoundTrigger::guidToString(&nModules[i].properties.uuid,
302 str,
303 SOUND_TRIGGER_MAX_STRING_LEN);
304 jstring uuid = env->NewStringUTF(str);
305
306 ALOGV("listModules module %d id %d description %s maxSoundModels %d",
307 i, nModules[i].handle, nModules[i].properties.description,
308 nModules[i].properties.max_sound_models);
309
310 jobject newModuleDesc = env->NewObject(gModulePropertiesClass, gModulePropertiesCstor,
311 nModules[i].handle,
312 implementor, description, uuid,
313 nModules[i].properties.version,
314 nModules[i].properties.max_sound_models,
315 nModules[i].properties.max_key_phrases,
316 nModules[i].properties.max_users,
317 nModules[i].properties.recognition_modes,
318 nModules[i].properties.capture_transition,
319 nModules[i].properties.max_buffer_ms,
320 nModules[i].properties.concurrent_capture,
321 nModules[i].properties.power_consumption_mw);
322
323 env->DeleteLocalRef(implementor);
324 env->DeleteLocalRef(description);
325 env->DeleteLocalRef(uuid);
326 if (newModuleDesc == NULL) {
327 status = SOUNDTRIGGER_STATUS_ERROR;
328 goto exit;
329 }
330 env->CallBooleanMethod(jModules, gArrayListMethods.add, newModuleDesc);
331 }
332
333exit:
334 free(nModules);
335 return (jint) status;
336}
337
338static void
339android_hardware_SoundTrigger_setup(JNIEnv *env, jobject thiz, jobject weak_this)
340{
341 ALOGV("setup");
342
343 sp<JNISoundTriggerCallback> callback = new JNISoundTriggerCallback(env, thiz, weak_this);
344
345 sound_trigger_module_handle_t handle =
346 (sound_trigger_module_handle_t)env->GetIntField(thiz, gModuleFields.mId);
347
348 sp<SoundTrigger> module = SoundTrigger::attach(handle, callback);
349 if (module == 0) {
350 return;
351 }
352
353 setSoundTrigger(env, thiz, module);
354}
355
356static void
357android_hardware_SoundTrigger_detach(JNIEnv *env, jobject thiz)
358{
359 ALOGV("detach");
360 sp<SoundTrigger> module = setSoundTrigger(env, thiz, 0);
361 ALOGV("detach module %p", module.get());
362 if (module != 0) {
363 ALOGV("detach module->detach()");
364 module->detach();
365 }
366}
367
368static void
369android_hardware_SoundTrigger_finalize(JNIEnv *env, jobject thiz)
370{
371 ALOGV("finalize");
372 sp<SoundTrigger> module = getSoundTrigger(env, thiz);
373 if (module != 0) {
374 ALOGW("SoundTrigger finalized without being detached");
375 }
376 android_hardware_SoundTrigger_detach(env, thiz);
377}
378
379static jint
380android_hardware_SoundTrigger_loadSoundModel(JNIEnv *env, jobject thiz,
381 jobject jSoundModel, jintArray jHandle)
382{
383 jint status = SOUNDTRIGGER_STATUS_OK;
384 char *nData = NULL;
385 struct sound_trigger_sound_model *nSoundModel;
386 jbyteArray jData;
387 sp<MemoryDealer> memoryDealer;
388 sp<IMemory> memory;
389 size_t size;
390 sound_model_handle_t handle;
Sandeep Siddharthad4233c62014-06-12 18:31:19 -0700391 jobject jUuid;
392 jstring jUuidString;
393 const char *nUuidString;
Eric Laurent60b62bc2014-04-18 17:50:49 -0700394
395 ALOGV("loadSoundModel");
396 sp<SoundTrigger> module = getSoundTrigger(env, thiz);
397 if (module == NULL) {
398 return SOUNDTRIGGER_STATUS_ERROR;
399 }
400 if (jHandle == NULL) {
401 return SOUNDTRIGGER_STATUS_BAD_VALUE;
402 }
403 jsize jHandleLen = env->GetArrayLength(jHandle);
404 if (jHandleLen == 0) {
405 return SOUNDTRIGGER_STATUS_BAD_VALUE;
406 }
407 jint *nHandle = env->GetIntArrayElements(jHandle, NULL);
408 if (nHandle == NULL) {
409 return SOUNDTRIGGER_STATUS_ERROR;
410 }
411 if (!env->IsInstanceOf(jSoundModel, gSoundModelClass)) {
412 status = SOUNDTRIGGER_STATUS_BAD_VALUE;
413 goto exit;
414 }
415 size_t offset;
416 sound_trigger_sound_model_type_t type;
Sandeep Siddharthad4233c62014-06-12 18:31:19 -0700417 if (env->IsInstanceOf(jSoundModel, gKeyphraseSoundModelClass)) {
Eric Laurent60b62bc2014-04-18 17:50:49 -0700418 offset = sizeof(struct sound_trigger_phrase_sound_model);
419 type = SOUND_MODEL_TYPE_KEYPHRASE;
420 } else {
421 offset = sizeof(struct sound_trigger_sound_model);
422 type = SOUND_MODEL_TYPE_UNKNOWN;
423 }
Sandeep Siddharthad4233c62014-06-12 18:31:19 -0700424
425 jUuid = env->GetObjectField(jSoundModel, gSoundModelFields.uuid);
426 jUuidString = (jstring)env->CallObjectMethod(jUuid, gUUIDMethods.toString);
427 nUuidString = env->GetStringUTFChars(jUuidString, NULL);
428 sound_trigger_uuid_t nUuid;
429 SoundTrigger::stringToGuid(nUuidString, &nUuid);
430 env->ReleaseStringUTFChars(jUuidString, nUuidString);
431 env->DeleteLocalRef(jUuidString);
432
Eric Laurent60b62bc2014-04-18 17:50:49 -0700433 jData = (jbyteArray)env->GetObjectField(jSoundModel, gSoundModelFields.data);
434 if (jData == NULL) {
435 status = SOUNDTRIGGER_STATUS_BAD_VALUE;
436 goto exit;
437 }
438 size = env->GetArrayLength(jData);
439
440 nData = (char *)env->GetByteArrayElements(jData, NULL);
441 if (jData == NULL) {
442 status = SOUNDTRIGGER_STATUS_ERROR;
443 goto exit;
444 }
445
446 memoryDealer = new MemoryDealer(offset + size, "SoundTrigge-JNI::LoadModel");
447 if (memoryDealer == 0) {
448 status = SOUNDTRIGGER_STATUS_ERROR;
449 goto exit;
450 }
451 memory = memoryDealer->allocate(offset + size);
452 if (memory == 0 || memory->pointer() == NULL) {
453 status = SOUNDTRIGGER_STATUS_ERROR;
454 goto exit;
455 }
456
457 nSoundModel = (struct sound_trigger_sound_model *)memory->pointer();
458
459 nSoundModel->type = type;
Sandeep Siddharthad4233c62014-06-12 18:31:19 -0700460 nSoundModel->uuid = nUuid;
Eric Laurent60b62bc2014-04-18 17:50:49 -0700461 nSoundModel->data_size = size;
462 nSoundModel->data_offset = offset;
463 memcpy((char *)nSoundModel + offset, nData, size);
464 if (type == SOUND_MODEL_TYPE_KEYPHRASE) {
465 struct sound_trigger_phrase_sound_model *phraseModel =
466 (struct sound_trigger_phrase_sound_model *)nSoundModel;
467
468 jobjectArray jPhrases =
Sandeep Siddharthad4233c62014-06-12 18:31:19 -0700469 (jobjectArray)env->GetObjectField(jSoundModel, gKeyphraseSoundModelFields.keyphrases);
Eric Laurent60b62bc2014-04-18 17:50:49 -0700470 if (jPhrases == NULL) {
471 status = SOUNDTRIGGER_STATUS_BAD_VALUE;
472 goto exit;
473 }
474
475 size_t numPhrases = env->GetArrayLength(jPhrases);
476 phraseModel->num_phrases = numPhrases;
477 ALOGV("loadSoundModel numPhrases %d", numPhrases);
478 for (size_t i = 0; i < numPhrases; i++) {
479 jobject jPhrase = env->GetObjectArrayElement(jPhrases, i);
Sandeep Siddharthad4233c62014-06-12 18:31:19 -0700480 phraseModel->phrases[i].id =
481 env->GetIntField(jPhrase,gKeyphraseFields.id);
Eric Laurent60b62bc2014-04-18 17:50:49 -0700482 phraseModel->phrases[i].recognition_mode =
Sandeep Siddharthad4233c62014-06-12 18:31:19 -0700483 env->GetIntField(jPhrase,gKeyphraseFields.recognitionModes);
Eric Laurent60b62bc2014-04-18 17:50:49 -0700484 phraseModel->phrases[i].num_users =
Sandeep Siddharthad4233c62014-06-12 18:31:19 -0700485 env->GetIntField(jPhrase, gKeyphraseFields.numUsers);
486 jstring jLocale = (jstring)env->GetObjectField(jPhrase, gKeyphraseFields.locale);
Eric Laurent60b62bc2014-04-18 17:50:49 -0700487 const char *nLocale = env->GetStringUTFChars(jLocale, NULL);
488 strncpy(phraseModel->phrases[i].locale,
489 nLocale,
490 SOUND_TRIGGER_MAX_LOCALE_LEN);
Sandeep Siddharthad4233c62014-06-12 18:31:19 -0700491 jstring jText = (jstring)env->GetObjectField(jPhrase, gKeyphraseFields.text);
Eric Laurent60b62bc2014-04-18 17:50:49 -0700492 const char *nText = env->GetStringUTFChars(jText, NULL);
493 strncpy(phraseModel->phrases[i].text,
494 nText,
495 SOUND_TRIGGER_MAX_STRING_LEN);
496
497 env->ReleaseStringUTFChars(jLocale, nLocale);
498 env->DeleteLocalRef(jLocale);
499 env->ReleaseStringUTFChars(jText, nText);
500 env->DeleteLocalRef(jText);
501 ALOGV("loadSoundModel phrases %d text %s locale %s",
502 i, phraseModel->phrases[i].text, phraseModel->phrases[i].locale);
503 }
504 env->DeleteLocalRef(jPhrases);
505 }
506 status = module->loadSoundModel(memory, &handle);
507 ALOGV("loadSoundModel status %d handle %d", status, handle);
508
509exit:
510 if (nHandle != NULL) {
511 nHandle[0] = (jint)handle;
512 env->ReleaseIntArrayElements(jHandle, nHandle, NULL);
513 }
514 if (nData != NULL) {
515 env->ReleaseByteArrayElements(jData, (jbyte *)nData, NULL);
516 }
517 return status;
518}
519
520static jint
521android_hardware_SoundTrigger_unloadSoundModel(JNIEnv *env, jobject thiz,
522 jint jHandle)
523{
524 jint status = SOUNDTRIGGER_STATUS_OK;
525 ALOGV("unloadSoundModel");
526 sp<SoundTrigger> module = getSoundTrigger(env, thiz);
527 if (module == NULL) {
528 return SOUNDTRIGGER_STATUS_ERROR;
529 }
530 status = module->unloadSoundModel((sound_model_handle_t)jHandle);
531
532 return status;
533}
534
535static jint
536android_hardware_SoundTrigger_startRecognition(JNIEnv *env, jobject thiz,
537 jint jHandle, jbyteArray jData)
538{
539 jint status = SOUNDTRIGGER_STATUS_OK;
540 ALOGV("startRecognition");
541 sp<SoundTrigger> module = getSoundTrigger(env, thiz);
542 if (module == NULL) {
543 return SOUNDTRIGGER_STATUS_ERROR;
544 }
545 jsize dataSize = 0;
546 char *nData = NULL;
547 sp<IMemory> memory;
548 if (jData != NULL) {
549 dataSize = env->GetArrayLength(jData);
550 if (dataSize == 0) {
551 return SOUNDTRIGGER_STATUS_BAD_VALUE;
552 }
553 nData = (char *)env->GetByteArrayElements(jData, NULL);
554 if (nData == NULL) {
555 return SOUNDTRIGGER_STATUS_ERROR;
556 }
557 sp<MemoryDealer> memoryDealer =
558 new MemoryDealer(dataSize, "SoundTrigge-JNI::StartRecognition");
559 if (memoryDealer == 0) {
560 return SOUNDTRIGGER_STATUS_ERROR;
561 }
562 memory = memoryDealer->allocate(dataSize);
563 if (memory == 0 || memory->pointer() == NULL) {
564 return SOUNDTRIGGER_STATUS_ERROR;
565 }
566 memcpy(memory->pointer(), nData, dataSize);
567 }
568
569 status = module->startRecognition(jHandle, memory);
570 return status;
571}
572
573static jint
574android_hardware_SoundTrigger_stopRecognition(JNIEnv *env, jobject thiz,
575 jint jHandle)
576{
577 jint status = SOUNDTRIGGER_STATUS_OK;
578 ALOGV("stopRecognition");
579 sp<SoundTrigger> module = getSoundTrigger(env, thiz);
580 if (module == NULL) {
581 return SOUNDTRIGGER_STATUS_ERROR;
582 }
583 status = module->stopRecognition(jHandle);
584 return status;
585}
586
587static JNINativeMethod gMethods[] = {
588 {"listModules",
589 "(Ljava/util/ArrayList;)I",
590 (void *)android_hardware_SoundTrigger_listModules},
591};
592
593
594static JNINativeMethod gModuleMethods[] = {
595 {"native_setup",
596 "(Ljava/lang/Object;)V",
597 (void *)android_hardware_SoundTrigger_setup},
598 {"native_finalize",
599 "()V",
600 (void *)android_hardware_SoundTrigger_finalize},
601 {"detach",
602 "()V",
603 (void *)android_hardware_SoundTrigger_detach},
604 {"loadSoundModel",
605 "(Landroid/hardware/soundtrigger/SoundTrigger$SoundModel;[I)I",
606 (void *)android_hardware_SoundTrigger_loadSoundModel},
607 {"unloadSoundModel",
608 "(I)I",
609 (void *)android_hardware_SoundTrigger_unloadSoundModel},
610 {"startRecognition",
611 "(I[B)I",
612 (void *)android_hardware_SoundTrigger_startRecognition},
613 {"stopRecognition",
614 "(I)I",
615 (void *)android_hardware_SoundTrigger_stopRecognition},
616};
617
618int register_android_hardware_SoundTrigger(JNIEnv *env)
619{
620 jclass arrayListClass = env->FindClass("java/util/ArrayList");
621 gArrayListClass = (jclass) env->NewGlobalRef(arrayListClass);
622 gArrayListMethods.add = env->GetMethodID(arrayListClass, "add", "(Ljava/lang/Object;)Z");
623
Sandeep Siddharthad4233c62014-06-12 18:31:19 -0700624 jclass uuidClass = env->FindClass("java/util/UUID");
625 gUUIDClass = (jclass) env->NewGlobalRef(uuidClass);
626 gUUIDMethods.toString = env->GetMethodID(uuidClass, "toString", "()Ljava/lang/String;");
627
Eric Laurent60b62bc2014-04-18 17:50:49 -0700628 jclass lClass = env->FindClass(kSoundTriggerClassPathName);
629 gSoundTriggerClass = (jclass) env->NewGlobalRef(lClass);
630
631 jclass moduleClass = env->FindClass(kModuleClassPathName);
632 gModuleClass = (jclass) env->NewGlobalRef(moduleClass);
633 gPostEventFromNative = env->GetStaticMethodID(moduleClass, "postEventFromNative",
634 "(Ljava/lang/Object;IIILjava/lang/Object;)V");
635 gModuleFields.mNativeContext = env->GetFieldID(moduleClass, "mNativeContext", "J");
636 gModuleFields.mId = env->GetFieldID(moduleClass, "mId", "I");
637
638
639 jclass modulePropertiesClass = env->FindClass(kModulePropertiesClassPathName);
640 gModulePropertiesClass = (jclass) env->NewGlobalRef(modulePropertiesClass);
641 gModulePropertiesCstor = env->GetMethodID(modulePropertiesClass, "<init>",
642 "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;IIIIIZIZI)V");
643
644 jclass soundModelClass = env->FindClass(kSoundModelClassPathName);
645 gSoundModelClass = (jclass) env->NewGlobalRef(soundModelClass);
Sandeep Siddharthad4233c62014-06-12 18:31:19 -0700646 gSoundModelFields.uuid = env->GetFieldID(soundModelClass, "uuid", "Ljava/util/UUID;");
Eric Laurent60b62bc2014-04-18 17:50:49 -0700647 gSoundModelFields.data = env->GetFieldID(soundModelClass, "data", "[B");
648
Sandeep Siddharthad4233c62014-06-12 18:31:19 -0700649 jclass keyphraseClass = env->FindClass(kKeyphraseClassPathName);
650 gKeyphraseClass = (jclass) env->NewGlobalRef(keyphraseClass);
651 gKeyphraseFields.id = env->GetFieldID(keyphraseClass, "id", "I");
652 gKeyphraseFields.recognitionModes = env->GetFieldID(keyphraseClass, "recognitionModes", "I");
653 gKeyphraseFields.locale = env->GetFieldID(keyphraseClass, "locale", "Ljava/lang/String;");
654 gKeyphraseFields.text = env->GetFieldID(keyphraseClass, "text", "Ljava/lang/String;");
655 gKeyphraseFields.numUsers = env->GetFieldID(keyphraseClass, "numUsers", "I");
Eric Laurent60b62bc2014-04-18 17:50:49 -0700656
Sandeep Siddharthad4233c62014-06-12 18:31:19 -0700657 jclass keyphraseSoundModelClass = env->FindClass(kKeyphraseSoundModelClassPathName);
658 gKeyphraseSoundModelClass = (jclass) env->NewGlobalRef(keyphraseSoundModelClass);
659 gKeyphraseSoundModelFields.keyphrases = env->GetFieldID(keyphraseSoundModelClass,
660 "keyphrases",
661 "[Landroid/hardware/soundtrigger/SoundTrigger$Keyphrase;");
Eric Laurent60b62bc2014-04-18 17:50:49 -0700662
663
664 jclass recognitionEventClass = env->FindClass(kRecognitionEventClassPathName);
665 gRecognitionEventClass = (jclass) env->NewGlobalRef(recognitionEventClass);
666 gRecognitionEventCstor = env->GetMethodID(recognitionEventClass, "<init>",
667 "(IIZII[B)V");
668
Sandeep Siddharthad4233c62014-06-12 18:31:19 -0700669 jclass keyphraseRecognitionEventClass = env->FindClass(kKeyphraseRecognitionEventClassPathName);
670 gKeyphraseRecognitionEventClass = (jclass) env->NewGlobalRef(keyphraseRecognitionEventClass);
671 gKeyphraseRecognitionEventCstor = env->GetMethodID(keyphraseRecognitionEventClass, "<init>",
672 "(IIZII[BZ[Landroid/hardware/soundtrigger/SoundTrigger$KeyphraseRecognitionExtra;)V");
Eric Laurent60b62bc2014-04-18 17:50:49 -0700673
674
Sandeep Siddharthad4233c62014-06-12 18:31:19 -0700675 jclass keyphraseRecognitionExtraClass = env->FindClass(kKeyphraseRecognitionExtraClassPathName);
676 gKeyphraseRecognitionExtraClass = (jclass) env->NewGlobalRef(keyphraseRecognitionExtraClass);
677 gKeyphraseRecognitionExtraCstor = env->GetMethodID(keyphraseRecognitionExtraClass, "<init>",
Eric Laurent60b62bc2014-04-18 17:50:49 -0700678 "([II)V");
679
680 int status = AndroidRuntime::registerNativeMethods(env,
681 kSoundTriggerClassPathName, gMethods, NELEM(gMethods));
682
683 if (status == 0) {
684 status = AndroidRuntime::registerNativeMethods(env,
685 kModuleClassPathName, gModuleMethods, NELEM(gModuleMethods));
686 }
687
688 return status;
689}