diff options
Diffstat (limited to 'qahw/src/qahw_effect.c')
-rw-r--r-- | qahw/src/qahw_effect.c | 321 |
1 files changed, 321 insertions, 0 deletions
diff --git a/qahw/src/qahw_effect.c b/qahw/src/qahw_effect.c new file mode 100644 index 00000000..cf7b3fd3 --- /dev/null +++ b/qahw/src/qahw_effect.c @@ -0,0 +1,321 @@ +/* +* Copyright (c) 2017, The Linux Foundation. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are +* met: +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above +* copyright notice, this list of conditions and the following +* disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of The Linux Foundation nor the names of its +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#define LOG_TAG "qahw_effect" +//#define LOG_NDEBUG 0 +#define LOG_NDDEBUG 0 + +#include <cutils/list.h> +#include <dlfcn.h> +#include <utils/Log.h> +#include <hardware/audio.h> +#include <hardware/audio_effect.h> +#include <stdlib.h> + +#include "qahw_effect_api.h" + +// The current effect API version. +#define QAHW_EFFECT_API_VERSION_CURRENT QAHW_EFFECT_API_VERSION_0_0 +#define PATH_MAX 4096 + +typedef struct { + char lib_path[PATH_MAX]; + pthread_mutex_t lock; + uint32_t ref_count; + audio_effect_library_t *desc; + void *handle; + struct listnode lib_list; +} qahw_effect_lib_t; + +// list of loaded effect libraries +static struct listnode effect_libraries_list; +static int effect_libraries_count = 0; +static pthread_mutex_t effect_libraries_lock = PTHREAD_MUTEX_INITIALIZER; + +qahw_effect_lib_t *get_qahw_effect_lib_by_name(const char *lib_path) { + struct listnode *node = NULL; + qahw_effect_lib_t *effect_lib = NULL, *effect_lib_temp = NULL; + + if (lib_path == NULL) + goto exit; + + list_for_each(node, &effect_libraries_list) { + effect_lib_temp = node_to_item(node, qahw_effect_lib_t, lib_list); + if(!strncmp(lib_path, effect_lib_temp->lib_path, PATH_MAX)) { + effect_lib = effect_lib_temp; + break; + } + } +exit: + return effect_lib; +} + + +qahw_effect_lib_t *get_qahw_effect_lib_by_desc(qahw_effect_lib_handle_t handle) { + struct listnode *node = NULL; + qahw_effect_lib_t *effect_lib = NULL, *effect_lib_temp = NULL; + + if (handle == NULL) + goto exit; + + list_for_each(node, &effect_libraries_list) { + effect_lib_temp = node_to_item(node, qahw_effect_lib_t, lib_list); + if (effect_lib_temp->desc == (audio_effect_library_t *)handle) { + effect_lib = effect_lib_temp; + break; + } + } +exit: + return effect_lib; +} + + +qahw_effect_lib_handle_t qahw_effect_load_library(const char *lib_path) { + audio_effect_library_t *desc; + qahw_effect_lib_t *qahw_effect_lib; + void *handle; + + if (strlen(lib_path) >= PATH_MAX -1) { + ALOGE("%s: effect libraries path too long", __func__); + return NULL; + } + + /* return existing lib handler if already loaded */ + pthread_mutex_lock(&effect_libraries_lock); + if (effect_libraries_count > 0) { + qahw_effect_lib = get_qahw_effect_lib_by_name(lib_path); + if (qahw_effect_lib != NULL) { + desc = qahw_effect_lib->desc; + pthread_mutex_lock(&qahw_effect_lib->lock); + qahw_effect_lib->ref_count++; + pthread_mutex_unlock(&qahw_effect_lib->lock); + goto done; + } + } + + handle = dlopen(lib_path, RTLD_NOW); + if (handle == NULL) { + ALOGE("%s: failed to dlopen lib %s", __func__, lib_path); + goto error; + } + + desc = (audio_effect_library_t *)dlsym(handle, AUDIO_EFFECT_LIBRARY_INFO_SYM_AS_STR); + if (desc == NULL) { + ALOGE("%s: could not find symbol %s", __func__, AUDIO_EFFECT_LIBRARY_INFO_SYM_AS_STR); + goto error; + } + + if (AUDIO_EFFECT_LIBRARY_TAG != desc->tag) { + ALOGE("%s: bad tag %08x in lib info struct", __func__, desc->tag); + goto error; + } + + if (EFFECT_API_VERSION_MAJOR(desc->version) != + EFFECT_API_VERSION_MAJOR(EFFECT_LIBRARY_API_VERSION)) { + ALOGE("%s: bad lib version %08x", __func__, desc->version); + goto error; + } + + qahw_effect_lib = (qahw_effect_lib_t *)calloc(1, sizeof(qahw_effect_lib_t)); + if (qahw_effect_lib == NULL) { + ALOGE("%s: calloc failed", __func__); + goto error; + } + + if (!effect_libraries_count) + list_init(&effect_libraries_list); + effect_libraries_count++; + + /* init and load effect lib into global list */ + strlcpy(qahw_effect_lib->lib_path, lib_path, PATH_MAX); + pthread_mutex_init(&qahw_effect_lib->lock, (const pthread_mutexattr_t *) NULL); + qahw_effect_lib->ref_count = 1; + qahw_effect_lib->desc = desc; + qahw_effect_lib->handle = handle; + + list_add_tail(&effect_libraries_list, &qahw_effect_lib->lib_list); + +done: + pthread_mutex_unlock(&effect_libraries_lock); + return (qahw_effect_lib_handle_t)desc; + +error: + if (handle != NULL) + dlclose(handle); + + pthread_mutex_unlock(&effect_libraries_lock); + return NULL; +} + + +int32_t qahw_effect_unload_library(qahw_effect_lib_handle_t handle) { + qahw_effect_lib_t *qahw_effect_lib; + + pthread_mutex_lock(&effect_libraries_lock); + if (effect_libraries_count <= 0) { + ALOGW("%s: no valid libraries loaded", __func__); + pthread_mutex_unlock(&effect_libraries_lock); + return -EINVAL; + } + + qahw_effect_lib = get_qahw_effect_lib_by_desc(handle); + if (qahw_effect_lib == NULL) { + ALOGW("%s: effect lib handle(%p) not in loaded queue", __func__, (void *)handle); + pthread_mutex_unlock(&effect_libraries_lock); + return -EINVAL; + } + + pthread_mutex_lock(&qahw_effect_lib->lock); + qahw_effect_lib->ref_count--; + if (qahw_effect_lib->ref_count > 0) { + ALOGW("%s: skip unloading effect lib, ref count %d", __func__, qahw_effect_lib->ref_count); + pthread_mutex_unlock(&qahw_effect_lib->lock); + goto done; + } + + if (qahw_effect_lib->handle) + dlclose(qahw_effect_lib->handle); + effect_libraries_count--; + list_remove(&qahw_effect_lib->lib_list); + pthread_mutex_unlock(&qahw_effect_lib->lock); + pthread_mutex_destroy(&qahw_effect_lib->lock); + free(qahw_effect_lib); + +done: + pthread_mutex_unlock(&effect_libraries_lock); + return 0; +} + + +int32_t qahw_effect_create(qahw_effect_lib_handle_t handle, + const qahw_effect_uuid_t *uuid, + int32_t io_handle, + qahw_effect_handle_t *effect_handle) { + int32_t rc = -EINVAL; + audio_effect_library_t *desc = (audio_effect_library_t *)handle; + + if (desc != NULL) { + rc = desc->create_effect((const effect_uuid_t *)uuid, 0, io_handle, + (effect_handle_t *)effect_handle); + } + + return rc; +} + + +int32_t qahw_effect_release(qahw_effect_lib_handle_t handle, + qahw_effect_handle_t effect_handle) { + int32_t rc = -EINVAL; + audio_effect_library_t *desc = (audio_effect_library_t *)handle; + + if (desc != NULL) { + rc = desc->release_effect((effect_handle_t)effect_handle); + } + + return rc; +} + + +int32_t qahw_effect_get_descriptor(qahw_effect_lib_handle_t handle, + const qahw_effect_uuid_t *uuid, + qahw_effect_descriptor_t *effect_desc) { + int32_t rc = -EINVAL; + audio_effect_library_t *desc = (audio_effect_library_t *)handle; + + if (desc != NULL) { + rc = desc->get_descriptor((const effect_uuid_t *)uuid, (effect_descriptor_t *)effect_desc); + } + + return rc; +} + + +int32_t qahw_effect_get_version() { + return QAHW_EFFECT_API_VERSION_CURRENT; +} + + +int32_t qahw_effect_process(qahw_effect_handle_t self, + qahw_audio_buffer_t *in_buffer, + qahw_audio_buffer_t *out_buffer) { + int32_t rc = -EINVAL; + struct effect_interface_s *itfe; + + if (self) { + itfe = *((struct effect_interface_s **)self); + if (itfe) { + rc = itfe->process((effect_handle_t)self, + (audio_buffer_t *)in_buffer, + (audio_buffer_t *)out_buffer); + } + } + + return rc; +} + + +int32_t qahw_effect_command(qahw_effect_handle_t self, + uint32_t cmd_code, + uint32_t cmd_size, + void *cmd_data, + uint32_t *reply_size, + void *reply_data) { + int32_t rc = -EINVAL; + struct effect_interface_s *itfe; + + if (self) { + itfe = *((struct effect_interface_s **)self); + if (itfe) { + rc = itfe->command((effect_handle_t)self, cmd_code, cmd_size, + cmd_data, reply_size, reply_data); + } + } + + return rc; +} + + +int32_t qahw_effect_process_reverse(qahw_effect_handle_t self, + qahw_audio_buffer_t *in_buffer, + qahw_audio_buffer_t *out_buffer) { + int32_t rc = -EINVAL; + struct effect_interface_s *itfe; + + if (self) { + itfe = *((struct effect_interface_s **)self); + if (itfe) { + rc = itfe->process_reverse((effect_handle_t)self, + (audio_buffer_t *)in_buffer, + (audio_buffer_t *)out_buffer); + } + } + + return rc; +} + |