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