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