SoundTrigger.cpp revision df3dc7e2fe6c639529b70e3f3a7d2bf0f4c6e871
1/*
2**
3** Copyright (C) 2014, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9**     http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18#define LOG_TAG "SoundTrigger"
19//#define LOG_NDEBUG 0
20
21#include <utils/Log.h>
22#include <utils/threads.h>
23#include <binder/IPCThreadState.h>
24#include <binder/IServiceManager.h>
25#include <binder/IMemory.h>
26
27#include <soundtrigger/SoundTrigger.h>
28#include <soundtrigger/ISoundTrigger.h>
29#include <soundtrigger/ISoundTriggerHwService.h>
30#include <soundtrigger/ISoundTriggerClient.h>
31#include <soundtrigger/SoundTriggerCallback.h>
32
33namespace android {
34
35namespace {
36    sp<ISoundTriggerHwService> gSoundTriggerHwService;
37    const int                  kSoundTriggerHwServicePollDelay = 500000; // 0.5s
38    const char*                kSoundTriggerHwServiceName      = "media.sound_trigger_hw";
39    Mutex                      gLock;
40
41    class DeathNotifier : public IBinder::DeathRecipient
42    {
43    public:
44        DeathNotifier() {
45        }
46
47        virtual void binderDied(const wp<IBinder>& who __unused) {
48            ALOGV("binderDied");
49            Mutex::Autolock _l(gLock);
50            gSoundTriggerHwService.clear();
51            ALOGW("Sound trigger service died!");
52        }
53    };
54
55    sp<DeathNotifier>         gDeathNotifier;
56}; // namespace anonymous
57
58const sp<ISoundTriggerHwService>& SoundTrigger::getSoundTriggerHwService()
59{
60    Mutex::Autolock _l(gLock);
61    if (gSoundTriggerHwService.get() == 0) {
62        sp<IServiceManager> sm = defaultServiceManager();
63        sp<IBinder> binder;
64        do {
65            binder = sm->getService(String16(kSoundTriggerHwServiceName));
66            if (binder != 0) {
67                break;
68            }
69            ALOGW("SoundTriggerHwService not published, waiting...");
70            usleep(kSoundTriggerHwServicePollDelay);
71        } while(true);
72        if (gDeathNotifier == NULL) {
73            gDeathNotifier = new DeathNotifier();
74        }
75        binder->linkToDeath(gDeathNotifier);
76        gSoundTriggerHwService = interface_cast<ISoundTriggerHwService>(binder);
77    }
78    ALOGE_IF(gSoundTriggerHwService == 0, "no SoundTriggerHwService!?");
79    return gSoundTriggerHwService;
80}
81
82// Static methods
83status_t SoundTrigger::listModules(struct sound_trigger_module_descriptor *modules,
84                                 uint32_t *numModules)
85{
86    ALOGV("listModules()");
87    const sp<ISoundTriggerHwService>& service = getSoundTriggerHwService();
88    if (service == 0) {
89        return NO_INIT;
90    }
91    return service->listModules(modules, numModules);
92}
93
94sp<SoundTrigger> SoundTrigger::attach(const sound_trigger_module_handle_t module,
95                                            const sp<SoundTriggerCallback>& callback)
96{
97    ALOGV("attach()");
98    sp<SoundTrigger> soundTrigger;
99    const sp<ISoundTriggerHwService>& service = getSoundTriggerHwService();
100    if (service == 0) {
101        return soundTrigger;
102    }
103    soundTrigger = new SoundTrigger(module, callback);
104    status_t status = service->attach(module, soundTrigger, soundTrigger->mISoundTrigger);
105
106    if (status == NO_ERROR && soundTrigger->mISoundTrigger != 0) {
107        soundTrigger->mISoundTrigger->asBinder()->linkToDeath(soundTrigger);
108    } else {
109        ALOGW("Error %d connecting to sound trigger service", status);
110        soundTrigger.clear();
111    }
112    return soundTrigger;
113}
114
115
116status_t SoundTrigger::setCaptureState(bool active)
117{
118    ALOGV("setCaptureState(%d)", active);
119    const sp<ISoundTriggerHwService>& service = getSoundTriggerHwService();
120    if (service == 0) {
121        return NO_INIT;
122    }
123    return service->setCaptureState(active);
124}
125
126// SoundTrigger
127SoundTrigger::SoundTrigger(sound_trigger_module_handle_t module,
128                                 const sp<SoundTriggerCallback>& callback)
129    : mModule(module), mCallback(callback)
130{
131}
132
133SoundTrigger::~SoundTrigger()
134{
135    if (mISoundTrigger != 0) {
136        mISoundTrigger->detach();
137    }
138}
139
140
141void SoundTrigger::detach() {
142    ALOGV("detach()");
143    Mutex::Autolock _l(mLock);
144    mCallback.clear();
145    if (mISoundTrigger != 0) {
146        mISoundTrigger->detach();
147        mISoundTrigger->asBinder()->unlinkToDeath(this);
148        mISoundTrigger = 0;
149    }
150}
151
152status_t SoundTrigger::loadSoundModel(const sp<IMemory>& modelMemory,
153                                sound_model_handle_t *handle)
154{
155    Mutex::Autolock _l(mLock);
156    if (mISoundTrigger == 0) {
157        return NO_INIT;
158    }
159
160    return mISoundTrigger->loadSoundModel(modelMemory, handle);
161}
162
163status_t SoundTrigger::unloadSoundModel(sound_model_handle_t handle)
164{
165    Mutex::Autolock _l(mLock);
166    if (mISoundTrigger == 0) {
167        return NO_INIT;
168    }
169    return mISoundTrigger->unloadSoundModel(handle);
170}
171
172status_t SoundTrigger::startRecognition(sound_model_handle_t handle,
173                                        const sp<IMemory>& dataMemory)
174{
175    Mutex::Autolock _l(mLock);
176    if (mISoundTrigger == 0) {
177        return NO_INIT;
178    }
179    return mISoundTrigger->startRecognition(handle, dataMemory);
180}
181
182status_t SoundTrigger::stopRecognition(sound_model_handle_t handle)
183{
184    Mutex::Autolock _l(mLock);
185    if (mISoundTrigger == 0) {
186        return NO_INIT;
187    }
188    return mISoundTrigger->stopRecognition(handle);
189}
190
191// BpSoundTriggerClient
192void SoundTrigger::onRecognitionEvent(const sp<IMemory>& eventMemory)
193{
194    Mutex::Autolock _l(mLock);
195    if (eventMemory == 0 || eventMemory->pointer() == NULL) {
196        return;
197    }
198
199    if (mCallback != 0) {
200        mCallback->onRecognitionEvent(
201                (struct sound_trigger_recognition_event *)eventMemory->pointer());
202    }
203}
204
205void SoundTrigger::onSoundModelEvent(const sp<IMemory>& eventMemory)
206{
207    Mutex::Autolock _l(mLock);
208    if (eventMemory == 0 || eventMemory->pointer() == NULL) {
209        return;
210    }
211
212    if (mCallback != 0) {
213        mCallback->onSoundModelEvent(
214                (struct sound_trigger_model_event *)eventMemory->pointer());
215    }
216}
217
218void SoundTrigger::onServiceStateChange(const sp<IMemory>& eventMemory)
219{
220    Mutex::Autolock _l(mLock);
221    if (eventMemory == 0 || eventMemory->pointer() == NULL) {
222        return;
223    }
224
225    if (mCallback != 0) {
226        mCallback->onServiceStateChange(
227                *((sound_trigger_service_state_t *)eventMemory->pointer()));
228    }
229}
230
231//IBinder::DeathRecipient
232void SoundTrigger::binderDied(const wp<IBinder>& who __unused) {
233    Mutex::Autolock _l(mLock);
234    ALOGW("SoundTrigger server binder Died ");
235    mISoundTrigger = 0;
236    if (mCallback != 0) {
237        mCallback->onServiceDied();
238    }
239}
240
241status_t SoundTrigger::stringToGuid(const char *str, sound_trigger_uuid_t *guid)
242{
243    if (str == NULL || guid == NULL) {
244        return BAD_VALUE;
245    }
246
247    int tmp[10];
248
249    if (sscanf(str, "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",
250            tmp, tmp+1, tmp+2, tmp+3, tmp+4, tmp+5, tmp+6, tmp+7, tmp+8, tmp+9) < 10) {
251        return BAD_VALUE;
252    }
253    guid->timeLow = (uint32_t)tmp[0];
254    guid->timeMid = (uint16_t)tmp[1];
255    guid->timeHiAndVersion = (uint16_t)tmp[2];
256    guid->clockSeq = (uint16_t)tmp[3];
257    guid->node[0] = (uint8_t)tmp[4];
258    guid->node[1] = (uint8_t)tmp[5];
259    guid->node[2] = (uint8_t)tmp[6];
260    guid->node[3] = (uint8_t)tmp[7];
261    guid->node[4] = (uint8_t)tmp[8];
262    guid->node[5] = (uint8_t)tmp[9];
263
264    return NO_ERROR;
265}
266
267status_t SoundTrigger::guidToString(const sound_trigger_uuid_t *guid, char *str, size_t maxLen)
268{
269    if (guid == NULL || str == NULL) {
270        return BAD_VALUE;
271    }
272
273    snprintf(str, maxLen, "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",
274            guid->timeLow,
275            guid->timeMid,
276            guid->timeHiAndVersion,
277            guid->clockSeq,
278            guid->node[0],
279            guid->node[1],
280            guid->node[2],
281            guid->node[3],
282            guid->node[4],
283            guid->node[5]);
284
285    return NO_ERROR;
286}
287
288}; // namespace android
289