summaryrefslogtreecommitdiffstats
path: root/modules/soundtrigger
diff options
context:
space:
mode:
authorEric Laurent <elaurent@google.com>2014-04-18 17:54:10 -0700
committerEric Laurent <elaurent@google.com>2014-06-04 14:34:43 -0700
commitcbca9056decfa8c98313e2c27a1debf4eb417a4c (patch)
tree08f56d0b8ff17203cedfa1df0c9a1671714d21d0 /modules/soundtrigger
parent46bbe8a7822278db4b3bd926e6f7cb2e0326a2df (diff)
downloadhardware_libhardware-cbca9056decfa8c98313e2c27a1debf4eb417a4c.zip
hardware_libhardware-cbca9056decfa8c98313e2c27a1debf4eb417a4c.tar.gz
hardware_libhardware-cbca9056decfa8c98313e2c27a1debf4eb417a4c.tar.bz2
sound trigger test/stub HAL - WIP
Change-Id: Ie8120df144662b12bba41e2346bac3ce816f9838
Diffstat (limited to 'modules/soundtrigger')
-rw-r--r--modules/soundtrigger/Android.mk27
-rw-r--r--modules/soundtrigger/sound_trigger_hw.c301
2 files changed, 328 insertions, 0 deletions
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 <errno.h>
+#include <pthread.h>
+#include <sys/prctl.h>
+#include <cutils/log.h>
+
+#include <hardware/hardware.h>
+#include <system/sound_trigger.h>
+#include <hardware/sound_trigger.h>
+
+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,
+ },
+};