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 
33 namespace android {
34 
35 namespace {
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:
DeathNotifier()44         DeathNotifier() {
45         }
46 
binderDied(const wp<IBinder> & who __unused)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 
getSoundTriggerHwService()58 const 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
listModules(const String16 & opPackageName,struct sound_trigger_module_descriptor * modules,uint32_t * numModules)83 status_t SoundTrigger::listModules(const String16& opPackageName,
84                                    struct sound_trigger_module_descriptor *modules,
85                                    uint32_t *numModules)
86 {
87     ALOGV("listModules()");
88     const sp<ISoundTriggerHwService> service = getSoundTriggerHwService();
89     if (service == 0) {
90         return NO_INIT;
91     }
92     return service->listModules(opPackageName, modules, numModules);
93 }
94 
attach(const String16 & opPackageName,const sound_trigger_module_handle_t module,const sp<SoundTriggerCallback> & callback)95 sp<SoundTrigger> SoundTrigger::attach(const String16& opPackageName,
96                                       const sound_trigger_module_handle_t module,
97                                       const sp<SoundTriggerCallback>& callback)
98 {
99     ALOGV("attach()");
100     sp<SoundTrigger> soundTrigger;
101     const sp<ISoundTriggerHwService> service = getSoundTriggerHwService();
102     if (service == 0) {
103         return soundTrigger;
104     }
105     soundTrigger = new SoundTrigger(module, callback);
106     status_t status = service->attach(opPackageName, module, soundTrigger,
107                                       soundTrigger->mISoundTrigger);
108 
109     if (status == NO_ERROR && soundTrigger->mISoundTrigger != 0) {
110         IInterface::asBinder(soundTrigger->mISoundTrigger)->linkToDeath(soundTrigger);
111     } else {
112         ALOGW("Error %d connecting to sound trigger service", status);
113         soundTrigger.clear();
114     }
115     return soundTrigger;
116 }
117 
118 
setCaptureState(bool active)119 status_t SoundTrigger::setCaptureState(bool active)
120 {
121     ALOGV("setCaptureState(%d)", active);
122     const sp<ISoundTriggerHwService> service = getSoundTriggerHwService();
123     if (service == 0) {
124         return NO_INIT;
125     }
126     return service->setCaptureState(active);
127 }
128 
129 // SoundTrigger
SoundTrigger(sound_trigger_module_handle_t,const sp<SoundTriggerCallback> & callback)130 SoundTrigger::SoundTrigger(sound_trigger_module_handle_t /*module*/,
131                                  const sp<SoundTriggerCallback>& callback)
132     : mCallback(callback)
133 {
134 }
135 
~SoundTrigger()136 SoundTrigger::~SoundTrigger()
137 {
138     if (mISoundTrigger != 0) {
139         mISoundTrigger->detach();
140     }
141 }
142 
143 
detach()144 void SoundTrigger::detach() {
145     ALOGV("detach()");
146     Mutex::Autolock _l(mLock);
147     mCallback.clear();
148     if (mISoundTrigger != 0) {
149         mISoundTrigger->detach();
150         IInterface::asBinder(mISoundTrigger)->unlinkToDeath(this);
151         mISoundTrigger = 0;
152     }
153 }
154 
loadSoundModel(const sp<IMemory> & modelMemory,sound_model_handle_t * handle)155 status_t SoundTrigger::loadSoundModel(const sp<IMemory>& modelMemory,
156                                 sound_model_handle_t *handle)
157 {
158     Mutex::Autolock _l(mLock);
159     if (mISoundTrigger == 0) {
160         return NO_INIT;
161     }
162 
163     return mISoundTrigger->loadSoundModel(modelMemory, handle);
164 }
165 
unloadSoundModel(sound_model_handle_t handle)166 status_t SoundTrigger::unloadSoundModel(sound_model_handle_t handle)
167 {
168     Mutex::Autolock _l(mLock);
169     if (mISoundTrigger == 0) {
170         return NO_INIT;
171     }
172     return mISoundTrigger->unloadSoundModel(handle);
173 }
174 
startRecognition(sound_model_handle_t handle,const sp<IMemory> & dataMemory)175 status_t SoundTrigger::startRecognition(sound_model_handle_t handle,
176                                         const sp<IMemory>& dataMemory)
177 {
178     Mutex::Autolock _l(mLock);
179     if (mISoundTrigger == 0) {
180         return NO_INIT;
181     }
182     return mISoundTrigger->startRecognition(handle, dataMemory);
183 }
184 
stopRecognition(sound_model_handle_t handle)185 status_t SoundTrigger::stopRecognition(sound_model_handle_t handle)
186 {
187     Mutex::Autolock _l(mLock);
188     if (mISoundTrigger == 0) {
189         return NO_INIT;
190     }
191     return mISoundTrigger->stopRecognition(handle);
192 }
193 
getModelState(sound_model_handle_t handle)194 status_t SoundTrigger::getModelState(sound_model_handle_t handle)
195 {
196     Mutex::Autolock _l(mLock);
197     if (mISoundTrigger == 0) {
198         return NO_INIT;
199     }
200     return mISoundTrigger->getModelState(handle);
201 }
202 
203 // BpSoundTriggerClient
onRecognitionEvent(const sp<IMemory> & eventMemory)204 void SoundTrigger::onRecognitionEvent(const sp<IMemory>& eventMemory)
205 {
206     Mutex::Autolock _l(mLock);
207     if (eventMemory == 0 || eventMemory->pointer() == NULL) {
208         return;
209     }
210 
211     if (mCallback != 0) {
212         mCallback->onRecognitionEvent(
213                 (struct sound_trigger_recognition_event *)eventMemory->pointer());
214     }
215 }
216 
onSoundModelEvent(const sp<IMemory> & eventMemory)217 void SoundTrigger::onSoundModelEvent(const sp<IMemory>& eventMemory)
218 {
219     Mutex::Autolock _l(mLock);
220     if (eventMemory == 0 || eventMemory->pointer() == NULL) {
221         return;
222     }
223 
224     if (mCallback != 0) {
225         mCallback->onSoundModelEvent(
226                 (struct sound_trigger_model_event *)eventMemory->pointer());
227     }
228 }
229 
onServiceStateChange(const sp<IMemory> & eventMemory)230 void SoundTrigger::onServiceStateChange(const sp<IMemory>& eventMemory)
231 {
232     Mutex::Autolock _l(mLock);
233     if (eventMemory == 0 || eventMemory->pointer() == NULL) {
234         return;
235     }
236 
237     if (mCallback != 0) {
238         mCallback->onServiceStateChange(
239                 *((sound_trigger_service_state_t *)eventMemory->pointer()));
240     }
241 }
242 
243 //IBinder::DeathRecipient
binderDied(const wp<IBinder> & who __unused)244 void SoundTrigger::binderDied(const wp<IBinder>& who __unused) {
245     Mutex::Autolock _l(mLock);
246     ALOGW("SoundTrigger server binder Died ");
247     mISoundTrigger = 0;
248     if (mCallback != 0) {
249         mCallback->onServiceDied();
250     }
251 }
252 
stringToGuid(const char * str,sound_trigger_uuid_t * guid)253 status_t SoundTrigger::stringToGuid(const char *str, sound_trigger_uuid_t *guid)
254 {
255     if (str == NULL || guid == NULL) {
256         return BAD_VALUE;
257     }
258 
259     int tmp[10];
260 
261     if (sscanf(str, "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",
262             tmp, tmp+1, tmp+2, tmp+3, tmp+4, tmp+5, tmp+6, tmp+7, tmp+8, tmp+9) < 10) {
263         return BAD_VALUE;
264     }
265     guid->timeLow = (uint32_t)tmp[0];
266     guid->timeMid = (uint16_t)tmp[1];
267     guid->timeHiAndVersion = (uint16_t)tmp[2];
268     guid->clockSeq = (uint16_t)tmp[3];
269     guid->node[0] = (uint8_t)tmp[4];
270     guid->node[1] = (uint8_t)tmp[5];
271     guid->node[2] = (uint8_t)tmp[6];
272     guid->node[3] = (uint8_t)tmp[7];
273     guid->node[4] = (uint8_t)tmp[8];
274     guid->node[5] = (uint8_t)tmp[9];
275 
276     return NO_ERROR;
277 }
278 
guidToString(const sound_trigger_uuid_t * guid,char * str,size_t maxLen)279 status_t SoundTrigger::guidToString(const sound_trigger_uuid_t *guid, char *str, size_t maxLen)
280 {
281     if (guid == NULL || str == NULL) {
282         return BAD_VALUE;
283     }
284 
285     snprintf(str, maxLen, "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",
286             guid->timeLow,
287             guid->timeMid,
288             guid->timeHiAndVersion,
289             guid->clockSeq,
290             guid->node[0],
291             guid->node[1],
292             guid->node[2],
293             guid->node[3],
294             guid->node[4],
295             guid->node[5]);
296 
297     return NO_ERROR;
298 }
299 
300 }; // namespace android
301