1/* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#define LOG_TAG "SoundTriggerHalImpl" 18//#define LOG_NDEBUG 0 19 20#include <android/log.h> 21#include "SoundTriggerHalImpl.h" 22 23 24namespace android { 25namespace hardware { 26namespace soundtrigger { 27namespace V2_0 { 28namespace implementation { 29 30// static 31void SoundTriggerHalImpl::soundModelCallback(struct sound_trigger_model_event *halEvent, 32 void *cookie) 33{ 34 if (halEvent == NULL) { 35 ALOGW("soundModelCallback called with NULL event"); 36 return; 37 } 38 sp<SoundModelClient> client = 39 wp<SoundModelClient>(static_cast<SoundModelClient *>(cookie)).promote(); 40 if (client == 0) { 41 ALOGW("soundModelCallback called on stale client"); 42 return; 43 } 44 if (halEvent->model != client->mHalHandle) { 45 ALOGW("soundModelCallback call with wrong handle %d on client with handle %d", 46 (int)halEvent->model, (int)client->mHalHandle); 47 return; 48 } 49 50 ISoundTriggerHwCallback::ModelEvent event; 51 convertSoundModelEventFromHal(&event, halEvent); 52 event.model = client->mId; 53 54 client->mCallback->soundModelCallback(event, client->mCookie); 55} 56 57// static 58void SoundTriggerHalImpl::recognitionCallback(struct sound_trigger_recognition_event *halEvent, 59 void *cookie) 60{ 61 if (halEvent == NULL) { 62 ALOGW("recognitionCallback call NULL event"); 63 return; 64 } 65 sp<SoundModelClient> client = 66 wp<SoundModelClient>(static_cast<SoundModelClient *>(cookie)).promote(); 67 if (client == 0) { 68 ALOGW("soundModelCallback called on stale client"); 69 return; 70 } 71 72 ISoundTriggerHwCallback::RecognitionEvent *event = convertRecognitionEventFromHal(halEvent); 73 event->model = client->mId; 74 if (halEvent->type == SOUND_MODEL_TYPE_KEYPHRASE) { 75 client->mCallback->phraseRecognitionCallback( 76 *(reinterpret_cast<ISoundTriggerHwCallback::PhraseRecognitionEvent *>(event)), 77 client->mCookie); 78 } else { 79 client->mCallback->recognitionCallback(*event, client->mCookie); 80 } 81 delete event; 82} 83 84 85 86// Methods from ::android::hardware::soundtrigger::V2_0::ISoundTriggerHw follow. 87Return<void> SoundTriggerHalImpl::getProperties(getProperties_cb _hidl_cb) 88{ 89 ALOGV("getProperties() mHwDevice %p", mHwDevice); 90 int ret; 91 struct sound_trigger_properties halProperties; 92 ISoundTriggerHw::Properties properties; 93 94 if (mHwDevice == NULL) { 95 ret = -ENODEV; 96 goto exit; 97 } 98 99 ret = mHwDevice->get_properties(mHwDevice, &halProperties); 100 101 convertPropertiesFromHal(&properties, &halProperties); 102 103 ALOGV("getProperties implementor %s recognitionModes %08x", 104 properties.implementor.c_str(), properties.recognitionModes); 105 106exit: 107 _hidl_cb(ret, properties); 108 return Void(); 109} 110 111int SoundTriggerHalImpl::doLoadSoundModel(const ISoundTriggerHw::SoundModel& soundModel, 112 const sp<ISoundTriggerHwCallback>& callback, 113 ISoundTriggerHwCallback::CallbackCookie cookie, 114 uint32_t *modelId) 115{ 116 int32_t ret = 0; 117 struct sound_trigger_sound_model *halSoundModel; 118 *modelId = 0; 119 sp<SoundModelClient> client; 120 121 ALOGV("doLoadSoundModel() data size %zu", soundModel.data.size()); 122 123 if (mHwDevice == NULL) { 124 ret = -ENODEV; 125 goto exit; 126 } 127 128 halSoundModel = convertSoundModelToHal(&soundModel); 129 if (halSoundModel == NULL) { 130 ret = -EINVAL; 131 goto exit; 132 } 133 134 { 135 AutoMutex lock(mLock); 136 do { 137 *modelId = nextUniqueId(); 138 } while (mClients.valueFor(*modelId) != 0 && *modelId != 0); 139 } 140 LOG_ALWAYS_FATAL_IF(*modelId == 0, 141 "wrap around in sound model IDs, num loaded models %zu", mClients.size()); 142 143 client = new SoundModelClient(*modelId, callback, cookie); 144 145 ret = mHwDevice->load_sound_model(mHwDevice, halSoundModel, soundModelCallback, 146 client.get(), &client->mHalHandle); 147 148 free(halSoundModel); 149 150 if (ret != 0) { 151 goto exit; 152 } 153 154 { 155 AutoMutex lock(mLock); 156 mClients.add(*modelId, client); 157 } 158 159exit: 160 return ret; 161} 162 163Return<void> SoundTriggerHalImpl::loadSoundModel(const ISoundTriggerHw::SoundModel& soundModel, 164 const sp<ISoundTriggerHwCallback>& callback, 165 ISoundTriggerHwCallback::CallbackCookie cookie, 166 loadSoundModel_cb _hidl_cb) 167{ 168 uint32_t modelId = 0; 169 int32_t ret = doLoadSoundModel(soundModel, callback, cookie, &modelId); 170 171 _hidl_cb(ret, modelId); 172 return Void(); 173} 174 175Return<void> SoundTriggerHalImpl::loadPhraseSoundModel( 176 const ISoundTriggerHw::PhraseSoundModel& soundModel, 177 const sp<ISoundTriggerHwCallback>& callback, 178 ISoundTriggerHwCallback::CallbackCookie cookie, 179 ISoundTriggerHw::loadPhraseSoundModel_cb _hidl_cb) 180{ 181 uint32_t modelId = 0; 182 int32_t ret = doLoadSoundModel((const ISoundTriggerHw::SoundModel&)soundModel, 183 callback, cookie, &modelId); 184 185 _hidl_cb(ret, modelId); 186 return Void(); 187} 188 189Return<int32_t> SoundTriggerHalImpl::unloadSoundModel(SoundModelHandle modelHandle) 190{ 191 int32_t ret; 192 sp<SoundModelClient> client; 193 194 if (mHwDevice == NULL) { 195 ret = -ENODEV; 196 goto exit; 197 } 198 199 { 200 AutoMutex lock(mLock); 201 client = mClients.valueFor(modelHandle); 202 if (client == 0) { 203 ret = -ENOSYS; 204 goto exit; 205 } 206 } 207 208 ret = mHwDevice->unload_sound_model(mHwDevice, client->mHalHandle); 209 210 mClients.removeItem(modelHandle); 211 212exit: 213 return ret; 214} 215 216Return<int32_t> SoundTriggerHalImpl::startRecognition(SoundModelHandle modelHandle, 217 const ISoundTriggerHw::RecognitionConfig& config, 218 const sp<ISoundTriggerHwCallback>& callback __unused, 219 ISoundTriggerHwCallback::CallbackCookie cookie __unused) 220{ 221 int32_t ret; 222 sp<SoundModelClient> client; 223 struct sound_trigger_recognition_config *halConfig; 224 225 if (mHwDevice == NULL) { 226 ret = -ENODEV; 227 goto exit; 228 } 229 230 { 231 AutoMutex lock(mLock); 232 client = mClients.valueFor(modelHandle); 233 if (client == 0) { 234 ret = -ENOSYS; 235 goto exit; 236 } 237 } 238 239 240 halConfig = convertRecognitionConfigToHal(&config); 241 242 if (halConfig == NULL) { 243 ret = -EINVAL; 244 goto exit; 245 } 246 ret = mHwDevice->start_recognition(mHwDevice, client->mHalHandle, halConfig, 247 recognitionCallback, client.get()); 248 249 free(halConfig); 250 251exit: 252 return ret; 253} 254 255Return<int32_t> SoundTriggerHalImpl::stopRecognition(SoundModelHandle modelHandle) 256{ 257 int32_t ret; 258 sp<SoundModelClient> client; 259 if (mHwDevice == NULL) { 260 ret = -ENODEV; 261 goto exit; 262 } 263 264 { 265 AutoMutex lock(mLock); 266 client = mClients.valueFor(modelHandle); 267 if (client == 0) { 268 ret = -ENOSYS; 269 goto exit; 270 } 271 } 272 273 ret = mHwDevice->stop_recognition(mHwDevice, client->mHalHandle); 274 275exit: 276 return ret; 277} 278 279Return<int32_t> SoundTriggerHalImpl::stopAllRecognitions() 280{ 281 int32_t ret; 282 if (mHwDevice == NULL) { 283 ret = -ENODEV; 284 goto exit; 285 } 286 287 if (mHwDevice->common.version >= SOUND_TRIGGER_DEVICE_API_VERSION_1_1 && 288 mHwDevice->stop_all_recognitions) { 289 ret = mHwDevice->stop_all_recognitions(mHwDevice); 290 } else { 291 ret = -ENOSYS; 292 } 293exit: 294 return ret; 295} 296 297SoundTriggerHalImpl::SoundTriggerHalImpl() 298 : mModuleName("primary"), mHwDevice(NULL), mNextModelId(1) 299{ 300} 301 302void SoundTriggerHalImpl::onFirstRef() 303{ 304 const hw_module_t *mod; 305 int rc; 306 307 rc = hw_get_module_by_class(SOUND_TRIGGER_HARDWARE_MODULE_ID, mModuleName, &mod); 308 if (rc != 0) { 309 ALOGE("couldn't load sound trigger module %s.%s (%s)", 310 SOUND_TRIGGER_HARDWARE_MODULE_ID, mModuleName, strerror(-rc)); 311 return; 312 } 313 rc = sound_trigger_hw_device_open(mod, &mHwDevice); 314 if (rc != 0) { 315 ALOGE("couldn't open sound trigger hw device in %s.%s (%s)", 316 SOUND_TRIGGER_HARDWARE_MODULE_ID, mModuleName, strerror(-rc)); 317 mHwDevice = NULL; 318 return; 319 } 320 if (mHwDevice->common.version < SOUND_TRIGGER_DEVICE_API_VERSION_1_0 || 321 mHwDevice->common.version > SOUND_TRIGGER_DEVICE_API_VERSION_CURRENT) { 322 ALOGE("wrong sound trigger hw device version %04x", mHwDevice->common.version); 323 sound_trigger_hw_device_close(mHwDevice); 324 mHwDevice = NULL; 325 return; 326 } 327 328 ALOGI("onFirstRef() mModuleName %s mHwDevice %p", mModuleName, mHwDevice); 329} 330 331SoundTriggerHalImpl::~SoundTriggerHalImpl() 332{ 333 if (mHwDevice != NULL) { 334 sound_trigger_hw_device_close(mHwDevice); 335 } 336} 337 338uint32_t SoundTriggerHalImpl::nextUniqueId() 339{ 340 return (uint32_t) atomic_fetch_add_explicit(&mNextModelId, 341 (uint_fast32_t) 1, memory_order_acq_rel); 342} 343 344void SoundTriggerHalImpl::convertUuidFromHal(Uuid *uuid, 345 const sound_trigger_uuid_t *halUuid) 346{ 347 uuid->timeLow = halUuid->timeLow; 348 uuid->timeMid = halUuid->timeMid; 349 uuid->versionAndTimeHigh = halUuid->timeHiAndVersion; 350 uuid->variantAndClockSeqHigh = halUuid->clockSeq; 351 memcpy(&uuid->node[0], &halUuid->node[0], 6); 352} 353 354void SoundTriggerHalImpl::convertUuidToHal(sound_trigger_uuid_t *halUuid, 355 const Uuid *uuid) 356{ 357 halUuid->timeLow = uuid->timeLow; 358 halUuid->timeMid = uuid->timeMid; 359 halUuid->timeHiAndVersion = uuid->versionAndTimeHigh; 360 halUuid->clockSeq = uuid->variantAndClockSeqHigh; 361 memcpy(&halUuid->node[0], &uuid->node[0], 6); 362} 363 364void SoundTriggerHalImpl::convertPropertiesFromHal( 365 ISoundTriggerHw::Properties *properties, 366 const struct sound_trigger_properties *halProperties) 367{ 368 properties->implementor = halProperties->implementor; 369 properties->description = halProperties->description; 370 properties->version = halProperties->version; 371 convertUuidFromHal(&properties->uuid, &halProperties->uuid); 372 properties->maxSoundModels = halProperties->max_sound_models; 373 properties->maxKeyPhrases = halProperties->max_key_phrases; 374 properties->maxUsers = halProperties->max_users; 375 properties->recognitionModes = halProperties->recognition_modes; 376 properties->captureTransition = halProperties->capture_transition; 377 properties->maxBufferMs = halProperties->max_buffer_ms; 378 properties->concurrentCapture = halProperties->concurrent_capture; 379 properties->triggerInEvent = halProperties->trigger_in_event; 380 properties->powerConsumptionMw = halProperties->power_consumption_mw; 381 382} 383 384void SoundTriggerHalImpl::convertTriggerPhraseToHal( 385 struct sound_trigger_phrase *halTriggerPhrase, 386 const ISoundTriggerHw::Phrase *triggerPhrase) 387{ 388 halTriggerPhrase->id = triggerPhrase->id; 389 halTriggerPhrase->recognition_mode = triggerPhrase->recognitionModes; 390 unsigned int i; 391 for (i = 0; i < triggerPhrase->users.size(); i++) { 392 halTriggerPhrase->users[i] = triggerPhrase->users[i]; 393 } 394 halTriggerPhrase->num_users = i; 395 396 strlcpy(halTriggerPhrase->locale, 397 triggerPhrase->locale.c_str(), SOUND_TRIGGER_MAX_LOCALE_LEN); 398 strlcpy(halTriggerPhrase->text, 399 triggerPhrase->text.c_str(), SOUND_TRIGGER_MAX_STRING_LEN); 400} 401 402struct sound_trigger_sound_model *SoundTriggerHalImpl::convertSoundModelToHal( 403 const ISoundTriggerHw::SoundModel *soundModel) 404{ 405 struct sound_trigger_sound_model *halModel = NULL; 406 if (soundModel->type == SoundModelType::KEYPHRASE) { 407 size_t allocSize = 408 sizeof(struct sound_trigger_phrase_sound_model) + soundModel->data.size(); 409 struct sound_trigger_phrase_sound_model *halKeyPhraseModel = 410 static_cast<struct sound_trigger_phrase_sound_model *>(malloc(allocSize)); 411 LOG_ALWAYS_FATAL_IF(halKeyPhraseModel == NULL, 412 "malloc failed for size %zu in convertSoundModelToHal PHRASE", allocSize); 413 414 const ISoundTriggerHw::PhraseSoundModel *keyPhraseModel = 415 reinterpret_cast<const ISoundTriggerHw::PhraseSoundModel *>(soundModel); 416 417 size_t i; 418 for (i = 0; i < keyPhraseModel->phrases.size() && i < SOUND_TRIGGER_MAX_PHRASES; i++) { 419 convertTriggerPhraseToHal(&halKeyPhraseModel->phrases[i], 420 &keyPhraseModel->phrases[i]); 421 } 422 halKeyPhraseModel->num_phrases = (unsigned int)i; 423 halModel = reinterpret_cast<struct sound_trigger_sound_model *>(halKeyPhraseModel); 424 halModel->data_offset = sizeof(struct sound_trigger_phrase_sound_model); 425 } else { 426 size_t allocSize = 427 sizeof(struct sound_trigger_sound_model) + soundModel->data.size(); 428 halModel = static_cast<struct sound_trigger_sound_model *>(malloc(allocSize)); 429 LOG_ALWAYS_FATAL_IF(halModel == NULL, 430 "malloc failed for size %zu in convertSoundModelToHal GENERIC", 431 allocSize); 432 433 halModel->data_offset = sizeof(struct sound_trigger_sound_model); 434 } 435 halModel->type = (sound_trigger_sound_model_type_t)soundModel->type; 436 convertUuidToHal(&halModel->uuid, &soundModel->uuid); 437 convertUuidToHal(&halModel->vendor_uuid, &soundModel->vendorUuid); 438 halModel->data_size = soundModel->data.size(); 439 uint8_t *dst = reinterpret_cast<uint8_t *>(halModel) + halModel->data_offset; 440 const uint8_t *src = reinterpret_cast<const uint8_t *>(&soundModel->data[0]); 441 memcpy(dst, src, soundModel->data.size()); 442 443 return halModel; 444} 445 446void SoundTriggerHalImpl::convertPhraseRecognitionExtraToHal( 447 struct sound_trigger_phrase_recognition_extra *halExtra, 448 const PhraseRecognitionExtra *extra) 449{ 450 halExtra->id = extra->id; 451 halExtra->recognition_modes = extra->recognitionModes; 452 halExtra->confidence_level = extra->confidenceLevel; 453 454 unsigned int i; 455 for (i = 0; i < extra->levels.size() && i < SOUND_TRIGGER_MAX_USERS; i++) { 456 halExtra->levels[i].user_id = extra->levels[i].userId; 457 halExtra->levels[i].level = extra->levels[i].levelPercent; 458 } 459 halExtra->num_levels = i; 460} 461 462struct sound_trigger_recognition_config *SoundTriggerHalImpl::convertRecognitionConfigToHal( 463 const ISoundTriggerHw::RecognitionConfig *config) 464{ 465 size_t allocSize = sizeof(struct sound_trigger_recognition_config) + config->data.size(); 466 struct sound_trigger_recognition_config *halConfig = 467 static_cast<struct sound_trigger_recognition_config *>(malloc(allocSize)); 468 469 LOG_ALWAYS_FATAL_IF(halConfig == NULL, 470 "malloc failed for size %zu in convertRecognitionConfigToHal", 471 allocSize); 472 473 halConfig->capture_handle = (audio_io_handle_t)config->captureHandle; 474 halConfig->capture_device = (audio_devices_t)config->captureDevice; 475 halConfig->capture_requested = config->captureRequested; 476 477 unsigned int i; 478 for (i = 0; i < config->phrases.size() && i < SOUND_TRIGGER_MAX_PHRASES; i++) { 479 convertPhraseRecognitionExtraToHal(&halConfig->phrases[i], 480 &config->phrases[i]); 481 } 482 halConfig->num_phrases = i; 483 484 halConfig->data_offset = sizeof(struct sound_trigger_recognition_config); 485 halConfig->data_size = config->data.size(); 486 uint8_t *dst = reinterpret_cast<uint8_t *>(halConfig) + halConfig->data_offset; 487 const uint8_t *src = reinterpret_cast<const uint8_t *>(&config->data[0]); 488 memcpy(dst, src, config->data.size()); 489 return halConfig; 490} 491 492// static 493void SoundTriggerHalImpl::convertSoundModelEventFromHal(ISoundTriggerHwCallback::ModelEvent *event, 494 const struct sound_trigger_model_event *halEvent) 495{ 496 event->status = (ISoundTriggerHwCallback::SoundModelStatus)halEvent->status; 497 // event->model to be remapped by called 498 event->data.setToExternal( 499 const_cast<uint8_t *>(reinterpret_cast<const uint8_t *>(halEvent)) + halEvent->data_offset, 500 halEvent->data_size); 501} 502 503// static 504ISoundTriggerHwCallback::RecognitionEvent *SoundTriggerHalImpl::convertRecognitionEventFromHal( 505 const struct sound_trigger_recognition_event *halEvent) 506{ 507 ISoundTriggerHwCallback::RecognitionEvent * event; 508 509 if (halEvent->type == SOUND_MODEL_TYPE_KEYPHRASE) { 510 const struct sound_trigger_phrase_recognition_event *halPhraseEvent = 511 reinterpret_cast<const struct sound_trigger_phrase_recognition_event *>(halEvent); 512 ISoundTriggerHwCallback::PhraseRecognitionEvent *phraseEvent = 513 new ISoundTriggerHwCallback::PhraseRecognitionEvent(); 514 515 PhraseRecognitionExtra *phraseExtras = 516 new PhraseRecognitionExtra[halPhraseEvent->num_phrases]; 517 for (unsigned int i = 0; i < halPhraseEvent->num_phrases; i++) { 518 convertPhraseRecognitionExtraFromHal(&phraseExtras[i], 519 &halPhraseEvent->phrase_extras[i]); 520 } 521 phraseEvent->phraseExtras.setToExternal(phraseExtras, halPhraseEvent->num_phrases); 522 // FIXME: transfer buffer ownership. should have a method for that in hidl_vec 523 phraseEvent->phraseExtras.resize(halPhraseEvent->num_phrases); 524 delete[] phraseExtras; 525 event = reinterpret_cast<ISoundTriggerHwCallback::RecognitionEvent *>(phraseEvent); 526 } else { 527 event = new ISoundTriggerHwCallback::RecognitionEvent(); 528 } 529 530 event->status = static_cast<ISoundTriggerHwCallback::RecognitionStatus>(halEvent->status); 531 event->type = static_cast<SoundModelType>(halEvent->type); 532 // event->model to be remapped by called 533 event->captureAvailable = halEvent->capture_available; 534 event->captureSession = halEvent->capture_session; 535 event->captureDelayMs = halEvent->capture_delay_ms; 536 event->capturePreambleMs = halEvent->capture_preamble_ms; 537 event->triggerInData = halEvent->trigger_in_data; 538 event->audioConfig.sampleRateHz = halEvent->audio_config.sample_rate; 539 event->audioConfig.channelMask = 540 (audio::common::V2_0::AudioChannelMask)halEvent->audio_config.channel_mask; 541 event->audioConfig.format = (audio::common::V2_0::AudioFormat)halEvent->audio_config.format; 542 event->data.setToExternal( 543 const_cast<uint8_t *>(reinterpret_cast<const uint8_t *>(halEvent)) + halEvent->data_offset, 544 halEvent->data_size); 545 546 return event; 547} 548 549// static 550void SoundTriggerHalImpl::convertPhraseRecognitionExtraFromHal( 551 PhraseRecognitionExtra *extra, 552 const struct sound_trigger_phrase_recognition_extra *halExtra) 553{ 554 extra->id = halExtra->id; 555 extra->recognitionModes = halExtra->recognition_modes; 556 extra->confidenceLevel = halExtra->confidence_level; 557 558 ConfidenceLevel *levels = 559 new ConfidenceLevel[halExtra->num_levels]; 560 for (unsigned int i = 0; i < halExtra->num_levels; i++) { 561 levels[i].userId = halExtra->levels[i].user_id; 562 levels[i].levelPercent = halExtra->levels[i].level; 563 } 564 extra->levels.setToExternal(levels, halExtra->num_levels); 565 // FIXME: transfer buffer ownership. should have a method for that in hidl_vec 566 extra->levels.resize(halExtra->num_levels); 567 delete[] levels; 568} 569 570ISoundTriggerHw *HIDL_FETCH_ISoundTriggerHw(const char* /* name */) 571{ 572 return new SoundTriggerHalImpl(); 573} 574} // namespace implementation 575} // namespace V2_0 576} // namespace soundtrigger 577} // namespace hardware 578} // namespace android 579 580 581 582