android_hardware_SoundTrigger.cpp revision 013f66b92db609fceeff9c8171daca13d057cc95
1/* 2** 3** Copyright 2014, The Android Open Source Project 4** 5** Licensed under the Apache License, Version 2.0 (the "License"); 6** you may not use this file except in compliance with the License. 7** You may obtain a copy of the License at 8** 9** http://www.apache.org/licenses/LICENSE-2.0 10** 11** Unless required by applicable law or agreed to in writing, software 12** distributed under the License is distributed on an "AS IS" BASIS, 13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14** See the License for the specific language governing permissions and 15** limitations under the License. 16*/ 17 18//#define LOG_NDEBUG 0 19#define LOG_TAG "SoundTrigger-JNI" 20#include <utils/Log.h> 21 22#include "jni.h" 23#include "JNIHelp.h" 24#include "android_runtime/AndroidRuntime.h" 25#include <system/sound_trigger.h> 26#include <soundtrigger/SoundTriggerCallback.h> 27#include <soundtrigger/SoundTrigger.h> 28#include <utils/RefBase.h> 29#include <utils/Vector.h> 30#include <binder/IMemory.h> 31#include <binder/MemoryDealer.h> 32 33using namespace android; 34 35static jclass gArrayListClass; 36static struct { 37 jmethodID add; 38} gArrayListMethods; 39 40static jclass gUUIDClass; 41static struct { 42 jmethodID toString; 43} gUUIDMethods; 44 45static 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 { 65 jfieldID uuid; 66 jfieldID data; 67} gSoundModelFields; 68 69static const char* const kKeyphraseClassPathName = 70 "android/hardware/soundtrigger/SoundTrigger$Keyphrase"; 71static jclass gKeyphraseClass; 72static struct { 73 jfieldID id; 74 jfieldID recognitionModes; 75 jfieldID locale; 76 jfieldID text; 77 jfieldID users; 78} gKeyphraseFields; 79 80static const char* const kKeyphraseSoundModelClassPathName = 81 "android/hardware/soundtrigger/SoundTrigger$KeyphraseSoundModel"; 82static jclass gKeyphraseSoundModelClass; 83static struct { 84 jfieldID keyphrases; 85} gKeyphraseSoundModelFields; 86 87static 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; 95 96static const char* const kRecognitionEventClassPathName = 97 "android/hardware/soundtrigger/SoundTrigger$RecognitionEvent"; 98static jclass gRecognitionEventClass; 99static jmethodID gRecognitionEventCstor; 100 101static const char* const kKeyphraseRecognitionEventClassPathName = 102 "android/hardware/soundtrigger/SoundTrigger$KeyphraseRecognitionEvent"; 103static jclass gKeyphraseRecognitionEventClass; 104static jmethodID gKeyphraseRecognitionEventCstor; 105 106static const char* const kKeyphraseRecognitionExtraClassPathName = 107 "android/hardware/soundtrigger/SoundTrigger$KeyphraseRecognitionExtra"; 108static jclass gKeyphraseRecognitionExtraClass; 109static jmethodID gKeyphraseRecognitionExtraCstor; 110static 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; 124 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, 202 gKeyphraseRecognitionExtraClass, NULL); 203 if (jExtras == NULL) { 204 return; 205 } 206 207 for (size_t i = 0; i < phraseEvent->num_phrases; i++) { 208 jobjectArray jConfidenceLevels = env->NewObjectArray( 209 phraseEvent->phrase_extras[i].num_levels, 210 gConfidenceLevelClass, NULL); 211 212 if (jConfidenceLevels == NULL) { 213 return; 214 } 215 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 224 jobject jNewExtra = env->NewObject(gKeyphraseRecognitionExtraClass, 225 gKeyphraseRecognitionExtraCstor, 226 phraseEvent->phrase_extras[i].id, 227 phraseEvent->phrase_extras[i].recognition_modes, 228 jConfidenceLevels); 229 230 if (jNewExtra == NULL) { 231 return; 232 } 233 env->SetObjectArrayElement(jExtras, i, jNewExtra); 234 env->DeleteLocalRef(jNewExtra); 235 env->DeleteLocalRef(jConfidenceLevels); 236 } 237 jEvent = env->NewObject(gKeyphraseRecognitionEventClass, gKeyphraseRecognitionEventCstor, 238 event->status, event->model, event->capture_available, 239 event->capture_session, event->capture_delay_ms, 240 event->capture_preamble_ms, jData, 241 phraseEvent->key_phrase_in_capture, jExtras); 242 } else { 243 jEvent = env->NewObject(gRecognitionEventClass, gRecognitionEventCstor, 244 event->status, event->model, event->capture_available, 245 event->capture_session, event->capture_delay_ms, 246 event->capture_preamble_ms, jData); 247 } 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; 417 jbyte *nData = NULL; 418 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; 424 jobject jUuid; 425 jstring jUuidString; 426 const char *nUuidString; 427 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; 450 if (env->IsInstanceOf(jSoundModel, gKeyphraseSoundModelClass)) { 451 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 } 457 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 466 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 473 nData = env->GetByteArrayElements(jData, NULL); 474 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; 493 nSoundModel->uuid = nUuid; 494 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 = 502 (jobjectArray)env->GetObjectField(jSoundModel, gKeyphraseSoundModelFields.keyphrases); 503 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); 513 phraseModel->phrases[i].id = 514 env->GetIntField(jPhrase,gKeyphraseFields.id); 515 phraseModel->phrases[i].recognition_mode = 516 env->GetIntField(jPhrase,gKeyphraseFields.recognitionModes); 517 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 527 jstring jLocale = (jstring)env->GetObjectField(jPhrase, gKeyphraseFields.locale); 528 const char *nLocale = env->GetStringUTFChars(jLocale, NULL); 529 strncpy(phraseModel->phrases[i].locale, 530 nLocale, 531 SOUND_TRIGGER_MAX_LOCALE_LEN); 532 jstring jText = (jstring)env->GetObjectField(jPhrase, gKeyphraseFields.text); 533 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); 544 env->DeleteLocalRef(jPhrase); 545 } 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) { 557 env->ReleaseByteArrayElements(jData, nData, NULL); 558 } 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, 579 jint jHandle, jobject jConfig) 580{ 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 } 587 588 if (!env->IsInstanceOf(jConfig, gRecognitionConfigClass)) { 589 return SOUNDTRIGGER_STATUS_BAD_VALUE; 590 } 591 592 jbyteArray jData = (jbyteArray)env->GetObjectField(jConfig, gRecognitionConfigFields.data); 593 jsize dataSize = 0; 594 jbyte *nData = NULL; 595 if (jData != NULL) { 596 dataSize = env->GetArrayLength(jData); 597 if (dataSize == 0) { 598 return SOUNDTRIGGER_STATUS_BAD_VALUE; 599 } 600 nData = env->GetByteArrayElements(jData, NULL); 601 if (nData == NULL) { 602 return SOUNDTRIGGER_STATUS_ERROR; 603 } 604 } 605 606 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 664 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", 706 "(ILandroid/hardware/soundtrigger/SoundTrigger$RecognitionConfig;)I", 707 (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 719 jclass uuidClass = env->FindClass("java/util/UUID"); 720 gUUIDClass = (jclass) env->NewGlobalRef(uuidClass); 721 gUUIDMethods.toString = env->GetMethodID(uuidClass, "toString", "()Ljava/lang/String;"); 722 723 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); 741 gSoundModelFields.uuid = env->GetFieldID(soundModelClass, "uuid", "Ljava/util/UUID;"); 742 gSoundModelFields.data = env->GetFieldID(soundModelClass, "data", "[B"); 743 744 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;"); 750 gKeyphraseFields.users = env->GetFieldID(keyphraseClass, "users", "[I"); 751 752 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;"); 757 758 759 jclass recognitionEventClass = env->FindClass(kRecognitionEventClassPathName); 760 gRecognitionEventClass = (jclass) env->NewGlobalRef(recognitionEventClass); 761 gRecognitionEventCstor = env->GetMethodID(recognitionEventClass, "<init>", 762 "(IIZIII[B)V"); 763 764 jclass keyphraseRecognitionEventClass = env->FindClass(kKeyphraseRecognitionEventClassPathName); 765 gKeyphraseRecognitionEventClass = (jclass) env->NewGlobalRef(keyphraseRecognitionEventClass); 766 gKeyphraseRecognitionEventCstor = env->GetMethodID(keyphraseRecognitionEventClass, "<init>", 767 "(IIZIII[BZ[Landroid/hardware/soundtrigger/SoundTrigger$KeyphraseRecognitionExtra;)V"); 768 769 770 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 782 jclass keyphraseRecognitionExtraClass = env->FindClass(kKeyphraseRecognitionExtraClassPathName); 783 gKeyphraseRecognitionExtraClass = (jclass) env->NewGlobalRef(keyphraseRecognitionExtraClass); 784 gKeyphraseRecognitionExtraCstor = env->GetMethodID(keyphraseRecognitionExtraClass, "<init>", 785 "(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"); 798 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 807 808 return status; 809} 810