blob: 8347d022490952c2d5cebd6ae43ae2b5d24e652e [file] [log] [blame]
Eric Laurentcbca9052014-04-18 17:54:10 -07001/*
2 * Copyright (C) 2011 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 "sound_trigger_hw_default"
18/*#define LOG_NDEBUG 0*/
19
20#include <errno.h>
21#include <pthread.h>
22#include <sys/prctl.h>
23#include <cutils/log.h>
24
25#include <hardware/hardware.h>
26#include <system/sound_trigger.h>
27#include <hardware/sound_trigger.h>
28
29static const struct sound_trigger_properties hw_properties = {
30 "The Android Open Source Project", // implementor
31 "Sound Trigger stub HAL", // description
32 1, // version
33 { 0xed7a7d60, 0xc65e, 0x11e3, 0x9be4, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } }, // uuid
34 1, // max_sound_models
35 1, // max_key_phrases
36 1, // max_users
37 RECOGNITION_MODE_VOICE_TRIGGER, // recognition_modes
38 false, // capture_transition
39 0, // max_buffer_ms
40 false, // concurrent_capture
41 0 // power_consumption_mw
42};
43
44struct stub_sound_trigger_device {
45 struct sound_trigger_hw_device device;
46 sound_model_handle_t model_handle;
47 recognition_callback_t recognition_callback;
48 void *recognition_cookie;
49 sound_model_callback_t sound_model_callback;
50 void *sound_model_cookie;
51 pthread_t callback_thread;
52 pthread_mutex_t lock;
53 pthread_cond_t cond;
54
55};
56
57
58static void *callback_thread_loop(void *context)
59{
60 struct stub_sound_trigger_device *stdev = (struct stub_sound_trigger_device *)context;
61 ALOGI("%s", __func__);
62
63 prctl(PR_SET_NAME, (unsigned long)"sound trigger callback", 0, 0, 0);
64
65 pthread_mutex_lock(&stdev->lock);
66 if (stdev->recognition_callback == NULL) {
67 goto exit;
68 }
69 struct timespec ts;
70 clock_gettime(CLOCK_REALTIME, &ts);
71 ts.tv_sec += 3;
72 ALOGI("%s wait 3 sec", __func__);
73 int rc = pthread_cond_timedwait(&stdev->cond, &stdev->lock, &ts);
74 if (rc == ETIMEDOUT && stdev->recognition_callback != NULL) {
75 char *data = (char *)calloc(1, sizeof(struct sound_trigger_phrase_recognition_event) + 1);
76 struct sound_trigger_phrase_recognition_event *event =
77 (struct sound_trigger_phrase_recognition_event *)data;
78 event->common.status = RECOGNITION_STATUS_SUCCESS;
79 event->common.type = SOUND_MODEL_TYPE_KEYPHRASE;
80 event->common.model = stdev->model_handle;
81 event->key_phrase_in_capture = false;
82 event->num_phrases = 1;
83 event->phrase_extras[0].recognition_modes = RECOGNITION_MODE_VOICE_TRIGGER;
84 event->phrase_extras[0].num_users = 1;
85 event->phrase_extras[0].confidence_levels[0] = 100;
86 event->common.data_offset = sizeof(struct sound_trigger_phrase_recognition_event);
87 event->common.data_size = 1;
88 data[event->common.data_offset] = 8;
89 ALOGI("%s send callback model %d", __func__, stdev->model_handle);
90 stdev->recognition_callback(&event->common, stdev->recognition_cookie);
91 free(data);
92 } else {
93 ALOGI("%s abort recognition model %d", __func__, stdev->model_handle);
94 }
95 stdev->recognition_callback = NULL;
96
97exit:
98 pthread_mutex_unlock(&stdev->lock);
99
100 return NULL;
101}
102
103static int stdev_get_properties(const struct sound_trigger_hw_device *dev,
104 struct sound_trigger_properties *properties)
105{
106 struct stub_sound_trigger_device *stdev = (struct stub_sound_trigger_device *)dev;
107
108 ALOGI("%s", __func__);
109 if (properties == NULL)
110 return -EINVAL;
111 memcpy(properties, &hw_properties, sizeof(struct sound_trigger_properties));
112 return 0;
113}
114
115static int stdev_load_sound_model(const struct sound_trigger_hw_device *dev,
116 struct sound_trigger_sound_model *sound_model,
117 sound_model_callback_t callback,
118 void *cookie,
119 sound_model_handle_t *handle)
120{
121 struct stub_sound_trigger_device *stdev = (struct stub_sound_trigger_device *)dev;
122 int status = 0;
123
124 ALOGI("%s stdev %p", __func__, stdev);
125 pthread_mutex_lock(&stdev->lock);
126 if (handle == NULL || sound_model == NULL) {
127 status = -EINVAL;
128 goto exit;
129 }
130 if (sound_model->data_size == 0 ||
131 sound_model->data_offset < sizeof(struct sound_trigger_sound_model)) {
132 status = -EINVAL;
133 goto exit;
134 }
135
136 if (stdev->model_handle == 1) {
137 status = -ENOSYS;
138 goto exit;
139 }
140 char *data = (char *)sound_model + sound_model->data_offset;
141 ALOGI("%s data size %d data %d - %d", __func__,
142 sound_model->data_size, data[0], data[sound_model->data_size - 1]);
143 stdev->model_handle = 1;
144 stdev->sound_model_callback = callback;
145 stdev->sound_model_cookie = cookie;
146
147 *handle = stdev->model_handle;
148
149exit:
150 pthread_mutex_unlock(&stdev->lock);
151 return status;
152}
153
154static int stdev_unload_sound_model(const struct sound_trigger_hw_device *dev,
155 sound_model_handle_t handle)
156{
157 struct stub_sound_trigger_device *stdev = (struct stub_sound_trigger_device *)dev;
158 int status = 0;
159
160 ALOGI("%s handle %d", __func__, handle);
161 pthread_mutex_lock(&stdev->lock);
162 if (handle != 1) {
163 status = -EINVAL;
164 goto exit;
165 }
166 if (stdev->model_handle == 0) {
167 status = -ENOSYS;
168 goto exit;
169 }
170 stdev->model_handle = 0;
171 if (stdev->recognition_callback != NULL) {
172 stdev->recognition_callback = NULL;
173 pthread_cond_signal(&stdev->cond);
174 pthread_mutex_unlock(&stdev->lock);
175 pthread_join(stdev->callback_thread, (void **) NULL);
176 pthread_mutex_lock(&stdev->lock);
177 }
178
179exit:
180 pthread_mutex_unlock(&stdev->lock);
181 return status;
182}
183
184static int stdev_start_recognition(const struct sound_trigger_hw_device *dev,
185 sound_model_handle_t sound_model_handle,
186 audio_io_handle_t capture_handle __unused,
187 audio_devices_t capture_device __unused,
188 recognition_callback_t callback,
189 void *cookie,
190 unsigned int data_size,
191 char *data)
192{
193 struct stub_sound_trigger_device *stdev = (struct stub_sound_trigger_device *)dev;
194 int status = 0;
195 ALOGI("%s sound model %d", __func__, sound_model_handle);
196 pthread_mutex_lock(&stdev->lock);
197 if (stdev->model_handle != sound_model_handle) {
198 status = -ENOSYS;
199 goto exit;
200 }
201 if (stdev->recognition_callback != NULL) {
202 status = -ENOSYS;
203 goto exit;
204 }
205 if (data_size != 0 && data == NULL) {
206 status = -EINVAL;
207 goto exit;
208 }
209 if (data_size != 0) {
210 ALOGI("%s data size %d data %d - %d", __func__,
211 data_size, data[0], data[data_size - 1]);
212 }
213
214 stdev->recognition_callback = callback;
215 stdev->recognition_cookie = cookie;
216 pthread_create(&stdev->callback_thread, (const pthread_attr_t *) NULL,
217 callback_thread_loop, stdev);
218exit:
219 pthread_mutex_unlock(&stdev->lock);
220 return status;
221}
222
223static int stdev_stop_recognition(const struct sound_trigger_hw_device *dev,
224 sound_model_handle_t sound_model_handle)
225{
226 struct stub_sound_trigger_device *stdev = (struct stub_sound_trigger_device *)dev;
227 int status = 0;
228 ALOGI("%s sound model %d", __func__, sound_model_handle);
229 pthread_mutex_lock(&stdev->lock);
230 if (stdev->model_handle != sound_model_handle) {
231 status = -ENOSYS;
232 goto exit;
233 }
234 if (stdev->recognition_callback == NULL) {
235 status = -ENOSYS;
236 goto exit;
237 }
238 stdev->recognition_callback = NULL;
239 pthread_cond_signal(&stdev->cond);
240 pthread_mutex_unlock(&stdev->lock);
241 pthread_join(stdev->callback_thread, (void **) NULL);
242 pthread_mutex_lock(&stdev->lock);
243
244exit:
245 pthread_mutex_unlock(&stdev->lock);
246 return status;
247}
248
249
250static int stdev_close(hw_device_t *device)
251{
252 free(device);
253 return 0;
254}
255
256static int stdev_open(const hw_module_t* module, const char* name,
257 hw_device_t** device)
258{
259 struct stub_sound_trigger_device *stdev;
260 int ret;
261
262 if (strcmp(name, SOUND_TRIGGER_HARDWARE_INTERFACE) != 0)
263 return -EINVAL;
264
265 stdev = calloc(1, sizeof(struct stub_sound_trigger_device));
266 if (!stdev)
267 return -ENOMEM;
268
269 stdev->device.common.tag = HARDWARE_DEVICE_TAG;
270 stdev->device.common.version = SOUND_TRIGGER_DEVICE_API_VERSION_1_0;
271 stdev->device.common.module = (struct hw_module_t *) module;
272 stdev->device.common.close = stdev_close;
273 stdev->device.get_properties = stdev_get_properties;
274 stdev->device.load_sound_model = stdev_load_sound_model;
275 stdev->device.unload_sound_model = stdev_unload_sound_model;
276 stdev->device.start_recognition = stdev_start_recognition;
277 stdev->device.stop_recognition = stdev_stop_recognition;
278
279 pthread_mutex_init(&stdev->lock, (const pthread_mutexattr_t *) NULL);
280 pthread_cond_init(&stdev->cond, (const pthread_condattr_t *) NULL);
281
282 *device = &stdev->device.common;
283
284 return 0;
285}
286
287static struct hw_module_methods_t hal_module_methods = {
288 .open = stdev_open,
289};
290
291struct sound_trigger_module HAL_MODULE_INFO_SYM = {
292 .common = {
293 .tag = HARDWARE_MODULE_TAG,
294 .module_api_version = SOUND_TRIGGER_MODULE_API_VERSION_1_0,
295 .hal_api_version = HARDWARE_HAL_API_VERSION,
296 .id = SOUND_TRIGGER_HARDWARE_MODULE_ID,
297 .name = "Default sound trigger HAL",
298 .author = "The Android Open Source Project",
299 .methods = &hal_module_methods,
300 },
301};