1 /*
2 * Copyright (C) 2014 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_flounder"
18 /*#define LOG_NDEBUG 0*/
19
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <poll.h>
23 #include <pthread.h>
24 #include <sys/ioctl.h>
25 #include <sys/prctl.h>
26 #include <cutils/log.h>
27 #include <cutils/uevent.h>
28
29 #include <hardware/hardware.h>
30 #include <system/sound_trigger.h>
31 #include <hardware/sound_trigger.h>
32 #include <tinyalsa/asoundlib.h>
33
34 #define FLOUNDER_MIXER_VAD 0
35 #define FLOUNDER_CTRL_DSP "VAD Mode"
36 #define UEVENT_MSG_LEN 1024
37
38 #define FLOUNDER_VAD_DEV "/dev/snd/hwC0D0"
39
40 #define FLOUNDER_STREAMING_DELAY_USEC 1000
41 #define FLOUNDER_STREAMING_READ_RETRY_ATTEMPTS 30
42 #define FLOUNDER_STREAMING_BUFFER_SIZE (16 * 1024)
43
44 static const struct sound_trigger_properties hw_properties = {
45 "The Android Open Source Project", // implementor
46 "Volantis OK Google ", // description
47 1, // version
48 { 0xe780f240, 0xf034, 0x11e3, 0xb79a, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } }, // uuid
49 1, // max_sound_models
50 1, // max_key_phrases
51 1, // max_users
52 RECOGNITION_MODE_VOICE_TRIGGER, // recognition_modes
53 true, // capture_transition
54 0, // max_capture_ms
55 false, // concurrent_capture
56 false, // trigger_in_event
57 0 // power_consumption_mw
58 };
59
60 struct flounder_sound_trigger_device {
61 struct sound_trigger_hw_device device;
62 sound_model_handle_t model_handle;
63 recognition_callback_t recognition_callback;
64 void *recognition_cookie;
65 sound_model_callback_t sound_model_callback;
66 void *sound_model_cookie;
67 pthread_t callback_thread;
68 pthread_mutex_t lock;
69 int send_sock;
70 int term_sock;
71 int vad_fd;
72 struct mixer *mixer;
73 struct mixer_ctl *ctl_dsp;
74 struct sound_trigger_recognition_config *config;
75 int is_streaming;
76 int opened;
77 char *streaming_buf;
78 size_t streaming_buf_read;
79 size_t streaming_buf_len;
80 };
81
82 struct rt_codec_cmd {
83 size_t number;
84 int *buf;
85 };
86
87 enum {
88 RT_READ_CODEC_DSP_IOCTL = _IOR('R', 0x04, struct rt_codec_cmd),
89 RT_WRITE_CODEC_DSP_IOCTL = _IOW('R', 0x04, struct rt_codec_cmd),
90 };
91
92 // Since there's only ever one sound_trigger_device, keep it as a global so that other people can
93 // dlopen this lib to get at the streaming audio.
94 static struct flounder_sound_trigger_device g_stdev = { .lock = PTHREAD_MUTEX_INITIALIZER };
95
stdev_dsp_set_power(struct flounder_sound_trigger_device * stdev,int val)96 static void stdev_dsp_set_power(struct flounder_sound_trigger_device *stdev,
97 int val)
98 {
99 stdev->is_streaming = 0;
100 stdev->streaming_buf_read = 0;
101 stdev->streaming_buf_len = 0;
102 mixer_ctl_set_value(stdev->ctl_dsp, 0, val);
103 }
104
stdev_init_mixer(struct flounder_sound_trigger_device * stdev)105 static int stdev_init_mixer(struct flounder_sound_trigger_device *stdev)
106 {
107 int ret = -1;
108
109 stdev->vad_fd = open(FLOUNDER_VAD_DEV, O_RDWR);
110 if (stdev->vad_fd < 0) {
111 ALOGE("Error opening vad device");
112 return ret;
113 }
114
115 stdev->mixer = mixer_open(FLOUNDER_MIXER_VAD);
116 if (!stdev->mixer)
117 goto err;
118
119 stdev->ctl_dsp = mixer_get_ctl_by_name(stdev->mixer, FLOUNDER_CTRL_DSP);
120 if (!stdev->ctl_dsp)
121 goto err;
122
123 stdev_dsp_set_power(stdev, 0); // Disable DSP at the beginning
124
125 return 0;
126
127 err:
128 close(stdev->vad_fd);
129 if (stdev->mixer)
130 mixer_close(stdev->mixer);
131 return ret;
132 }
133
stdev_close_term_sock(struct flounder_sound_trigger_device * stdev)134 static void stdev_close_term_sock(struct flounder_sound_trigger_device *stdev)
135 {
136 if (stdev->send_sock >=0) {
137 close(stdev->send_sock);
138 stdev->send_sock = -1;
139 }
140 if (stdev->term_sock >=0) {
141 close(stdev->term_sock);
142 stdev->term_sock = -1;
143 }
144 }
145
stdev_close_mixer(struct flounder_sound_trigger_device * stdev)146 static void stdev_close_mixer(struct flounder_sound_trigger_device *stdev)
147 {
148 if (stdev) {
149 stdev_dsp_set_power(stdev, 0);
150 mixer_close(stdev->mixer);
151 stdev_close_term_sock(stdev);
152 close(stdev->vad_fd);
153 }
154 }
155
vad_load_sound_model(struct flounder_sound_trigger_device * stdev,char * buf,size_t len)156 static int vad_load_sound_model(struct flounder_sound_trigger_device *stdev,
157 char *buf, size_t len)
158 {
159 struct rt_codec_cmd cmd;
160 int ret = 0;
161
162 if (!buf || (len == 0))
163 return ret;
164
165 cmd.number = len / sizeof(int);
166 cmd.buf = (int *)buf;
167
168 ret = ioctl(stdev->vad_fd, RT_WRITE_CODEC_DSP_IOCTL, &cmd);
169 if (ret)
170 ALOGE("Error VAD write ioctl");
171 return ret;
172 }
173
sound_trigger_event_alloc(struct flounder_sound_trigger_device * stdev)174 static char *sound_trigger_event_alloc(struct flounder_sound_trigger_device *
175 stdev)
176 {
177 char *data;
178 struct sound_trigger_phrase_recognition_event *event;
179
180 data = (char *)calloc(1,
181 sizeof(struct sound_trigger_phrase_recognition_event));
182 if (!data)
183 return NULL;
184
185 event = (struct sound_trigger_phrase_recognition_event *)data;
186 event->common.status = RECOGNITION_STATUS_SUCCESS;
187 event->common.type = SOUND_MODEL_TYPE_KEYPHRASE;
188 event->common.model = stdev->model_handle;
189
190 if (stdev->config) {
191 unsigned int i;
192
193 event->num_phrases = stdev->config->num_phrases;
194 if (event->num_phrases > SOUND_TRIGGER_MAX_PHRASES)
195 event->num_phrases = SOUND_TRIGGER_MAX_PHRASES;
196 for (i=0; i < event->num_phrases; i++)
197 memcpy(&event->phrase_extras[i], &stdev->config->phrases[i],
198 sizeof(struct sound_trigger_phrase_recognition_extra));
199 }
200
201 event->num_phrases = 1;
202 event->phrase_extras[0].confidence_level = 100;
203 event->phrase_extras[0].num_levels = 1;
204 event->phrase_extras[0].levels[0].level = 100;
205 event->phrase_extras[0].levels[0].user_id = 0;
206 // Signify that all the data is comming through streaming, not through the
207 // buffer.
208 event->common.capture_available = true;
209
210 event->common.audio_config = AUDIO_CONFIG_INITIALIZER;
211 event->common.audio_config.sample_rate = 16000;
212 event->common.audio_config.channel_mask = AUDIO_CHANNEL_IN_MONO;
213 event->common.audio_config.format = AUDIO_FORMAT_PCM_16_BIT;
214
215 return data;
216 }
217
218 // The stdev should be locked when you call this function.
fetch_streaming_buffer(struct flounder_sound_trigger_device * stdev)219 static int fetch_streaming_buffer(struct flounder_sound_trigger_device * stdev)
220 {
221 struct rt_codec_cmd cmd;
222 int ret = 0;
223 int i;
224
225 cmd.number = FLOUNDER_STREAMING_BUFFER_SIZE / sizeof(int);
226 cmd.buf = (int*) stdev->streaming_buf;
227
228 ALOGV("%s: Fetching bytes", __func__);
229 for (i = 0; i < FLOUNDER_STREAMING_READ_RETRY_ATTEMPTS; i++) {
230 ret = ioctl(stdev->vad_fd, RT_READ_CODEC_DSP_IOCTL, &cmd);
231 if (ret == 0) {
232 usleep(FLOUNDER_STREAMING_DELAY_USEC);
233 } else if (ret < 0) {
234 ALOGV("%s: IOCTL failed with code %d", __func__, ret);
235 return ret;
236 } else {
237 // The IOCTL returns the number of int16 samples that were read, so we need to multipy
238 // it by 2 .
239 ALOGV("%s: IOCTL captured %d samples", __func__, ret);
240 stdev->streaming_buf_read = 0;
241 stdev->streaming_buf_len = ret << 1;
242 return 0;
243 }
244 }
245 ALOGV("%s: Timeout waiting for data from dsp", __func__);
246 return 0;
247 }
248
callback_thread_loop(void * context)249 static void *callback_thread_loop(void *context)
250 {
251 char msg[UEVENT_MSG_LEN];
252 struct flounder_sound_trigger_device *stdev =
253 (struct flounder_sound_trigger_device *)context;
254 struct pollfd fds[2];
255 int exit_sockets[2];
256 int err = 0;
257 int i, n;
258
259 ALOGI("%s", __func__);
260 prctl(PR_SET_NAME, (unsigned long)"sound trigger callback", 0, 0, 0);
261
262 pthread_mutex_lock(&stdev->lock);
263 if (stdev->recognition_callback == NULL)
264 goto exit;
265
266 if (socketpair(AF_UNIX, SOCK_STREAM, 0, exit_sockets) == -1)
267 goto exit;
268
269 stdev_close_term_sock(stdev);
270 stdev->send_sock = exit_sockets[0];
271 stdev->term_sock = exit_sockets[1];
272
273 memset(fds, 0, 2 * sizeof(struct pollfd));
274 fds[0].events = POLLIN;
275 fds[0].fd = uevent_open_socket(64*1024, true);
276 if (fds[0].fd == -1) {
277 ALOGE("Error opening socket for hotplug uevent");
278 goto exit;
279 }
280 fds[1].events = POLLIN;
281 fds[1].fd = stdev->term_sock;
282
283 stdev_dsp_set_power(stdev, 1);
284
285 pthread_mutex_unlock(&stdev->lock);
286
287 while (1) {
288 err = poll(fds, 2, -1);
289 pthread_mutex_lock(&stdev->lock);
290 if ((err < 0) || (stdev->recognition_callback == NULL)) {
291 ALOGE("Error in hotplug CPU poll: %d", errno);
292 break;
293 }
294
295 if (fds[0].revents & POLLIN) {
296 n = uevent_kernel_multicast_recv(fds[0].fd, msg, UEVENT_MSG_LEN);
297 if (n <= 0) {
298 pthread_mutex_unlock(&stdev->lock);
299 continue;
300 }
301 for (i=0; i < n;) {
302 if (strstr(msg + i, "HOTWORD")) {
303 struct sound_trigger_phrase_recognition_event *event;
304
305 event = (struct sound_trigger_phrase_recognition_event *)
306 sound_trigger_event_alloc(stdev);
307 if (event) {
308 stdev->is_streaming = 1;
309 ALOGI("%s send callback model %d", __func__,
310 stdev->model_handle);
311 stdev->recognition_callback(&event->common,
312 stdev->recognition_cookie);
313 free(event);
314 // Start reading data from the DSP while the upper levels do their thing.
315 if (stdev->config && stdev->config->capture_requested) {
316 fetch_streaming_buffer(stdev);
317 }
318 }
319 goto found;
320 }
321 i += strlen(msg + i) + 1;
322 }
323 } else if (fds[1].revents & POLLIN) {
324 read(fds[1].fd, &n, sizeof(n)); /* clear the socket */
325 ALOGI("%s: Termination message", __func__);
326 break;
327 } else {
328 ALOGI("%s: Message to ignore", __func__);
329 }
330 pthread_mutex_unlock(&stdev->lock);
331 }
332
333 found:
334 close(fds[0].fd);
335
336 exit:
337 stdev->recognition_callback = NULL;
338 stdev_close_term_sock(stdev);
339
340 if (stdev->config && !stdev->config->capture_requested)
341 stdev_dsp_set_power(stdev, 0);
342
343 pthread_mutex_unlock(&stdev->lock);
344
345 return (void *)(long)err;
346 }
347
stdev_get_properties(const struct sound_trigger_hw_device * dev,struct sound_trigger_properties * properties)348 static int stdev_get_properties(const struct sound_trigger_hw_device *dev,
349 struct sound_trigger_properties *properties)
350 {
351 struct flounder_sound_trigger_device *stdev =
352 (struct flounder_sound_trigger_device *)dev;
353
354 ALOGI("%s", __func__);
355 if (properties == NULL)
356 return -EINVAL;
357 memcpy(properties, &hw_properties, sizeof(struct sound_trigger_properties));
358 return 0;
359 }
360
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)361 static int stdev_load_sound_model(const struct sound_trigger_hw_device *dev,
362 struct sound_trigger_sound_model *sound_model,
363 sound_model_callback_t callback,
364 void *cookie,
365 sound_model_handle_t *handle)
366 {
367 struct flounder_sound_trigger_device *stdev =
368 (struct flounder_sound_trigger_device *)dev;
369 int ret = 0;
370
371 ALOGI("%s", __func__);
372 pthread_mutex_lock(&stdev->lock);
373 if (handle == NULL || sound_model == NULL) {
374 ret = -EINVAL;
375 goto exit;
376 }
377
378 if (stdev->model_handle == 1) {
379 ret = -ENOSYS;
380 goto exit;
381 }
382
383 ret = vad_load_sound_model(stdev,
384 (char *)sound_model + sound_model->data_offset,
385 sound_model->data_size);
386 stdev->model_handle = 1;
387 stdev->sound_model_callback = callback;
388 stdev->sound_model_cookie = cookie;
389 *handle = stdev->model_handle;
390
391 exit:
392 pthread_mutex_unlock(&stdev->lock);
393 return ret;
394 }
395
stdev_unload_sound_model(const struct sound_trigger_hw_device * dev,sound_model_handle_t handle)396 static int stdev_unload_sound_model(const struct sound_trigger_hw_device *dev,
397 sound_model_handle_t handle)
398 {
399 struct flounder_sound_trigger_device *stdev =
400 (struct flounder_sound_trigger_device *)dev;
401 int status = 0;
402
403 ALOGI("%s handle %d", __func__, handle);
404 pthread_mutex_lock(&stdev->lock);
405 if (handle != 1) {
406 status = -EINVAL;
407 goto exit;
408 }
409 if (stdev->model_handle == 0) {
410 status = -ENOSYS;
411 goto exit;
412 }
413 stdev->model_handle = 0;
414 free(stdev->config);
415 stdev->config = NULL;
416 if (stdev->recognition_callback != NULL) {
417 stdev->recognition_callback = NULL;
418 if (stdev->send_sock >=0)
419 write(stdev->send_sock, "T", 1);
420 pthread_mutex_unlock(&stdev->lock);
421
422 pthread_join(stdev->callback_thread, (void **)NULL);
423
424 pthread_mutex_lock(&stdev->lock);
425 }
426
427 exit:
428 stdev_dsp_set_power(stdev, 0);
429
430 pthread_mutex_unlock(&stdev->lock);
431 return status;
432 }
433
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)434 static int stdev_start_recognition(const struct sound_trigger_hw_device *dev,
435 sound_model_handle_t sound_model_handle,
436 const struct sound_trigger_recognition_config *config,
437 recognition_callback_t callback,
438 void *cookie)
439 {
440 struct flounder_sound_trigger_device *stdev =
441 (struct flounder_sound_trigger_device *)dev;
442 int status = 0;
443
444 ALOGI("%s sound model %d", __func__, sound_model_handle);
445 pthread_mutex_lock(&stdev->lock);
446 if (stdev->model_handle != sound_model_handle) {
447 status = -ENOSYS;
448 goto exit;
449 }
450 if (stdev->recognition_callback != NULL) {
451 status = -ENOSYS;
452 goto exit;
453 }
454
455 free(stdev->config);
456 stdev->config = NULL;
457 if (config) {
458 stdev->config = malloc(sizeof(*config));
459 if (!stdev->config) {
460 status = -ENOMEM;
461 goto exit;
462 }
463 memcpy(stdev->config, config, sizeof(*config));
464 }
465
466 stdev_dsp_set_power(stdev, 0);
467
468 stdev->recognition_callback = callback;
469 stdev->recognition_cookie = cookie;
470 pthread_create(&stdev->callback_thread, (const pthread_attr_t *) NULL,
471 callback_thread_loop, stdev);
472 exit:
473 pthread_mutex_unlock(&stdev->lock);
474 return status;
475 }
476
stdev_stop_recognition(const struct sound_trigger_hw_device * dev,sound_model_handle_t sound_model_handle)477 static int stdev_stop_recognition(const struct sound_trigger_hw_device *dev,
478 sound_model_handle_t sound_model_handle)
479 {
480 struct flounder_sound_trigger_device *stdev =
481 (struct flounder_sound_trigger_device *)dev;
482 int status = 0;
483
484 ALOGI("%s sound model %d", __func__, sound_model_handle);
485 pthread_mutex_lock(&stdev->lock);
486 if (stdev->model_handle != sound_model_handle) {
487 status = -ENOSYS;
488 goto exit;
489 }
490 if (stdev->recognition_callback == NULL) {
491 status = -ENOSYS;
492 goto exit;
493 }
494 free(stdev->config);
495 stdev->config = NULL;
496 stdev->recognition_callback = NULL;
497 if (stdev->send_sock >=0)
498 write(stdev->send_sock, "T", 1);
499 pthread_mutex_unlock(&stdev->lock);
500
501 pthread_join(stdev->callback_thread, (void **)NULL);
502
503 pthread_mutex_lock(&stdev->lock);
504
505 exit:
506 stdev_dsp_set_power(stdev, 0);
507
508 pthread_mutex_unlock(&stdev->lock);
509 return status;
510 }
511
512 __attribute__ ((visibility ("default")))
sound_trigger_open_for_streaming()513 int sound_trigger_open_for_streaming()
514 {
515 struct flounder_sound_trigger_device *stdev = &g_stdev;
516 int ret = 0;
517
518 pthread_mutex_lock(&stdev->lock);
519
520 if (!stdev->opened) {
521 ALOGE("%s: stdev has not been opened", __func__);
522 ret = -EFAULT;
523 goto exit;
524 }
525 if (!stdev->is_streaming) {
526 ALOGE("%s: DSP is not currently streaming", __func__);
527 ret = -EBUSY;
528 goto exit;
529 }
530 // TODO: Probably want to get something from whoever called us to bind to it/assert that it's a
531 // valid connection. Perhaps returning a more
532 // meaningful handle would be a good idea as well.
533 ret = 1;
534 exit:
535 pthread_mutex_unlock(&stdev->lock);
536 return ret;
537 }
538
539 __attribute__ ((visibility ("default")))
sound_trigger_read_samples(int audio_handle,void * buffer,size_t buffer_len)540 size_t sound_trigger_read_samples(int audio_handle, void *buffer, size_t buffer_len)
541 {
542 struct flounder_sound_trigger_device *stdev = &g_stdev;
543 int i;
544 size_t ret = 0;
545
546 if (audio_handle <= 0) {
547 ALOGE("%s: invalid audio handle", __func__);
548 return -EINVAL;
549 }
550
551 pthread_mutex_lock(&stdev->lock);
552
553 if (!stdev->opened) {
554 ALOGE("%s: stdev has not been opened", __func__);
555 ret = -EFAULT;
556 goto exit;
557 }
558 if (!stdev->is_streaming) {
559 ALOGE("%s: DSP is not currently streaming", __func__);
560 ret = -EINVAL;
561 goto exit;
562 }
563
564 if (stdev->streaming_buf_read == stdev->streaming_buf_len) {
565 ret = fetch_streaming_buffer(stdev);
566 }
567
568 if (!ret) {
569 ret = stdev->streaming_buf_len - stdev->streaming_buf_read;
570 if (ret > buffer_len)
571 ret = buffer_len;
572 memcpy(buffer, stdev->streaming_buf + stdev->streaming_buf_read, ret);
573 stdev->streaming_buf_read += ret;
574 ALOGV("%s: Sent %zu bytes to buffer", __func__, ret);
575 }
576
577 exit:
578 pthread_mutex_unlock(&stdev->lock);
579 return ret;
580 }
581
582 __attribute__ ((visibility ("default")))
sound_trigger_close_for_streaming(int audio_handle __unused)583 int sound_trigger_close_for_streaming(int audio_handle __unused)
584 {
585 // TODO: Power down the DSP? I think we shouldn't in case we want to open this mic for streaming
586 // for the voice search?
587 return 0;
588 }
589
stdev_close(hw_device_t * device)590 static int stdev_close(hw_device_t *device)
591 {
592 struct flounder_sound_trigger_device *stdev =
593 (struct flounder_sound_trigger_device *)device;
594 int ret = 0;
595
596 pthread_mutex_lock(&stdev->lock);
597 if (!stdev->opened) {
598 ALOGE("%s: device already closed", __func__);
599 ret = -EFAULT;
600 goto exit;
601 }
602 free(stdev->streaming_buf);
603 stdev_close_mixer(stdev);
604 stdev->model_handle = 0;
605 stdev->send_sock = 0;
606 stdev->term_sock = 0;
607 stdev->opened = false;
608
609 exit:
610 pthread_mutex_unlock(&stdev->lock);
611 return ret;
612 }
613
stdev_open(const hw_module_t * module,const char * name,hw_device_t ** device)614 static int stdev_open(const hw_module_t *module, const char *name,
615 hw_device_t **device)
616 {
617 struct flounder_sound_trigger_device *stdev;
618 int ret;
619
620 if (strcmp(name, SOUND_TRIGGER_HARDWARE_INTERFACE) != 0)
621 return -EINVAL;
622
623 stdev = &g_stdev;
624 pthread_mutex_lock(&stdev->lock);
625
626 if (stdev->opened) {
627 ALOGE("%s: Only one sountrigger can be opened at a time", __func__);
628 ret = -EBUSY;
629 goto exit;
630 }
631
632 stdev->streaming_buf = malloc(FLOUNDER_STREAMING_BUFFER_SIZE);
633 if (!stdev->streaming_buf) {
634 ret = -ENOMEM;
635 goto exit;
636 }
637
638 ret = stdev_init_mixer(stdev);
639 if (ret) {
640 ALOGE("Error mixer init");
641 free(stdev->streaming_buf);
642 goto exit;
643 }
644
645 stdev->device.common.tag = HARDWARE_DEVICE_TAG;
646 stdev->device.common.version = SOUND_TRIGGER_DEVICE_API_VERSION_1_0;
647 stdev->device.common.module = (struct hw_module_t *)module;
648 stdev->device.common.close = stdev_close;
649 stdev->device.get_properties = stdev_get_properties;
650 stdev->device.load_sound_model = stdev_load_sound_model;
651 stdev->device.unload_sound_model = stdev_unload_sound_model;
652 stdev->device.start_recognition = stdev_start_recognition;
653 stdev->device.stop_recognition = stdev_stop_recognition;
654 stdev->send_sock = stdev->term_sock = -1;
655 stdev->streaming_buf_read = 0;
656 stdev->streaming_buf_len = 0;
657 stdev->opened = true;
658
659 *device = &stdev->device.common; /* same address as stdev */
660 exit:
661 pthread_mutex_unlock(&stdev->lock);
662 return ret;
663 }
664
665 static struct hw_module_methods_t hal_module_methods = {
666 .open = stdev_open,
667 };
668
669 struct sound_trigger_module HAL_MODULE_INFO_SYM = {
670 .common = {
671 .tag = HARDWARE_MODULE_TAG,
672 .module_api_version = SOUND_TRIGGER_MODULE_API_VERSION_1_0,
673 .hal_api_version = HARDWARE_HAL_API_VERSION,
674 .id = SOUND_TRIGGER_HARDWARE_MODULE_ID,
675 .name = "Default sound trigger HAL",
676 .author = "The Android Open Source Project",
677 .methods = &hal_module_methods,
678 },
679 };
680