blob: 747af79efa1b95120894cb87726a6a8dc3cbeee7 [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
25#include <binder/IServiceManager.h>
26#include <binder/MemoryBase.h>
27#include <binder/MemoryHeapBase.h>
Eric Laurent936c84a2014-07-17 10:26:04 -070028#include <cutils/atomic.h>
29#include <cutils/properties.h>
Eric Laurentb7a11d82014-04-18 17:40:41 -070030#include <hardware/hardware.h>
Eric Laurent936c84a2014-07-17 10:26:04 -070031#include <utils/Errors.h>
32#include <utils/Log.h>
33
Eric Laurentdcb162f2014-07-11 09:14:45 -070034#include "SoundTriggerHwService.h"
Eric Laurent936c84a2014-07-17 10:26:04 -070035#include <system/sound_trigger.h>
36#include <hardware/sound_trigger.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");
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) {
Eric Laurentdcb162f2014-07-11 09:14:45 -0700142 AutoMutex lock(mServiceLock);
Eric Laurent936c84a2014-07-17 10:26:04 -0700143 ALOGV("detachModule");
Eric Laurentb7a11d82014-04-18 17:40:41 -0700144 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 }
Eric Laurent1a1cba82014-06-09 16:20:05 -0700370 sp<Model> model = mModels.valueAt(index);
Eric Laurentb7a11d82014-04-18 17:40:41 -0700371 mModels.removeItem(handle);
Eric Laurent1a1cba82014-06-09 16:20:05 -0700372 if (model->mState == Model::STATE_ACTIVE) {
373 mHwDevice->stop_recognition(mHwDevice, model->mHandle);
374 model->deallocateMemory();
375 }
Eric Laurentb7a11d82014-04-18 17:40:41 -0700376 return mHwDevice->unload_sound_model(mHwDevice, handle);
377}
378
379status_t SoundTriggerHwService::Module::startRecognition(sound_model_handle_t handle,
Eric Laurent0832b2d2014-07-06 16:17:25 -0700380 const sp<IMemory>& dataMemory)
Eric Laurentb7a11d82014-04-18 17:40:41 -0700381{
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 }
Eric Laurent0832b2d2014-07-06 16:17:25 -0700394 if ((dataMemory == 0) ||
395 (dataMemory->size() < sizeof(struct sound_trigger_recognition_config))) {
396 return BAD_VALUE;
397 }
Eric Laurentb7a11d82014-04-18 17:40:41 -0700398
399 if (model->mState == Model::STATE_ACTIVE) {
400 return INVALID_OPERATION;
401 }
402 model->mState = Model::STATE_ACTIVE;
403
Eric Laurent0832b2d2014-07-06 16:17:25 -0700404 struct sound_trigger_recognition_config *config =
405 (struct sound_trigger_recognition_config *)dataMemory->pointer();
Eric Laurentb7a11d82014-04-18 17:40:41 -0700406
407 //TODO: get capture handle and device from audio policy service
Eric Laurent0832b2d2014-07-06 16:17:25 -0700408 config->capture_handle = AUDIO_IO_HANDLE_NONE;
409 config->capture_device = AUDIO_DEVICE_NONE;
410 return mHwDevice->start_recognition(mHwDevice, handle, config,
Eric Laurentb7a11d82014-04-18 17:40:41 -0700411 SoundTriggerHwService::recognitionCallback,
Eric Laurent0832b2d2014-07-06 16:17:25 -0700412 this);
Eric Laurentb7a11d82014-04-18 17:40:41 -0700413}
414
415status_t SoundTriggerHwService::Module::stopRecognition(sound_model_handle_t handle)
416{
417 ALOGV("stopRecognition() model handle %d", handle);
Eric Laurentb7a11d82014-04-18 17:40:41 -0700418
419 AutoMutex lock(mLock);
420 sp<Model> model = getModel(handle);
421 if (model == 0) {
422 return BAD_VALUE;
423 }
424
425 if (model->mState != Model::STATE_ACTIVE) {
426 return INVALID_OPERATION;
427 }
428 mHwDevice->stop_recognition(mHwDevice, handle);
429 model->deallocateMemory();
430 model->mState = Model::STATE_IDLE;
431 return NO_ERROR;
432}
433
434void SoundTriggerHwService::Module::sendRecognitionEvent(
435 struct sound_trigger_recognition_event *event)
436{
437 sp<SoundTriggerHwService> service;
438 sp<IMemory> eventMemory;
439 ALOGV("sendRecognitionEvent for model %d", event->model);
440 {
441 AutoMutex lock(mLock);
442 sp<Model> model = getModel(event->model);
443 if (model == 0) {
444 return;
445 }
446 if (model->mState != Model::STATE_ACTIVE) {
447 ALOGV("sendRecognitionEvent model->mState %d != Model::STATE_ACTIVE", model->mState);
448 return;
449 }
450 if (mClient == 0) {
451 return;
452 }
453 service = mService.promote();
454 if (service == 0) {
455 return;
456 }
457
458 //sanitize event
459 switch (event->type) {
460 case SOUND_MODEL_TYPE_KEYPHRASE:
461 ALOGW_IF(event->data_offset !=
462 sizeof(struct sound_trigger_phrase_recognition_event),
463 "sendRecognitionEvent(): invalid data offset %u for keyphrase event type",
464 event->data_offset);
465 event->data_offset = sizeof(struct sound_trigger_phrase_recognition_event);
466 break;
467 case SOUND_MODEL_TYPE_UNKNOWN:
468 ALOGW_IF(event->data_offset !=
469 sizeof(struct sound_trigger_recognition_event),
470 "sendRecognitionEvent(): invalid data offset %u for unknown event type",
471 event->data_offset);
472 event->data_offset = sizeof(struct sound_trigger_recognition_event);
473 break;
474 default:
475 return;
476 }
477
478 size_t size = event->data_offset + event->data_size;
479 eventMemory = model->allocateMemory(size);
480 if (eventMemory == 0 || eventMemory->pointer() == NULL) {
481 return;
482 }
483 memcpy(eventMemory->pointer(), event, size);
484 }
485 service->sendRecognitionEvent(new RecognitionEvent(eventMemory, this));
486}
487
488void SoundTriggerHwService::Module::onRecognitionEvent(sp<IMemory> eventMemory)
489{
490 ALOGV("Module::onRecognitionEvent");
491
492 AutoMutex lock(mLock);
493
494 if (eventMemory == 0 || eventMemory->pointer() == NULL) {
495 return;
496 }
497 struct sound_trigger_recognition_event *event =
498 (struct sound_trigger_recognition_event *)eventMemory->pointer();
499
500 sp<Model> model = getModel(event->model);
501 if (model == 0) {
502 ALOGI("%s model == 0", __func__);
503 return;
504 }
505 if (model->mState != Model::STATE_ACTIVE) {
506 ALOGV("onRecognitionEvent model->mState %d != Model::STATE_ACTIVE", model->mState);
507 return;
508 }
509 if (mClient == 0) {
510 ALOGI("%s mClient == 0", __func__);
511 return;
512 }
513 mClient->onRecognitionEvent(eventMemory);
514 model->mState = Model::STATE_IDLE;
515 model->deallocateMemory();
516}
517
518sp<SoundTriggerHwService::Model> SoundTriggerHwService::Module::getModel(
519 sound_model_handle_t handle)
520{
521 sp<Model> model;
522 ssize_t index = mModels.indexOfKey(handle);
523 if (index >= 0) {
524 model = mModels.valueAt(index);
525 }
526 return model;
527}
528
529void SoundTriggerHwService::Module::binderDied(
530 const wp<IBinder> &who __unused) {
531 ALOGW("client binder died for module %d", mDescriptor.handle);
532 detach();
533}
534
535
536SoundTriggerHwService::Model::Model(sound_model_handle_t handle) :
537 mHandle(handle), mState(STATE_IDLE), mInputHandle(AUDIO_IO_HANDLE_NONE),
538 mCaptureSession(AUDIO_SESSION_ALLOCATE),
539 mMemoryDealer(new MemoryDealer(sizeof(struct sound_trigger_recognition_event),
540 "SoundTriggerHwService::Event"))
541{
542
543}
544
545
546sp<IMemory> SoundTriggerHwService::Model::allocateMemory(size_t size)
547{
548 sp<IMemory> memory;
549 if (mMemoryDealer->getMemoryHeap()->getSize() < size) {
550 mMemoryDealer = new MemoryDealer(size, "SoundTriggerHwService::Event");
551 }
552 memory = mMemoryDealer->allocate(size);
553 return memory;
554}
555
556void SoundTriggerHwService::Model::deallocateMemory()
557{
558 mMemoryDealer->deallocate(0);
559}
560
561status_t SoundTriggerHwService::Module::dump(int fd __unused,
562 const Vector<String16>& args __unused) {
563 String8 result;
564 return NO_ERROR;
565}
566
567}; // namespace android