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