• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
29 static 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         false, // trigger_in_event
42         0 // power_consumption_mw
43 };
44 
45 struct stub_sound_trigger_device {
46     struct sound_trigger_hw_device device;
47     sound_model_handle_t model_handle;
48     recognition_callback_t recognition_callback;
49     void *recognition_cookie;
50     sound_model_callback_t sound_model_callback;
51     void *sound_model_cookie;
52     pthread_t callback_thread;
53     pthread_mutex_t lock;
54     pthread_cond_t  cond;
55 };
56 
57 
callback_thread_loop(void * context)58 static 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->num_phrases = 1;
82         event->phrase_extras[0].recognition_modes = RECOGNITION_MODE_VOICE_TRIGGER;
83         event->phrase_extras[0].confidence_level = 100;
84         event->phrase_extras[0].num_levels = 1;
85         event->phrase_extras[0].levels[0].level = 100;
86         event->phrase_extras[0].levels[0].user_id = 0;
87         event->common.data_offset = sizeof(struct sound_trigger_phrase_recognition_event);
88         event->common.data_size = 1;
89         data[event->common.data_offset] = 8;
90         ALOGI("%s send callback model %d", __func__, stdev->model_handle);
91         stdev->recognition_callback(&event->common, stdev->recognition_cookie);
92         free(data);
93     } else {
94         ALOGI("%s abort recognition model %d", __func__, stdev->model_handle);
95     }
96     stdev->recognition_callback = NULL;
97 
98 exit:
99     pthread_mutex_unlock(&stdev->lock);
100 
101     return NULL;
102 }
103 
stdev_get_properties(const struct sound_trigger_hw_device * dev,struct sound_trigger_properties * properties)104 static int stdev_get_properties(const struct sound_trigger_hw_device *dev,
105                                 struct sound_trigger_properties *properties)
106 {
107     struct stub_sound_trigger_device *stdev = (struct stub_sound_trigger_device *)dev;
108 
109     ALOGI("%s", __func__);
110     if (properties == NULL)
111         return -EINVAL;
112     memcpy(properties, &hw_properties, sizeof(struct sound_trigger_properties));
113     return 0;
114 }
115 
stdev_load_sound_model(const struct sound_trigger_hw_device * dev,struct sound_trigger_sound_model * sound_model,sound_model_callback_t callback,void * cookie,sound_model_handle_t * handle)116 static int stdev_load_sound_model(const struct sound_trigger_hw_device *dev,
117                                   struct sound_trigger_sound_model *sound_model,
118                                   sound_model_callback_t callback,
119                                   void *cookie,
120                                   sound_model_handle_t *handle)
121 {
122     struct stub_sound_trigger_device *stdev = (struct stub_sound_trigger_device *)dev;
123     int status = 0;
124 
125     ALOGI("%s stdev %p", __func__, stdev);
126     pthread_mutex_lock(&stdev->lock);
127     if (handle == NULL || sound_model == NULL) {
128         status = -EINVAL;
129         goto exit;
130     }
131     if (sound_model->data_size == 0 ||
132             sound_model->data_offset < sizeof(struct sound_trigger_sound_model)) {
133         status = -EINVAL;
134         goto exit;
135     }
136 
137     if (stdev->model_handle == 1) {
138         status = -ENOSYS;
139         goto exit;
140     }
141     char *data = (char *)sound_model + sound_model->data_offset;
142     ALOGI("%s data size %d data %d - %d", __func__,
143           sound_model->data_size, data[0], data[sound_model->data_size - 1]);
144     stdev->model_handle = 1;
145     stdev->sound_model_callback = callback;
146     stdev->sound_model_cookie = cookie;
147 
148     *handle = stdev->model_handle;
149 
150 exit:
151     pthread_mutex_unlock(&stdev->lock);
152     return status;
153 }
154 
stdev_unload_sound_model(const struct sound_trigger_hw_device * dev,sound_model_handle_t handle)155 static int stdev_unload_sound_model(const struct sound_trigger_hw_device *dev,
156                                     sound_model_handle_t handle)
157 {
158     struct stub_sound_trigger_device *stdev = (struct stub_sound_trigger_device *)dev;
159     int status = 0;
160 
161     ALOGI("%s handle %d", __func__, handle);
162     pthread_mutex_lock(&stdev->lock);
163     if (handle != 1) {
164         status = -EINVAL;
165         goto exit;
166     }
167     if (stdev->model_handle == 0) {
168         status = -ENOSYS;
169         goto exit;
170     }
171     stdev->model_handle = 0;
172     if (stdev->recognition_callback != NULL) {
173         stdev->recognition_callback = NULL;
174         pthread_cond_signal(&stdev->cond);
175         pthread_mutex_unlock(&stdev->lock);
176         pthread_join(stdev->callback_thread, (void **) NULL);
177         pthread_mutex_lock(&stdev->lock);
178     }
179 
180 exit:
181     pthread_mutex_unlock(&stdev->lock);
182     return status;
183 }
184 
stdev_start_recognition(const struct sound_trigger_hw_device * dev,sound_model_handle_t sound_model_handle,const struct sound_trigger_recognition_config * config,recognition_callback_t callback,void * cookie)185 static int stdev_start_recognition(const struct sound_trigger_hw_device *dev,
186                                    sound_model_handle_t sound_model_handle,
187                                    const struct sound_trigger_recognition_config *config,
188                                    recognition_callback_t callback,
189                                    void *cookie)
190 {
191     struct stub_sound_trigger_device *stdev = (struct stub_sound_trigger_device *)dev;
192     int status = 0;
193     ALOGI("%s sound model %d", __func__, sound_model_handle);
194     pthread_mutex_lock(&stdev->lock);
195     if (stdev->model_handle != sound_model_handle) {
196         status = -ENOSYS;
197         goto exit;
198     }
199     if (stdev->recognition_callback != NULL) {
200         status = -ENOSYS;
201         goto exit;
202     }
203     if (config->data_size != 0) {
204         char *data = (char *)config + config->data_offset;
205         ALOGI("%s data size %d data %d - %d", __func__,
206               config->data_size, data[0], data[config->data_size - 1]);
207     }
208 
209     stdev->recognition_callback = callback;
210     stdev->recognition_cookie = cookie;
211     pthread_create(&stdev->callback_thread, (const pthread_attr_t *) NULL,
212                         callback_thread_loop, stdev);
213 exit:
214     pthread_mutex_unlock(&stdev->lock);
215     return status;
216 }
217 
stdev_stop_recognition(const struct sound_trigger_hw_device * dev,sound_model_handle_t sound_model_handle)218 static int stdev_stop_recognition(const struct sound_trigger_hw_device *dev,
219                                  sound_model_handle_t sound_model_handle)
220 {
221     struct stub_sound_trigger_device *stdev = (struct stub_sound_trigger_device *)dev;
222     int status = 0;
223     ALOGI("%s sound model %d", __func__, sound_model_handle);
224     pthread_mutex_lock(&stdev->lock);
225     if (stdev->model_handle != sound_model_handle) {
226         status = -ENOSYS;
227         goto exit;
228     }
229     if (stdev->recognition_callback == NULL) {
230         status = -ENOSYS;
231         goto exit;
232     }
233     stdev->recognition_callback = NULL;
234     pthread_cond_signal(&stdev->cond);
235     pthread_mutex_unlock(&stdev->lock);
236     pthread_join(stdev->callback_thread, (void **) NULL);
237     pthread_mutex_lock(&stdev->lock);
238 
239 exit:
240     pthread_mutex_unlock(&stdev->lock);
241     return status;
242 }
243 
244 
stdev_close(hw_device_t * device)245 static int stdev_close(hw_device_t *device)
246 {
247     free(device);
248     return 0;
249 }
250 
stdev_open(const hw_module_t * module,const char * name,hw_device_t ** device)251 static int stdev_open(const hw_module_t* module, const char* name,
252                      hw_device_t** device)
253 {
254     struct stub_sound_trigger_device *stdev;
255     int ret;
256 
257     if (strcmp(name, SOUND_TRIGGER_HARDWARE_INTERFACE) != 0)
258         return -EINVAL;
259 
260     stdev = calloc(1, sizeof(struct stub_sound_trigger_device));
261     if (!stdev)
262         return -ENOMEM;
263 
264     stdev->device.common.tag = HARDWARE_DEVICE_TAG;
265     stdev->device.common.version = SOUND_TRIGGER_DEVICE_API_VERSION_1_0;
266     stdev->device.common.module = (struct hw_module_t *) module;
267     stdev->device.common.close = stdev_close;
268     stdev->device.get_properties = stdev_get_properties;
269     stdev->device.load_sound_model = stdev_load_sound_model;
270     stdev->device.unload_sound_model = stdev_unload_sound_model;
271     stdev->device.start_recognition = stdev_start_recognition;
272     stdev->device.stop_recognition = stdev_stop_recognition;
273 
274     pthread_mutex_init(&stdev->lock, (const pthread_mutexattr_t *) NULL);
275     pthread_cond_init(&stdev->cond, (const pthread_condattr_t *) NULL);
276 
277     *device = &stdev->device.common;
278 
279     return 0;
280 }
281 
282 static struct hw_module_methods_t hal_module_methods = {
283     .open = stdev_open,
284 };
285 
286 struct sound_trigger_module HAL_MODULE_INFO_SYM = {
287     .common = {
288         .tag = HARDWARE_MODULE_TAG,
289         .module_api_version = SOUND_TRIGGER_MODULE_API_VERSION_1_0,
290         .hal_api_version = HARDWARE_HAL_API_VERSION,
291         .id = SOUND_TRIGGER_HARDWARE_MODULE_ID,
292         .name = "Default sound trigger HAL",
293         .author = "The Android Open Source Project",
294         .methods = &hal_module_methods,
295     },
296 };
297