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                         stdev->is_streaming = 1;
310                         ALOGI("%s send callback model %d", __func__,
311                               stdev->model_handle);
312                         stdev->recognition_callback(&event->common,
313                                                     stdev->recognition_cookie);
314                         free(event);
315                         // Start reading data from the DSP while the upper levels do their thing.
316                         if (stdev->config && stdev->config->capture_requested) {
317                             fetch_streaming_buffer(stdev);
318                         }
319                     }
320                     goto found;
321                 }
322                 i += strlen(msg + i) + 1;
323             }
324         } else if (fds[1].revents & POLLIN) {
325             read(fds[1].fd, &n, sizeof(n)); /* clear the socket */
326             ALOGI("%s: Termination message", __func__);
327             break;
328         } else {
329             ALOGI("%s: Message to ignore", __func__);
330         }
331         pthread_mutex_unlock(&stdev->lock);
332     }
333 
334 found:
335     close(fds[0].fd);
336 
337 exit:
338     stdev->recognition_callback = NULL;
339     stdev_close_term_sock(stdev);
340 
341     if (stdev->config && !stdev->config->capture_requested)
342         stdev_dsp_set_power(stdev, 0);
343 
344     pthread_mutex_unlock(&stdev->lock);
345 
346     return (void *)(long)err;
347 }
348 
stdev_get_properties(const struct sound_trigger_hw_device * dev,struct sound_trigger_properties * properties)349 static int stdev_get_properties(const struct sound_trigger_hw_device *dev,
350                                 struct sound_trigger_properties *properties)
351 {
352     struct flounder_sound_trigger_device *stdev =
353                                (struct flounder_sound_trigger_device *)dev;
354 
355     ALOGI("%s", __func__);
356     if (properties == NULL)
357         return -EINVAL;
358     memcpy(properties, &hw_properties, sizeof(struct sound_trigger_properties));
359     return 0;
360 }
361 
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)362 static int stdev_load_sound_model(const struct sound_trigger_hw_device *dev,
363                                   struct sound_trigger_sound_model *sound_model,
364                                   sound_model_callback_t callback,
365                                   void *cookie,
366                                   sound_model_handle_t *handle)
367 {
368     struct flounder_sound_trigger_device *stdev =
369                                  (struct flounder_sound_trigger_device *)dev;
370     int ret = 0;
371 
372     ALOGI("%s", __func__);
373     pthread_mutex_lock(&stdev->lock);
374     if (handle == NULL || sound_model == NULL) {
375         ret = -EINVAL;
376         goto exit;
377     }
378 
379     if (stdev->model_handle == 1) {
380         ret = -ENOSYS;
381         goto exit;
382     }
383 
384     ret = vad_load_sound_model(stdev,
385                                (char *)sound_model + sound_model->data_offset,
386                                sound_model->data_size);
387     if (ret)
388         goto exit;
389 
390     stdev->model_handle = 1;
391     stdev->sound_model_callback = callback;
392     stdev->sound_model_cookie = cookie;
393     *handle = stdev->model_handle;
394 
395 exit:
396     pthread_mutex_unlock(&stdev->lock);
397     return ret;
398 }
399 
stdev_unload_sound_model(const struct sound_trigger_hw_device * dev,sound_model_handle_t handle)400 static int stdev_unload_sound_model(const struct sound_trigger_hw_device *dev,
401                                     sound_model_handle_t handle)
402 {
403     struct flounder_sound_trigger_device *stdev =
404                                    (struct flounder_sound_trigger_device *)dev;
405     int status = 0;
406 
407     ALOGI("%s handle %d", __func__, handle);
408     pthread_mutex_lock(&stdev->lock);
409     if (handle != 1) {
410         status = -EINVAL;
411         goto exit;
412     }
413     if (stdev->model_handle == 0) {
414         status = -ENOSYS;
415         goto exit;
416     }
417     stdev->model_handle = 0;
418     free(stdev->config);
419     stdev->config = NULL;
420     if (stdev->recognition_callback != NULL) {
421         stdev->recognition_callback = NULL;
422         if (stdev->send_sock >=0)
423             write(stdev->send_sock, "T", 1);
424         pthread_mutex_unlock(&stdev->lock);
425 
426         pthread_join(stdev->callback_thread, (void **)NULL);
427 
428         pthread_mutex_lock(&stdev->lock);
429     }
430 
431 exit:
432     stdev_dsp_set_power(stdev, 0);
433 
434     pthread_mutex_unlock(&stdev->lock);
435     return status;
436 }
437 
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)438 static int stdev_start_recognition(const struct sound_trigger_hw_device *dev,
439                                    sound_model_handle_t sound_model_handle,
440                                    const struct sound_trigger_recognition_config *config,
441                                    recognition_callback_t callback,
442                                    void *cookie)
443 {
444     struct flounder_sound_trigger_device *stdev =
445                                   (struct flounder_sound_trigger_device *)dev;
446     int status = 0;
447 
448     ALOGI("%s sound model %d", __func__, sound_model_handle);
449     pthread_mutex_lock(&stdev->lock);
450     if (stdev->model_handle != sound_model_handle) {
451         status = -ENOSYS;
452         goto exit;
453     }
454     if (stdev->recognition_callback != NULL) {
455         status = -ENOSYS;
456         goto exit;
457     }
458 
459     free(stdev->config);
460     stdev->config = NULL;
461     if (config) {
462         stdev->config = malloc(sizeof(*config));
463         if (!stdev->config) {
464             status = -ENOMEM;
465             goto exit;
466         }
467         memcpy(stdev->config, config, sizeof(*config));
468     }
469 
470     stdev_dsp_set_power(stdev, 0);
471 
472     stdev->recognition_callback = callback;
473     stdev->recognition_cookie = cookie;
474     pthread_create(&stdev->callback_thread, (const pthread_attr_t *) NULL,
475                         callback_thread_loop, stdev);
476 exit:
477     pthread_mutex_unlock(&stdev->lock);
478     return status;
479 }
480 
stdev_stop_recognition(const struct sound_trigger_hw_device * dev,sound_model_handle_t sound_model_handle)481 static int stdev_stop_recognition(const struct sound_trigger_hw_device *dev,
482                                   sound_model_handle_t sound_model_handle)
483 {
484     struct flounder_sound_trigger_device *stdev =
485                                  (struct flounder_sound_trigger_device *)dev;
486     int status = 0;
487 
488     ALOGI("%s sound model %d", __func__, sound_model_handle);
489     pthread_mutex_lock(&stdev->lock);
490     if (stdev->model_handle != sound_model_handle) {
491         status = -ENOSYS;
492         goto exit;
493     }
494     if (stdev->recognition_callback == NULL) {
495         status = -ENOSYS;
496         goto exit;
497     }
498     free(stdev->config);
499     stdev->config = NULL;
500     stdev->recognition_callback = NULL;
501     if (stdev->send_sock >=0)
502         write(stdev->send_sock, "T", 1);
503     pthread_mutex_unlock(&stdev->lock);
504 
505     pthread_join(stdev->callback_thread, (void **)NULL);
506 
507     pthread_mutex_lock(&stdev->lock);
508 
509 exit:
510     stdev_dsp_set_power(stdev, 0);
511 
512     pthread_mutex_unlock(&stdev->lock);
513     return status;
514 }
515 
516 __attribute__ ((visibility ("default")))
sound_trigger_open_for_streaming()517 int sound_trigger_open_for_streaming()
518 {
519     struct flounder_sound_trigger_device *stdev = &g_stdev;
520     int ret = 0;
521 
522     pthread_mutex_lock(&stdev->lock);
523 
524     if (!stdev->opened) {
525         ALOGE("%s: stdev has not been opened", __func__);
526         ret = -EFAULT;
527         goto exit;
528     }
529     if (!stdev->is_streaming) {
530         ALOGE("%s: DSP is not currently streaming", __func__);
531         ret = -EBUSY;
532         goto exit;
533     }
534     // TODO: Probably want to get something from whoever called us to bind to it/assert that it's a
535     // valid connection. Perhaps returning a more
536     // meaningful handle would be a good idea as well.
537     ret = 1;
538 exit:
539     pthread_mutex_unlock(&stdev->lock);
540     return ret;
541 }
542 
543 __attribute__ ((visibility ("default")))
sound_trigger_read_samples(int audio_handle,void * buffer,size_t buffer_len)544 size_t sound_trigger_read_samples(int audio_handle, void *buffer, size_t  buffer_len)
545 {
546     struct flounder_sound_trigger_device *stdev = &g_stdev;
547     int i;
548     size_t ret = 0;
549 
550     if (audio_handle <= 0) {
551         ALOGE("%s: invalid audio handle", __func__);
552         return -EINVAL;
553     }
554 
555     pthread_mutex_lock(&stdev->lock);
556 
557     if (!stdev->opened) {
558         ALOGE("%s: stdev has not been opened", __func__);
559         ret = -EFAULT;
560         goto exit;
561     }
562     if (!stdev->is_streaming) {
563         ALOGE("%s: DSP is not currently streaming", __func__);
564         ret = -EINVAL;
565         goto exit;
566     }
567 
568     if (stdev->streaming_buf_read == stdev->streaming_buf_len) {
569         ret = fetch_streaming_buffer(stdev);
570     }
571 
572     if (!ret) {
573         ret = stdev->streaming_buf_len - stdev->streaming_buf_read;
574         if (ret > buffer_len)
575             ret = buffer_len;
576         memcpy(buffer, stdev->streaming_buf + stdev->streaming_buf_read, ret);
577         stdev->streaming_buf_read += ret;
578         ALOGV("%s: Sent %zu bytes to buffer", __func__, ret);
579     }
580 
581 exit:
582     pthread_mutex_unlock(&stdev->lock);
583     return ret;
584 }
585 
586 __attribute__ ((visibility ("default")))
sound_trigger_close_for_streaming(int audio_handle __unused)587 int sound_trigger_close_for_streaming(int audio_handle __unused)
588 {
589     // TODO: Power down the DSP? I think we shouldn't in case we want to open this mic for streaming
590     // for the voice search?
591     return 0;
592 }
593 
stdev_close(hw_device_t * device)594 static int stdev_close(hw_device_t *device)
595 {
596     struct flounder_sound_trigger_device *stdev =
597                                 (struct flounder_sound_trigger_device *)device;
598     int ret = 0;
599 
600     pthread_mutex_lock(&stdev->lock);
601     if (!stdev->opened) {
602         ALOGE("%s: device already closed", __func__);
603         ret = -EFAULT;
604         goto exit;
605     }
606     free(stdev->streaming_buf);
607     stdev_close_mixer(stdev);
608     stdev->model_handle = 0;
609     stdev->send_sock = 0;
610     stdev->term_sock = 0;
611     stdev->opened = false;
612 
613 exit:
614     pthread_mutex_unlock(&stdev->lock);
615     return ret;
616 }
617 
stdev_open(const hw_module_t * module,const char * name,hw_device_t ** device)618 static int stdev_open(const hw_module_t *module, const char *name,
619                       hw_device_t **device)
620 {
621     struct flounder_sound_trigger_device *stdev;
622     int ret;
623 
624     if (strcmp(name, SOUND_TRIGGER_HARDWARE_INTERFACE) != 0)
625         return -EINVAL;
626 
627     stdev = &g_stdev;
628     pthread_mutex_lock(&stdev->lock);
629 
630     if (stdev->opened) {
631         ALOGE("%s: Only one sountrigger can be opened at a time", __func__);
632         ret = -EBUSY;
633         goto exit;
634     }
635 
636     stdev->streaming_buf = malloc(FLOUNDER_STREAMING_BUFFER_SIZE);
637     if (!stdev->streaming_buf) {
638         ret = -ENOMEM;
639         goto exit;
640     }
641 
642     ret = stdev_init_mixer(stdev);
643     if (ret) {
644         ALOGE("Error mixer init");
645         free(stdev->streaming_buf);
646         goto exit;
647     }
648 
649     stdev->device.common.tag = HARDWARE_DEVICE_TAG;
650     stdev->device.common.version = SOUND_TRIGGER_DEVICE_API_VERSION_1_0;
651     stdev->device.common.module = (struct hw_module_t *)module;
652     stdev->device.common.close = stdev_close;
653     stdev->device.get_properties = stdev_get_properties;
654     stdev->device.load_sound_model = stdev_load_sound_model;
655     stdev->device.unload_sound_model = stdev_unload_sound_model;
656     stdev->device.start_recognition = stdev_start_recognition;
657     stdev->device.stop_recognition = stdev_stop_recognition;
658     stdev->send_sock = stdev->term_sock = -1;
659     stdev->streaming_buf_read = 0;
660     stdev->streaming_buf_len = 0;
661     stdev->opened = true;
662 
663     *device = &stdev->device.common; /* same address as stdev */
664 exit:
665     pthread_mutex_unlock(&stdev->lock);
666     return ret;
667 }
668 
669 static struct hw_module_methods_t hal_module_methods = {
670     .open = stdev_open,
671 };
672 
673 struct sound_trigger_module HAL_MODULE_INFO_SYM = {
674     .common = {
675         .tag = HARDWARE_MODULE_TAG,
676         .module_api_version = SOUND_TRIGGER_MODULE_API_VERSION_1_0,
677         .hal_api_version = HARDWARE_HAL_API_VERSION,
678         .id = SOUND_TRIGGER_HARDWARE_MODULE_ID,
679         .name = "Default sound trigger HAL",
680         .author = "The Android Open Source Project",
681         .methods = &hal_module_methods,
682     },
683 };
684