From cbca9056decfa8c98313e2c27a1debf4eb417a4c Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Fri, 18 Apr 2014 17:54:10 -0700 Subject: sound trigger test/stub HAL - WIP Change-Id: Ie8120df144662b12bba41e2346bac3ce816f9838 --- modules/soundtrigger/Android.mk | 27 +++ modules/soundtrigger/sound_trigger_hw.c | 301 ++++++++++++++++++++++++++++++++ 2 files changed, 328 insertions(+) create mode 100644 modules/soundtrigger/Android.mk create mode 100644 modules/soundtrigger/sound_trigger_hw.c diff --git a/modules/soundtrigger/Android.mk b/modules/soundtrigger/Android.mk new file mode 100644 index 0000000..325980c --- /dev/null +++ b/modules/soundtrigger/Android.mk @@ -0,0 +1,27 @@ +# Copyright (C) 2011 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +LOCAL_PATH := $(call my-dir) + +# Stub sound_trigger HAL module, used for tests +include $(CLEAR_VARS) + +LOCAL_MODULE := sound_trigger.stub.default +LOCAL_MODULE_RELATIVE_PATH := hw +LOCAL_SRC_FILES := sound_trigger_hw.c +LOCAL_SHARED_LIBRARIES := liblog libcutils +LOCAL_MODULE_TAGS := optional +LOCAL_32_BIT_ONLY := true + +include $(BUILD_SHARED_LIBRARY) diff --git a/modules/soundtrigger/sound_trigger_hw.c b/modules/soundtrigger/sound_trigger_hw.c new file mode 100644 index 0000000..8347d02 --- /dev/null +++ b/modules/soundtrigger/sound_trigger_hw.c @@ -0,0 +1,301 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "sound_trigger_hw_default" +/*#define LOG_NDEBUG 0*/ + +#include +#include +#include +#include + +#include +#include +#include + +static const struct sound_trigger_properties hw_properties = { + "The Android Open Source Project", // implementor + "Sound Trigger stub HAL", // description + 1, // version + { 0xed7a7d60, 0xc65e, 0x11e3, 0x9be4, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } }, // uuid + 1, // max_sound_models + 1, // max_key_phrases + 1, // max_users + RECOGNITION_MODE_VOICE_TRIGGER, // recognition_modes + false, // capture_transition + 0, // max_buffer_ms + false, // concurrent_capture + 0 // power_consumption_mw +}; + +struct stub_sound_trigger_device { + struct sound_trigger_hw_device device; + sound_model_handle_t model_handle; + recognition_callback_t recognition_callback; + void *recognition_cookie; + sound_model_callback_t sound_model_callback; + void *sound_model_cookie; + pthread_t callback_thread; + pthread_mutex_t lock; + pthread_cond_t cond; + +}; + + +static void *callback_thread_loop(void *context) +{ + struct stub_sound_trigger_device *stdev = (struct stub_sound_trigger_device *)context; + ALOGI("%s", __func__); + + prctl(PR_SET_NAME, (unsigned long)"sound trigger callback", 0, 0, 0); + + pthread_mutex_lock(&stdev->lock); + if (stdev->recognition_callback == NULL) { + goto exit; + } + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + ts.tv_sec += 3; + ALOGI("%s wait 3 sec", __func__); + int rc = pthread_cond_timedwait(&stdev->cond, &stdev->lock, &ts); + if (rc == ETIMEDOUT && stdev->recognition_callback != NULL) { + char *data = (char *)calloc(1, sizeof(struct sound_trigger_phrase_recognition_event) + 1); + struct sound_trigger_phrase_recognition_event *event = + (struct sound_trigger_phrase_recognition_event *)data; + event->common.status = RECOGNITION_STATUS_SUCCESS; + event->common.type = SOUND_MODEL_TYPE_KEYPHRASE; + event->common.model = stdev->model_handle; + event->key_phrase_in_capture = false; + event->num_phrases = 1; + event->phrase_extras[0].recognition_modes = RECOGNITION_MODE_VOICE_TRIGGER; + event->phrase_extras[0].num_users = 1; + event->phrase_extras[0].confidence_levels[0] = 100; + event->common.data_offset = sizeof(struct sound_trigger_phrase_recognition_event); + event->common.data_size = 1; + data[event->common.data_offset] = 8; + ALOGI("%s send callback model %d", __func__, stdev->model_handle); + stdev->recognition_callback(&event->common, stdev->recognition_cookie); + free(data); + } else { + ALOGI("%s abort recognition model %d", __func__, stdev->model_handle); + } + stdev->recognition_callback = NULL; + +exit: + pthread_mutex_unlock(&stdev->lock); + + return NULL; +} + +static int stdev_get_properties(const struct sound_trigger_hw_device *dev, + struct sound_trigger_properties *properties) +{ + struct stub_sound_trigger_device *stdev = (struct stub_sound_trigger_device *)dev; + + ALOGI("%s", __func__); + if (properties == NULL) + return -EINVAL; + memcpy(properties, &hw_properties, sizeof(struct sound_trigger_properties)); + return 0; +} + +static int 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) +{ + struct stub_sound_trigger_device *stdev = (struct stub_sound_trigger_device *)dev; + int status = 0; + + ALOGI("%s stdev %p", __func__, stdev); + pthread_mutex_lock(&stdev->lock); + if (handle == NULL || sound_model == NULL) { + status = -EINVAL; + goto exit; + } + if (sound_model->data_size == 0 || + sound_model->data_offset < sizeof(struct sound_trigger_sound_model)) { + status = -EINVAL; + goto exit; + } + + if (stdev->model_handle == 1) { + status = -ENOSYS; + goto exit; + } + char *data = (char *)sound_model + sound_model->data_offset; + ALOGI("%s data size %d data %d - %d", __func__, + sound_model->data_size, data[0], data[sound_model->data_size - 1]); + stdev->model_handle = 1; + stdev->sound_model_callback = callback; + stdev->sound_model_cookie = cookie; + + *handle = stdev->model_handle; + +exit: + pthread_mutex_unlock(&stdev->lock); + return status; +} + +static int stdev_unload_sound_model(const struct sound_trigger_hw_device *dev, + sound_model_handle_t handle) +{ + struct stub_sound_trigger_device *stdev = (struct stub_sound_trigger_device *)dev; + int status = 0; + + ALOGI("%s handle %d", __func__, handle); + pthread_mutex_lock(&stdev->lock); + if (handle != 1) { + status = -EINVAL; + goto exit; + } + if (stdev->model_handle == 0) { + status = -ENOSYS; + goto exit; + } + stdev->model_handle = 0; + if (stdev->recognition_callback != NULL) { + stdev->recognition_callback = NULL; + pthread_cond_signal(&stdev->cond); + pthread_mutex_unlock(&stdev->lock); + pthread_join(stdev->callback_thread, (void **) NULL); + pthread_mutex_lock(&stdev->lock); + } + +exit: + pthread_mutex_unlock(&stdev->lock); + return status; +} + +static int stdev_start_recognition(const struct sound_trigger_hw_device *dev, + sound_model_handle_t sound_model_handle, + audio_io_handle_t capture_handle __unused, + audio_devices_t capture_device __unused, + recognition_callback_t callback, + void *cookie, + unsigned int data_size, + char *data) +{ + struct stub_sound_trigger_device *stdev = (struct stub_sound_trigger_device *)dev; + int status = 0; + ALOGI("%s sound model %d", __func__, sound_model_handle); + pthread_mutex_lock(&stdev->lock); + if (stdev->model_handle != sound_model_handle) { + status = -ENOSYS; + goto exit; + } + if (stdev->recognition_callback != NULL) { + status = -ENOSYS; + goto exit; + } + if (data_size != 0 && data == NULL) { + status = -EINVAL; + goto exit; + } + if (data_size != 0) { + ALOGI("%s data size %d data %d - %d", __func__, + data_size, data[0], data[data_size - 1]); + } + + stdev->recognition_callback = callback; + stdev->recognition_cookie = cookie; + pthread_create(&stdev->callback_thread, (const pthread_attr_t *) NULL, + callback_thread_loop, stdev); +exit: + pthread_mutex_unlock(&stdev->lock); + return status; +} + +static int stdev_stop_recognition(const struct sound_trigger_hw_device *dev, + sound_model_handle_t sound_model_handle) +{ + struct stub_sound_trigger_device *stdev = (struct stub_sound_trigger_device *)dev; + int status = 0; + ALOGI("%s sound model %d", __func__, sound_model_handle); + pthread_mutex_lock(&stdev->lock); + if (stdev->model_handle != sound_model_handle) { + status = -ENOSYS; + goto exit; + } + if (stdev->recognition_callback == NULL) { + status = -ENOSYS; + goto exit; + } + stdev->recognition_callback = NULL; + pthread_cond_signal(&stdev->cond); + pthread_mutex_unlock(&stdev->lock); + pthread_join(stdev->callback_thread, (void **) NULL); + pthread_mutex_lock(&stdev->lock); + +exit: + pthread_mutex_unlock(&stdev->lock); + return status; +} + + +static int stdev_close(hw_device_t *device) +{ + free(device); + return 0; +} + +static int stdev_open(const hw_module_t* module, const char* name, + hw_device_t** device) +{ + struct stub_sound_trigger_device *stdev; + int ret; + + if (strcmp(name, SOUND_TRIGGER_HARDWARE_INTERFACE) != 0) + return -EINVAL; + + stdev = calloc(1, sizeof(struct stub_sound_trigger_device)); + if (!stdev) + return -ENOMEM; + + stdev->device.common.tag = HARDWARE_DEVICE_TAG; + stdev->device.common.version = SOUND_TRIGGER_DEVICE_API_VERSION_1_0; + stdev->device.common.module = (struct hw_module_t *) module; + stdev->device.common.close = stdev_close; + stdev->device.get_properties = stdev_get_properties; + stdev->device.load_sound_model = stdev_load_sound_model; + stdev->device.unload_sound_model = stdev_unload_sound_model; + stdev->device.start_recognition = stdev_start_recognition; + stdev->device.stop_recognition = stdev_stop_recognition; + + pthread_mutex_init(&stdev->lock, (const pthread_mutexattr_t *) NULL); + pthread_cond_init(&stdev->cond, (const pthread_condattr_t *) NULL); + + *device = &stdev->device.common; + + return 0; +} + +static struct hw_module_methods_t hal_module_methods = { + .open = stdev_open, +}; + +struct sound_trigger_module HAL_MODULE_INFO_SYM = { + .common = { + .tag = HARDWARE_MODULE_TAG, + .module_api_version = SOUND_TRIGGER_MODULE_API_VERSION_1_0, + .hal_api_version = HARDWARE_HAL_API_VERSION, + .id = SOUND_TRIGGER_HARDWARE_MODULE_ID, + .name = "Default sound trigger HAL", + .author = "The Android Open Source Project", + .methods = &hal_module_methods, + }, +}; -- cgit v1.1