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