Home | History | Annotate | Download | only in soundtrigger
      1 /*
      2  * Copyright (C) 2011 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_default"
     18 /*#define LOG_NDEBUG 0*/
     19 
     20 #include <errno.h>
     21 #include <pthread.h>
     22 #include <sys/prctl.h>
     23 #include <cutils/log.h>
     24 
     25 #include <hardware/hardware.h>
     26 #include <system/sound_trigger.h>
     27 #include <hardware/sound_trigger.h>
     28 
     29 static const struct sound_trigger_properties hw_properties = {
     30         "The Android Open Source Project", // implementor
     31         "Sound Trigger stub HAL", // description
     32         1, // version
     33         { 0xed7a7d60, 0xc65e, 0x11e3, 0x9be4, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } }, // uuid
     34         1, // max_sound_models
     35         1, // max_key_phrases
     36         1, // max_users
     37         RECOGNITION_MODE_VOICE_TRIGGER, // recognition_modes
     38         false, // capture_transition
     39         0, // max_buffer_ms
     40         false, // concurrent_capture
     41         false, // trigger_in_event
     42         0 // power_consumption_mw
     43 };
     44 
     45 struct stub_sound_trigger_device {
     46     struct sound_trigger_hw_device device;
     47     sound_model_handle_t model_handle;
     48     recognition_callback_t recognition_callback;
     49     void *recognition_cookie;
     50     sound_model_callback_t sound_model_callback;
     51     void *sound_model_cookie;
     52     pthread_t callback_thread;
     53     pthread_mutex_t lock;
     54     pthread_cond_t  cond;
     55 };
     56 
     57 
     58 static void *callback_thread_loop(void *context)
     59 {
     60     struct stub_sound_trigger_device *stdev = (struct stub_sound_trigger_device *)context;
     61     ALOGI("%s", __func__);
     62 
     63     prctl(PR_SET_NAME, (unsigned long)"sound trigger callback", 0, 0, 0);
     64 
     65     pthread_mutex_lock(&stdev->lock);
     66     if (stdev->recognition_callback == NULL) {
     67         goto exit;
     68     }
     69     struct timespec ts;
     70     clock_gettime(CLOCK_REALTIME, &ts);
     71     ts.tv_sec += 3;
     72     ALOGI("%s wait 3 sec", __func__);
     73     int rc = pthread_cond_timedwait(&stdev->cond, &stdev->lock, &ts);
     74     if (rc == ETIMEDOUT && stdev->recognition_callback != NULL) {
     75         char *data = (char *)calloc(1, sizeof(struct sound_trigger_phrase_recognition_event) + 1);
     76         struct sound_trigger_phrase_recognition_event *event =
     77                 (struct sound_trigger_phrase_recognition_event *)data;
     78         event->common.status = RECOGNITION_STATUS_SUCCESS;
     79         event->common.type = SOUND_MODEL_TYPE_KEYPHRASE;
     80         event->common.model = stdev->model_handle;
     81         event->num_phrases = 1;
     82         event->phrase_extras[0].recognition_modes = RECOGNITION_MODE_VOICE_TRIGGER;
     83         event->phrase_extras[0].confidence_level = 100;
     84         event->phrase_extras[0].num_levels = 1;
     85         event->phrase_extras[0].levels[0].level = 100;
     86         event->phrase_extras[0].levels[0].user_id = 0;
     87         event->common.data_offset = sizeof(struct sound_trigger_phrase_recognition_event);
     88         event->common.data_size = 1;
     89         data[event->common.data_offset] = 8;
     90         ALOGI("%s send callback model %d", __func__, stdev->model_handle);
     91         stdev->recognition_callback(&event->common, stdev->recognition_cookie);
     92         free(data);
     93     } else {
     94         ALOGI("%s abort recognition model %d", __func__, stdev->model_handle);
     95     }
     96     stdev->recognition_callback = NULL;
     97 
     98 exit:
     99     pthread_mutex_unlock(&stdev->lock);
    100 
    101     return NULL;
    102 }
    103 
    104 static int stdev_get_properties(const struct sound_trigger_hw_device *dev,
    105                                 struct sound_trigger_properties *properties)
    106 {
    107     struct stub_sound_trigger_device *stdev = (struct stub_sound_trigger_device *)dev;
    108 
    109     ALOGI("%s", __func__);
    110     if (properties == NULL)
    111         return -EINVAL;
    112     memcpy(properties, &hw_properties, sizeof(struct sound_trigger_properties));
    113     return 0;
    114 }
    115 
    116 static int stdev_load_sound_model(const struct sound_trigger_hw_device *dev,
    117                                   struct sound_trigger_sound_model *sound_model,
    118                                   sound_model_callback_t callback,
    119                                   void *cookie,
    120                                   sound_model_handle_t *handle)
    121 {
    122     struct stub_sound_trigger_device *stdev = (struct stub_sound_trigger_device *)dev;
    123     int status = 0;
    124 
    125     ALOGI("%s stdev %p", __func__, stdev);
    126     pthread_mutex_lock(&stdev->lock);
    127     if (handle == NULL || sound_model == NULL) {
    128         status = -EINVAL;
    129         goto exit;
    130     }
    131     if (sound_model->data_size == 0 ||
    132             sound_model->data_offset < sizeof(struct sound_trigger_sound_model)) {
    133         status = -EINVAL;
    134         goto exit;
    135     }
    136 
    137     if (stdev->model_handle == 1) {
    138         status = -ENOSYS;
    139         goto exit;
    140     }
    141     char *data = (char *)sound_model + sound_model->data_offset;
    142     ALOGI("%s data size %d data %d - %d", __func__,
    143           sound_model->data_size, data[0], data[sound_model->data_size - 1]);
    144     stdev->model_handle = 1;
    145     stdev->sound_model_callback = callback;
    146     stdev->sound_model_cookie = cookie;
    147 
    148     *handle = stdev->model_handle;
    149 
    150 exit:
    151     pthread_mutex_unlock(&stdev->lock);
    152     return status;
    153 }
    154 
    155 static int stdev_unload_sound_model(const struct sound_trigger_hw_device *dev,
    156                                     sound_model_handle_t handle)
    157 {
    158     struct stub_sound_trigger_device *stdev = (struct stub_sound_trigger_device *)dev;
    159     int status = 0;
    160 
    161     ALOGI("%s handle %d", __func__, handle);
    162     pthread_mutex_lock(&stdev->lock);
    163     if (handle != 1) {
    164         status = -EINVAL;
    165         goto exit;
    166     }
    167     if (stdev->model_handle == 0) {
    168         status = -ENOSYS;
    169         goto exit;
    170     }
    171     stdev->model_handle = 0;
    172     if (stdev->recognition_callback != NULL) {
    173         stdev->recognition_callback = NULL;
    174         pthread_cond_signal(&stdev->cond);
    175         pthread_mutex_unlock(&stdev->lock);
    176         pthread_join(stdev->callback_thread, (void **) NULL);
    177         pthread_mutex_lock(&stdev->lock);
    178     }
    179 
    180 exit:
    181     pthread_mutex_unlock(&stdev->lock);
    182     return status;
    183 }
    184 
    185 static int stdev_start_recognition(const struct sound_trigger_hw_device *dev,
    186                                    sound_model_handle_t sound_model_handle,
    187                                    const struct sound_trigger_recognition_config *config,
    188                                    recognition_callback_t callback,
    189                                    void *cookie)
    190 {
    191     struct stub_sound_trigger_device *stdev = (struct stub_sound_trigger_device *)dev;
    192     int status = 0;
    193     ALOGI("%s sound model %d", __func__, sound_model_handle);
    194     pthread_mutex_lock(&stdev->lock);
    195     if (stdev->model_handle != sound_model_handle) {
    196         status = -ENOSYS;
    197         goto exit;
    198     }
    199     if (stdev->recognition_callback != NULL) {
    200         status = -ENOSYS;
    201         goto exit;
    202     }
    203     if (config->data_size != 0) {
    204         char *data = (char *)config + config->data_offset;
    205         ALOGI("%s data size %d data %d - %d", __func__,
    206               config->data_size, data[0], data[config->data_size - 1]);
    207     }
    208 
    209     stdev->recognition_callback = callback;
    210     stdev->recognition_cookie = cookie;
    211     pthread_create(&stdev->callback_thread, (const pthread_attr_t *) NULL,
    212                         callback_thread_loop, stdev);
    213 exit:
    214     pthread_mutex_unlock(&stdev->lock);
    215     return status;
    216 }
    217 
    218 static int stdev_stop_recognition(const struct sound_trigger_hw_device *dev,
    219                                  sound_model_handle_t sound_model_handle)
    220 {
    221     struct stub_sound_trigger_device *stdev = (struct stub_sound_trigger_device *)dev;
    222     int status = 0;
    223     ALOGI("%s sound model %d", __func__, sound_model_handle);
    224     pthread_mutex_lock(&stdev->lock);
    225     if (stdev->model_handle != sound_model_handle) {
    226         status = -ENOSYS;
    227         goto exit;
    228     }
    229     if (stdev->recognition_callback == NULL) {
    230         status = -ENOSYS;
    231         goto exit;
    232     }
    233     stdev->recognition_callback = NULL;
    234     pthread_cond_signal(&stdev->cond);
    235     pthread_mutex_unlock(&stdev->lock);
    236     pthread_join(stdev->callback_thread, (void **) NULL);
    237     pthread_mutex_lock(&stdev->lock);
    238 
    239 exit:
    240     pthread_mutex_unlock(&stdev->lock);
    241     return status;
    242 }
    243 
    244 
    245 static int stdev_close(hw_device_t *device)
    246 {
    247     free(device);
    248     return 0;
    249 }
    250 
    251 static int stdev_open(const hw_module_t* module, const char* name,
    252                      hw_device_t** device)
    253 {
    254     struct stub_sound_trigger_device *stdev;
    255     int ret;
    256 
    257     if (strcmp(name, SOUND_TRIGGER_HARDWARE_INTERFACE) != 0)
    258         return -EINVAL;
    259 
    260     stdev = calloc(1, sizeof(struct stub_sound_trigger_device));
    261     if (!stdev)
    262         return -ENOMEM;
    263 
    264     stdev->device.common.tag = HARDWARE_DEVICE_TAG;
    265     stdev->device.common.version = SOUND_TRIGGER_DEVICE_API_VERSION_1_0;
    266     stdev->device.common.module = (struct hw_module_t *) module;
    267     stdev->device.common.close = stdev_close;
    268     stdev->device.get_properties = stdev_get_properties;
    269     stdev->device.load_sound_model = stdev_load_sound_model;
    270     stdev->device.unload_sound_model = stdev_unload_sound_model;
    271     stdev->device.start_recognition = stdev_start_recognition;
    272     stdev->device.stop_recognition = stdev_stop_recognition;
    273 
    274     pthread_mutex_init(&stdev->lock, (const pthread_mutexattr_t *) NULL);
    275     pthread_cond_init(&stdev->cond, (const pthread_condattr_t *) NULL);
    276 
    277     *device = &stdev->device.common;
    278 
    279     return 0;
    280 }
    281 
    282 static struct hw_module_methods_t hal_module_methods = {
    283     .open = stdev_open,
    284 };
    285 
    286 struct sound_trigger_module HAL_MODULE_INFO_SYM = {
    287     .common = {
    288         .tag = HARDWARE_MODULE_TAG,
    289         .module_api_version = SOUND_TRIGGER_MODULE_API_VERSION_1_0,
    290         .hal_api_version = HARDWARE_HAL_API_VERSION,
    291         .id = SOUND_TRIGGER_HARDWARE_MODULE_ID,
    292         .name = "Default sound trigger HAL",
    293         .author = "The Android Open Source Project",
    294         .methods = &hal_module_methods,
    295     },
    296 };
    297