• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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