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