SoundTriggerHwService.cpp revision 1a1cba8f9a93db188b09d9754987354029129113
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 sp<Model> model = mModels.valueAt(index); 371 mModels.removeItem(handle); 372 if (model->mState == Model::STATE_ACTIVE) { 373 mHwDevice->stop_recognition(mHwDevice, model->mHandle); 374 model->deallocateMemory(); 375 } 376 return mHwDevice->unload_sound_model(mHwDevice, handle); 377} 378 379status_t SoundTriggerHwService::Module::startRecognition(sound_model_handle_t handle, 380 const sp<IMemory>& dataMemory) 381{ 382 ALOGV("startRecognition() model handle %d", handle); 383 384 if (dataMemory != 0 && dataMemory->pointer() == NULL) { 385 ALOGE("startRecognition() dataMemory is non-0 but has NULL pointer()"); 386 return BAD_VALUE; 387 388 } 389 AutoMutex lock(mLock); 390 sp<Model> model = getModel(handle); 391 if (model == 0) { 392 return BAD_VALUE; 393 } 394 395 if (model->mState == Model::STATE_ACTIVE) { 396 return INVALID_OPERATION; 397 } 398 model->mState = Model::STATE_ACTIVE; 399 400 char *data = NULL; 401 unsigned int data_size = 0; 402 if (dataMemory != 0 && dataMemory->size() != 0) { 403 data_size = (unsigned int)dataMemory->size(); 404 data = (char *)dataMemory->pointer(); 405 ALOGV("startRecognition() data size %d data %d - %d", 406 data_size, data[0], data[data_size - 1]); 407 } 408 409 //TODO: get capture handle and device from audio policy service 410 audio_io_handle_t capture_handle = 0; 411 return mHwDevice->start_recognition(mHwDevice, handle, capture_handle, AUDIO_DEVICE_NONE, 412 SoundTriggerHwService::recognitionCallback, 413 this, 414 data_size, 415 data); 416} 417 418status_t SoundTriggerHwService::Module::stopRecognition(sound_model_handle_t handle) 419{ 420 ALOGV("stopRecognition() model handle %d", handle); 421 422 AutoMutex lock(mLock); 423 sp<Model> model = getModel(handle); 424 if (model == 0) { 425 return BAD_VALUE; 426 } 427 428 if (model->mState != Model::STATE_ACTIVE) { 429 return INVALID_OPERATION; 430 } 431 mHwDevice->stop_recognition(mHwDevice, handle); 432 model->deallocateMemory(); 433 model->mState = Model::STATE_IDLE; 434 return NO_ERROR; 435} 436 437void SoundTriggerHwService::Module::sendRecognitionEvent( 438 struct sound_trigger_recognition_event *event) 439{ 440 sp<SoundTriggerHwService> service; 441 sp<IMemory> eventMemory; 442 ALOGV("sendRecognitionEvent for model %d", event->model); 443 { 444 AutoMutex lock(mLock); 445 sp<Model> model = getModel(event->model); 446 if (model == 0) { 447 return; 448 } 449 if (model->mState != Model::STATE_ACTIVE) { 450 ALOGV("sendRecognitionEvent model->mState %d != Model::STATE_ACTIVE", model->mState); 451 return; 452 } 453 if (mClient == 0) { 454 return; 455 } 456 service = mService.promote(); 457 if (service == 0) { 458 return; 459 } 460 461 //sanitize event 462 switch (event->type) { 463 case SOUND_MODEL_TYPE_KEYPHRASE: 464 ALOGW_IF(event->data_offset != 465 sizeof(struct sound_trigger_phrase_recognition_event), 466 "sendRecognitionEvent(): invalid data offset %u for keyphrase event type", 467 event->data_offset); 468 event->data_offset = sizeof(struct sound_trigger_phrase_recognition_event); 469 break; 470 case SOUND_MODEL_TYPE_UNKNOWN: 471 ALOGW_IF(event->data_offset != 472 sizeof(struct sound_trigger_recognition_event), 473 "sendRecognitionEvent(): invalid data offset %u for unknown event type", 474 event->data_offset); 475 event->data_offset = sizeof(struct sound_trigger_recognition_event); 476 break; 477 default: 478 return; 479 } 480 481 size_t size = event->data_offset + event->data_size; 482 eventMemory = model->allocateMemory(size); 483 if (eventMemory == 0 || eventMemory->pointer() == NULL) { 484 return; 485 } 486 memcpy(eventMemory->pointer(), event, size); 487 } 488 service->sendRecognitionEvent(new RecognitionEvent(eventMemory, this)); 489} 490 491void SoundTriggerHwService::Module::onRecognitionEvent(sp<IMemory> eventMemory) 492{ 493 ALOGV("Module::onRecognitionEvent"); 494 495 AutoMutex lock(mLock); 496 497 if (eventMemory == 0 || eventMemory->pointer() == NULL) { 498 return; 499 } 500 struct sound_trigger_recognition_event *event = 501 (struct sound_trigger_recognition_event *)eventMemory->pointer(); 502 503 sp<Model> model = getModel(event->model); 504 if (model == 0) { 505 ALOGI("%s model == 0", __func__); 506 return; 507 } 508 if (model->mState != Model::STATE_ACTIVE) { 509 ALOGV("onRecognitionEvent model->mState %d != Model::STATE_ACTIVE", model->mState); 510 return; 511 } 512 if (mClient == 0) { 513 ALOGI("%s mClient == 0", __func__); 514 return; 515 } 516 mClient->onRecognitionEvent(eventMemory); 517 model->mState = Model::STATE_IDLE; 518 model->deallocateMemory(); 519} 520 521sp<SoundTriggerHwService::Model> SoundTriggerHwService::Module::getModel( 522 sound_model_handle_t handle) 523{ 524 sp<Model> model; 525 ssize_t index = mModels.indexOfKey(handle); 526 if (index >= 0) { 527 model = mModels.valueAt(index); 528 } 529 return model; 530} 531 532void SoundTriggerHwService::Module::binderDied( 533 const wp<IBinder> &who __unused) { 534 ALOGW("client binder died for module %d", mDescriptor.handle); 535 detach(); 536} 537 538 539SoundTriggerHwService::Model::Model(sound_model_handle_t handle) : 540 mHandle(handle), mState(STATE_IDLE), mInputHandle(AUDIO_IO_HANDLE_NONE), 541 mCaptureSession(AUDIO_SESSION_ALLOCATE), 542 mMemoryDealer(new MemoryDealer(sizeof(struct sound_trigger_recognition_event), 543 "SoundTriggerHwService::Event")) 544{ 545 546} 547 548 549sp<IMemory> SoundTriggerHwService::Model::allocateMemory(size_t size) 550{ 551 sp<IMemory> memory; 552 if (mMemoryDealer->getMemoryHeap()->getSize() < size) { 553 mMemoryDealer = new MemoryDealer(size, "SoundTriggerHwService::Event"); 554 } 555 memory = mMemoryDealer->allocate(size); 556 return memory; 557} 558 559void SoundTriggerHwService::Model::deallocateMemory() 560{ 561 mMemoryDealer->deallocate(0); 562} 563 564status_t SoundTriggerHwService::Module::dump(int fd __unused, 565 const Vector<String16>& args __unused) { 566 String8 result; 567 return NO_ERROR; 568} 569 570}; // namespace android 571