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