blob: 3654136b336117331a2416800de4f9dd9f820cb1 [file] [log] [blame]
Eric Laurentb7a11d82014-04-18 17:40:41 -07001/*
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
Eric Laurent8ba53d82014-08-01 23:15:05 +000025#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>
Eric Laurentb7a11d82014-04-18 17:40:41 -070030#include <binder/IServiceManager.h>
31#include <binder/MemoryBase.h>
32#include <binder/MemoryHeapBase.h>
Eric Laurentb7a11d82014-04-18 17:40:41 -070033#include <hardware/hardware.h>
Eric Laurent936c84a2014-07-17 10:26:04 -070034#include <hardware/sound_trigger.h>
Eric Laurent8ba53d82014-08-01 23:15:05 +000035#include <ServiceUtilities.h>
36#include "SoundTriggerHwService.h"
Eric Laurentb7a11d82014-04-18 17:40:41 -070037
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");
Eric Laurent8ba53d82014-08-01 23:15:05 +0000106 if (!captureHotwordAllowed()) {
107 return PERMISSION_DENIED;
108 }
109
Eric Laurentb7a11d82014-04-18 17:40:41 -0700110 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);
Eric Laurent8ba53d82014-08-01 23:15:05 +0000127 if (!captureHotwordAllowed()) {
128 return PERMISSION_DENIED;
129 }
130
Eric Laurentb7a11d82014-04-18 17:40:41 -0700131 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) {
Eric Laurent936c84a2014-07-17 10:26:04 -0700150 ALOGV("detachModule");
Eric Laurent8ba53d82014-08-01 23:15:05 +0000151 AutoMutex lock(mServiceLock);
Eric Laurentb7a11d82014-04-18 17:40:41 -0700152 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()");
Eric Laurent8ba53d82014-08-01 23:15:05 +0000321 if (!captureHotwordAllowed()) {
322 return;
323 }
Eric Laurentb7a11d82014-04-18 17:40:41 -0700324 {
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");
Eric Laurent8ba53d82014-08-01 23:15:05 +0000351 if (!captureHotwordAllowed()) {
352 return PERMISSION_DENIED;
353 }
Eric Laurentb7a11d82014-04-18 17:40:41 -0700354
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);
Eric Laurent8ba53d82014-08-01 23:15:05 +0000378 if (!captureHotwordAllowed()) {
379 return PERMISSION_DENIED;
380 }
Eric Laurentb7a11d82014-04-18 17:40:41 -0700381
382 AutoMutex lock(mLock);
383 ssize_t index = mModels.indexOfKey(handle);
384 if (index < 0) {
385 return BAD_VALUE;
386 }
Eric Laurent1a1cba82014-06-09 16:20:05 -0700387 sp<Model> model = mModels.valueAt(index);
Eric Laurentb7a11d82014-04-18 17:40:41 -0700388 mModels.removeItem(handle);
Eric Laurent1a1cba82014-06-09 16:20:05 -0700389 if (model->mState == Model::STATE_ACTIVE) {
390 mHwDevice->stop_recognition(mHwDevice, model->mHandle);
391 model->deallocateMemory();
392 }
Eric Laurentb7a11d82014-04-18 17:40:41 -0700393 return mHwDevice->unload_sound_model(mHwDevice, handle);
394}
395
396status_t SoundTriggerHwService::Module::startRecognition(sound_model_handle_t handle,
Eric Laurent0832b2d2014-07-06 16:17:25 -0700397 const sp<IMemory>& dataMemory)
Eric Laurentb7a11d82014-04-18 17:40:41 -0700398{
399 ALOGV("startRecognition() model handle %d", handle);
Eric Laurent8ba53d82014-08-01 23:15:05 +0000400 if (!captureHotwordAllowed()) {
401 return PERMISSION_DENIED;
402 }
Eric Laurentb7a11d82014-04-18 17:40:41 -0700403
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 }
Eric Laurent0832b2d2014-07-06 16:17:25 -0700414 if ((dataMemory == 0) ||
415 (dataMemory->size() < sizeof(struct sound_trigger_recognition_config))) {
416 return BAD_VALUE;
417 }
Eric Laurentb7a11d82014-04-18 17:40:41 -0700418
419 if (model->mState == Model::STATE_ACTIVE) {
420 return INVALID_OPERATION;
421 }
422 model->mState = Model::STATE_ACTIVE;
423
Eric Laurent0832b2d2014-07-06 16:17:25 -0700424 struct sound_trigger_recognition_config *config =
425 (struct sound_trigger_recognition_config *)dataMemory->pointer();
Eric Laurentb7a11d82014-04-18 17:40:41 -0700426
427 //TODO: get capture handle and device from audio policy service
Eric Laurent0832b2d2014-07-06 16:17:25 -0700428 config->capture_handle = AUDIO_IO_HANDLE_NONE;
429 config->capture_device = AUDIO_DEVICE_NONE;
430 return mHwDevice->start_recognition(mHwDevice, handle, config,
Eric Laurentb7a11d82014-04-18 17:40:41 -0700431 SoundTriggerHwService::recognitionCallback,
Eric Laurent0832b2d2014-07-06 16:17:25 -0700432 this);
Eric Laurentb7a11d82014-04-18 17:40:41 -0700433}
434
435status_t SoundTriggerHwService::Module::stopRecognition(sound_model_handle_t handle)
436{
437 ALOGV("stopRecognition() model handle %d", handle);
Eric Laurent8ba53d82014-08-01 23:15:05 +0000438 if (!captureHotwordAllowed()) {
439 return PERMISSION_DENIED;
440 }
Eric Laurentb7a11d82014-04-18 17:40:41 -0700441
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