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 memset(&config, 0, sizeof(config));
232 config.channels = 1;
233 config.rate = 16000;
234 config.period_size = 240;
235 config.period_count = 8;
236 config.format = PCM_FORMAT_S16_LE;
237 config.start_threshold = 0;
238 config.stop_threshold = 0;
239 config.silence_threshold = 0;
240 stdev->pcm = pcm_open(DRAGON_ST_CARD_NUM, DRAGON_ST_DEV_NUM,
241 PCM_IN | PCM_MMAP, &config);
242 if (!stdev->pcm || !pcm_is_ready(stdev->pcm)) {
243 ALOGE("Unable to open PCM device (%s)\n", pcm_get_error(stdev->pcm));
244 err = -1;
245 goto exit;
246 }
247 err = pcm_start(stdev->pcm);
248 if (err) {
249 ALOGE("Unable to start PCM device (%s)\n", pcm_get_error(stdev->pcm));
250 goto exit;
251 }
252
253 memset(fds, 0, 2 * sizeof(struct pollfd));
254 fds[0].events = POLLIN;
255 fds[0].fd = pcm_get_poll_fd(stdev->pcm);;
256 if (fds[0].fd == -1) {
257 ALOGE("Error opening socket for hotplug uevent");
258 goto exit;
259 }
260 fds[1].events = POLLIN;
261 fds[1].fd = stdev->term_sock;
262
263 pthread_mutex_unlock(&stdev->lock);
264
265 while (1) {
266 err = poll(fds, 2, -1);
267 pthread_mutex_lock(&stdev->lock);
268 if ((err < 0) || (stdev->recognition_callback == NULL)) {
269 ALOGE_IF(err < 0, "Error in hotplug CPU poll: %d", errno);
270 break;
271 }
272
273 if (fds[0].revents & POLLIN) {
274 struct sound_trigger_phrase_recognition_event *event;
275 recognition_callback_t callback = stdev->recognition_callback;
276 void *cookie = stdev->recognition_cookie;
277
278 event = (struct sound_trigger_phrase_recognition_event *)
279 sound_trigger_event_alloc(stdev);
280 if (!event) {
281 pcm_close(stdev->pcm);
282 stdev->pcm = NULL;
283 goto exit;
284 }
285 stdev->is_streaming = 1;
286 ALOGI("%s send callback model %d", __func__,
287 stdev->model_handle);
288 pthread_mutex_unlock(&stdev->lock);
289 if (callback != NULL) {
290 callback(&event->common, cookie);
291 }
292 pthread_mutex_lock(&stdev->lock);
293 free(event);
294 /* Leave the device open for streaming. */
295 goto exit;
296 } else if (fds[1].revents & POLLIN) {
297 read(fds[1].fd, &n, sizeof(n)); /* clear the socket */
298 ALOGI("%s: Termination message", __func__);
299 break;
300 } else {
301 ALOGI("%s: Message to ignore", __func__);
302 }
303 pthread_mutex_unlock(&stdev->lock);
304 }
305
306 if (stdev->pcm) {
307 pcm_close(stdev->pcm);
308 stdev->pcm = NULL;
309 }
310
311 exit:
312 stdev->recognition_callback = NULL;
313 stdev_close_term_sock(stdev);
314
315 if (stdev->config && !stdev->config->capture_requested)
316 stdev_dsp_set_power(stdev, 0);
317
318 pthread_mutex_unlock(&stdev->lock);
319
320 return (void *)(long)err;
321 }
322
stdev_get_properties(const struct sound_trigger_hw_device * dev,struct sound_trigger_properties * properties)323 static int stdev_get_properties(const struct sound_trigger_hw_device *dev,
324 struct sound_trigger_properties *properties)
325 {
326 struct dragon_sound_trigger_device *stdev =
327 (struct dragon_sound_trigger_device *)dev;
328
329 ALOGI("%s", __func__);
330 if (properties == NULL)
331 return -EINVAL;
332 memcpy(properties, &hw_properties, sizeof(struct sound_trigger_properties));
333 return 0;
334 }
335
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)336 static int stdev_load_sound_model(const struct sound_trigger_hw_device *dev,
337 struct sound_trigger_sound_model *sound_model,
338 sound_model_callback_t callback,
339 void *cookie,
340 sound_model_handle_t *handle)
341 {
342 struct dragon_sound_trigger_device *stdev =
343 (struct dragon_sound_trigger_device *)dev;
344 int ret = 0;
345
346 ALOGI("%s", __func__);
347 pthread_mutex_lock(&stdev->lock);
348 if (handle == NULL || sound_model == NULL) {
349 ret = -EINVAL;
350 goto exit;
351 }
352
353 if (stdev->model_handle == 1) {
354 ret = -ENOSYS;
355 goto exit;
356 }
357
358 ret = vad_load_sound_model(stdev,
359 (char *)sound_model + sound_model->data_offset,
360 sound_model->data_size);
361 if (ret)
362 goto exit;
363
364 stdev->model_handle = 1;
365 stdev->sound_model_callback = callback;
366 stdev->sound_model_cookie = cookie;
367 *handle = stdev->model_handle;
368
369 exit:
370 pthread_mutex_unlock(&stdev->lock);
371 return ret;
372 }
373
stdev_unload_sound_model(const struct sound_trigger_hw_device * dev,sound_model_handle_t handle)374 static int stdev_unload_sound_model(const struct sound_trigger_hw_device *dev,
375 sound_model_handle_t handle)
376 {
377 struct dragon_sound_trigger_device *stdev =
378 (struct dragon_sound_trigger_device *)dev;
379 int status = 0;
380
381 ALOGI("%s handle %d", __func__, handle);
382 pthread_mutex_lock(&stdev->lock);
383 if (handle != 1) {
384 status = -EINVAL;
385 goto exit;
386 }
387 if (stdev->model_handle == 0) {
388 status = -ENOSYS;
389 goto exit;
390 }
391 stdev->model_handle = 0;
392 free(stdev->config);
393 stdev->config = NULL;
394 if (stdev->recognition_callback != NULL) {
395 stdev->recognition_callback = NULL;
396 if (stdev->send_sock >=0)
397 write(stdev->send_sock, "T", 1);
398 pthread_mutex_unlock(&stdev->lock);
399
400 pthread_join(stdev->callback_thread, (void **)NULL);
401
402 pthread_mutex_lock(&stdev->lock);
403 }
404
405 exit:
406 stdev_dsp_set_power(stdev, 0);
407
408 pthread_mutex_unlock(&stdev->lock);
409 return status;
410 }
411
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)412 static int stdev_start_recognition(const struct sound_trigger_hw_device *dev,
413 sound_model_handle_t sound_model_handle,
414 const struct sound_trigger_recognition_config *config,
415 recognition_callback_t callback,
416 void *cookie)
417 {
418 struct dragon_sound_trigger_device *stdev =
419 (struct dragon_sound_trigger_device *)dev;
420 int status = 0;
421
422 ALOGI("%s sound model %d", __func__, sound_model_handle);
423 pthread_mutex_lock(&stdev->lock);
424 if (stdev->model_handle != sound_model_handle) {
425 status = -ENOSYS;
426 goto exit;
427 }
428 if (stdev->recognition_callback != NULL) {
429 status = -ENOSYS;
430 goto exit;
431 }
432
433 free(stdev->config);
434 stdev->config = NULL;
435 if (config) {
436 stdev->config = malloc(sizeof(*config));
437 if (!stdev->config) {
438 status = -ENOMEM;
439 goto exit;
440 }
441 memcpy(stdev->config, config, sizeof(*config));
442 }
443
444 if (stdev->pcm) {
445 pcm_close(stdev->pcm);
446 stdev->pcm = NULL;
447 }
448
449 stdev_dsp_set_power(stdev, 0);
450
451 stdev->recognition_callback = callback;
452 stdev->recognition_cookie = cookie;
453 pthread_create(&stdev->callback_thread, (const pthread_attr_t *) NULL,
454 callback_thread_loop, stdev);
455 exit:
456 pthread_mutex_unlock(&stdev->lock);
457 return status;
458 }
459
stdev_stop_recognition(const struct sound_trigger_hw_device * dev,sound_model_handle_t sound_model_handle)460 static int stdev_stop_recognition(const struct sound_trigger_hw_device *dev,
461 sound_model_handle_t sound_model_handle)
462 {
463 struct dragon_sound_trigger_device *stdev =
464 (struct dragon_sound_trigger_device *)dev;
465 int status = 0;
466
467 ALOGI("%s sound model %d", __func__, sound_model_handle);
468 pthread_mutex_lock(&stdev->lock);
469 if (stdev->model_handle != sound_model_handle) {
470 status = -ENOSYS;
471 goto exit;
472 }
473 if (stdev->recognition_callback == NULL) {
474 status = -ENOSYS;
475 goto exit;
476 }
477 free(stdev->config);
478 stdev->config = NULL;
479 stdev->recognition_callback = NULL;
480 if (stdev->send_sock >=0)
481 write(stdev->send_sock, "T", 1);
482 pthread_mutex_unlock(&stdev->lock);
483
484 pthread_join(stdev->callback_thread, (void **)NULL);
485
486 if (stdev->pcm) {
487 pcm_close(stdev->pcm);
488 stdev->pcm = NULL;
489 }
490
491 pthread_mutex_lock(&stdev->lock);
492
493 exit:
494 stdev_dsp_set_power(stdev, 0);
495
496 pthread_mutex_unlock(&stdev->lock);
497 return status;
498 }
499
500 __attribute__ ((visibility ("default")))
sound_trigger_open_for_streaming()501 int sound_trigger_open_for_streaming()
502 {
503 struct dragon_sound_trigger_device *stdev = &g_stdev;
504 int ret = 0;
505
506 pthread_mutex_lock(&stdev->lock);
507
508 if (!stdev->opened) {
509 ALOGE("%s: stdev has not been opened", __func__);
510 ret = -EFAULT;
511 goto exit;
512 }
513 if (!stdev->is_streaming) {
514 ALOGE("%s: DSP is not currently streaming", __func__);
515 ret = -EBUSY;
516 goto exit;
517 }
518 if (!stdev->pcm) {
519 ALOGE("%s: PCM is not open", __func__);
520 ret = -EINVAL;
521 goto exit;
522 }
523 // TODO: Probably want to get something from whoever called us to bind to it/assert that it's a
524 // valid connection. Perhaps returning a more
525 // meaningful handle would be a good idea as well.
526 ret = 1;
527 exit:
528 pthread_mutex_unlock(&stdev->lock);
529 return ret;
530 }
531
532 __attribute__ ((visibility ("default")))
sound_trigger_read_samples(int audio_handle,void * buffer,size_t buffer_len)533 size_t sound_trigger_read_samples(int audio_handle, void *buffer, size_t buffer_len)
534 {
535 struct dragon_sound_trigger_device *stdev = &g_stdev;
536 int i;
537 int ret = 0;
538 int frames;
539 int orig_frames;
540 unsigned int offset;
541 unsigned int bytes_mmapped;
542 int16_t* snd_buffer;
543 unsigned int retry_attempts = 0;
544
545 if (audio_handle <= 0) {
546 ALOGE("%s: invalid audio handle", __func__);
547 return -EINVAL;
548 }
549
550 pthread_mutex_lock(&stdev->lock);
551
552 if (!stdev->opened) {
553 ALOGE("%s: stdev has not been opened", __func__);
554 ret = -EFAULT;
555 goto exit;
556 }
557 if (!stdev->is_streaming) {
558 ALOGE("%s: DSP is not currently streaming", __func__);
559 ret = -EINVAL;
560 goto exit;
561 }
562 if (!stdev->pcm) {
563 ALOGE("%s: PCM has closed", __func__);
564 ret = -EINVAL;
565 goto exit;
566 }
567
568
569 read_again:
570 frames = pcm_mmap_avail(stdev->pcm);
571 if (frames < 0) {
572 ALOGE("%s: DSP mmap error %d", __func__, frames);
573 ret = frames;
574 goto exit;
575 }
576 if (frames == 0) {
577 // ALOGE("%s: DSP mmap retry %d", __func__, frames);
578 retry_attempts++;
579 if (retry_attempts > 10)
580 goto exit;
581 usleep(35000);
582 goto read_again;
583 }
584
585 if (frames > buffer_len / 2)
586 frames = buffer_len / 2;
587
588 orig_frames = frames;
589
590 ret = pcm_mmap_begin(stdev->pcm, (void**)&snd_buffer, &offset, &frames);
591 if (ret < 0) {
592 ALOGE("Failed to mmap hotword buffer %d", ret);
593 goto exit;
594 }
595 memcpy(buffer, snd_buffer + offset, frames * 2);
596 pcm_mmap_commit(stdev->pcm, offset, frames);
597 ret = frames * 2;
598 ALOGV("%s: Sent %u frames to buffer", __func__, frames);
599
600 exit:
601 pthread_mutex_unlock(&stdev->lock);
602 return ret;
603 }
604
605 __attribute__ ((visibility ("default")))
sound_trigger_close_for_streaming(int audio_handle)606 int sound_trigger_close_for_streaming(int audio_handle)
607 {
608 struct dragon_sound_trigger_device *stdev = &g_stdev;
609
610 if (audio_handle <= 0) {
611 ALOGE("%s: invalid audio handle", __func__);
612 return -EINVAL;
613 }
614
615 if (stdev->pcm) {
616 pcm_close(stdev->pcm);
617 stdev->pcm = NULL;
618 }
619
620 return 0;
621 }
622
stdev_close(hw_device_t * device)623 static int stdev_close(hw_device_t *device)
624 {
625 struct dragon_sound_trigger_device *stdev =
626 (struct dragon_sound_trigger_device *)device;
627 int ret = 0;
628
629 pthread_mutex_lock(&stdev->lock);
630 if (!stdev->opened) {
631 ALOGE("%s: device already closed", __func__);
632 ret = -EFAULT;
633 goto exit;
634 }
635 stdev_close_mixer(stdev);
636 stdev->model_handle = 0;
637 stdev->send_sock = 0;
638 stdev->term_sock = 0;
639 stdev->opened = false;
640
641 exit:
642 pthread_mutex_unlock(&stdev->lock);
643 return ret;
644 }
645
stdev_open(const hw_module_t * module,const char * name,hw_device_t ** device)646 static int stdev_open(const hw_module_t *module, const char *name,
647 hw_device_t **device)
648 {
649 struct dragon_sound_trigger_device *stdev;
650 int ret;
651
652 if (strcmp(name, SOUND_TRIGGER_HARDWARE_INTERFACE) != 0)
653 return -EINVAL;
654
655 stdev = &g_stdev;
656 pthread_mutex_lock(&stdev->lock);
657
658 if (stdev->opened) {
659 ALOGE("%s: Only one sountrigger can be opened at a time", __func__);
660 ret = -EBUSY;
661 goto exit;
662 }
663
664 ret = stdev_init_mixer(stdev);
665 if (ret) {
666 ALOGE("Error mixer init");
667 goto exit;
668 }
669
670 stdev->device.common.tag = HARDWARE_DEVICE_TAG;
671 stdev->device.common.version = SOUND_TRIGGER_DEVICE_API_VERSION_1_0;
672 stdev->device.common.module = (struct hw_module_t *)module;
673 stdev->device.common.close = stdev_close;
674 stdev->device.get_properties = stdev_get_properties;
675 stdev->device.load_sound_model = stdev_load_sound_model;
676 stdev->device.unload_sound_model = stdev_unload_sound_model;
677 stdev->device.start_recognition = stdev_start_recognition;
678 stdev->device.stop_recognition = stdev_stop_recognition;
679 stdev->send_sock = stdev->term_sock = -1;
680 stdev->opened = true;
681
682 *device = &stdev->device.common; /* same address as stdev */
683 exit:
684 pthread_mutex_unlock(&stdev->lock);
685 return ret;
686 }
687
688 static struct hw_module_methods_t hal_module_methods = {
689 .open = stdev_open,
690 };
691
692 struct sound_trigger_module HAL_MODULE_INFO_SYM = {
693 .common = {
694 .tag = HARDWARE_MODULE_TAG,
695 .module_api_version = SOUND_TRIGGER_MODULE_API_VERSION_1_0,
696 .hal_api_version = HARDWARE_HAL_API_VERSION,
697 .id = SOUND_TRIGGER_HARDWARE_MODULE_ID,
698 .name = "Default sound trigger HAL",
699 .author = "The Android Open Source Project",
700 .methods = &hal_module_methods,
701 },
702 };
703