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    client->asBinder()->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_UNKNOWN:
245        ALOGW_IF(event->data_size != 0 && event->data_offset !=
246                    sizeof(struct sound_trigger_recognition_event),
247                    "prepareRecognitionEvent_l(): invalid data offset %u for unknown event type",
248                    event->data_offset);
249        event->data_offset = sizeof(struct sound_trigger_recognition_event);
250        break;
251    default:
252        return eventMemory;
253    }
254
255    size_t size = event->data_offset + event->data_size;
256    eventMemory = mMemoryDealer->allocate(size);
257    if (eventMemory == 0 || eventMemory->pointer() == NULL) {
258        eventMemory.clear();
259        return eventMemory;
260    }
261    memcpy(eventMemory->pointer(), event, size);
262
263    return eventMemory;
264}
265
266void SoundTriggerHwService::sendRecognitionEvent(struct sound_trigger_recognition_event *event,
267                                                 Module *module)
268 {
269     AutoMutex lock(mServiceLock);
270     if (module == NULL) {
271         return;
272     }
273     sp<IMemory> eventMemory = prepareRecognitionEvent_l(event);
274     if (eventMemory == 0) {
275         return;
276     }
277     sp<Module> strongModule;
278     for (size_t i = 0; i < mModules.size(); i++) {
279         if (mModules.valueAt(i).get() == module) {
280             strongModule = mModules.valueAt(i);
281             break;
282         }
283     }
284     if (strongModule == 0) {
285         return;
286     }
287
288     sendCallbackEvent_l(new CallbackEvent(CallbackEvent::TYPE_RECOGNITION,
289                                                  eventMemory, strongModule));
290}
291
292// static
293void SoundTriggerHwService::soundModelCallback(struct sound_trigger_model_event *event,
294                                               void *cookie)
295{
296    Module *module = (Module *)cookie;
297    if (module == NULL) {
298        return;
299    }
300    sp<SoundTriggerHwService> service = module->service().promote();
301    if (service == 0) {
302        return;
303    }
304
305    service->sendSoundModelEvent(event, module);
306}
307
308sp<IMemory> SoundTriggerHwService::prepareSoundModelEvent_l(struct sound_trigger_model_event *event)
309{
310    sp<IMemory> eventMemory;
311
312    size_t size = event->data_offset + event->data_size;
313    eventMemory = mMemoryDealer->allocate(size);
314    if (eventMemory == 0 || eventMemory->pointer() == NULL) {
315        eventMemory.clear();
316        return eventMemory;
317    }
318    memcpy(eventMemory->pointer(), event, size);
319
320    return eventMemory;
321}
322
323void SoundTriggerHwService::sendSoundModelEvent(struct sound_trigger_model_event *event,
324                                                Module *module)
325{
326    AutoMutex lock(mServiceLock);
327    sp<IMemory> eventMemory = prepareSoundModelEvent_l(event);
328    if (eventMemory == 0) {
329        return;
330    }
331    sp<Module> strongModule;
332    for (size_t i = 0; i < mModules.size(); i++) {
333        if (mModules.valueAt(i).get() == module) {
334            strongModule = mModules.valueAt(i);
335            break;
336        }
337    }
338    if (strongModule == 0) {
339        return;
340    }
341    sendCallbackEvent_l(new CallbackEvent(CallbackEvent::TYPE_SOUNDMODEL,
342                                                 eventMemory, strongModule));
343}
344
345
346sp<IMemory> SoundTriggerHwService::prepareServiceStateEvent_l(sound_trigger_service_state_t state)
347{
348    sp<IMemory> eventMemory;
349
350    size_t size = sizeof(sound_trigger_service_state_t);
351    eventMemory = mMemoryDealer->allocate(size);
352    if (eventMemory == 0 || eventMemory->pointer() == NULL) {
353        eventMemory.clear();
354        return eventMemory;
355    }
356    *((sound_trigger_service_state_t *)eventMemory->pointer()) = state;
357    return eventMemory;
358}
359
360// call with mServiceLock held
361void SoundTriggerHwService::sendServiceStateEvent_l(sound_trigger_service_state_t state,
362                                                  Module *module)
363{
364    sp<IMemory> eventMemory = prepareServiceStateEvent_l(state);
365    if (eventMemory == 0) {
366        return;
367    }
368    sp<Module> strongModule;
369    for (size_t i = 0; i < mModules.size(); i++) {
370        if (mModules.valueAt(i).get() == module) {
371            strongModule = mModules.valueAt(i);
372            break;
373        }
374    }
375    if (strongModule == 0) {
376        return;
377    }
378    sendCallbackEvent_l(new CallbackEvent(CallbackEvent::TYPE_SERVICE_STATE,
379                                                 eventMemory, strongModule));
380}
381
382// call with mServiceLock held
383void SoundTriggerHwService::sendCallbackEvent_l(const sp<CallbackEvent>& event)
384{
385    mCallbackThread->sendCallbackEvent(event);
386}
387
388void SoundTriggerHwService::onCallbackEvent(const sp<CallbackEvent>& event)
389{
390    ALOGV("onCallbackEvent");
391    sp<Module> module;
392    {
393        AutoMutex lock(mServiceLock);
394        module = event->mModule.promote();
395        if (module == 0) {
396            return;
397        }
398    }
399    module->onCallbackEvent(event);
400    {
401        AutoMutex lock(mServiceLock);
402        // clear now to execute with mServiceLock locked
403        event->mMemory.clear();
404    }
405}
406
407#undef LOG_TAG
408#define LOG_TAG "SoundTriggerHwService::CallbackThread"
409
410SoundTriggerHwService::CallbackThread::CallbackThread(const wp<SoundTriggerHwService>& service)
411    : mService(service)
412{
413}
414
415SoundTriggerHwService::CallbackThread::~CallbackThread()
416{
417    while (!mEventQueue.isEmpty()) {
418        mEventQueue[0]->mMemory.clear();
419        mEventQueue.removeAt(0);
420    }
421}
422
423void SoundTriggerHwService::CallbackThread::onFirstRef()
424{
425    run("soundTrigger cbk", ANDROID_PRIORITY_URGENT_AUDIO);
426}
427
428bool SoundTriggerHwService::CallbackThread::threadLoop()
429{
430    while (!exitPending()) {
431        sp<CallbackEvent> event;
432        sp<SoundTriggerHwService> service;
433        {
434            Mutex::Autolock _l(mCallbackLock);
435            while (mEventQueue.isEmpty() && !exitPending()) {
436                ALOGV("CallbackThread::threadLoop() sleep");
437                mCallbackCond.wait(mCallbackLock);
438                ALOGV("CallbackThread::threadLoop() wake up");
439            }
440            if (exitPending()) {
441                break;
442            }
443            event = mEventQueue[0];
444            mEventQueue.removeAt(0);
445            service = mService.promote();
446        }
447        if (service != 0) {
448            service->onCallbackEvent(event);
449        }
450    }
451    return false;
452}
453
454void SoundTriggerHwService::CallbackThread::exit()
455{
456    Mutex::Autolock _l(mCallbackLock);
457    requestExit();
458    mCallbackCond.broadcast();
459}
460
461void SoundTriggerHwService::CallbackThread::sendCallbackEvent(
462                        const sp<SoundTriggerHwService::CallbackEvent>& event)
463{
464    AutoMutex lock(mCallbackLock);
465    mEventQueue.add(event);
466    mCallbackCond.signal();
467}
468
469SoundTriggerHwService::CallbackEvent::CallbackEvent(event_type type, sp<IMemory> memory,
470                                                    wp<Module> module)
471    : mType(type), mMemory(memory), mModule(module)
472{
473}
474
475SoundTriggerHwService::CallbackEvent::~CallbackEvent()
476{
477}
478
479
480#undef LOG_TAG
481#define LOG_TAG "SoundTriggerHwService::Module"
482
483SoundTriggerHwService::Module::Module(const sp<SoundTriggerHwService>& service,
484                                      sound_trigger_hw_device* hwDevice,
485                                      sound_trigger_module_descriptor descriptor,
486                                      const sp<ISoundTriggerClient>& client)
487 : mService(service), mHwDevice(hwDevice), mDescriptor(descriptor),
488   mClient(client), mServiceState(SOUND_TRIGGER_STATE_NO_INIT)
489{
490}
491
492SoundTriggerHwService::Module::~Module() {
493}
494
495void SoundTriggerHwService::Module::detach() {
496    ALOGV("detach()");
497    if (!captureHotwordAllowed()) {
498        return;
499    }
500    {
501        AutoMutex lock(mLock);
502        for (size_t i = 0; i < mModels.size(); i++) {
503            sp<Model> model = mModels.valueAt(i);
504            ALOGV("detach() unloading model %d", model->mHandle);
505            if (model->mState == Model::STATE_ACTIVE) {
506                mHwDevice->stop_recognition(mHwDevice, model->mHandle);
507            }
508            mHwDevice->unload_sound_model(mHwDevice, model->mHandle);
509        }
510        mModels.clear();
511    }
512    if (mClient != 0) {
513        mClient->asBinder()->unlinkToDeath(this);
514    }
515    sp<SoundTriggerHwService> service = mService.promote();
516    if (service == 0) {
517        return;
518    }
519    service->detachModule(this);
520}
521
522status_t SoundTriggerHwService::Module::loadSoundModel(const sp<IMemory>& modelMemory,
523                                sound_model_handle_t *handle)
524{
525    ALOGV("loadSoundModel() handle");
526    if (!captureHotwordAllowed()) {
527        return PERMISSION_DENIED;
528    }
529
530    if (modelMemory == 0 || modelMemory->pointer() == NULL) {
531        ALOGE("loadSoundModel() modelMemory is 0 or has NULL pointer()");
532        return BAD_VALUE;
533    }
534    struct sound_trigger_sound_model *sound_model =
535            (struct sound_trigger_sound_model *)modelMemory->pointer();
536
537    AutoMutex lock(mLock);
538
539    if (mModels.size() >= mDescriptor.properties.max_sound_models) {
540        if (mModels.size() == 0) {
541            return INVALID_OPERATION;
542        }
543        ALOGW("loadSoundModel() max number of models exceeded %d making room for a new one",
544              mDescriptor.properties.max_sound_models);
545        unloadSoundModel_l(mModels.valueAt(0)->mHandle);
546    }
547
548    status_t status = mHwDevice->load_sound_model(mHwDevice,
549                                                  sound_model,
550                                                  SoundTriggerHwService::soundModelCallback,
551                                                  this,
552                                                  handle);
553    if (status != NO_ERROR) {
554        return status;
555    }
556    audio_session_t session;
557    audio_io_handle_t ioHandle;
558    audio_devices_t device;
559
560    status = AudioSystem::acquireSoundTriggerSession(&session, &ioHandle, &device);
561    if (status != NO_ERROR) {
562        return status;
563    }
564
565    sp<Model> model = new Model(*handle, session, ioHandle, device, sound_model->type);
566    mModels.replaceValueFor(*handle, model);
567
568    return status;
569}
570
571status_t SoundTriggerHwService::Module::unloadSoundModel(sound_model_handle_t handle)
572{
573    ALOGV("unloadSoundModel() model handle %d", handle);
574    if (!captureHotwordAllowed()) {
575        return PERMISSION_DENIED;
576    }
577
578    AutoMutex lock(mLock);
579    return unloadSoundModel_l(handle);
580}
581
582status_t SoundTriggerHwService::Module::unloadSoundModel_l(sound_model_handle_t handle)
583{
584    ssize_t index = mModels.indexOfKey(handle);
585    if (index < 0) {
586        return BAD_VALUE;
587    }
588    sp<Model> model = mModels.valueAt(index);
589    mModels.removeItem(handle);
590    if (model->mState == Model::STATE_ACTIVE) {
591        mHwDevice->stop_recognition(mHwDevice, model->mHandle);
592        model->mState = Model::STATE_IDLE;
593    }
594    AudioSystem::releaseSoundTriggerSession(model->mCaptureSession);
595    return mHwDevice->unload_sound_model(mHwDevice, handle);
596}
597
598status_t SoundTriggerHwService::Module::startRecognition(sound_model_handle_t handle,
599                                 const sp<IMemory>& dataMemory)
600{
601    ALOGV("startRecognition() model handle %d", handle);
602    if (!captureHotwordAllowed()) {
603        return PERMISSION_DENIED;
604    }
605
606    if (dataMemory != 0 && dataMemory->pointer() == NULL) {
607        ALOGE("startRecognition() dataMemory is non-0 but has NULL pointer()");
608        return BAD_VALUE;
609
610    }
611    AutoMutex lock(mLock);
612    if (mServiceState == SOUND_TRIGGER_STATE_DISABLED) {
613        return INVALID_OPERATION;
614    }
615    sp<Model> model = getModel(handle);
616    if (model == 0) {
617        return BAD_VALUE;
618    }
619    if ((dataMemory == 0) ||
620            (dataMemory->size() < sizeof(struct sound_trigger_recognition_config))) {
621        return BAD_VALUE;
622    }
623
624    if (model->mState == Model::STATE_ACTIVE) {
625        return INVALID_OPERATION;
626    }
627
628    struct sound_trigger_recognition_config *config =
629            (struct sound_trigger_recognition_config *)dataMemory->pointer();
630
631    //TODO: get capture handle and device from audio policy service
632    config->capture_handle = model->mCaptureIOHandle;
633    config->capture_device = model->mCaptureDevice;
634    status_t status = mHwDevice->start_recognition(mHwDevice, handle, config,
635                                        SoundTriggerHwService::recognitionCallback,
636                                        this);
637
638    if (status == NO_ERROR) {
639        model->mState = Model::STATE_ACTIVE;
640        model->mConfig = *config;
641    }
642
643    return status;
644}
645
646status_t SoundTriggerHwService::Module::stopRecognition(sound_model_handle_t handle)
647{
648    ALOGV("stopRecognition() model handle %d", handle);
649    if (!captureHotwordAllowed()) {
650        return PERMISSION_DENIED;
651    }
652
653    AutoMutex lock(mLock);
654    sp<Model> model = getModel(handle);
655    if (model == 0) {
656        return BAD_VALUE;
657    }
658
659    if (model->mState != Model::STATE_ACTIVE) {
660        return INVALID_OPERATION;
661    }
662    mHwDevice->stop_recognition(mHwDevice, handle);
663    model->mState = Model::STATE_IDLE;
664    return NO_ERROR;
665}
666
667
668void SoundTriggerHwService::Module::onCallbackEvent(const sp<CallbackEvent>& event)
669{
670    ALOGV("onCallbackEvent type %d", event->mType);
671
672    sp<IMemory> eventMemory = event->mMemory;
673
674    if (eventMemory == 0 || eventMemory->pointer() == NULL) {
675        return;
676    }
677    if (mClient == 0) {
678        ALOGI("%s mClient == 0", __func__);
679        return;
680    }
681
682    switch (event->mType) {
683    case CallbackEvent::TYPE_RECOGNITION: {
684        struct sound_trigger_recognition_event *recognitionEvent =
685                (struct sound_trigger_recognition_event *)eventMemory->pointer();
686        sp<ISoundTriggerClient> client;
687        {
688            AutoMutex lock(mLock);
689            sp<Model> model = getModel(recognitionEvent->model);
690            if (model == 0) {
691                ALOGW("%s model == 0", __func__);
692                return;
693            }
694            if (model->mState != Model::STATE_ACTIVE) {
695                ALOGV("onCallbackEvent model->mState %d != Model::STATE_ACTIVE", model->mState);
696                return;
697            }
698
699            recognitionEvent->capture_session = model->mCaptureSession;
700            model->mState = Model::STATE_IDLE;
701            client = mClient;
702        }
703        if (client != 0) {
704            client->onRecognitionEvent(eventMemory);
705        }
706    } break;
707    case CallbackEvent::TYPE_SOUNDMODEL: {
708        struct sound_trigger_model_event *soundmodelEvent =
709                (struct sound_trigger_model_event *)eventMemory->pointer();
710        sp<ISoundTriggerClient> client;
711        {
712            AutoMutex lock(mLock);
713            sp<Model> model = getModel(soundmodelEvent->model);
714            if (model == 0) {
715                ALOGW("%s model == 0", __func__);
716                return;
717            }
718            client = mClient;
719        }
720        if (client != 0) {
721            client->onSoundModelEvent(eventMemory);
722        }
723    } break;
724    case CallbackEvent::TYPE_SERVICE_STATE: {
725        sp<ISoundTriggerClient> client;
726        {
727            AutoMutex lock(mLock);
728            client = mClient;
729        }
730        if (client != 0) {
731            client->onServiceStateChange(eventMemory);
732        }
733    } break;
734    default:
735        LOG_ALWAYS_FATAL("onCallbackEvent unknown event type %d", event->mType);
736    }
737}
738
739sp<SoundTriggerHwService::Model> SoundTriggerHwService::Module::getModel(
740        sound_model_handle_t handle)
741{
742    sp<Model> model;
743    ssize_t index = mModels.indexOfKey(handle);
744    if (index >= 0) {
745        model = mModels.valueAt(index);
746    }
747    return model;
748}
749
750void SoundTriggerHwService::Module::binderDied(
751    const wp<IBinder> &who __unused) {
752    ALOGW("client binder died for module %d", mDescriptor.handle);
753    detach();
754}
755
756// Called with mServiceLock held
757void SoundTriggerHwService::Module::setCaptureState_l(bool active)
758{
759    ALOGV("Module::setCaptureState_l %d", active);
760    sp<SoundTriggerHwService> service;
761    sound_trigger_service_state_t state;
762
763    Vector< sp<IMemory> > events;
764    {
765        AutoMutex lock(mLock);
766        state = (active && !mDescriptor.properties.concurrent_capture) ?
767                                        SOUND_TRIGGER_STATE_DISABLED : SOUND_TRIGGER_STATE_ENABLED;
768
769        if (state == mServiceState) {
770            return;
771        }
772
773        mServiceState = state;
774
775        service = mService.promote();
776        if (service == 0) {
777            return;
778        }
779
780        if (state == SOUND_TRIGGER_STATE_ENABLED) {
781            goto exit;
782        }
783
784        for (size_t i = 0; i < mModels.size(); i++) {
785            sp<Model> model = mModels.valueAt(i);
786            if (model->mState == Model::STATE_ACTIVE) {
787                mHwDevice->stop_recognition(mHwDevice, model->mHandle);
788                // keep model in ACTIVE state so that event is processed by onCallbackEvent()
789                struct sound_trigger_phrase_recognition_event phraseEvent;
790                switch (model->mType) {
791                case SOUND_MODEL_TYPE_KEYPHRASE:
792                    phraseEvent.num_phrases = model->mConfig.num_phrases;
793                    for (size_t i = 0; i < phraseEvent.num_phrases; i++) {
794                        phraseEvent.phrase_extras[i] = model->mConfig.phrases[i];
795                    }
796                    break;
797                case SOUND_MODEL_TYPE_UNKNOWN:
798                default:
799                    break;
800                }
801                phraseEvent.common.status = RECOGNITION_STATUS_ABORT;
802                phraseEvent.common.type = model->mType;
803                phraseEvent.common.model = model->mHandle;
804                phraseEvent.common.data_size = 0;
805                sp<IMemory> eventMemory = service->prepareRecognitionEvent_l(&phraseEvent.common);
806                if (eventMemory != 0) {
807                    events.add(eventMemory);
808                }
809            }
810        }
811    }
812
813    for (size_t i = 0; i < events.size(); i++) {
814        service->sendCallbackEvent_l(new CallbackEvent(CallbackEvent::TYPE_RECOGNITION, events[i],
815                                                     this));
816    }
817
818exit:
819    service->sendServiceStateEvent_l(state, this);
820}
821
822
823SoundTriggerHwService::Model::Model(sound_model_handle_t handle, audio_session_t session,
824                                    audio_io_handle_t ioHandle, audio_devices_t device,
825                                    sound_trigger_sound_model_type_t type) :
826    mHandle(handle), mState(STATE_IDLE), mCaptureSession(session),
827    mCaptureIOHandle(ioHandle), mCaptureDevice(device), mType(type)
828{
829
830}
831
832status_t SoundTriggerHwService::Module::dump(int fd __unused,
833                                             const Vector<String16>& args __unused) {
834    String8 result;
835    return NO_ERROR;
836}
837
838}; // namespace android
839