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