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