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