SoundTriggerHwService.cpp revision 00a727c430c474f77f8835675a9d773f0314fb68
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 <system/sound_trigger.h>
26#include <cutils/atomic.h>
27#include <cutils/properties.h>
28#include <hardware/hardware.h>
29#include <media/AudioSystem.h>
30#include <utils/Errors.h>
31#include <utils/Log.h>
32#include <binder/IServiceManager.h>
33#include <binder/MemoryBase.h>
34#include <binder/MemoryHeapBase.h>
35#include <hardware/sound_trigger.h>
36#include <ServiceUtilities.h>
37#include "SoundTriggerHwService.h"
38
39namespace android {
40
41#ifdef SOUND_TRIGGER_USE_STUB_MODULE
42#define HW_MODULE_PREFIX "stub"
43#else
44#define HW_MODULE_PREFIX "primary"
45#endif
46
47SoundTriggerHwService::SoundTriggerHwService()
48    : BnSoundTriggerHwService(),
49      mNextUniqueId(1),
50      mMemoryDealer(new MemoryDealer(1024 * 1024, "SoundTriggerHwService")),
51      mCaptureState(false)
52{
53}
54
55void SoundTriggerHwService::onFirstRef()
56{
57    const hw_module_t *mod;
58    int rc;
59    sound_trigger_hw_device *dev;
60
61    rc = hw_get_module_by_class(SOUND_TRIGGER_HARDWARE_MODULE_ID, HW_MODULE_PREFIX, &mod);
62    if (rc != 0) {
63        ALOGE("couldn't load sound trigger module %s.%s (%s)",
64              SOUND_TRIGGER_HARDWARE_MODULE_ID, "primary", strerror(-rc));
65        return;
66    }
67    rc = sound_trigger_hw_device_open(mod, &dev);
68    if (rc != 0) {
69        ALOGE("couldn't open sound trigger hw device in %s.%s (%s)",
70              SOUND_TRIGGER_HARDWARE_MODULE_ID, "primary", strerror(-rc));
71        return;
72    }
73    if (dev->common.version != SOUND_TRIGGER_DEVICE_API_VERSION_CURRENT) {
74        ALOGE("wrong sound trigger hw device version %04x", dev->common.version);
75        return;
76    }
77
78    sound_trigger_module_descriptor descriptor;
79    rc = dev->get_properties(dev, &descriptor.properties);
80    if (rc != 0) {
81        ALOGE("could not read implementation properties");
82        return;
83    }
84    descriptor.handle =
85            (sound_trigger_module_handle_t)android_atomic_inc(&mNextUniqueId);
86    ALOGI("loaded default module %s, handle %d", descriptor.properties.description,
87                                                 descriptor.handle);
88
89    sp<ISoundTriggerClient> client;
90    sp<Module> module = new Module(this, dev, descriptor, client);
91    mModules.add(descriptor.handle, module);
92    mCallbackThread = new CallbackThread(this);
93}
94
95SoundTriggerHwService::~SoundTriggerHwService()
96{
97    if (mCallbackThread != 0) {
98        mCallbackThread->exit();
99    }
100    for (size_t i = 0; i < mModules.size(); i++) {
101        sound_trigger_hw_device_close(mModules.valueAt(i)->hwDevice());
102    }
103}
104
105status_t SoundTriggerHwService::listModules(struct sound_trigger_module_descriptor *modules,
106                             uint32_t *numModules)
107{
108    ALOGV("listModules");
109    if (!captureHotwordAllowed()) {
110        return PERMISSION_DENIED;
111    }
112
113    AutoMutex lock(mServiceLock);
114    if (numModules == NULL || (*numModules != 0 && modules == NULL)) {
115        return BAD_VALUE;
116    }
117    size_t maxModules = *numModules;
118    *numModules = mModules.size();
119    for (size_t i = 0; i < mModules.size() && i < maxModules; i++) {
120        modules[i] = mModules.valueAt(i)->descriptor();
121    }
122    return NO_ERROR;
123}
124
125status_t SoundTriggerHwService::attach(const sound_trigger_module_handle_t handle,
126                        const sp<ISoundTriggerClient>& client,
127                        sp<ISoundTrigger>& moduleInterface)
128{
129    ALOGV("attach module %d", handle);
130    if (!captureHotwordAllowed()) {
131        return PERMISSION_DENIED;
132    }
133
134    AutoMutex lock(mServiceLock);
135    moduleInterface.clear();
136    if (client == 0) {
137        return BAD_VALUE;
138    }
139    ssize_t index = mModules.indexOfKey(handle);
140    if (index < 0) {
141        return BAD_VALUE;
142    }
143    sp<Module> module = mModules.valueAt(index);
144
145    module->setClient(client);
146    IInterface::asBinder(client)->linkToDeath(module);
147    moduleInterface = module;
148
149    module->setCaptureState_l(mCaptureState);
150
151    return NO_ERROR;
152}
153
154status_t SoundTriggerHwService::setCaptureState(bool active)
155{
156    ALOGV("setCaptureState %d", active);
157    AutoMutex lock(mServiceLock);
158    mCaptureState = active;
159    for (size_t i = 0; i < mModules.size(); i++) {
160        mModules.valueAt(i)->setCaptureState_l(active);
161    }
162    return NO_ERROR;
163}
164
165
166void SoundTriggerHwService::detachModule(sp<Module> module)
167{
168    ALOGV("detachModule");
169    AutoMutex lock(mServiceLock);
170    module->clearClient();
171}
172
173
174static const int kDumpLockRetries = 50;
175static const int kDumpLockSleep = 60000;
176
177static bool tryLock(Mutex& mutex)
178{
179    bool locked = false;
180    for (int i = 0; i < kDumpLockRetries; ++i) {
181        if (mutex.tryLock() == NO_ERROR) {
182            locked = true;
183            break;
184        }
185        usleep(kDumpLockSleep);
186    }
187    return locked;
188}
189
190status_t SoundTriggerHwService::dump(int fd, const Vector<String16>& args __unused) {
191    String8 result;
192    if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
193        result.appendFormat("Permission Denial: can't dump SoundTriggerHwService");
194        write(fd, result.string(), result.size());
195    } else {
196        bool locked = tryLock(mServiceLock);
197        // failed to lock - SoundTriggerHwService is probably deadlocked
198        if (!locked) {
199            result.append("SoundTriggerHwService may be deadlocked\n");
200            write(fd, result.string(), result.size());
201        }
202
203        if (locked) mServiceLock.unlock();
204    }
205    return NO_ERROR;
206}
207
208status_t SoundTriggerHwService::onTransact(
209    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
210    return BnSoundTriggerHwService::onTransact(code, data, reply, flags);
211}
212
213
214// static
215void SoundTriggerHwService::recognitionCallback(struct sound_trigger_recognition_event *event,
216                                                void *cookie)
217{
218    Module *module = (Module *)cookie;
219    if (module == NULL) {
220        return;
221    }
222    sp<SoundTriggerHwService> service = module->service().promote();
223    if (service == 0) {
224        return;
225    }
226
227    service->sendRecognitionEvent(event, module);
228}
229
230sp<IMemory> SoundTriggerHwService::prepareRecognitionEvent_l(
231                                                    struct sound_trigger_recognition_event *event)
232{
233    sp<IMemory> eventMemory;
234
235    //sanitize event
236    switch (event->type) {
237    case SOUND_MODEL_TYPE_KEYPHRASE:
238        ALOGW_IF(event->data_size != 0 && event->data_offset !=
239                    sizeof(struct sound_trigger_phrase_recognition_event),
240                    "prepareRecognitionEvent_l(): invalid data offset %u for keyphrase event type",
241                    event->data_offset);
242        event->data_offset = sizeof(struct sound_trigger_phrase_recognition_event);
243        break;
244    case SOUND_MODEL_TYPE_GENERIC:
245        ALOGW_IF(event->data_size != 0 && event->data_offset !=
246                    sizeof(struct sound_trigger_generic_recognition_event),
247                    "prepareRecognitionEvent_l(): invalid data offset %u for generic event type",
248                    event->data_offset);
249        event->data_offset = sizeof(struct sound_trigger_generic_recognition_event);
250        break;
251    case SOUND_MODEL_TYPE_UNKNOWN:
252        ALOGW_IF(event->data_size != 0 && event->data_offset !=
253                    sizeof(struct sound_trigger_recognition_event),
254                    "prepareRecognitionEvent_l(): invalid data offset %u for unknown event type",
255                    event->data_offset);
256        event->data_offset = sizeof(struct sound_trigger_recognition_event);
257        break;
258    default:
259        return eventMemory;
260    }
261
262    size_t size = event->data_offset + event->data_size;
263    eventMemory = mMemoryDealer->allocate(size);
264    if (eventMemory == 0 || eventMemory->pointer() == NULL) {
265        eventMemory.clear();
266        return eventMemory;
267    }
268    memcpy(eventMemory->pointer(), event, size);
269
270    return eventMemory;
271}
272
273void SoundTriggerHwService::sendRecognitionEvent(struct sound_trigger_recognition_event *event,
274                                                 Module *module)
275 {
276     AutoMutex lock(mServiceLock);
277     if (module == NULL) {
278         return;
279     }
280     sp<IMemory> eventMemory = prepareRecognitionEvent_l(event);
281     if (eventMemory == 0) {
282         return;
283     }
284     sp<Module> strongModule;
285     for (size_t i = 0; i < mModules.size(); i++) {
286         if (mModules.valueAt(i).get() == module) {
287             strongModule = mModules.valueAt(i);
288             break;
289         }
290     }
291     if (strongModule == 0) {
292         return;
293     }
294
295     sendCallbackEvent_l(new CallbackEvent(CallbackEvent::TYPE_RECOGNITION,
296                                                  eventMemory, strongModule));
297}
298
299// static
300void SoundTriggerHwService::soundModelCallback(struct sound_trigger_model_event *event,
301                                               void *cookie)
302{
303    Module *module = (Module *)cookie;
304    if (module == NULL) {
305        return;
306    }
307    sp<SoundTriggerHwService> service = module->service().promote();
308    if (service == 0) {
309        return;
310    }
311
312    service->sendSoundModelEvent(event, module);
313}
314
315sp<IMemory> SoundTriggerHwService::prepareSoundModelEvent_l(struct sound_trigger_model_event *event)
316{
317    sp<IMemory> eventMemory;
318
319    size_t size = event->data_offset + event->data_size;
320    eventMemory = mMemoryDealer->allocate(size);
321    if (eventMemory == 0 || eventMemory->pointer() == NULL) {
322        eventMemory.clear();
323        return eventMemory;
324    }
325    memcpy(eventMemory->pointer(), event, size);
326
327    return eventMemory;
328}
329
330void SoundTriggerHwService::sendSoundModelEvent(struct sound_trigger_model_event *event,
331                                                Module *module)
332{
333    AutoMutex lock(mServiceLock);
334    sp<IMemory> eventMemory = prepareSoundModelEvent_l(event);
335    if (eventMemory == 0) {
336        return;
337    }
338    sp<Module> strongModule;
339    for (size_t i = 0; i < mModules.size(); i++) {
340        if (mModules.valueAt(i).get() == module) {
341            strongModule = mModules.valueAt(i);
342            break;
343        }
344    }
345    if (strongModule == 0) {
346        return;
347    }
348    sendCallbackEvent_l(new CallbackEvent(CallbackEvent::TYPE_SOUNDMODEL,
349                                                 eventMemory, strongModule));
350}
351
352
353sp<IMemory> SoundTriggerHwService::prepareServiceStateEvent_l(sound_trigger_service_state_t state)
354{
355    sp<IMemory> eventMemory;
356
357    size_t size = sizeof(sound_trigger_service_state_t);
358    eventMemory = mMemoryDealer->allocate(size);
359    if (eventMemory == 0 || eventMemory->pointer() == NULL) {
360        eventMemory.clear();
361        return eventMemory;
362    }
363    *((sound_trigger_service_state_t *)eventMemory->pointer()) = state;
364    return eventMemory;
365}
366
367// call with mServiceLock held
368void SoundTriggerHwService::sendServiceStateEvent_l(sound_trigger_service_state_t state,
369                                                  Module *module)
370{
371    sp<IMemory> eventMemory = prepareServiceStateEvent_l(state);
372    if (eventMemory == 0) {
373        return;
374    }
375    sp<Module> strongModule;
376    for (size_t i = 0; i < mModules.size(); i++) {
377        if (mModules.valueAt(i).get() == module) {
378            strongModule = mModules.valueAt(i);
379            break;
380        }
381    }
382    if (strongModule == 0) {
383        return;
384    }
385    sendCallbackEvent_l(new CallbackEvent(CallbackEvent::TYPE_SERVICE_STATE,
386                                                 eventMemory, strongModule));
387}
388
389// call with mServiceLock held
390void SoundTriggerHwService::sendCallbackEvent_l(const sp<CallbackEvent>& event)
391{
392    mCallbackThread->sendCallbackEvent(event);
393}
394
395void SoundTriggerHwService::onCallbackEvent(const sp<CallbackEvent>& event)
396{
397    ALOGV("onCallbackEvent");
398    sp<Module> module;
399    {
400        AutoMutex lock(mServiceLock);
401        module = event->mModule.promote();
402        if (module == 0) {
403            return;
404        }
405    }
406    module->onCallbackEvent(event);
407    {
408        AutoMutex lock(mServiceLock);
409        // clear now to execute with mServiceLock locked
410        event->mMemory.clear();
411    }
412}
413
414#undef LOG_TAG
415#define LOG_TAG "SoundTriggerHwService::CallbackThread"
416
417SoundTriggerHwService::CallbackThread::CallbackThread(const wp<SoundTriggerHwService>& service)
418    : mService(service)
419{
420}
421
422SoundTriggerHwService::CallbackThread::~CallbackThread()
423{
424    while (!mEventQueue.isEmpty()) {
425        mEventQueue[0]->mMemory.clear();
426        mEventQueue.removeAt(0);
427    }
428}
429
430void SoundTriggerHwService::CallbackThread::onFirstRef()
431{
432    run("soundTrigger cbk", ANDROID_PRIORITY_URGENT_AUDIO);
433}
434
435bool SoundTriggerHwService::CallbackThread::threadLoop()
436{
437    while (!exitPending()) {
438        sp<CallbackEvent> event;
439        sp<SoundTriggerHwService> service;
440        {
441            Mutex::Autolock _l(mCallbackLock);
442            while (mEventQueue.isEmpty() && !exitPending()) {
443                ALOGV("CallbackThread::threadLoop() sleep");
444                mCallbackCond.wait(mCallbackLock);
445                ALOGV("CallbackThread::threadLoop() wake up");
446            }
447            if (exitPending()) {
448                break;
449            }
450            event = mEventQueue[0];
451            mEventQueue.removeAt(0);
452            service = mService.promote();
453        }
454        if (service != 0) {
455            service->onCallbackEvent(event);
456        }
457    }
458    return false;
459}
460
461void SoundTriggerHwService::CallbackThread::exit()
462{
463    Mutex::Autolock _l(mCallbackLock);
464    requestExit();
465    mCallbackCond.broadcast();
466}
467
468void SoundTriggerHwService::CallbackThread::sendCallbackEvent(
469                        const sp<SoundTriggerHwService::CallbackEvent>& event)
470{
471    AutoMutex lock(mCallbackLock);
472    mEventQueue.add(event);
473    mCallbackCond.signal();
474}
475
476SoundTriggerHwService::CallbackEvent::CallbackEvent(event_type type, sp<IMemory> memory,
477                                                    wp<Module> module)
478    : mType(type), mMemory(memory), mModule(module)
479{
480}
481
482SoundTriggerHwService::CallbackEvent::~CallbackEvent()
483{
484}
485
486
487#undef LOG_TAG
488#define LOG_TAG "SoundTriggerHwService::Module"
489
490SoundTriggerHwService::Module::Module(const sp<SoundTriggerHwService>& service,
491                                      sound_trigger_hw_device* hwDevice,
492                                      sound_trigger_module_descriptor descriptor,
493                                      const sp<ISoundTriggerClient>& client)
494 : mService(service), mHwDevice(hwDevice), mDescriptor(descriptor),
495   mClient(client), mServiceState(SOUND_TRIGGER_STATE_NO_INIT)
496{
497}
498
499SoundTriggerHwService::Module::~Module() {
500}
501
502void SoundTriggerHwService::Module::detach() {
503    ALOGV("detach()");
504    if (!captureHotwordAllowed()) {
505        return;
506    }
507    {
508        AutoMutex lock(mLock);
509        for (size_t i = 0; i < mModels.size(); i++) {
510            sp<Model> model = mModels.valueAt(i);
511            ALOGV("detach() unloading model %d", model->mHandle);
512            if (model->mState == Model::STATE_ACTIVE) {
513                mHwDevice->stop_recognition(mHwDevice, model->mHandle);
514            }
515            mHwDevice->unload_sound_model(mHwDevice, model->mHandle);
516        }
517        mModels.clear();
518    }
519    if (mClient != 0) {
520        IInterface::asBinder(mClient)->unlinkToDeath(this);
521    }
522    sp<SoundTriggerHwService> service = mService.promote();
523    if (service == 0) {
524        return;
525    }
526    service->detachModule(this);
527}
528
529status_t SoundTriggerHwService::Module::loadSoundModel(const sp<IMemory>& modelMemory,
530                                sound_model_handle_t *handle)
531{
532    ALOGV("loadSoundModel() handle");
533    if (!captureHotwordAllowed()) {
534        return PERMISSION_DENIED;
535    }
536
537    if (modelMemory == 0 || modelMemory->pointer() == NULL) {
538        ALOGE("loadSoundModel() modelMemory is 0 or has NULL pointer()");
539        return BAD_VALUE;
540    }
541    struct sound_trigger_sound_model *sound_model =
542            (struct sound_trigger_sound_model *)modelMemory->pointer();
543
544    AutoMutex lock(mLock);
545
546    if (mModels.size() >= mDescriptor.properties.max_sound_models) {
547        if (mModels.size() == 0) {
548            return INVALID_OPERATION;
549        }
550        ALOGW("loadSoundModel() max number of models exceeded %d making room for a new one",
551              mDescriptor.properties.max_sound_models);
552        unloadSoundModel_l(mModels.valueAt(0)->mHandle);
553    }
554
555    status_t status = mHwDevice->load_sound_model(mHwDevice,
556                                                  sound_model,
557                                                  SoundTriggerHwService::soundModelCallback,
558                                                  this,
559                                                  handle);
560    if (status != NO_ERROR) {
561        return status;
562    }
563    audio_session_t session;
564    audio_io_handle_t ioHandle;
565    audio_devices_t device;
566
567    status = AudioSystem::acquireSoundTriggerSession(&session, &ioHandle, &device);
568    if (status != NO_ERROR) {
569        return status;
570    }
571
572    sp<Model> model = new Model(*handle, session, ioHandle, device, sound_model->type);
573    mModels.replaceValueFor(*handle, model);
574
575    return status;
576}
577
578status_t SoundTriggerHwService::Module::unloadSoundModel(sound_model_handle_t handle)
579{
580    ALOGV("unloadSoundModel() model handle %d", handle);
581    if (!captureHotwordAllowed()) {
582        return PERMISSION_DENIED;
583    }
584
585    AutoMutex lock(mLock);
586    return unloadSoundModel_l(handle);
587}
588
589status_t SoundTriggerHwService::Module::unloadSoundModel_l(sound_model_handle_t handle)
590{
591    ssize_t index = mModels.indexOfKey(handle);
592    if (index < 0) {
593        return BAD_VALUE;
594    }
595    sp<Model> model = mModels.valueAt(index);
596    mModels.removeItem(handle);
597    if (model->mState == Model::STATE_ACTIVE) {
598        mHwDevice->stop_recognition(mHwDevice, model->mHandle);
599        model->mState = Model::STATE_IDLE;
600    }
601    AudioSystem::releaseSoundTriggerSession(model->mCaptureSession);
602    return mHwDevice->unload_sound_model(mHwDevice, handle);
603}
604
605status_t SoundTriggerHwService::Module::startRecognition(sound_model_handle_t handle,
606                                 const sp<IMemory>& dataMemory)
607{
608    ALOGV("startRecognition() model handle %d", handle);
609    if (!captureHotwordAllowed()) {
610        return PERMISSION_DENIED;
611    }
612
613    if (dataMemory != 0 && dataMemory->pointer() == NULL) {
614        ALOGE("startRecognition() dataMemory is non-0 but has NULL pointer()");
615        return BAD_VALUE;
616
617    }
618    AutoMutex lock(mLock);
619    if (mServiceState == SOUND_TRIGGER_STATE_DISABLED) {
620        return INVALID_OPERATION;
621    }
622    sp<Model> model = getModel(handle);
623    if (model == 0) {
624        return BAD_VALUE;
625    }
626    if ((dataMemory == 0) ||
627            (dataMemory->size() < sizeof(struct sound_trigger_recognition_config))) {
628        return BAD_VALUE;
629    }
630
631    if (model->mState == Model::STATE_ACTIVE) {
632        return INVALID_OPERATION;
633    }
634
635    struct sound_trigger_recognition_config *config =
636            (struct sound_trigger_recognition_config *)dataMemory->pointer();
637
638    //TODO: get capture handle and device from audio policy service
639    config->capture_handle = model->mCaptureIOHandle;
640    config->capture_device = model->mCaptureDevice;
641    status_t status = mHwDevice->start_recognition(mHwDevice, handle, config,
642                                        SoundTriggerHwService::recognitionCallback,
643                                        this);
644
645    if (status == NO_ERROR) {
646        model->mState = Model::STATE_ACTIVE;
647        model->mConfig = *config;
648    }
649
650    return status;
651}
652
653status_t SoundTriggerHwService::Module::stopRecognition(sound_model_handle_t handle)
654{
655    ALOGV("stopRecognition() model handle %d", handle);
656    if (!captureHotwordAllowed()) {
657        return PERMISSION_DENIED;
658    }
659
660    AutoMutex lock(mLock);
661    sp<Model> model = getModel(handle);
662    if (model == 0) {
663        return BAD_VALUE;
664    }
665
666    if (model->mState != Model::STATE_ACTIVE) {
667        return INVALID_OPERATION;
668    }
669    mHwDevice->stop_recognition(mHwDevice, handle);
670    model->mState = Model::STATE_IDLE;
671    return NO_ERROR;
672}
673
674
675void SoundTriggerHwService::Module::onCallbackEvent(const sp<CallbackEvent>& event)
676{
677    ALOGV("onCallbackEvent type %d", event->mType);
678
679    sp<IMemory> eventMemory = event->mMemory;
680
681    if (eventMemory == 0 || eventMemory->pointer() == NULL) {
682        return;
683    }
684    if (mClient == 0) {
685        ALOGI("%s mClient == 0", __func__);
686        return;
687    }
688
689    switch (event->mType) {
690    case CallbackEvent::TYPE_RECOGNITION: {
691        struct sound_trigger_recognition_event *recognitionEvent =
692                (struct sound_trigger_recognition_event *)eventMemory->pointer();
693        sp<ISoundTriggerClient> client;
694        {
695            AutoMutex lock(mLock);
696            sp<Model> model = getModel(recognitionEvent->model);
697            if (model == 0) {
698                ALOGW("%s model == 0", __func__);
699                return;
700            }
701            if (model->mState != Model::STATE_ACTIVE) {
702                ALOGV("onCallbackEvent model->mState %d != Model::STATE_ACTIVE", model->mState);
703                return;
704            }
705
706            recognitionEvent->capture_session = model->mCaptureSession;
707            model->mState = Model::STATE_IDLE;
708            client = mClient;
709        }
710        if (client != 0) {
711            client->onRecognitionEvent(eventMemory);
712        }
713    } break;
714    case CallbackEvent::TYPE_SOUNDMODEL: {
715        struct sound_trigger_model_event *soundmodelEvent =
716                (struct sound_trigger_model_event *)eventMemory->pointer();
717        sp<ISoundTriggerClient> client;
718        {
719            AutoMutex lock(mLock);
720            sp<Model> model = getModel(soundmodelEvent->model);
721            if (model == 0) {
722                ALOGW("%s model == 0", __func__);
723                return;
724            }
725            client = mClient;
726        }
727        if (client != 0) {
728            client->onSoundModelEvent(eventMemory);
729        }
730    } break;
731    case CallbackEvent::TYPE_SERVICE_STATE: {
732        sp<ISoundTriggerClient> client;
733        {
734            AutoMutex lock(mLock);
735            client = mClient;
736        }
737        if (client != 0) {
738            client->onServiceStateChange(eventMemory);
739        }
740    } break;
741    default:
742        LOG_ALWAYS_FATAL("onCallbackEvent unknown event type %d", event->mType);
743    }
744}
745
746sp<SoundTriggerHwService::Model> SoundTriggerHwService::Module::getModel(
747        sound_model_handle_t handle)
748{
749    sp<Model> model;
750    ssize_t index = mModels.indexOfKey(handle);
751    if (index >= 0) {
752        model = mModels.valueAt(index);
753    }
754    return model;
755}
756
757void SoundTriggerHwService::Module::binderDied(
758    const wp<IBinder> &who __unused) {
759    ALOGW("client binder died for module %d", mDescriptor.handle);
760    detach();
761}
762
763// Called with mServiceLock held
764void SoundTriggerHwService::Module::setCaptureState_l(bool active)
765{
766    ALOGV("Module::setCaptureState_l %d", active);
767    sp<SoundTriggerHwService> service;
768    sound_trigger_service_state_t state;
769
770    Vector< sp<IMemory> > events;
771    {
772        AutoMutex lock(mLock);
773        state = (active && !mDescriptor.properties.concurrent_capture) ?
774                                        SOUND_TRIGGER_STATE_DISABLED : SOUND_TRIGGER_STATE_ENABLED;
775
776        if (state == mServiceState) {
777            return;
778        }
779
780        mServiceState = state;
781
782        service = mService.promote();
783        if (service == 0) {
784            return;
785        }
786
787        if (state == SOUND_TRIGGER_STATE_ENABLED) {
788            goto exit;
789        }
790
791        for (size_t i = 0; i < mModels.size(); i++) {
792            sp<Model> model = mModels.valueAt(i);
793            if (model->mState == Model::STATE_ACTIVE) {
794                mHwDevice->stop_recognition(mHwDevice, model->mHandle);
795                // keep model in ACTIVE state so that event is processed by onCallbackEvent()
796                if (model->mType == SOUND_MODEL_TYPE_KEYPHRASE) {
797                    struct sound_trigger_phrase_recognition_event event;
798                    memset(&event, 0, sizeof(struct sound_trigger_phrase_recognition_event));
799                    event.num_phrases = model->mConfig.num_phrases;
800                    for (size_t i = 0; i < event.num_phrases; i++) {
801                        event.phrase_extras[i] = model->mConfig.phrases[i];
802                    }
803                    event.common.status = RECOGNITION_STATUS_ABORT;
804                    event.common.type = model->mType;
805                    event.common.model = model->mHandle;
806                    event.common.data_size = 0;
807                    sp<IMemory> eventMemory = service->prepareRecognitionEvent_l(&event.common);
808                    if (eventMemory != 0) {
809                        events.add(eventMemory);
810                    }
811                } else if (model->mType == SOUND_MODEL_TYPE_GENERIC) {
812                    struct sound_trigger_generic_recognition_event event;
813                    memset(&event, 0, sizeof(struct sound_trigger_generic_recognition_event));
814                    event.common.status = RECOGNITION_STATUS_ABORT;
815                    event.common.type = model->mType;
816                    event.common.model = model->mHandle;
817                    event.common.data_size = 0;
818                    sp<IMemory> eventMemory = service->prepareRecognitionEvent_l(&event.common);
819                    if (eventMemory != 0) {
820                        events.add(eventMemory);
821                    }
822                } else {
823                    goto exit;
824                }
825            }
826        }
827    }
828
829    for (size_t i = 0; i < events.size(); i++) {
830        service->sendCallbackEvent_l(new CallbackEvent(CallbackEvent::TYPE_RECOGNITION, events[i],
831                                                     this));
832    }
833
834exit:
835    service->sendServiceStateEvent_l(state, this);
836}
837
838
839SoundTriggerHwService::Model::Model(sound_model_handle_t handle, audio_session_t session,
840                                    audio_io_handle_t ioHandle, audio_devices_t device,
841                                    sound_trigger_sound_model_type_t type) :
842    mHandle(handle), mState(STATE_IDLE), mCaptureSession(session),
843    mCaptureIOHandle(ioHandle), mCaptureDevice(device), mType(type)
844{
845
846}
847
848status_t SoundTriggerHwService::Module::dump(int fd __unused,
849                                             const Vector<String16>& args __unused) {
850    String8 result;
851    return NO_ERROR;
852}
853
854}; // namespace android
855