SoundTriggerHwService.cpp revision 8ba53d87a2d311ff4b3f04e30b2e09309ae7421c
1/* 2 * Copyright (C) 2014 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 "SoundTriggerHwService" 18//#define LOG_NDEBUG 0 19 20#include <stdio.h> 21#include <string.h> 22#include <sys/types.h> 23#include <pthread.h> 24 25#include <system/sound_trigger.h> 26#include <cutils/atomic.h> 27#include <cutils/properties.h> 28#include <utils/Errors.h> 29#include <utils/Log.h> 30#include <binder/IServiceManager.h> 31#include <binder/MemoryBase.h> 32#include <binder/MemoryHeapBase.h> 33#include <hardware/hardware.h> 34#include <hardware/sound_trigger.h> 35#include <ServiceUtilities.h> 36#include "SoundTriggerHwService.h" 37 38namespace android { 39 40#ifdef SOUND_TRIGGER_USE_STUB_MODULE 41#define HW_MODULE_PREFIX "stub" 42#else 43#define HW_MODULE_PREFIX "primary" 44#endif 45 46SoundTriggerHwService::SoundTriggerHwService() 47 : BnSoundTriggerHwService(), 48 mNextUniqueId(1) 49{ 50} 51 52void SoundTriggerHwService::onFirstRef() 53{ 54 const hw_module_t *mod; 55 int rc; 56 sound_trigger_hw_device *dev; 57 58 rc = hw_get_module_by_class(SOUND_TRIGGER_HARDWARE_MODULE_ID, HW_MODULE_PREFIX, &mod); 59 if (rc != 0) { 60 ALOGE("couldn't load sound trigger module %s.%s (%s)", 61 SOUND_TRIGGER_HARDWARE_MODULE_ID, "primary", strerror(-rc)); 62 return; 63 } 64 rc = sound_trigger_hw_device_open(mod, &dev); 65 if (rc != 0) { 66 ALOGE("couldn't open sound trigger hw device in %s.%s (%s)", 67 SOUND_TRIGGER_HARDWARE_MODULE_ID, "primary", strerror(-rc)); 68 return; 69 } 70 if (dev->common.version != SOUND_TRIGGER_DEVICE_API_VERSION_CURRENT) { 71 ALOGE("wrong sound trigger hw device version %04x", dev->common.version); 72 return; 73 } 74 75 sound_trigger_module_descriptor descriptor; 76 rc = dev->get_properties(dev, &descriptor.properties); 77 if (rc != 0) { 78 ALOGE("could not read implementation properties"); 79 return; 80 } 81 descriptor.handle = 82 (sound_trigger_module_handle_t)android_atomic_inc(&mNextUniqueId); 83 ALOGI("loaded default module %s, handle %d", descriptor.properties.description, 84 descriptor.handle); 85 86 sp<ISoundTriggerClient> client; 87 sp<Module> module = new Module(this, dev, descriptor, client); 88 mModules.add(descriptor.handle, module); 89 mCallbackThread = new CallbackThread(this); 90} 91 92SoundTriggerHwService::~SoundTriggerHwService() 93{ 94 if (mCallbackThread != 0) { 95 mCallbackThread->exit(); 96 } 97 for (size_t i = 0; i < mModules.size(); i++) { 98 sound_trigger_hw_device_close(mModules.valueAt(i)->hwDevice()); 99 } 100} 101 102status_t SoundTriggerHwService::listModules(struct sound_trigger_module_descriptor *modules, 103 uint32_t *numModules) 104{ 105 ALOGV("listModules"); 106 if (!captureHotwordAllowed()) { 107 return PERMISSION_DENIED; 108 } 109 110 AutoMutex lock(mServiceLock); 111 if (numModules == NULL || (*numModules != 0 && modules == NULL)) { 112 return BAD_VALUE; 113 } 114 size_t maxModules = *numModules; 115 *numModules = mModules.size(); 116 for (size_t i = 0; i < mModules.size() && i < maxModules; i++) { 117 modules[i] = mModules.valueAt(i)->descriptor(); 118 } 119 return NO_ERROR; 120} 121 122status_t SoundTriggerHwService::attach(const sound_trigger_module_handle_t handle, 123 const sp<ISoundTriggerClient>& client, 124 sp<ISoundTrigger>& moduleInterface) 125{ 126 ALOGV("attach module %d", handle); 127 if (!captureHotwordAllowed()) { 128 return PERMISSION_DENIED; 129 } 130 131 AutoMutex lock(mServiceLock); 132 moduleInterface.clear(); 133 if (client == 0) { 134 return BAD_VALUE; 135 } 136 ssize_t index = mModules.indexOfKey(handle); 137 if (index < 0) { 138 return BAD_VALUE; 139 } 140 sp<Module> module = mModules.valueAt(index); 141 142 module->setClient(client); 143 client->asBinder()->linkToDeath(module); 144 moduleInterface = module; 145 146 return NO_ERROR; 147} 148 149void SoundTriggerHwService::detachModule(sp<Module> module) { 150 ALOGV("detachModule"); 151 AutoMutex lock(mServiceLock); 152 module->clearClient(); 153} 154 155static const int kDumpLockRetries = 50; 156static const int kDumpLockSleep = 60000; 157 158static bool tryLock(Mutex& mutex) 159{ 160 bool locked = false; 161 for (int i = 0; i < kDumpLockRetries; ++i) { 162 if (mutex.tryLock() == NO_ERROR) { 163 locked = true; 164 break; 165 } 166 usleep(kDumpLockSleep); 167 } 168 return locked; 169} 170 171status_t SoundTriggerHwService::dump(int fd, const Vector<String16>& args __unused) { 172 String8 result; 173 if (checkCallingPermission(String16("android.permission.DUMP")) == false) { 174 result.appendFormat("Permission Denial: can't dump SoundTriggerHwService"); 175 write(fd, result.string(), result.size()); 176 } else { 177 bool locked = tryLock(mServiceLock); 178 // failed to lock - SoundTriggerHwService is probably deadlocked 179 if (!locked) { 180 result.append("SoundTriggerHwService may be deadlocked\n"); 181 write(fd, result.string(), result.size()); 182 } 183 184 if (locked) mServiceLock.unlock(); 185 } 186 return NO_ERROR; 187} 188 189status_t SoundTriggerHwService::onTransact( 190 uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { 191 return BnSoundTriggerHwService::onTransact(code, data, reply, flags); 192} 193 194 195// static 196void SoundTriggerHwService::recognitionCallback(struct sound_trigger_recognition_event *event, 197 void *cookie) 198{ 199 Module *module = (Module *)cookie; 200 if (module == NULL) { 201 return; 202 } 203 module->sendRecognitionEvent(event); 204} 205 206 207void SoundTriggerHwService::sendRecognitionEvent(const sp<RecognitionEvent>& event) 208{ 209 mCallbackThread->sendRecognitionEvent(event); 210} 211 212void SoundTriggerHwService::onRecognitionEvent(const sp<RecognitionEvent>& event) 213{ 214 ALOGV("onRecognitionEvent"); 215 sp<Module> module; 216 { 217 AutoMutex lock(mServiceLock); 218 module = event->mModule.promote(); 219 if (module == 0) { 220 return; 221 } 222 } 223 module->onRecognitionEvent(event->mEventMemory); 224} 225 226// static 227void SoundTriggerHwService::soundModelCallback(struct sound_trigger_model_event *event __unused, 228 void *cookie) 229{ 230 Module *module = (Module *)cookie; 231 232} 233 234#undef LOG_TAG 235#define LOG_TAG "SoundTriggerHwService::CallbackThread" 236 237SoundTriggerHwService::CallbackThread::CallbackThread(const wp<SoundTriggerHwService>& service) 238 : mService(service) 239{ 240} 241 242SoundTriggerHwService::CallbackThread::~CallbackThread() 243{ 244 mEventQueue.clear(); 245} 246 247void SoundTriggerHwService::CallbackThread::onFirstRef() 248{ 249 run("soundTrigger cbk", ANDROID_PRIORITY_URGENT_AUDIO); 250} 251 252bool SoundTriggerHwService::CallbackThread::threadLoop() 253{ 254 while (!exitPending()) { 255 sp<RecognitionEvent> event; 256 sp<SoundTriggerHwService> service; 257 { 258 Mutex::Autolock _l(mCallbackLock); 259 while (mEventQueue.isEmpty() && !exitPending()) { 260 ALOGV("CallbackThread::threadLoop() sleep"); 261 mCallbackCond.wait(mCallbackLock); 262 ALOGV("CallbackThread::threadLoop() wake up"); 263 } 264 if (exitPending()) { 265 break; 266 } 267 event = mEventQueue[0]; 268 mEventQueue.removeAt(0); 269 service = mService.promote(); 270 } 271 if (service != 0) { 272 service->onRecognitionEvent(event); 273 } 274 } 275 return false; 276} 277 278void SoundTriggerHwService::CallbackThread::exit() 279{ 280 Mutex::Autolock _l(mCallbackLock); 281 requestExit(); 282 mCallbackCond.broadcast(); 283} 284 285void SoundTriggerHwService::CallbackThread::sendRecognitionEvent( 286 const sp<SoundTriggerHwService::RecognitionEvent>& event) 287{ 288 AutoMutex lock(mCallbackLock); 289 mEventQueue.add(event); 290 mCallbackCond.signal(); 291} 292 293SoundTriggerHwService::RecognitionEvent::RecognitionEvent( 294 sp<IMemory> eventMemory, 295 wp<Module> module) 296 : mEventMemory(eventMemory), mModule(module) 297{ 298} 299 300SoundTriggerHwService::RecognitionEvent::~RecognitionEvent() 301{ 302} 303 304#undef LOG_TAG 305#define LOG_TAG "SoundTriggerHwService::Module" 306 307SoundTriggerHwService::Module::Module(const sp<SoundTriggerHwService>& service, 308 sound_trigger_hw_device* hwDevice, 309 sound_trigger_module_descriptor descriptor, 310 const sp<ISoundTriggerClient>& client) 311 : mService(service), mHwDevice(hwDevice), mDescriptor(descriptor), 312 mClient(client) 313{ 314} 315 316SoundTriggerHwService::Module::~Module() { 317} 318 319void SoundTriggerHwService::Module::detach() { 320 ALOGV("detach()"); 321 if (!captureHotwordAllowed()) { 322 return; 323 } 324 { 325 AutoMutex lock(mLock); 326 for (size_t i = 0; i < mModels.size(); i++) { 327 sp<Model> model = mModels.valueAt(i); 328 ALOGV("detach() unloading model %d", model->mHandle); 329 if (model->mState == Model::STATE_ACTIVE) { 330 mHwDevice->stop_recognition(mHwDevice, model->mHandle); 331 model->deallocateMemory(); 332 } 333 mHwDevice->unload_sound_model(mHwDevice, model->mHandle); 334 } 335 mModels.clear(); 336 } 337 if (mClient != 0) { 338 mClient->asBinder()->unlinkToDeath(this); 339 } 340 sp<SoundTriggerHwService> service = mService.promote(); 341 if (service == 0) { 342 return; 343 } 344 service->detachModule(this); 345} 346 347status_t SoundTriggerHwService::Module::loadSoundModel(const sp<IMemory>& modelMemory, 348 sound_model_handle_t *handle) 349{ 350 ALOGV("loadSoundModel() handle"); 351 if (!captureHotwordAllowed()) { 352 return PERMISSION_DENIED; 353 } 354 355 if (modelMemory == 0 || modelMemory->pointer() == NULL) { 356 ALOGE("loadSoundModel() modelMemory is 0 or has NULL pointer()"); 357 return BAD_VALUE; 358 } 359 struct sound_trigger_sound_model *sound_model = 360 (struct sound_trigger_sound_model *)modelMemory->pointer(); 361 362 AutoMutex lock(mLock); 363 status_t status = mHwDevice->load_sound_model(mHwDevice, 364 sound_model, 365 SoundTriggerHwService::soundModelCallback, 366 this, 367 handle); 368 if (status == NO_ERROR) { 369 mModels.replaceValueFor(*handle, new Model(*handle)); 370 } 371 372 return status; 373} 374 375status_t SoundTriggerHwService::Module::unloadSoundModel(sound_model_handle_t handle) 376{ 377 ALOGV("unloadSoundModel() model handle %d", handle); 378 if (!captureHotwordAllowed()) { 379 return PERMISSION_DENIED; 380 } 381 382 AutoMutex lock(mLock); 383 ssize_t index = mModels.indexOfKey(handle); 384 if (index < 0) { 385 return BAD_VALUE; 386 } 387 sp<Model> model = mModels.valueAt(index); 388 mModels.removeItem(handle); 389 if (model->mState == Model::STATE_ACTIVE) { 390 mHwDevice->stop_recognition(mHwDevice, model->mHandle); 391 model->deallocateMemory(); 392 } 393 return mHwDevice->unload_sound_model(mHwDevice, handle); 394} 395 396status_t SoundTriggerHwService::Module::startRecognition(sound_model_handle_t handle, 397 const sp<IMemory>& dataMemory) 398{ 399 ALOGV("startRecognition() model handle %d", handle); 400 if (!captureHotwordAllowed()) { 401 return PERMISSION_DENIED; 402 } 403 404 if (dataMemory != 0 && dataMemory->pointer() == NULL) { 405 ALOGE("startRecognition() dataMemory is non-0 but has NULL pointer()"); 406 return BAD_VALUE; 407 408 } 409 AutoMutex lock(mLock); 410 sp<Model> model = getModel(handle); 411 if (model == 0) { 412 return BAD_VALUE; 413 } 414 if ((dataMemory == 0) || 415 (dataMemory->size() < sizeof(struct sound_trigger_recognition_config))) { 416 return BAD_VALUE; 417 } 418 419 if (model->mState == Model::STATE_ACTIVE) { 420 return INVALID_OPERATION; 421 } 422 model->mState = Model::STATE_ACTIVE; 423 424 struct sound_trigger_recognition_config *config = 425 (struct sound_trigger_recognition_config *)dataMemory->pointer(); 426 427 //TODO: get capture handle and device from audio policy service 428 config->capture_handle = AUDIO_IO_HANDLE_NONE; 429 config->capture_device = AUDIO_DEVICE_NONE; 430 return mHwDevice->start_recognition(mHwDevice, handle, config, 431 SoundTriggerHwService::recognitionCallback, 432 this); 433} 434 435status_t SoundTriggerHwService::Module::stopRecognition(sound_model_handle_t handle) 436{ 437 ALOGV("stopRecognition() model handle %d", handle); 438 if (!captureHotwordAllowed()) { 439 return PERMISSION_DENIED; 440 } 441 442 AutoMutex lock(mLock); 443 sp<Model> model = getModel(handle); 444 if (model == 0) { 445 return BAD_VALUE; 446 } 447 448 if (model->mState != Model::STATE_ACTIVE) { 449 return INVALID_OPERATION; 450 } 451 mHwDevice->stop_recognition(mHwDevice, handle); 452 model->deallocateMemory(); 453 model->mState = Model::STATE_IDLE; 454 return NO_ERROR; 455} 456 457void SoundTriggerHwService::Module::sendRecognitionEvent( 458 struct sound_trigger_recognition_event *event) 459{ 460 sp<SoundTriggerHwService> service; 461 sp<IMemory> eventMemory; 462 ALOGV("sendRecognitionEvent for model %d", event->model); 463 { 464 AutoMutex lock(mLock); 465 sp<Model> model = getModel(event->model); 466 if (model == 0) { 467 return; 468 } 469 if (model->mState != Model::STATE_ACTIVE) { 470 ALOGV("sendRecognitionEvent model->mState %d != Model::STATE_ACTIVE", model->mState); 471 return; 472 } 473 if (mClient == 0) { 474 return; 475 } 476 service = mService.promote(); 477 if (service == 0) { 478 return; 479 } 480 481 //sanitize event 482 switch (event->type) { 483 case SOUND_MODEL_TYPE_KEYPHRASE: 484 ALOGW_IF(event->data_offset != 485 sizeof(struct sound_trigger_phrase_recognition_event), 486 "sendRecognitionEvent(): invalid data offset %u for keyphrase event type", 487 event->data_offset); 488 event->data_offset = sizeof(struct sound_trigger_phrase_recognition_event); 489 break; 490 case SOUND_MODEL_TYPE_UNKNOWN: 491 ALOGW_IF(event->data_offset != 492 sizeof(struct sound_trigger_recognition_event), 493 "sendRecognitionEvent(): invalid data offset %u for unknown event type", 494 event->data_offset); 495 event->data_offset = sizeof(struct sound_trigger_recognition_event); 496 break; 497 default: 498 return; 499 } 500 501 size_t size = event->data_offset + event->data_size; 502 eventMemory = model->allocateMemory(size); 503 if (eventMemory == 0 || eventMemory->pointer() == NULL) { 504 return; 505 } 506 memcpy(eventMemory->pointer(), event, size); 507 } 508 service->sendRecognitionEvent(new RecognitionEvent(eventMemory, this)); 509} 510 511void SoundTriggerHwService::Module::onRecognitionEvent(sp<IMemory> eventMemory) 512{ 513 ALOGV("Module::onRecognitionEvent"); 514 515 AutoMutex lock(mLock); 516 517 if (eventMemory == 0 || eventMemory->pointer() == NULL) { 518 return; 519 } 520 struct sound_trigger_recognition_event *event = 521 (struct sound_trigger_recognition_event *)eventMemory->pointer(); 522 523 sp<Model> model = getModel(event->model); 524 if (model == 0) { 525 ALOGI("%s model == 0", __func__); 526 return; 527 } 528 if (model->mState != Model::STATE_ACTIVE) { 529 ALOGV("onRecognitionEvent model->mState %d != Model::STATE_ACTIVE", model->mState); 530 return; 531 } 532 if (mClient == 0) { 533 ALOGI("%s mClient == 0", __func__); 534 return; 535 } 536 mClient->onRecognitionEvent(eventMemory); 537 model->mState = Model::STATE_IDLE; 538 model->deallocateMemory(); 539} 540 541sp<SoundTriggerHwService::Model> SoundTriggerHwService::Module::getModel( 542 sound_model_handle_t handle) 543{ 544 sp<Model> model; 545 ssize_t index = mModels.indexOfKey(handle); 546 if (index >= 0) { 547 model = mModels.valueAt(index); 548 } 549 return model; 550} 551 552void SoundTriggerHwService::Module::binderDied( 553 const wp<IBinder> &who __unused) { 554 ALOGW("client binder died for module %d", mDescriptor.handle); 555 detach(); 556} 557 558 559SoundTriggerHwService::Model::Model(sound_model_handle_t handle) : 560 mHandle(handle), mState(STATE_IDLE), mInputHandle(AUDIO_IO_HANDLE_NONE), 561 mCaptureSession(AUDIO_SESSION_ALLOCATE), 562 mMemoryDealer(new MemoryDealer(sizeof(struct sound_trigger_recognition_event), 563 "SoundTriggerHwService::Event")) 564{ 565 566} 567 568 569sp<IMemory> SoundTriggerHwService::Model::allocateMemory(size_t size) 570{ 571 sp<IMemory> memory; 572 if (mMemoryDealer->getMemoryHeap()->getSize() < size) { 573 mMemoryDealer = new MemoryDealer(size, "SoundTriggerHwService::Event"); 574 } 575 memory = mMemoryDealer->allocate(size); 576 return memory; 577} 578 579void SoundTriggerHwService::Model::deallocateMemory() 580{ 581 mMemoryDealer->deallocate(0); 582} 583 584status_t SoundTriggerHwService::Module::dump(int fd __unused, 585 const Vector<String16>& args __unused) { 586 String8 result; 587 return NO_ERROR; 588} 589 590}; // namespace android 591