diff options
Diffstat (limited to 'msm8909/post_proc')
-rw-r--r-- | msm8909/post_proc/Android.mk | 34 | ||||
-rw-r--r-- | msm8909/post_proc/bass_boost.c | 280 | ||||
-rw-r--r-- | msm8909/post_proc/bass_boost.h | 59 | ||||
-rw-r--r-- | msm8909/post_proc/bundle.c | 780 | ||||
-rw-r--r-- | msm8909/post_proc/bundle.h | 92 | ||||
-rw-r--r-- | msm8909/post_proc/effect_api.c | 620 | ||||
-rw-r--r-- | msm8909/post_proc/effect_api.h | 151 | ||||
-rw-r--r-- | msm8909/post_proc/equalizer.c | 497 | ||||
-rw-r--r-- | msm8909/post_proc/equalizer.h | 63 | ||||
-rw-r--r-- | msm8909/post_proc/reverb.c | 613 | ||||
-rw-r--r-- | msm8909/post_proc/reverb.h | 84 | ||||
-rw-r--r-- | msm8909/post_proc/virtualizer.c | 503 | ||||
-rw-r--r-- | msm8909/post_proc/virtualizer.h | 60 |
13 files changed, 3836 insertions, 0 deletions
diff --git a/msm8909/post_proc/Android.mk b/msm8909/post_proc/Android.mk new file mode 100644 index 00000000..9d14c491 --- /dev/null +++ b/msm8909/post_proc/Android.mk @@ -0,0 +1,34 @@ + +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) + +ifeq ($(strip $(AUDIO_FEATURE_ENABLED_PROXY_DEVICE)),true) + LOCAL_CFLAGS += -DAFE_PROXY_ENABLED +endif + +LOCAL_SRC_FILES:= \ + bundle.c \ + equalizer.c \ + bass_boost.c \ + virtualizer.c \ + reverb.c \ + effect_api.c + +LOCAL_CFLAGS+= -O2 -fvisibility=hidden + +LOCAL_SHARED_LIBRARIES := \ + libcutils \ + liblog \ + libtinyalsa + +LOCAL_MODULE_TAGS := optional + +LOCAL_MODULE_RELATIVE_PATH := soundfx +LOCAL_MODULE:= libqcompostprocbundle + +LOCAL_C_INCLUDES := \ + external/tinyalsa/include \ + $(call include-path-for, audio-effects) + +include $(BUILD_SHARED_LIBRARY) diff --git a/msm8909/post_proc/bass_boost.c b/msm8909/post_proc/bass_boost.c new file mode 100644 index 00000000..7cd170b0 --- /dev/null +++ b/msm8909/post_proc/bass_boost.c @@ -0,0 +1,280 @@ +/* + * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. + * Not a Contribution. + * + * Copyright (C) 2013 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 "offload_effect_bass_boost" +#define LOG_NDEBUG 0 + +#include <cutils/list.h> +#include <cutils/log.h> +#include <tinyalsa/asoundlib.h> +#include <sound/audio_effects.h> +#include <audio_effects/effect_bassboost.h> + +#include "effect_api.h" +#include "bass_boost.h" + +/* Offload bassboost UUID: 2c4a8c24-1581-487f-94f6-0002a5d5c51b */ +const effect_descriptor_t bassboost_descriptor = { + {0x0634f220, 0xddd4, 0x11db, 0xa0fc, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b }}, + {0x2c4a8c24, 0x1581, 0x487f, 0x94f6, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // uuid + EFFECT_CONTROL_API_VERSION, + (EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_DEVICE_IND | EFFECT_FLAG_HW_ACC_TUNNEL), + 0, /* TODO */ + 1, + "MSM offload bassboost", + "The Android Open Source Project", +}; + +/* + * Bassboost operations + */ + +int bassboost_get_strength(bassboost_context_t *context) +{ + ALOGV("%s: ctxt %p, strength: %d", __func__, + context, context->strength); + return context->strength; +} + +int bassboost_set_strength(bassboost_context_t *context, uint32_t strength) +{ + ALOGV("%s: ctxt %p, strength: %d", __func__, context, strength); + context->strength = strength; + + offload_bassboost_set_strength(&(context->offload_bass), strength); + if (context->ctl) + offload_bassboost_send_params(context->ctl, context->offload_bass, + OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG | + OFFLOAD_SEND_BASSBOOST_STRENGTH); + return 0; +} + +int bassboost_get_parameter(effect_context_t *context, effect_param_t *p, + uint32_t *size) +{ + bassboost_context_t *bass_ctxt = (bassboost_context_t *)context; + int voffset = ((p->psize - 1) / sizeof(int32_t) + 1) * sizeof(int32_t); + int32_t *param_tmp = (int32_t *)p->data; + int32_t param = *param_tmp++; + void *value = p->data + voffset; + int i; + + ALOGV("%s: ctxt %p, param %d", __func__, bass_ctxt, param); + + p->status = 0; + + switch (param) { + case BASSBOOST_PARAM_STRENGTH_SUPPORTED: + if (p->vsize < sizeof(uint32_t)) + p->status = -EINVAL; + p->vsize = sizeof(uint32_t); + break; + case BASSBOOST_PARAM_STRENGTH: + if (p->vsize < sizeof(int16_t)) + p->status = -EINVAL; + p->vsize = sizeof(int16_t); + break; + default: + p->status = -EINVAL; + } + + *size = sizeof(effect_param_t) + voffset + p->vsize; + + if (p->status != 0) + return 0; + + switch (param) { + case BASSBOOST_PARAM_STRENGTH_SUPPORTED: + *(uint32_t *)value = 1; + break; + + case BASSBOOST_PARAM_STRENGTH: + *(int16_t *)value = bassboost_get_strength(bass_ctxt); + break; + + default: + p->status = -EINVAL; + break; + } + + return 0; +} + +int bassboost_set_parameter(effect_context_t *context, effect_param_t *p, + uint32_t size __unused) +{ + bassboost_context_t *bass_ctxt = (bassboost_context_t *)context; + int voffset = ((p->psize - 1) / sizeof(int32_t) + 1) * sizeof(int32_t); + void *value = p->data + voffset; + int32_t *param_tmp = (int32_t *)p->data; + int32_t param = *param_tmp++; + uint32_t strength; + + ALOGV("%s: ctxt %p, param %d", __func__, bass_ctxt, param); + + p->status = 0; + + switch (param) { + case BASSBOOST_PARAM_STRENGTH: + strength = (uint32_t)(*(int16_t *)value); + bassboost_set_strength(bass_ctxt, strength); + break; + default: + p->status = -EINVAL; + break; + } + + return 0; +} + +int bassboost_set_device(effect_context_t *context, uint32_t device) +{ + bassboost_context_t *bass_ctxt = (bassboost_context_t *)context; + + ALOGV("%s: ctxt %p, device 0x%x", __func__, bass_ctxt, device); + bass_ctxt->device = device; + if((device == AUDIO_DEVICE_OUT_SPEAKER) || + (device == AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT) || + (device == AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER) || +#ifdef AFE_PROXY_ENABLED + (device == AUDIO_DEVICE_OUT_PROXY) || +#endif + (device == AUDIO_DEVICE_OUT_AUX_DIGITAL) || + (device == AUDIO_DEVICE_OUT_USB_ACCESSORY) || + (device == AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET)) { + if (!bass_ctxt->temp_disabled) { + if (effect_is_active(&bass_ctxt->common)) { + offload_bassboost_set_enable_flag(&(bass_ctxt->offload_bass), false); + if (bass_ctxt->ctl) + offload_bassboost_send_params(bass_ctxt->ctl, + bass_ctxt->offload_bass, + OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG); + } + bass_ctxt->temp_disabled = true; + } + ALOGI("%s: ctxt %p, disabled based on device", __func__, bass_ctxt); + } else { + if (bass_ctxt->temp_disabled) { + if (effect_is_active(&bass_ctxt->common)) { + offload_bassboost_set_enable_flag(&(bass_ctxt->offload_bass), true); + if (bass_ctxt->ctl) + offload_bassboost_send_params(bass_ctxt->ctl, + bass_ctxt->offload_bass, + OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG); + } + bass_ctxt->temp_disabled = false; + } + } + offload_bassboost_set_device(&(bass_ctxt->offload_bass), device); + return 0; +} + +int bassboost_reset(effect_context_t *context) +{ + bassboost_context_t *bass_ctxt = (bassboost_context_t *)context; + + return 0; +} + +int bassboost_init(effect_context_t *context) +{ + bassboost_context_t *bass_ctxt = (bassboost_context_t *)context; + + ALOGV("%s: ctxt %p", __func__, bass_ctxt); + context->config.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ; + context->config.inputCfg.channels = AUDIO_CHANNEL_OUT_STEREO; + context->config.inputCfg.format = AUDIO_FORMAT_PCM_16_BIT; + context->config.inputCfg.samplingRate = 44100; + context->config.inputCfg.bufferProvider.getBuffer = NULL; + context->config.inputCfg.bufferProvider.releaseBuffer = NULL; + context->config.inputCfg.bufferProvider.cookie = NULL; + context->config.inputCfg.mask = EFFECT_CONFIG_ALL; + context->config.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_ACCUMULATE; + context->config.outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO; + context->config.outputCfg.format = AUDIO_FORMAT_PCM_16_BIT; + context->config.outputCfg.samplingRate = 44100; + context->config.outputCfg.bufferProvider.getBuffer = NULL; + context->config.outputCfg.bufferProvider.releaseBuffer = NULL; + context->config.outputCfg.bufferProvider.cookie = NULL; + context->config.outputCfg.mask = EFFECT_CONFIG_ALL; + + set_config(context, &context->config); + + bass_ctxt->temp_disabled = false; + memset(&(bass_ctxt->offload_bass), 0, sizeof(struct bass_boost_params)); + + return 0; +} + +int bassboost_enable(effect_context_t *context) +{ + bassboost_context_t *bass_ctxt = (bassboost_context_t *)context; + + ALOGV("%s: ctxt %p, strength %d", __func__, bass_ctxt, bass_ctxt->strength); + + if (!offload_bassboost_get_enable_flag(&(bass_ctxt->offload_bass)) && + !(bass_ctxt->temp_disabled)) { + offload_bassboost_set_enable_flag(&(bass_ctxt->offload_bass), true); + if (bass_ctxt->ctl && bass_ctxt->strength) + offload_bassboost_send_params(bass_ctxt->ctl, + bass_ctxt->offload_bass, + OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG | + OFFLOAD_SEND_BASSBOOST_STRENGTH); + } + return 0; +} + +int bassboost_disable(effect_context_t *context) +{ + bassboost_context_t *bass_ctxt = (bassboost_context_t *)context; + + ALOGV("%s: ctxt %p", __func__, bass_ctxt); + if (offload_bassboost_get_enable_flag(&(bass_ctxt->offload_bass))) { + offload_bassboost_set_enable_flag(&(bass_ctxt->offload_bass), false); + if (bass_ctxt->ctl) + offload_bassboost_send_params(bass_ctxt->ctl, + bass_ctxt->offload_bass, + OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG); + } + return 0; +} + +int bassboost_start(effect_context_t *context, output_context_t *output) +{ + bassboost_context_t *bass_ctxt = (bassboost_context_t *)context; + + ALOGV("%s: ctxt %p, ctl %p, strength %d", __func__, bass_ctxt, + output->ctl, bass_ctxt->strength); + bass_ctxt->ctl = output->ctl; + if (offload_bassboost_get_enable_flag(&(bass_ctxt->offload_bass))) + if (bass_ctxt->ctl) + offload_bassboost_send_params(bass_ctxt->ctl, bass_ctxt->offload_bass, + OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG | + OFFLOAD_SEND_BASSBOOST_STRENGTH); + return 0; +} + +int bassboost_stop(effect_context_t *context, output_context_t *output __unused) +{ + bassboost_context_t *bass_ctxt = (bassboost_context_t *)context; + + ALOGV("%s: ctxt %p", __func__, bass_ctxt); + bass_ctxt->ctl = NULL; + return 0; +} diff --git a/msm8909/post_proc/bass_boost.h b/msm8909/post_proc/bass_boost.h new file mode 100644 index 00000000..430a07db --- /dev/null +++ b/msm8909/post_proc/bass_boost.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Not a Contribution. + * + * Copyright (C) 2013 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. + */ + +#ifndef OFFLOAD_EFFECT_BASS_BOOST_H_ +#define OFFLOAD_EFFECT_BASS_BOOST_H_ + +#include "bundle.h" + +extern const effect_descriptor_t bassboost_descriptor; + +typedef struct bassboost_context_s { + effect_context_t common; + + int strength; + + // Offload vars + struct mixer_ctl *ctl; + bool temp_disabled; + uint32_t device; + struct bass_boost_params offload_bass; +} bassboost_context_t; + +int bassboost_get_parameter(effect_context_t *context, effect_param_t *p, + uint32_t *size); + +int bassboost_set_parameter(effect_context_t *context, effect_param_t *p, + uint32_t size); + +int bassboost_set_device(effect_context_t *context, uint32_t device); + +int bassboost_reset(effect_context_t *context); + +int bassboost_init(effect_context_t *context); + +int bassboost_enable(effect_context_t *context); + +int bassboost_disable(effect_context_t *context); + +int bassboost_start(effect_context_t *context, output_context_t *output); + +int bassboost_stop(effect_context_t *context, output_context_t *output); + +#endif /* OFFLOAD_EFFECT_BASS_BOOST_H_ */ diff --git a/msm8909/post_proc/bundle.c b/msm8909/post_proc/bundle.c new file mode 100644 index 00000000..37e78b16 --- /dev/null +++ b/msm8909/post_proc/bundle.c @@ -0,0 +1,780 @@ +/* + * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. + * Not a Contribution. + * + * Copyright (C) 2013 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 "offload_effect_bundle" +#define LOG_NDEBUG 0 + +#include <cutils/list.h> +#include <cutils/log.h> +#include <system/thread_defs.h> +#include <tinyalsa/asoundlib.h> +#include <hardware/audio_effect.h> +#include <stdlib.h> + +#include "bundle.h" +#include "equalizer.h" +#include "bass_boost.h" +#include "virtualizer.h" +#include "reverb.h" + +enum { + EFFECT_STATE_UNINITIALIZED, + EFFECT_STATE_INITIALIZED, + EFFECT_STATE_ACTIVE, +}; + +const effect_descriptor_t *descriptors[] = { + &equalizer_descriptor, + &bassboost_descriptor, + &virtualizer_descriptor, + &aux_env_reverb_descriptor, + &ins_env_reverb_descriptor, + &aux_preset_reverb_descriptor, + &ins_preset_reverb_descriptor, + NULL, +}; + +pthread_once_t once = PTHREAD_ONCE_INIT; +int init_status; +/* + * list of created effects. + * Updated by offload_effects_bundle_hal_start_output() + * and offload_effects_bundle_hal_stop_output() + */ +struct listnode created_effects_list; +/* + * list of active output streams. + * Updated by offload_effects_bundle_hal_start_output() + * and offload_effects_bundle_hal_stop_output() + */ +struct listnode active_outputs_list; +/* + * lock must be held when modifying or accessing + * created_effects_list or active_outputs_list + */ +pthread_mutex_t lock; + + +/* + * Local functions + */ +static void init_once() { + list_init(&created_effects_list); + list_init(&active_outputs_list); + + pthread_mutex_init(&lock, NULL); + + init_status = 0; +} + +int lib_init() +{ + pthread_once(&once, init_once); + return init_status; +} + +bool effect_exists(effect_context_t *context) +{ + struct listnode *node; + + list_for_each(node, &created_effects_list) { + effect_context_t *fx_ctxt = node_to_item(node, + effect_context_t, + effects_list_node); + if (fx_ctxt == context) { + return true; + } + } + return false; +} + +output_context_t *get_output(audio_io_handle_t output) +{ + struct listnode *node; + + list_for_each(node, &active_outputs_list) { + output_context_t *out_ctxt = node_to_item(node, + output_context_t, + outputs_list_node); + if (out_ctxt->handle == output) + return out_ctxt; + } + return NULL; +} + +void add_effect_to_output(output_context_t * output, effect_context_t *context) +{ + struct listnode *fx_node; + + ALOGV("%s: e_ctxt %p, o_ctxt %p", __func__, context, output); + list_for_each(fx_node, &output->effects_list) { + effect_context_t *fx_ctxt = node_to_item(fx_node, + effect_context_t, + output_node); + if (fx_ctxt == context) + return; + } + list_add_tail(&output->effects_list, &context->output_node); + if (context->ops.start) + context->ops.start(context, output); + +} + +void remove_effect_from_output(output_context_t * output, + effect_context_t *context) +{ + struct listnode *fx_node; + + ALOGV("%s: e_ctxt %p, o_ctxt %p", __func__, context, output); + list_for_each(fx_node, &output->effects_list) { + effect_context_t *fx_ctxt = node_to_item(fx_node, + effect_context_t, + output_node); + if (fx_ctxt == context) { + if (context->ops.stop) + context->ops.stop(context, output); + list_remove(&context->output_node); + return; + } + } +} + +bool effects_enabled() +{ + struct listnode *out_node; + + list_for_each(out_node, &active_outputs_list) { + struct listnode *fx_node; + output_context_t *out_ctxt = node_to_item(out_node, + output_context_t, + outputs_list_node); + + list_for_each(fx_node, &out_ctxt->effects_list) { + effect_context_t *fx_ctxt = node_to_item(fx_node, + effect_context_t, + output_node); + if ((fx_ctxt->state == EFFECT_STATE_ACTIVE) && + (fx_ctxt->ops.process != NULL)) + return true; + } + } + return false; +} + + +/* + * Interface from audio HAL + */ +__attribute__ ((visibility ("default"))) +int offload_effects_bundle_hal_start_output(audio_io_handle_t output, int pcm_id) +{ + int ret = 0; + struct listnode *node; + char mixer_string[128]; + output_context_t * out_ctxt = NULL; + + ALOGV("%s output %d pcm_id %d", __func__, output, pcm_id); + + if (lib_init() != 0) + return init_status; + + pthread_mutex_lock(&lock); + if (get_output(output) != NULL) { + ALOGW("%s output already started", __func__); + ret = -ENOSYS; + goto exit; + } + + out_ctxt = (output_context_t *) + malloc(sizeof(output_context_t)); + if (!out_ctxt) { + ALOGE("%s fail to allocate for output context", __func__); + ret = -ENOMEM; + goto exit; + } + out_ctxt->handle = output; + out_ctxt->pcm_device_id = pcm_id; + + /* populate the mixer control to send offload parameters */ + snprintf(mixer_string, sizeof(mixer_string), + "%s %d", "Audio Effects Config", out_ctxt->pcm_device_id); + out_ctxt->mixer = mixer_open(MIXER_CARD); + if (!out_ctxt->mixer) { + ALOGE("Failed to open mixer"); + out_ctxt->ctl = NULL; + ret = -EINVAL; + free(out_ctxt); + goto exit; + } else { + out_ctxt->ctl = mixer_get_ctl_by_name(out_ctxt->mixer, mixer_string); + if (!out_ctxt->ctl) { + ALOGE("mixer_get_ctl_by_name failed"); + mixer_close(out_ctxt->mixer); + out_ctxt->mixer = NULL; + ret = -EINVAL; + free(out_ctxt); + goto exit; + } + } + + list_init(&out_ctxt->effects_list); + + list_for_each(node, &created_effects_list) { + effect_context_t *fx_ctxt = node_to_item(node, + effect_context_t, + effects_list_node); + if (fx_ctxt->out_handle == output) { + if (fx_ctxt->ops.start) + fx_ctxt->ops.start(fx_ctxt, out_ctxt); + list_add_tail(&out_ctxt->effects_list, &fx_ctxt->output_node); + } + } + list_add_tail(&active_outputs_list, &out_ctxt->outputs_list_node); +exit: + pthread_mutex_unlock(&lock); + return ret; +} + +__attribute__ ((visibility ("default"))) +int offload_effects_bundle_hal_stop_output(audio_io_handle_t output, int pcm_id) +{ + int ret; + struct listnode *node; + struct listnode *fx_node; + output_context_t *out_ctxt; + + ALOGV("%s output %d pcm_id %d", __func__, output, pcm_id); + + if (lib_init() != 0) + return init_status; + + pthread_mutex_lock(&lock); + + out_ctxt = get_output(output); + if (out_ctxt == NULL) { + ALOGW("%s output not started", __func__); + ret = -ENOSYS; + goto exit; + } + + if (out_ctxt->mixer) + mixer_close(out_ctxt->mixer); + + list_for_each(fx_node, &out_ctxt->effects_list) { + effect_context_t *fx_ctxt = node_to_item(fx_node, + effect_context_t, + output_node); + if (fx_ctxt->ops.stop) + fx_ctxt->ops.stop(fx_ctxt, out_ctxt); + } + + list_remove(&out_ctxt->outputs_list_node); + + free(out_ctxt); + +exit: + pthread_mutex_unlock(&lock); + return ret; +} + + +/* + * Effect operations + */ +int set_config(effect_context_t *context, effect_config_t *config) +{ + context->config = *config; + + if (context->ops.reset) + context->ops.reset(context); + + return 0; +} + +void get_config(effect_context_t *context, effect_config_t *config) +{ + *config = context->config; +} + + +/* + * Effect Library Interface Implementation + */ +int effect_lib_create(const effect_uuid_t *uuid, + int32_t sessionId, + int32_t ioId, + effect_handle_t *pHandle) { + int ret; + int i; + + ALOGV("%s: sessionId: %d, ioId: %d", __func__, sessionId, ioId); + if (lib_init() != 0) + return init_status; + + if (pHandle == NULL || uuid == NULL) + return -EINVAL; + + for (i = 0; descriptors[i] != NULL; i++) { + if (memcmp(uuid, &descriptors[i]->uuid, sizeof(effect_uuid_t)) == 0) + break; + } + + if (descriptors[i] == NULL) + return -EINVAL; + + effect_context_t *context; + if (memcmp(uuid, &equalizer_descriptor.uuid, + sizeof(effect_uuid_t)) == 0) { + equalizer_context_t *eq_ctxt = (equalizer_context_t *) + calloc(1, sizeof(equalizer_context_t)); + if (eq_ctxt == NULL) { + return -ENOMEM; + } + context = (effect_context_t *)eq_ctxt; + context->ops.init = equalizer_init; + context->ops.reset = equalizer_reset; + context->ops.set_parameter = equalizer_set_parameter; + context->ops.get_parameter = equalizer_get_parameter; + context->ops.set_device = equalizer_set_device; + context->ops.enable = equalizer_enable; + context->ops.disable = equalizer_disable; + context->ops.start = equalizer_start; + context->ops.stop = equalizer_stop; + + context->desc = &equalizer_descriptor; + eq_ctxt->ctl = NULL; + } else if (memcmp(uuid, &bassboost_descriptor.uuid, + sizeof(effect_uuid_t)) == 0) { + bassboost_context_t *bass_ctxt = (bassboost_context_t *) + calloc(1, sizeof(bassboost_context_t)); + if (bass_ctxt == NULL) { + return -ENOMEM; + } + context = (effect_context_t *)bass_ctxt; + context->ops.init = bassboost_init; + context->ops.reset = bassboost_reset; + context->ops.set_parameter = bassboost_set_parameter; + context->ops.get_parameter = bassboost_get_parameter; + context->ops.set_device = bassboost_set_device; + context->ops.enable = bassboost_enable; + context->ops.disable = bassboost_disable; + context->ops.start = bassboost_start; + context->ops.stop = bassboost_stop; + + context->desc = &bassboost_descriptor; + bass_ctxt->ctl = NULL; + } else if (memcmp(uuid, &virtualizer_descriptor.uuid, + sizeof(effect_uuid_t)) == 0) { + virtualizer_context_t *virt_ctxt = (virtualizer_context_t *) + calloc(1, sizeof(virtualizer_context_t)); + if (virt_ctxt == NULL) { + return -ENOMEM; + } + context = (effect_context_t *)virt_ctxt; + context->ops.init = virtualizer_init; + context->ops.reset = virtualizer_reset; + context->ops.set_parameter = virtualizer_set_parameter; + context->ops.get_parameter = virtualizer_get_parameter; + context->ops.set_device = virtualizer_set_device; + context->ops.enable = virtualizer_enable; + context->ops.disable = virtualizer_disable; + context->ops.start = virtualizer_start; + context->ops.stop = virtualizer_stop; + + context->desc = &virtualizer_descriptor; + virt_ctxt->ctl = NULL; + } else if ((memcmp(uuid, &aux_env_reverb_descriptor.uuid, + sizeof(effect_uuid_t)) == 0) || + (memcmp(uuid, &ins_env_reverb_descriptor.uuid, + sizeof(effect_uuid_t)) == 0) || + (memcmp(uuid, &aux_preset_reverb_descriptor.uuid, + sizeof(effect_uuid_t)) == 0) || + (memcmp(uuid, &ins_preset_reverb_descriptor.uuid, + sizeof(effect_uuid_t)) == 0)) { + reverb_context_t *reverb_ctxt = (reverb_context_t *) + calloc(1, sizeof(reverb_context_t)); + if (reverb_ctxt == NULL) { + return -ENOMEM; + } + context = (effect_context_t *)reverb_ctxt; + context->ops.init = reverb_init; + context->ops.reset = reverb_reset; + context->ops.set_parameter = reverb_set_parameter; + context->ops.get_parameter = reverb_get_parameter; + context->ops.set_device = reverb_set_device; + context->ops.enable = reverb_enable; + context->ops.disable = reverb_disable; + context->ops.start = reverb_start; + context->ops.stop = reverb_stop; + + if (memcmp(uuid, &aux_env_reverb_descriptor.uuid, + sizeof(effect_uuid_t)) == 0) { + context->desc = &aux_env_reverb_descriptor; + reverb_auxiliary_init(reverb_ctxt); + } else if (memcmp(uuid, &ins_env_reverb_descriptor.uuid, + sizeof(effect_uuid_t)) == 0) { + context->desc = &ins_env_reverb_descriptor; + reverb_preset_init(reverb_ctxt); + } else if (memcmp(uuid, &aux_preset_reverb_descriptor.uuid, + sizeof(effect_uuid_t)) == 0) { + context->desc = &aux_preset_reverb_descriptor; + reverb_auxiliary_init(reverb_ctxt); + } else if (memcmp(uuid, &ins_preset_reverb_descriptor.uuid, + sizeof(effect_uuid_t)) == 0) { + context->desc = &ins_preset_reverb_descriptor; + reverb_preset_init(reverb_ctxt); + } + reverb_ctxt->ctl = NULL; + } else { + return -EINVAL; + } + + context->itfe = &effect_interface; + context->state = EFFECT_STATE_UNINITIALIZED; + context->out_handle = (audio_io_handle_t)ioId; + + ret = context->ops.init(context); + if (ret < 0) { + ALOGW("%s init failed", __func__); + free(context); + return ret; + } + + context->state = EFFECT_STATE_INITIALIZED; + + pthread_mutex_lock(&lock); + list_add_tail(&created_effects_list, &context->effects_list_node); + output_context_t *out_ctxt = get_output(ioId); + if (out_ctxt != NULL) + add_effect_to_output(out_ctxt, context); + pthread_mutex_unlock(&lock); + + *pHandle = (effect_handle_t)context; + + ALOGV("%s created context %p", __func__, context); + + return 0; + +} + +int effect_lib_release(effect_handle_t handle) +{ + effect_context_t *context = (effect_context_t *)handle; + int status; + + if (lib_init() != 0) + return init_status; + + ALOGV("%s context %p", __func__, handle); + pthread_mutex_lock(&lock); + status = -EINVAL; + if (effect_exists(context)) { + output_context_t *out_ctxt = get_output(context->out_handle); + if (out_ctxt != NULL) + remove_effect_from_output(out_ctxt, context); + list_remove(&context->effects_list_node); + if (context->ops.release) + context->ops.release(context); + free(context); + status = 0; + } + pthread_mutex_unlock(&lock); + + return status; +} + +int effect_lib_get_descriptor(const effect_uuid_t *uuid, + effect_descriptor_t *descriptor) +{ + int i; + + if (lib_init() != 0) + return init_status; + + if (descriptor == NULL || uuid == NULL) { + ALOGV("%s called with NULL pointer", __func__); + return -EINVAL; + } + + for (i = 0; descriptors[i] != NULL; i++) { + if (memcmp(uuid, &descriptors[i]->uuid, sizeof(effect_uuid_t)) == 0) { + *descriptor = *descriptors[i]; + return 0; + } + } + + return -EINVAL; +} + + +/* + * Effect Control Interface Implementation + */ + +/* Stub function for effect interface: never called for offloaded effects */ +int effect_process(effect_handle_t self, + audio_buffer_t *inBuffer __unused, + audio_buffer_t *outBuffer __unused) +{ + effect_context_t * context = (effect_context_t *)self; + int status = 0; + + ALOGW("%s: ctxt %p, Called ?????", __func__, context); + + pthread_mutex_lock(&lock); + if (!effect_exists(context)) { + status = -ENOSYS; + goto exit; + } + + if (context->state != EFFECT_STATE_ACTIVE) { + status = -ENODATA; + goto exit; + } + +exit: + pthread_mutex_unlock(&lock); + return status; +} + +int effect_command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize, + void *pCmdData, uint32_t *replySize, void *pReplyData) +{ + + effect_context_t * context = (effect_context_t *)self; + int retsize; + int status = 0; + + pthread_mutex_lock(&lock); + + if (!effect_exists(context)) { + status = -ENOSYS; + goto exit; + } + + ALOGV("%s: ctxt %p, cmd %d", __func__, context, cmdCode); + if (context == NULL || context->state == EFFECT_STATE_UNINITIALIZED) { + status = -ENOSYS; + goto exit; + } + + switch (cmdCode) { + case EFFECT_CMD_INIT: + if (pReplyData == NULL || *replySize != sizeof(int)) { + status = -EINVAL; + goto exit; + } + if (context->ops.init) + *(int *) pReplyData = context->ops.init(context); + else + *(int *) pReplyData = 0; + break; + case EFFECT_CMD_SET_CONFIG: + if (pCmdData == NULL || cmdSize != sizeof(effect_config_t) + || pReplyData == NULL || *replySize != sizeof(int)) { + status = -EINVAL; + goto exit; + } + *(int *) pReplyData = set_config(context, (effect_config_t *) pCmdData); + break; + case EFFECT_CMD_GET_CONFIG: + if (pReplyData == NULL || + *replySize != sizeof(effect_config_t)) { + status = -EINVAL; + goto exit; + } + if (!context->offload_enabled) { + status = -EINVAL; + goto exit; + } + + get_config(context, (effect_config_t *)pReplyData); + break; + case EFFECT_CMD_RESET: + if (context->ops.reset) + context->ops.reset(context); + break; + case EFFECT_CMD_ENABLE: + if (pReplyData == NULL || *replySize != sizeof(int)) { + status = -EINVAL; + goto exit; + } + if (context->state != EFFECT_STATE_INITIALIZED) { + status = -ENOSYS; + goto exit; + } + context->state = EFFECT_STATE_ACTIVE; + if (context->ops.enable) + context->ops.enable(context); + *(int *)pReplyData = 0; + break; + case EFFECT_CMD_DISABLE: + if (pReplyData == NULL || *replySize != sizeof(int)) { + status = -EINVAL; + goto exit; + } + if (context->state != EFFECT_STATE_ACTIVE) { + status = -ENOSYS; + goto exit; + } + context->state = EFFECT_STATE_INITIALIZED; + if (context->ops.disable) + context->ops.disable(context); + *(int *)pReplyData = 0; + break; + case EFFECT_CMD_GET_PARAM: { + if (pCmdData == NULL || + cmdSize < (int)(sizeof(effect_param_t) + sizeof(uint32_t)) || + pReplyData == NULL || + *replySize < (int)(sizeof(effect_param_t) + sizeof(uint32_t) + + sizeof(uint16_t))) { + status = -EINVAL; + ALOGW("EFFECT_CMD_GET_PARAM invalid command cmdSize %d *replySize %d", + cmdSize, *replySize); + goto exit; + } + if (!context->offload_enabled) { + status = -EINVAL; + goto exit; + } + effect_param_t *q = (effect_param_t *)pCmdData; + memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + q->psize); + effect_param_t *p = (effect_param_t *)pReplyData; + if (context->ops.get_parameter) + context->ops.get_parameter(context, p, replySize); + } break; + case EFFECT_CMD_SET_PARAM: { + if (pCmdData == NULL || + cmdSize < (int)(sizeof(effect_param_t) + sizeof(uint32_t) + + sizeof(uint16_t)) || + pReplyData == NULL || *replySize != sizeof(int32_t)) { + status = -EINVAL; + ALOGW("EFFECT_CMD_SET_PARAM invalid command cmdSize %d *replySize %d", + cmdSize, *replySize); + goto exit; + } + *(int32_t *)pReplyData = 0; + effect_param_t *p = (effect_param_t *)pCmdData; + if (context->ops.set_parameter) + *(int32_t *)pReplyData = context->ops.set_parameter(context, p, + *replySize); + + } break; + case EFFECT_CMD_SET_DEVICE: { + uint32_t device; + ALOGV("\t EFFECT_CMD_SET_DEVICE start"); + if (pCmdData == NULL || cmdSize < sizeof(uint32_t)) { + status = -EINVAL; + ALOGW("EFFECT_CMD_SET_DEVICE invalid command cmdSize %d", cmdSize); + goto exit; + } + device = *(uint32_t *)pCmdData; + if (context->ops.set_device) + context->ops.set_device(context, device); + } break; + case EFFECT_CMD_SET_VOLUME: + case EFFECT_CMD_SET_AUDIO_MODE: + break; + + case EFFECT_CMD_OFFLOAD: { + output_context_t *out_ctxt; + + if (cmdSize != sizeof(effect_offload_param_t) || pCmdData == NULL + || pReplyData == NULL || *replySize != sizeof(int)) { + ALOGW("%s EFFECT_CMD_OFFLOAD bad format", __func__); + status = -EINVAL; + break; + } + + effect_offload_param_t* offload_param = (effect_offload_param_t*)pCmdData; + + ALOGV("%s EFFECT_CMD_OFFLOAD offload %d output %d", __func__, + offload_param->isOffload, offload_param->ioHandle); + + *(int *)pReplyData = 0; + + context->offload_enabled = offload_param->isOffload; + if (context->out_handle == offload_param->ioHandle) + break; + + out_ctxt = get_output(context->out_handle); + if (out_ctxt != NULL) + remove_effect_from_output(out_ctxt, context); + + context->out_handle = offload_param->ioHandle; + out_ctxt = get_output(context->out_handle); + if (out_ctxt != NULL) + add_effect_to_output(out_ctxt, context); + + } break; + + + default: + if (cmdCode >= EFFECT_CMD_FIRST_PROPRIETARY && context->ops.command) + status = context->ops.command(context, cmdCode, cmdSize, + pCmdData, replySize, pReplyData); + else { + ALOGW("%s invalid command %d", __func__, cmdCode); + status = -EINVAL; + } + break; + } + +exit: + pthread_mutex_unlock(&lock); + + return status; +} + +/* Effect Control Interface Implementation: get_descriptor */ +int effect_get_descriptor(effect_handle_t self, + effect_descriptor_t *descriptor) +{ + effect_context_t *context = (effect_context_t *)self; + + if (!effect_exists(context) || (descriptor == NULL)) + return -EINVAL; + + *descriptor = *context->desc; + + return 0; +} + +bool effect_is_active(effect_context_t * ctxt) { + return ctxt->state == EFFECT_STATE_ACTIVE; +} + +/* effect_handle_t interface implementation for offload effects */ +const struct effect_interface_s effect_interface = { + effect_process, + effect_command, + effect_get_descriptor, + NULL, +}; + +__attribute__ ((visibility ("default"))) +audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = { + tag : AUDIO_EFFECT_LIBRARY_TAG, + version : EFFECT_LIBRARY_API_VERSION, + name : "Offload Effects Bundle Library", + implementor : "The Linux Foundation", + create_effect : effect_lib_create, + release_effect : effect_lib_release, + get_descriptor : effect_lib_get_descriptor, +}; diff --git a/msm8909/post_proc/bundle.h b/msm8909/post_proc/bundle.h new file mode 100644 index 00000000..cbe7dba8 --- /dev/null +++ b/msm8909/post_proc/bundle.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Not a contribution. + * + * Copyright (C) 2013 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. + */ + +#ifndef OFFLOAD_EFFECT_BUNDLE_H +#define OFFLOAD_EFFECT_BUNDLE_H + +#include <tinyalsa/asoundlib.h> +#include <sound/audio_effects.h> +#include "effect_api.h" + +/* Retry for delay for mixer open */ +#define RETRY_NUMBER 10 +#define RETRY_US 500000 + +#define MIXER_CARD 0 +#define SOUND_CARD 0 + +extern const struct effect_interface_s effect_interface; + +typedef struct output_context_s output_context_t; +typedef struct effect_ops_s effect_ops_t; +typedef struct effect_context_s effect_context_t; + +struct output_context_s { + /* node in active_outputs_list */ + struct listnode outputs_list_node; + /* io handle */ + audio_io_handle_t handle; + /* list of effects attached to this output */ + struct listnode effects_list; + /* pcm device id */ + int pcm_device_id; + struct mixer *mixer; + struct mixer_ctl *ctl; +}; + +/* effect specific operations. + * Only the init() and process() operations must be defined. + * Others are optional. + */ +struct effect_ops_s { + int (*init)(effect_context_t *context); + int (*release)(effect_context_t *context); + int (*reset)(effect_context_t *context); + int (*enable)(effect_context_t *context); + int (*start)(effect_context_t *context, output_context_t *output); + int (*stop)(effect_context_t *context, output_context_t *output); + int (*disable)(effect_context_t *context); + int (*process)(effect_context_t *context, audio_buffer_t *in, audio_buffer_t *out); + int (*set_parameter)(effect_context_t *context, effect_param_t *param, uint32_t size); + int (*get_parameter)(effect_context_t *context, effect_param_t *param, uint32_t *size); + int (*set_device)(effect_context_t *context, uint32_t device); + int (*command)(effect_context_t *context, uint32_t cmdCode, uint32_t cmdSize, + void *pCmdData, uint32_t *replySize, void *pReplyData); +}; + +struct effect_context_s { + const struct effect_interface_s *itfe; + /* node in created_effects_list */ + struct listnode effects_list_node; + /* node in output_context_t.effects_list */ + struct listnode output_node; + effect_config_t config; + const effect_descriptor_t *desc; + /* io handle of the output the effect is attached to */ + audio_io_handle_t out_handle; + uint32_t state; + bool offload_enabled; + effect_ops_t ops; +}; + +int set_config(effect_context_t *context, effect_config_t *config); + +bool effect_is_active(effect_context_t *context); + +#endif /* OFFLOAD_EFFECT_BUNDLE_H */ diff --git a/msm8909/post_proc/effect_api.c b/msm8909/post_proc/effect_api.c new file mode 100644 index 00000000..10ccfecb --- /dev/null +++ b/msm8909/post_proc/effect_api.c @@ -0,0 +1,620 @@ +/* + * Copyright (c) 2013-2014, 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 "offload_effect_api" +#define LOG_NDEBUG 0 +//#define VERY_VERY_VERBOSE_LOGGING +#ifdef VERY_VERY_VERBOSE_LOGGING +#define ALOGVV ALOGV +#else +#define ALOGVV(a...) do { } while(0) +#endif + +#include <stdbool.h> +#include <cutils/log.h> +#include <tinyalsa/asoundlib.h> +#include <sound/audio_effects.h> +#include <errno.h> + +#include "effect_api.h" + +#define ARRAY_SIZE(array) (sizeof array / sizeof array[0]) + +#define OFFLOAD_PRESET_START_OFFSET_FOR_OPENSL 19 +const int map_eq_opensl_preset_2_offload_preset[] = { + OFFLOAD_PRESET_START_OFFSET_FOR_OPENSL, /* Normal Preset */ + OFFLOAD_PRESET_START_OFFSET_FOR_OPENSL+1, /* Classical Preset */ + OFFLOAD_PRESET_START_OFFSET_FOR_OPENSL+2, /* Dance Preset */ + OFFLOAD_PRESET_START_OFFSET_FOR_OPENSL+3, /* Flat Preset */ + OFFLOAD_PRESET_START_OFFSET_FOR_OPENSL+4, /* Folk Preset */ + OFFLOAD_PRESET_START_OFFSET_FOR_OPENSL+5, /* Heavy Metal Preset */ + OFFLOAD_PRESET_START_OFFSET_FOR_OPENSL+6, /* Hip Hop Preset */ + OFFLOAD_PRESET_START_OFFSET_FOR_OPENSL+7, /* Jazz Preset */ + OFFLOAD_PRESET_START_OFFSET_FOR_OPENSL+8, /* Pop Preset */ + OFFLOAD_PRESET_START_OFFSET_FOR_OPENSL+9, /* Rock Preset */ + OFFLOAD_PRESET_START_OFFSET_FOR_OPENSL+10 /* FX Booster */ +}; + +const int map_reverb_opensl_preset_2_offload_preset + [NUM_OSL_REVERB_PRESETS_SUPPORTED][2] = { + {1, 15}, + {2, 16}, + {3, 17}, + {4, 18}, + {5, 3}, + {6, 20} +}; + +int offload_update_mixer_and_effects_ctl(int card, int device_id, + struct mixer *mixer, + struct mixer_ctl *ctl) +{ + char mixer_string[128]; + + snprintf(mixer_string, sizeof(mixer_string), + "%s %d", "Audio Effects Config", device_id); + ALOGV("%s: mixer_string: %s", __func__, mixer_string); + mixer = mixer_open(card); + if (!mixer) { + ALOGE("Failed to open mixer"); + ctl = NULL; + return -EINVAL; + } else { + ctl = mixer_get_ctl_by_name(mixer, mixer_string); + if (!ctl) { + ALOGE("mixer_get_ctl_by_name failed"); + mixer_close(mixer); + mixer = NULL; + return -EINVAL; + } + } + ALOGV("mixer: %p, ctl: %p", mixer, ctl); + return 0; +} + +void offload_close_mixer(struct mixer *mixer) +{ + mixer_close(mixer); +} + +void offload_bassboost_set_device(struct bass_boost_params *bassboost, + uint32_t device) +{ + ALOGVV("%s: device 0x%x", __func__, device); + bassboost->device = device; +} + +void offload_bassboost_set_enable_flag(struct bass_boost_params *bassboost, + bool enable) +{ + ALOGVV("%s: enable=%d", __func__, (int)enable); + bassboost->enable_flag = enable; +} + +int offload_bassboost_get_enable_flag(struct bass_boost_params *bassboost) +{ + ALOGVV("%s: enable=%d", __func__, (int)bassboost->enable_flag); + return bassboost->enable_flag; +} + +void offload_bassboost_set_strength(struct bass_boost_params *bassboost, + int strength) +{ + ALOGVV("%s: strength %d", __func__, strength); + bassboost->strength = strength; +} + +void offload_bassboost_set_mode(struct bass_boost_params *bassboost, + int mode) +{ + ALOGVV("%s: mode %d", __func__, mode); + bassboost->mode = mode; +} + +int offload_bassboost_send_params(struct mixer_ctl *ctl, + struct bass_boost_params bassboost, + unsigned param_send_flags) +{ + int param_values[128] = {0}; + int *p_param_values = param_values; + + ALOGV("%s: flags 0x%x", __func__, param_send_flags); + *p_param_values++ = BASS_BOOST_MODULE; + *p_param_values++ = bassboost.device; + *p_param_values++ = 0; /* num of commands*/ + if (param_send_flags & OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG) { + *p_param_values++ = BASS_BOOST_ENABLE; + *p_param_values++ = CONFIG_SET; + *p_param_values++ = 0; /* start offset if param size if greater than 128 */ + *p_param_values++ = BASS_BOOST_ENABLE_PARAM_LEN; + *p_param_values++ = bassboost.enable_flag; + param_values[2] += 1; + } + if (param_send_flags & OFFLOAD_SEND_BASSBOOST_STRENGTH) { + *p_param_values++ = BASS_BOOST_STRENGTH; + *p_param_values++ = CONFIG_SET; + *p_param_values++ = 0; /* start offset if param size if greater than 128 */ + *p_param_values++ = BASS_BOOST_STRENGTH_PARAM_LEN; + *p_param_values++ = bassboost.strength; + param_values[2] += 1; + } + if (param_send_flags & OFFLOAD_SEND_BASSBOOST_MODE) { + *p_param_values++ = BASS_BOOST_MODE; + *p_param_values++ = CONFIG_SET; + *p_param_values++ = 0; /* start offset if param size if greater than 128 */ + *p_param_values++ = BASS_BOOST_MODE_PARAM_LEN; + *p_param_values++ = bassboost.mode; + param_values[2] += 1; + } + + if (param_values[2] && ctl) + mixer_ctl_set_array(ctl, param_values, ARRAY_SIZE(param_values)); + + return 0; +} + +void offload_virtualizer_set_device(struct virtualizer_params *virtualizer, + uint32_t device) +{ + ALOGVV("%s: device=0x%x", __func__, device); + virtualizer->device = device; +} + +void offload_virtualizer_set_enable_flag(struct virtualizer_params *virtualizer, + bool enable) +{ + ALOGVV("%s: enable=%d", __func__, (int)enable); + virtualizer->enable_flag = enable; +} + +int offload_virtualizer_get_enable_flag(struct virtualizer_params *virtualizer) +{ + ALOGVV("%s: enabled %d", __func__, (int)virtualizer->enable_flag); + return virtualizer->enable_flag; +} + +void offload_virtualizer_set_strength(struct virtualizer_params *virtualizer, + int strength) +{ + ALOGVV("%s: strength %d", __func__, strength); + virtualizer->strength = strength; +} + +void offload_virtualizer_set_out_type(struct virtualizer_params *virtualizer, + int out_type) +{ + ALOGVV("%s: out_type %d", __func__, out_type); + virtualizer->out_type = out_type; +} + +void offload_virtualizer_set_gain_adjust(struct virtualizer_params *virtualizer, + int gain_adjust) +{ + ALOGVV("%s: gain %d", __func__, gain_adjust); + virtualizer->gain_adjust = gain_adjust; +} + +int offload_virtualizer_send_params(struct mixer_ctl *ctl, + struct virtualizer_params virtualizer, + unsigned param_send_flags) +{ + int param_values[128] = {0}; + int *p_param_values = param_values; + + ALOGV("%s: flags 0x%x", __func__, param_send_flags); + *p_param_values++ = VIRTUALIZER_MODULE; + *p_param_values++ = virtualizer.device; + *p_param_values++ = 0; /* num of commands*/ + if (param_send_flags & OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG) { + *p_param_values++ = VIRTUALIZER_ENABLE; + *p_param_values++ = CONFIG_SET; + *p_param_values++ = 0; /* start offset if param size if greater than 128 */ + *p_param_values++ = VIRTUALIZER_ENABLE_PARAM_LEN; + *p_param_values++ = virtualizer.enable_flag; + param_values[2] += 1; + } + if (param_send_flags & OFFLOAD_SEND_VIRTUALIZER_STRENGTH) { + *p_param_values++ = VIRTUALIZER_STRENGTH; + *p_param_values++ = CONFIG_SET; + *p_param_values++ = 0; /* start offset if param size if greater than 128 */ + *p_param_values++ = VIRTUALIZER_STRENGTH_PARAM_LEN; + *p_param_values++ = virtualizer.strength; + param_values[2] += 1; + } + if (param_send_flags & OFFLOAD_SEND_VIRTUALIZER_OUT_TYPE) { + *p_param_values++ = VIRTUALIZER_OUT_TYPE; + *p_param_values++ = CONFIG_SET; + *p_param_values++ = 0; /* start offset if param size if greater than 128 */ + *p_param_values++ = VIRTUALIZER_OUT_TYPE_PARAM_LEN; + *p_param_values++ = virtualizer.out_type; + param_values[2] += 1; + } + if (param_send_flags & OFFLOAD_SEND_VIRTUALIZER_GAIN_ADJUST) { + *p_param_values++ = VIRTUALIZER_GAIN_ADJUST; + *p_param_values++ = CONFIG_SET; + *p_param_values++ = 0; /* start offset if param size if greater than 128 */ + *p_param_values++ = VIRTUALIZER_GAIN_ADJUST_PARAM_LEN; + *p_param_values++ = virtualizer.gain_adjust; + param_values[2] += 1; + } + + if (param_values[2] && ctl) + mixer_ctl_set_array(ctl, param_values, ARRAY_SIZE(param_values)); + + return 0; +} + +void offload_eq_set_device(struct eq_params *eq, uint32_t device) +{ + ALOGVV("%s: device 0x%x", __func__, device); + eq->device = device; +} + +void offload_eq_set_enable_flag(struct eq_params *eq, bool enable) +{ + ALOGVV("%s: enable=%d", __func__, (int)enable); + eq->enable_flag = enable; +} + +int offload_eq_get_enable_flag(struct eq_params *eq) +{ + ALOGVV("%s: enabled=%d", __func__, (int)eq->enable_flag); + return eq->enable_flag; +} + +void offload_eq_set_preset(struct eq_params *eq, int preset) +{ + ALOGVV("%s: preset %d", __func__, preset); + eq->config.preset_id = preset; + eq->config.eq_pregain = Q27_UNITY; +} + +void offload_eq_set_bands_level(struct eq_params *eq, int num_bands, + const uint16_t *band_freq_list, + int *band_gain_list) +{ + int i; + ALOGVV("%s", __func__); + eq->config.num_bands = num_bands; + for (i=0; i<num_bands; i++) { + eq->per_band_cfg[i].band_idx = i; + eq->per_band_cfg[i].filter_type = EQ_BAND_BOOST; + eq->per_band_cfg[i].freq_millihertz = band_freq_list[i] * 1000; + eq->per_band_cfg[i].gain_millibels = band_gain_list[i] * 100; + eq->per_band_cfg[i].quality_factor = Q8_UNITY; + } +} + +int offload_eq_send_params(struct mixer_ctl *ctl, struct eq_params eq, + unsigned param_send_flags) +{ + int param_values[128] = {0}; + int *p_param_values = param_values; + uint32_t i; + + ALOGV("%s: flags 0x%x", __func__, param_send_flags); + if ((eq.config.preset_id < -1) || + ((param_send_flags & OFFLOAD_SEND_EQ_PRESET) && (eq.config.preset_id == -1))) { + ALOGV("No Valid preset to set"); + return 0; + } + *p_param_values++ = EQ_MODULE; + *p_param_values++ = eq.device; + *p_param_values++ = 0; /* num of commands*/ + if (param_send_flags & OFFLOAD_SEND_EQ_ENABLE_FLAG) { + *p_param_values++ = EQ_ENABLE; + *p_param_values++ = CONFIG_SET; + *p_param_values++ = 0; /* start offset if param size if greater than 128 */ + *p_param_values++ = EQ_ENABLE_PARAM_LEN; + *p_param_values++ = eq.enable_flag; + param_values[2] += 1; + } + if (param_send_flags & OFFLOAD_SEND_EQ_PRESET) { + *p_param_values++ = EQ_CONFIG; + *p_param_values++ = CONFIG_SET; + *p_param_values++ = 0; /* start offset if param size if greater than 128 */ + *p_param_values++ = EQ_CONFIG_PARAM_LEN; + *p_param_values++ = eq.config.eq_pregain; + *p_param_values++ = + map_eq_opensl_preset_2_offload_preset[eq.config.preset_id]; + *p_param_values++ = 0; + param_values[2] += 1; + } + if (param_send_flags & OFFLOAD_SEND_EQ_BANDS_LEVEL) { + *p_param_values++ = EQ_CONFIG; + *p_param_values++ = CONFIG_SET; + *p_param_values++ = 0; /* start offset if param size if greater than 128 */ + *p_param_values++ = EQ_CONFIG_PARAM_LEN + + eq.config.num_bands * EQ_CONFIG_PER_BAND_PARAM_LEN; + *p_param_values++ = eq.config.eq_pregain; + *p_param_values++ = CUSTOM_OPENSL_PRESET; + *p_param_values++ = eq.config.num_bands; + for (i=0; i<eq.config.num_bands; i++) { + *p_param_values++ = eq.per_band_cfg[i].band_idx; + *p_param_values++ = eq.per_band_cfg[i].filter_type; + *p_param_values++ = eq.per_band_cfg[i].freq_millihertz; + *p_param_values++ = eq.per_band_cfg[i].gain_millibels; + *p_param_values++ = eq.per_band_cfg[i].quality_factor; + } + param_values[2] += 1; + } + + if (param_values[2] && ctl) + mixer_ctl_set_array(ctl, param_values, ARRAY_SIZE(param_values)); + + return 0; +} + +void offload_reverb_set_device(struct reverb_params *reverb, uint32_t device) +{ + ALOGVV("%s: device 0x%x", __func__, device); + reverb->device = device; +} + +void offload_reverb_set_enable_flag(struct reverb_params *reverb, bool enable) +{ + ALOGVV("%s: enable=%d", __func__, (int)enable); + reverb->enable_flag = enable; +} + +int offload_reverb_get_enable_flag(struct reverb_params *reverb) +{ + ALOGVV("%s: enabled=%d", __func__, reverb->enable_flag); + return reverb->enable_flag; +} + +void offload_reverb_set_mode(struct reverb_params *reverb, int mode) +{ + ALOGVV("%s", __func__); + reverb->mode = mode; +} + +void offload_reverb_set_preset(struct reverb_params *reverb, int preset) +{ + ALOGVV("%s: preset %d", __func__, preset); + if (preset && (preset <= NUM_OSL_REVERB_PRESETS_SUPPORTED)) + reverb->preset = map_reverb_opensl_preset_2_offload_preset[preset-1][1]; +} + +void offload_reverb_set_wet_mix(struct reverb_params *reverb, int wet_mix) +{ + ALOGVV("%s: wet_mix %d", __func__, wet_mix); + reverb->wet_mix = wet_mix; +} + +void offload_reverb_set_gain_adjust(struct reverb_params *reverb, + int gain_adjust) +{ + ALOGVV("%s: gain %d", __func__, gain_adjust); + reverb->gain_adjust = gain_adjust; +} + +void offload_reverb_set_room_level(struct reverb_params *reverb, int room_level) +{ + ALOGVV("%s: level %d", __func__, room_level); + reverb->room_level = room_level; +} + +void offload_reverb_set_room_hf_level(struct reverb_params *reverb, + int room_hf_level) +{ + ALOGVV("%s: level %d", __func__, room_hf_level); + reverb->room_hf_level = room_hf_level; +} + +void offload_reverb_set_decay_time(struct reverb_params *reverb, int decay_time) +{ + ALOGVV("%s: decay time %d", __func__, decay_time); + reverb->decay_time = decay_time; +} + +void offload_reverb_set_decay_hf_ratio(struct reverb_params *reverb, + int decay_hf_ratio) +{ + ALOGVV("%s: decay_hf_ratio %d", __func__, decay_hf_ratio); + reverb->decay_hf_ratio = decay_hf_ratio; +} + +void offload_reverb_set_reflections_level(struct reverb_params *reverb, + int reflections_level) +{ + ALOGVV("%s: ref level %d", __func__, reflections_level); + reverb->reflections_level = reflections_level; +} + +void offload_reverb_set_reflections_delay(struct reverb_params *reverb, + int reflections_delay) +{ + ALOGVV("%s: ref delay", __func__, reflections_delay); + reverb->reflections_delay = reflections_delay; +} + +void offload_reverb_set_reverb_level(struct reverb_params *reverb, + int reverb_level) +{ + ALOGD("%s: reverb level %d", __func__, reverb_level); + reverb->level = reverb_level; +} + +void offload_reverb_set_delay(struct reverb_params *reverb, int delay) +{ + ALOGVV("%s: delay %d", __func__, delay); + reverb->delay = delay; +} + +void offload_reverb_set_diffusion(struct reverb_params *reverb, int diffusion) +{ + ALOGVV("%s: diffusion %d", __func__, diffusion); + reverb->diffusion = diffusion; +} + +void offload_reverb_set_density(struct reverb_params *reverb, int density) +{ + ALOGVV("%s: density %d", __func__, density); + reverb->density = density; +} + +int offload_reverb_send_params(struct mixer_ctl *ctl, + struct reverb_params reverb, + unsigned param_send_flags) +{ + int param_values[128] = {0}; + int *p_param_values = param_values; + + ALOGV("%s: flags 0x%x", __func__, param_send_flags); + *p_param_values++ = REVERB_MODULE; + *p_param_values++ = reverb.device; + *p_param_values++ = 0; /* num of commands*/ + + if (param_send_flags & OFFLOAD_SEND_REVERB_ENABLE_FLAG) { + *p_param_values++ = REVERB_ENABLE; + *p_param_values++ = CONFIG_SET; + *p_param_values++ = 0; /* start offset if param size if greater than 128 */ + *p_param_values++ = REVERB_ENABLE_PARAM_LEN; + *p_param_values++ = reverb.enable_flag; + param_values[2] += 1; + } + if (param_send_flags & OFFLOAD_SEND_REVERB_MODE) { + *p_param_values++ = REVERB_MODE; + *p_param_values++ = CONFIG_SET; + *p_param_values++ = 0; /* start offset if param size if greater than 128 */ + *p_param_values++ = REVERB_MODE_PARAM_LEN; + *p_param_values++ = reverb.mode; + param_values[2] += 1; + } + if (param_send_flags & OFFLOAD_SEND_REVERB_PRESET) { + *p_param_values++ = REVERB_PRESET; + *p_param_values++ = CONFIG_SET; + *p_param_values++ = 0; /* start offset if param size if greater than 128 */ + *p_param_values++ = REVERB_PRESET_PARAM_LEN; + *p_param_values++ = reverb.preset; + param_values[2] += 1; + } + if (param_send_flags & OFFLOAD_SEND_REVERB_WET_MIX) { + *p_param_values++ = REVERB_WET_MIX; + *p_param_values++ = CONFIG_SET; + *p_param_values++ = 0; /* start offset if param size if greater than 128 */ + *p_param_values++ = REVERB_WET_MIX_PARAM_LEN; + *p_param_values++ = reverb.wet_mix; + param_values[2] += 1; + } + if (param_send_flags & OFFLOAD_SEND_REVERB_GAIN_ADJUST) { + *p_param_values++ = REVERB_GAIN_ADJUST; + *p_param_values++ = CONFIG_SET; + *p_param_values++ = 0; /* start offset if param size if greater than 128 */ + *p_param_values++ = REVERB_GAIN_ADJUST_PARAM_LEN; + *p_param_values++ = reverb.gain_adjust; + param_values[2] += 1; + } + if (param_send_flags & OFFLOAD_SEND_REVERB_ROOM_LEVEL) { + *p_param_values++ = REVERB_ROOM_LEVEL; + *p_param_values++ = CONFIG_SET; + *p_param_values++ = 0; /* start offset if param size if greater than 128 */ + *p_param_values++ = REVERB_ROOM_LEVEL_PARAM_LEN; + *p_param_values++ = reverb.room_level; + param_values[2] += 1; + } + if (param_send_flags & OFFLOAD_SEND_REVERB_ROOM_HF_LEVEL) { + *p_param_values++ = REVERB_ROOM_HF_LEVEL; + *p_param_values++ = CONFIG_SET; + *p_param_values++ = 0; /* start offset if param size if greater than 128 */ + *p_param_values++ = REVERB_ROOM_HF_LEVEL_PARAM_LEN; + *p_param_values++ = reverb.room_hf_level; + param_values[2] += 1; + } + if (param_send_flags & OFFLOAD_SEND_REVERB_DECAY_TIME) { + *p_param_values++ = REVERB_DECAY_TIME; + *p_param_values++ = CONFIG_SET; + *p_param_values++ = 0; /* start offset if param size if greater than 128 */ + *p_param_values++ = REVERB_DECAY_TIME_PARAM_LEN; + *p_param_values++ = reverb.decay_time; + param_values[2] += 1; + } + if (param_send_flags & OFFLOAD_SEND_REVERB_DECAY_HF_RATIO) { + *p_param_values++ = REVERB_DECAY_HF_RATIO; + *p_param_values++ = CONFIG_SET; + *p_param_values++ = 0; /* start offset if param size if greater than 128 */ + *p_param_values++ = REVERB_DECAY_HF_RATIO_PARAM_LEN; + *p_param_values++ = reverb.decay_hf_ratio; + param_values[2] += 1; + } + if (param_send_flags & OFFLOAD_SEND_REVERB_REFLECTIONS_LEVEL) { + *p_param_values++ = REVERB_REFLECTIONS_LEVEL; + *p_param_values++ = CONFIG_SET; + *p_param_values++ = 0; /* start offset if param size if greater than 128 */ + *p_param_values++ = REVERB_REFLECTIONS_LEVEL_PARAM_LEN; + *p_param_values++ = reverb.reflections_level; + param_values[2] += 1; + } + if (param_send_flags & OFFLOAD_SEND_REVERB_REFLECTIONS_DELAY) { + *p_param_values++ = REVERB_REFLECTIONS_DELAY; + *p_param_values++ = CONFIG_SET; + *p_param_values++ = 0; /* start offset if param size if greater than 128 */ + *p_param_values++ = REVERB_REFLECTIONS_DELAY_PARAM_LEN; + *p_param_values++ = reverb.reflections_delay; + param_values[2] += 1; + } + if (param_send_flags & OFFLOAD_SEND_REVERB_LEVEL) { + *p_param_values++ = REVERB_LEVEL; + *p_param_values++ = CONFIG_SET; + *p_param_values++ = 0; /* start offset if param size if greater than 128 */ + *p_param_values++ = REVERB_LEVEL_PARAM_LEN; + *p_param_values++ = reverb.level; + param_values[2] += 1; + } + if (param_send_flags & OFFLOAD_SEND_REVERB_DELAY) { + *p_param_values++ = REVERB_DELAY; + *p_param_values++ = CONFIG_SET; + *p_param_values++ = 0; /* start offset if param size if greater than 128 */ + *p_param_values++ = REVERB_DELAY_PARAM_LEN; + *p_param_values++ = reverb.delay; + param_values[2] += 1; + } + if (param_send_flags & OFFLOAD_SEND_REVERB_DIFFUSION) { + *p_param_values++ = REVERB_DIFFUSION; + *p_param_values++ = CONFIG_SET; + *p_param_values++ = 0; /* start offset if param size if greater than 128 */ + *p_param_values++ = REVERB_DIFFUSION_PARAM_LEN; + *p_param_values++ = reverb.diffusion; + param_values[2] += 1; + } + if (param_send_flags & OFFLOAD_SEND_REVERB_DENSITY) { + *p_param_values++ = REVERB_DENSITY; + *p_param_values++ = CONFIG_SET; + *p_param_values++ = 0; /* start offset if param size if greater than 128 */ + *p_param_values++ = REVERB_DENSITY_PARAM_LEN; + *p_param_values++ = reverb.density; + param_values[2] += 1; + } + + if (param_values[2] && ctl) + mixer_ctl_set_array(ctl, param_values, ARRAY_SIZE(param_values)); + + return 0; +} diff --git a/msm8909/post_proc/effect_api.h b/msm8909/post_proc/effect_api.h new file mode 100644 index 00000000..342c6068 --- /dev/null +++ b/msm8909/post_proc/effect_api.h @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2013, 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. + */ + +#ifndef OFFLOAD_EFFECT_API_H_ +#define OFFLOAD_EFFECT_API_H_ + +int offload_update_mixer_and_effects_ctl(int card, int device_id, + struct mixer *mixer, + struct mixer_ctl *ctl); +void offload_close_mixer(struct mixer *mixer); + +#define OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG (1 << 0) +#define OFFLOAD_SEND_BASSBOOST_STRENGTH \ + (OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG << 1) +#define OFFLOAD_SEND_BASSBOOST_MODE \ + (OFFLOAD_SEND_BASSBOOST_STRENGTH << 1) +void offload_bassboost_set_device(struct bass_boost_params *bassboost, + uint32_t device); +void offload_bassboost_set_enable_flag(struct bass_boost_params *bassboost, + bool enable); +int offload_bassboost_get_enable_flag(struct bass_boost_params *bassboost); +void offload_bassboost_set_strength(struct bass_boost_params *bassboost, + int strength); +void offload_bassboost_set_mode(struct bass_boost_params *bassboost, + int mode); +int offload_bassboost_send_params(struct mixer_ctl *ctl, + struct bass_boost_params bassboost, + unsigned param_send_flags); + +#define OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG (1 << 0) +#define OFFLOAD_SEND_VIRTUALIZER_STRENGTH \ + (OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG << 1) +#define OFFLOAD_SEND_VIRTUALIZER_OUT_TYPE \ + (OFFLOAD_SEND_VIRTUALIZER_STRENGTH << 1) +#define OFFLOAD_SEND_VIRTUALIZER_GAIN_ADJUST \ + (OFFLOAD_SEND_VIRTUALIZER_OUT_TYPE << 1) +void offload_virtualizer_set_device(struct virtualizer_params *virtualizer, + uint32_t device); +void offload_virtualizer_set_enable_flag(struct virtualizer_params *virtualizer, + bool enable); +int offload_virtualizer_get_enable_flag(struct virtualizer_params *virtualizer); +void offload_virtualizer_set_strength(struct virtualizer_params *virtualizer, + int strength); +void offload_virtualizer_set_out_type(struct virtualizer_params *virtualizer, + int out_type); +void offload_virtualizer_set_gain_adjust(struct virtualizer_params *virtualizer, + int gain_adjust); +int offload_virtualizer_send_params(struct mixer_ctl *ctl, + struct virtualizer_params virtualizer, + unsigned param_send_flags); + +#define OFFLOAD_SEND_EQ_ENABLE_FLAG (1 << 0) +#define OFFLOAD_SEND_EQ_PRESET \ + (OFFLOAD_SEND_EQ_ENABLE_FLAG << 1) +#define OFFLOAD_SEND_EQ_BANDS_LEVEL \ + (OFFLOAD_SEND_EQ_PRESET << 1) +void offload_eq_set_device(struct eq_params *eq, uint32_t device); +void offload_eq_set_enable_flag(struct eq_params *eq, bool enable); +int offload_eq_get_enable_flag(struct eq_params *eq); +void offload_eq_set_preset(struct eq_params *eq, int preset); +void offload_eq_set_bands_level(struct eq_params *eq, int num_bands, + const uint16_t *band_freq_list, + int *band_gain_list); +int offload_eq_send_params(struct mixer_ctl *ctl, struct eq_params eq, + unsigned param_send_flags); + +#define OFFLOAD_SEND_REVERB_ENABLE_FLAG (1 << 0) +#define OFFLOAD_SEND_REVERB_MODE \ + (OFFLOAD_SEND_REVERB_ENABLE_FLAG << 1) +#define OFFLOAD_SEND_REVERB_PRESET \ + (OFFLOAD_SEND_REVERB_MODE << 1) +#define OFFLOAD_SEND_REVERB_WET_MIX \ + (OFFLOAD_SEND_REVERB_PRESET << 1) +#define OFFLOAD_SEND_REVERB_GAIN_ADJUST \ + (OFFLOAD_SEND_REVERB_WET_MIX << 1) +#define OFFLOAD_SEND_REVERB_ROOM_LEVEL \ + (OFFLOAD_SEND_REVERB_GAIN_ADJUST << 1) +#define OFFLOAD_SEND_REVERB_ROOM_HF_LEVEL \ + (OFFLOAD_SEND_REVERB_ROOM_LEVEL << 1) +#define OFFLOAD_SEND_REVERB_DECAY_TIME \ + (OFFLOAD_SEND_REVERB_ROOM_HF_LEVEL << 1) +#define OFFLOAD_SEND_REVERB_DECAY_HF_RATIO \ + (OFFLOAD_SEND_REVERB_DECAY_TIME << 1) +#define OFFLOAD_SEND_REVERB_REFLECTIONS_LEVEL \ + (OFFLOAD_SEND_REVERB_DECAY_HF_RATIO << 1) +#define OFFLOAD_SEND_REVERB_REFLECTIONS_DELAY \ + (OFFLOAD_SEND_REVERB_REFLECTIONS_LEVEL << 1) +#define OFFLOAD_SEND_REVERB_LEVEL \ + (OFFLOAD_SEND_REVERB_REFLECTIONS_DELAY << 1) +#define OFFLOAD_SEND_REVERB_DELAY \ + (OFFLOAD_SEND_REVERB_LEVEL << 1) +#define OFFLOAD_SEND_REVERB_DIFFUSION \ + (OFFLOAD_SEND_REVERB_DELAY << 1) +#define OFFLOAD_SEND_REVERB_DENSITY \ + (OFFLOAD_SEND_REVERB_DIFFUSION << 1) +void offload_reverb_set_device(struct reverb_params *reverb, uint32_t device); +void offload_reverb_set_enable_flag(struct reverb_params *reverb, bool enable); +int offload_reverb_get_enable_flag(struct reverb_params *reverb); +void offload_reverb_set_mode(struct reverb_params *reverb, int mode); +void offload_reverb_set_preset(struct reverb_params *reverb, int preset); +void offload_reverb_set_wet_mix(struct reverb_params *reverb, int wet_mix); +void offload_reverb_set_gain_adjust(struct reverb_params *reverb, + int gain_adjust); +void offload_reverb_set_room_level(struct reverb_params *reverb, + int room_level); +void offload_reverb_set_room_hf_level(struct reverb_params *reverb, + int room_hf_level); +void offload_reverb_set_decay_time(struct reverb_params *reverb, + int decay_time); +void offload_reverb_set_decay_hf_ratio(struct reverb_params *reverb, + int decay_hf_ratio); +void offload_reverb_set_reflections_level(struct reverb_params *reverb, + int reflections_level); +void offload_reverb_set_reflections_delay(struct reverb_params *reverb, + int reflections_delay); +void offload_reverb_set_reverb_level(struct reverb_params *reverb, + int reverb_level); +void offload_reverb_set_delay(struct reverb_params *reverb, int delay); +void offload_reverb_set_diffusion(struct reverb_params *reverb, int diffusion); +void offload_reverb_set_density(struct reverb_params *reverb, int density); +int offload_reverb_send_params(struct mixer_ctl *ctl, + struct reverb_params reverb, + unsigned param_send_flags); + +#endif /*OFFLOAD_EFFECT_API_H_*/ diff --git a/msm8909/post_proc/equalizer.c b/msm8909/post_proc/equalizer.c new file mode 100644 index 00000000..ce1b462b --- /dev/null +++ b/msm8909/post_proc/equalizer.c @@ -0,0 +1,497 @@ +/* + * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. + * Not a Contribution. + * + * Copyright (C) 2013 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 "offload_effect_equalizer" +#define LOG_NDEBUG 0 + +#include <cutils/list.h> +#include <cutils/log.h> +#include <tinyalsa/asoundlib.h> +#include <sound/audio_effects.h> +#include <audio_effects/effect_equalizer.h> + +#include "effect_api.h" +#include "equalizer.h" + +/* Offload equalizer UUID: a0dac280-401c-11e3-9379-0002a5d5c51b */ +const effect_descriptor_t equalizer_descriptor = { + {0x0bed4300, 0xddd6, 0x11db, 0x8f34, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // type + {0xa0dac280, 0x401c, 0x11e3, 0x9379, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // uuid + EFFECT_CONTROL_API_VERSION, + (EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_HW_ACC_TUNNEL), + 0, /* TODO */ + 1, + "MSM offload equalizer", + "The Android Open Source Project", +}; + +static const char *equalizer_preset_names[] = { + "Normal", + "Classical", + "Dance", + "Flat", + "Folk", + "Heavy Metal", + "Hip Hop", + "Jazz", + "Pop", + "Rock" +}; + +static const uint32_t equalizer_band_freq_range[NUM_EQ_BANDS][2] = { + {30000, 120000}, + {120001, 460000}, + {460001, 1800000}, + {1800001, 7000000}, + {7000001, 20000000}}; + +static const int16_t equalizer_band_presets_level[] = { + 3, 0, 0, 0, 3, /* Normal Preset */ + 5, 3, -2, 4, 4, /* Classical Preset */ + 6, 0, 2, 4, 1, /* Dance Preset */ + 0, 0, 0, 0, 0, /* Flat Preset */ + 3, 0, 0, 2, -1, /* Folk Preset */ + 4, 1, 9, 3, 0, /* Heavy Metal Preset */ + 5, 3, 0, 1, 3, /* Hip Hop Preset */ + 4, 2, -2, 2, 5, /* Jazz Preset */ + -1, 2, 5, 1, -2, /* Pop Preset */ + 5, 3, -1, 3, 5}; /* Rock Preset */ + +const uint16_t equalizer_band_presets_freq[NUM_EQ_BANDS] = { + 60, /* Frequencies in Hz */ + 230, + 910, + 3600, + 14000 +}; + +/* + * Equalizer operations + */ + +int equalizer_get_band_level(equalizer_context_t *context, int32_t band) +{ + ALOGV("%s: ctxt %p, band: %d level: %d", __func__, context, band, + context->band_levels[band] * 100); + return context->band_levels[band] * 100; +} + +int equalizer_set_band_level(equalizer_context_t *context, int32_t band, + int32_t level) +{ + ALOGV("%s: ctxt %p, band: %d, level: %d", __func__, context, band, level); + if (level > 0) { + level = (int)((level+50)/100); + } else { + level = (int)((level-50)/100); + } + context->band_levels[band] = level; + context->preset = PRESET_CUSTOM; + + offload_eq_set_preset(&(context->offload_eq), PRESET_CUSTOM); + offload_eq_set_bands_level(&(context->offload_eq), + NUM_EQ_BANDS, + equalizer_band_presets_freq, + context->band_levels); + if (context->ctl) + offload_eq_send_params(context->ctl, context->offload_eq, + OFFLOAD_SEND_EQ_ENABLE_FLAG | + OFFLOAD_SEND_EQ_BANDS_LEVEL); + return 0; +} + +int equalizer_get_center_frequency(equalizer_context_t *context, int32_t band) +{ + ALOGV("%s: ctxt %p, band: %d", __func__, context, band); + return (equalizer_band_freq_range[band][0] + + equalizer_band_freq_range[band][1]) / 2; +} + +int equalizer_get_band_freq_range(equalizer_context_t *context, int32_t band, + uint32_t *low, uint32_t *high) +{ + ALOGV("%s: ctxt %p, band: %d", __func__, context, band); + *low = equalizer_band_freq_range[band][0]; + *high = equalizer_band_freq_range[band][1]; + return 0; +} + +int equalizer_get_band(equalizer_context_t *context, uint32_t freq) +{ + int i; + + ALOGV("%s: ctxt %p, freq: %d", __func__, context, freq); + for(i = 0; i < NUM_EQ_BANDS; i++) { + if (freq <= equalizer_band_freq_range[i][1]) { + return i; + } + } + return NUM_EQ_BANDS - 1; +} + +int equalizer_get_preset(equalizer_context_t *context) +{ + ALOGV("%s: ctxt %p, preset: %d", __func__, context, context->preset); + return context->preset; +} + +int equalizer_set_preset(equalizer_context_t *context, int preset) +{ + int i; + + ALOGV("%s: ctxt %p, preset: %d", __func__, context, preset); + context->preset = preset; + for (i=0; i<NUM_EQ_BANDS; i++) + context->band_levels[i] = + equalizer_band_presets_level[i + preset * NUM_EQ_BANDS]; + + offload_eq_set_preset(&(context->offload_eq), preset); + offload_eq_set_bands_level(&(context->offload_eq), + NUM_EQ_BANDS, + equalizer_band_presets_freq, + context->band_levels); + if(context->ctl) + offload_eq_send_params(context->ctl, context->offload_eq, + OFFLOAD_SEND_EQ_ENABLE_FLAG | + OFFLOAD_SEND_EQ_PRESET); + return 0; +} + +const char * equalizer_get_preset_name(equalizer_context_t *context, + int32_t preset) +{ + ALOGV("%s: ctxt %p, preset: %s", __func__, context, + equalizer_preset_names[preset]); + if (preset == PRESET_CUSTOM) { + return "Custom"; + } else { + return equalizer_preset_names[preset]; + } +} + +int equalizer_get_num_presets(equalizer_context_t *context) +{ + ALOGV("%s: ctxt %p, presets_num: %d", __func__, context, + sizeof(equalizer_preset_names)/sizeof(char *)); + return sizeof(equalizer_preset_names)/sizeof(char *); +} + +int equalizer_get_parameter(effect_context_t *context, effect_param_t *p, + uint32_t *size) +{ + equalizer_context_t *eq_ctxt = (equalizer_context_t *)context; + int voffset = ((p->psize - 1) / sizeof(int32_t) + 1) * sizeof(int32_t); + int32_t *param_tmp = (int32_t *)p->data; + int32_t param = *param_tmp++; + int32_t param2; + char *name; + void *value = p->data + voffset; + int i; + + ALOGV("%s: ctxt %p, param %d", __func__, eq_ctxt, param); + + p->status = 0; + + switch (param) { + case EQ_PARAM_NUM_BANDS: + case EQ_PARAM_CUR_PRESET: + case EQ_PARAM_GET_NUM_OF_PRESETS: + case EQ_PARAM_BAND_LEVEL: + case EQ_PARAM_GET_BAND: + if (p->vsize < sizeof(int16_t)) + p->status = -EINVAL; + p->vsize = sizeof(int16_t); + break; + + case EQ_PARAM_LEVEL_RANGE: + if (p->vsize < 2 * sizeof(int16_t)) + p->status = -EINVAL; + p->vsize = 2 * sizeof(int16_t); + break; + case EQ_PARAM_BAND_FREQ_RANGE: + if (p->vsize < 2 * sizeof(int32_t)) + p->status = -EINVAL; + p->vsize = 2 * sizeof(int32_t); + break; + + case EQ_PARAM_CENTER_FREQ: + if (p->vsize < sizeof(int32_t)) + p->status = -EINVAL; + p->vsize = sizeof(int32_t); + break; + + case EQ_PARAM_GET_PRESET_NAME: + break; + + case EQ_PARAM_PROPERTIES: + if (p->vsize < (2 + NUM_EQ_BANDS) * sizeof(uint16_t)) + p->status = -EINVAL; + p->vsize = (2 + NUM_EQ_BANDS) * sizeof(uint16_t); + break; + + default: + p->status = -EINVAL; + } + + *size = sizeof(effect_param_t) + voffset + p->vsize; + + if (p->status != 0) + return 0; + + switch (param) { + case EQ_PARAM_NUM_BANDS: + *(uint16_t *)value = (uint16_t)NUM_EQ_BANDS; + break; + + case EQ_PARAM_LEVEL_RANGE: + *(int16_t *)value = -1500; + *((int16_t *)value + 1) = 1500; + break; + + case EQ_PARAM_BAND_LEVEL: + param2 = *param_tmp; + if (param2 >= NUM_EQ_BANDS) { + p->status = -EINVAL; + break; + } + *(int16_t *)value = (int16_t)equalizer_get_band_level(eq_ctxt, param2); + break; + + case EQ_PARAM_CENTER_FREQ: + param2 = *param_tmp; + if (param2 >= NUM_EQ_BANDS) { + p->status = -EINVAL; + break; + } + *(int32_t *)value = equalizer_get_center_frequency(eq_ctxt, param2); + break; + + case EQ_PARAM_BAND_FREQ_RANGE: + param2 = *param_tmp; + if (param2 >= NUM_EQ_BANDS) { + p->status = -EINVAL; + break; + } + equalizer_get_band_freq_range(eq_ctxt, param2, (uint32_t *)value, + ((uint32_t *)value + 1)); + break; + + case EQ_PARAM_GET_BAND: + param2 = *param_tmp; + *(uint16_t *)value = (uint16_t)equalizer_get_band(eq_ctxt, param2); + break; + + case EQ_PARAM_CUR_PRESET: + *(uint16_t *)value = (uint16_t)equalizer_get_preset(eq_ctxt); + break; + + case EQ_PARAM_GET_NUM_OF_PRESETS: + *(uint16_t *)value = (uint16_t)equalizer_get_num_presets(eq_ctxt); + break; + + case EQ_PARAM_GET_PRESET_NAME: + param2 = *param_tmp; + ALOGV("%s: EQ_PARAM_GET_PRESET_NAME: param2: %d", __func__, param2); + if (param2 >= equalizer_get_num_presets(eq_ctxt)) { + p->status = -EINVAL; + break; + } + name = (char *)value; + strlcpy(name, equalizer_get_preset_name(eq_ctxt, param2), p->vsize - 1); + name[p->vsize - 1] = 0; + p->vsize = strlen(name) + 1; + break; + + case EQ_PARAM_PROPERTIES: { + int16_t *prop = (int16_t *)value; + prop[0] = (int16_t)equalizer_get_preset(eq_ctxt); + prop[1] = (int16_t)NUM_EQ_BANDS; + for (i = 0; i < NUM_EQ_BANDS; i++) { + prop[2 + i] = (int16_t)equalizer_get_band_level(eq_ctxt, i); + } + } break; + + default: + p->status = -EINVAL; + break; + } + + return 0; +} + +int equalizer_set_parameter(effect_context_t *context, effect_param_t *p, + uint32_t size __unused) +{ + equalizer_context_t *eq_ctxt = (equalizer_context_t *)context; + int voffset = ((p->psize - 1) / sizeof(int32_t) + 1) * sizeof(int32_t); + void *value = p->data + voffset; + int32_t *param_tmp = (int32_t *)p->data; + int32_t param = *param_tmp++; + int32_t preset; + int32_t band; + int32_t level; + int i; + + ALOGV("%s: ctxt %p, param %d", __func__, eq_ctxt, param); + + p->status = 0; + + switch (param) { + case EQ_PARAM_CUR_PRESET: + preset = (int32_t)(*(uint16_t *)value); + + if ((preset >= equalizer_get_num_presets(eq_ctxt)) || (preset < 0)) { + p->status = -EINVAL; + break; + } + equalizer_set_preset(eq_ctxt, preset); + break; + case EQ_PARAM_BAND_LEVEL: + band = *param_tmp; + level = (int32_t)(*(int16_t *)value); + if (band >= NUM_EQ_BANDS) { + p->status = -EINVAL; + break; + } + equalizer_set_band_level(eq_ctxt, band, level); + break; + case EQ_PARAM_PROPERTIES: { + int16_t *prop = (int16_t *)value; + if ((int)prop[0] >= equalizer_get_num_presets(eq_ctxt)) { + p->status = -EINVAL; + break; + } + if (prop[0] >= 0) { + equalizer_set_preset(eq_ctxt, (int)prop[0]); + } else { + if ((int)prop[1] != NUM_EQ_BANDS) { + p->status = -EINVAL; + break; + } + for (i = 0; i < NUM_EQ_BANDS; i++) { + equalizer_set_band_level(eq_ctxt, i, (int)prop[2 + i]); + } + } + } break; + default: + p->status = -EINVAL; + break; + } + + return 0; +} + +int equalizer_set_device(effect_context_t *context, uint32_t device) +{ + ALOGV("%s: ctxt %p, device: 0x%x", __func__, context, device); + equalizer_context_t *eq_ctxt = (equalizer_context_t *)context; + eq_ctxt->device = device; + offload_eq_set_device(&(eq_ctxt->offload_eq), device); + return 0; +} + +int equalizer_reset(effect_context_t *context) +{ + equalizer_context_t *eq_ctxt = (equalizer_context_t *)context; + + return 0; +} + +int equalizer_init(effect_context_t *context) +{ + ALOGV("%s: ctxt %p", __func__, context); + equalizer_context_t *eq_ctxt = (equalizer_context_t *)context; + + context->config.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ; + context->config.inputCfg.channels = AUDIO_CHANNEL_OUT_STEREO; + context->config.inputCfg.format = AUDIO_FORMAT_PCM_16_BIT; + context->config.inputCfg.samplingRate = 44100; + context->config.inputCfg.bufferProvider.getBuffer = NULL; + context->config.inputCfg.bufferProvider.releaseBuffer = NULL; + context->config.inputCfg.bufferProvider.cookie = NULL; + context->config.inputCfg.mask = EFFECT_CONFIG_ALL; + context->config.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_ACCUMULATE; + context->config.outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO; + context->config.outputCfg.format = AUDIO_FORMAT_PCM_16_BIT; + context->config.outputCfg.samplingRate = 44100; + context->config.outputCfg.bufferProvider.getBuffer = NULL; + context->config.outputCfg.bufferProvider.releaseBuffer = NULL; + context->config.outputCfg.bufferProvider.cookie = NULL; + context->config.outputCfg.mask = EFFECT_CONFIG_ALL; + + set_config(context, &context->config); + + memset(&(eq_ctxt->offload_eq), 0, sizeof(struct eq_params)); + offload_eq_set_preset(&(eq_ctxt->offload_eq), INVALID_PRESET); + + return 0; +} + +int equalizer_enable(effect_context_t *context) +{ + equalizer_context_t *eq_ctxt = (equalizer_context_t *)context; + + ALOGV("%s: ctxt %p", __func__, context); + + if (!offload_eq_get_enable_flag(&(eq_ctxt->offload_eq))) { + offload_eq_set_enable_flag(&(eq_ctxt->offload_eq), true); + if (eq_ctxt->ctl) + offload_eq_send_params(eq_ctxt->ctl, eq_ctxt->offload_eq, + OFFLOAD_SEND_EQ_ENABLE_FLAG | + OFFLOAD_SEND_EQ_BANDS_LEVEL); + } + return 0; +} + +int equalizer_disable(effect_context_t *context) +{ + equalizer_context_t *eq_ctxt = (equalizer_context_t *)context; + + ALOGV("%s:ctxt %p", __func__, eq_ctxt); + if (offload_eq_get_enable_flag(&(eq_ctxt->offload_eq))) { + offload_eq_set_enable_flag(&(eq_ctxt->offload_eq), false); + if (eq_ctxt->ctl) + offload_eq_send_params(eq_ctxt->ctl, eq_ctxt->offload_eq, + OFFLOAD_SEND_EQ_ENABLE_FLAG); + } + return 0; +} + +int equalizer_start(effect_context_t *context, output_context_t *output) +{ + equalizer_context_t *eq_ctxt = (equalizer_context_t *)context; + + ALOGV("%s: ctxt %p, ctl %p", __func__, eq_ctxt, output->ctl); + eq_ctxt->ctl = output->ctl; + if (offload_eq_get_enable_flag(&(eq_ctxt->offload_eq))) + if (eq_ctxt->ctl) + offload_eq_send_params(eq_ctxt->ctl, eq_ctxt->offload_eq, + OFFLOAD_SEND_EQ_ENABLE_FLAG | + OFFLOAD_SEND_EQ_BANDS_LEVEL); + return 0; +} + +int equalizer_stop(effect_context_t *context, output_context_t *output __unused) +{ + equalizer_context_t *eq_ctxt = (equalizer_context_t *)context; + + ALOGV("%s: ctxt %p", __func__, eq_ctxt); + eq_ctxt->ctl = NULL; + return 0; +} diff --git a/msm8909/post_proc/equalizer.h b/msm8909/post_proc/equalizer.h new file mode 100644 index 00000000..19af1867 --- /dev/null +++ b/msm8909/post_proc/equalizer.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Not a Contribution. + * + * Copyright (C) 2013 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. + */ + +#ifndef OFFLOAD_EQUALIZER_H_ +#define OFFLOAD_EQUALIZER_H_ + +#include "bundle.h" + +#define NUM_EQ_BANDS 5 +#define INVALID_PRESET -2 +#define PRESET_CUSTOM -1 + +extern const effect_descriptor_t equalizer_descriptor; + +typedef struct equalizer_context_s { + effect_context_t common; + + int preset; + int band_levels[NUM_EQ_BANDS]; + + // Offload vars + struct mixer_ctl *ctl; + uint32_t device; + struct eq_params offload_eq; +} equalizer_context_t; + +int equalizer_get_parameter(effect_context_t *context, effect_param_t *p, + uint32_t *size); + +int equalizer_set_parameter(effect_context_t *context, effect_param_t *p, + uint32_t size); + +int equalizer_set_device(effect_context_t *context, uint32_t device); + +int equalizer_reset(effect_context_t *context); + +int equalizer_init(effect_context_t *context); + +int equalizer_enable(effect_context_t *context); + +int equalizer_disable(effect_context_t *context); + +int equalizer_start(effect_context_t *context, output_context_t *output); + +int equalizer_stop(effect_context_t *context, output_context_t *output); + +#endif /*OFFLOAD_EQUALIZER_H_*/ diff --git a/msm8909/post_proc/reverb.c b/msm8909/post_proc/reverb.c new file mode 100644 index 00000000..c89039e5 --- /dev/null +++ b/msm8909/post_proc/reverb.c @@ -0,0 +1,613 @@ +/* + * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. + * Not a Contribution. + * + * Copyright (C) 2013 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 "offload_effect_reverb" +#define LOG_NDEBUG 0 + +#include <cutils/list.h> +#include <cutils/log.h> +#include <tinyalsa/asoundlib.h> +#include <sound/audio_effects.h> +#include <audio_effects/effect_environmentalreverb.h> +#include <audio_effects/effect_presetreverb.h> + +#include "effect_api.h" +#include "reverb.h" + +/* Offload auxiliary environmental reverb UUID: 79a18026-18fd-4185-8233-0002a5d5c51b */ +const effect_descriptor_t aux_env_reverb_descriptor = { + { 0xc2e5d5f0, 0x94bd, 0x4763, 0x9cac, { 0x4e, 0x23, 0x4d, 0x06, 0x83, 0x9e } }, + { 0x79a18026, 0x18fd, 0x4185, 0x8233, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } }, + EFFECT_CONTROL_API_VERSION, + (EFFECT_FLAG_TYPE_AUXILIARY | EFFECT_FLAG_HW_ACC_TUNNEL), + 0, /* TODO */ + 1, + "MSM offload Auxiliary Environmental Reverb", + "The Android Open Source Project", +}; + +/* Offload insert environmental reverb UUID: eb64ea04-973b-43d2-8f5e-0002a5d5c51b */ +const effect_descriptor_t ins_env_reverb_descriptor = { + {0xc2e5d5f0, 0x94bd, 0x4763, 0x9cac, {0x4e, 0x23, 0x4d, 0x06, 0x83, 0x9e}}, + {0xeb64ea04, 0x973b, 0x43d2, 0x8f5e, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, + EFFECT_CONTROL_API_VERSION, + (EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_INSERT_FIRST | EFFECT_FLAG_HW_ACC_TUNNEL), + 0, /* TODO */ + 1, + "MSM offload Insert Environmental Reverb", + "The Android Open Source Project", +}; + +// Offload auxiliary preset reverb UUID: 6987be09-b142-4b41-9056-0002a5d5c51b */ +const effect_descriptor_t aux_preset_reverb_descriptor = { + {0x47382d60, 0xddd8, 0x11db, 0xbf3a, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, + {0x6987be09, 0xb142, 0x4b41, 0x9056, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, + EFFECT_CONTROL_API_VERSION, + (EFFECT_FLAG_TYPE_AUXILIARY | EFFECT_FLAG_HW_ACC_TUNNEL), + 0, /* TODO */ + 1, + "MSM offload Auxiliary Preset Reverb", + "The Android Open Source Project", +}; + +// Offload insert preset reverb UUID: aa2bebf6-47cf-4613-9bca-0002a5d5c51b */ +const effect_descriptor_t ins_preset_reverb_descriptor = { + {0x47382d60, 0xddd8, 0x11db, 0xbf3a, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, + {0xaa2bebf6, 0x47cf, 0x4613, 0x9bca, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, + EFFECT_CONTROL_API_VERSION, + (EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_INSERT_FIRST | EFFECT_FLAG_HW_ACC_TUNNEL), + 0, /* TODO */ + 1, + "MSM offload Insert Preset Reverb", + "The Android Open Source Project", +}; + +static const reverb_settings_t reverb_presets[] = { + // REVERB_PRESET_NONE: values are unused + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + // REVERB_PRESET_SMALLROOM + {-400, -600, 1100, 830, -400, 5, 500, 10, 1000, 1000}, + // REVERB_PRESET_MEDIUMROOM + {-400, -600, 1300, 830, -1000, 20, -200, 20, 1000, 1000}, + // REVERB_PRESET_LARGEROOM + {-400, -600, 1500, 830, -1600, 5, -1000, 40, 1000, 1000}, + // REVERB_PRESET_MEDIUMHALL + {-400, -600, 1800, 700, -1300, 15, -800, 30, 1000, 1000}, + // REVERB_PRESET_LARGEHALL + {-400, -600, 1800, 700, -2000, 30, -1400, 60, 1000, 1000}, + // REVERB_PRESET_PLATE + {-400, -200, 1300, 900, 0, 2, 0, 10, 1000, 750}, +}; + + +void reverb_auxiliary_init(reverb_context_t *context) +{ + context->auxiliary = true; + context->preset = false; +} + +void reverb_preset_init(reverb_context_t *context) +{ + context->auxiliary = false; + context->preset = true; + context->cur_preset = REVERB_PRESET_LAST + 1; + context->next_preset = REVERB_DEFAULT_PRESET; +} + +/* + * Reverb operations + */ +int16_t reverb_get_room_level(reverb_context_t *context) +{ + ALOGV("%s: ctxt %p, room level: %d", __func__, context, context->reverb_settings.roomLevel); + return context->reverb_settings.roomLevel; +} + +void reverb_set_room_level(reverb_context_t *context, int16_t room_level) +{ + ALOGV("%s: ctxt %p, room level: %d", __func__, context, room_level); + context->reverb_settings.roomLevel = room_level; + offload_reverb_set_room_level(&(context->offload_reverb), room_level); + if (context->ctl) + offload_reverb_send_params(context->ctl, context->offload_reverb, + OFFLOAD_SEND_REVERB_ENABLE_FLAG | + OFFLOAD_SEND_REVERB_ROOM_LEVEL); +} + +int16_t reverb_get_room_hf_level(reverb_context_t *context) +{ + ALOGV("%s: ctxt %p, room hf level: %d", __func__, context, + context->reverb_settings.roomHFLevel); + return context->reverb_settings.roomHFLevel; +} + +void reverb_set_room_hf_level(reverb_context_t *context, int16_t room_hf_level) +{ + ALOGV("%s: ctxt %p, room hf level: %d", __func__, context, room_hf_level); + context->reverb_settings.roomHFLevel = room_hf_level; + offload_reverb_set_room_hf_level(&(context->offload_reverb), room_hf_level); + if (context->ctl) + offload_reverb_send_params(context->ctl, context->offload_reverb, + OFFLOAD_SEND_REVERB_ENABLE_FLAG | + OFFLOAD_SEND_REVERB_ROOM_HF_LEVEL); +} + +uint32_t reverb_get_decay_time(reverb_context_t *context) +{ + ALOGV("%s: ctxt %p, decay time: %d", __func__, context, + context->reverb_settings.decayTime); + return context->reverb_settings.decayTime; +} + +void reverb_set_decay_time(reverb_context_t *context, uint32_t decay_time) +{ + ALOGV("%s: ctxt %p, decay_time: %d", __func__, context, decay_time); + context->reverb_settings.decayTime = decay_time; + offload_reverb_set_decay_time(&(context->offload_reverb), decay_time); + if (context->ctl) + offload_reverb_send_params(context->ctl, context->offload_reverb, + OFFLOAD_SEND_REVERB_ENABLE_FLAG | + OFFLOAD_SEND_REVERB_DECAY_TIME); +} + +int16_t reverb_get_decay_hf_ratio(reverb_context_t *context) +{ + ALOGV("%s: ctxt %p, decay hf ratio: %d", __func__, context, + context->reverb_settings.decayHFRatio); + return context->reverb_settings.decayHFRatio; +} + +void reverb_set_decay_hf_ratio(reverb_context_t *context, int16_t decay_hf_ratio) +{ + ALOGV("%s: ctxt %p, decay_hf_ratio: %d", __func__, context, decay_hf_ratio); + context->reverb_settings.decayHFRatio = decay_hf_ratio; + offload_reverb_set_decay_hf_ratio(&(context->offload_reverb), decay_hf_ratio); + if (context->ctl) + offload_reverb_send_params(context->ctl, context->offload_reverb, + OFFLOAD_SEND_REVERB_ENABLE_FLAG | + OFFLOAD_SEND_REVERB_DECAY_HF_RATIO); +} + +int16_t reverb_get_reverb_level(reverb_context_t *context) +{ + ALOGV("%s: ctxt %p, reverb level: %d", __func__, context, + context->reverb_settings.reverbLevel); + return context->reverb_settings.reverbLevel; +} + +void reverb_set_reverb_level(reverb_context_t *context, int16_t reverb_level) +{ + ALOGV("%s: ctxt %p, reverb level: %d", __func__, context, reverb_level); + context->reverb_settings.reverbLevel = reverb_level; + offload_reverb_set_reverb_level(&(context->offload_reverb), reverb_level); + if (context->ctl) + offload_reverb_send_params(context->ctl, context->offload_reverb, + OFFLOAD_SEND_REVERB_ENABLE_FLAG | + OFFLOAD_SEND_REVERB_LEVEL); +} + +int16_t reverb_get_diffusion(reverb_context_t *context) +{ + ALOGV("%s: ctxt %p, diffusion: %d", __func__, context, + context->reverb_settings.diffusion); + return context->reverb_settings.diffusion; +} + +void reverb_set_diffusion(reverb_context_t *context, int16_t diffusion) +{ + ALOGV("%s: ctxt %p, diffusion: %d", __func__, context, diffusion); + context->reverb_settings.diffusion = diffusion; + offload_reverb_set_diffusion(&(context->offload_reverb), diffusion); + if (context->ctl) + offload_reverb_send_params(context->ctl, context->offload_reverb, + OFFLOAD_SEND_REVERB_ENABLE_FLAG | + OFFLOAD_SEND_REVERB_DIFFUSION); +} + +int16_t reverb_get_density(reverb_context_t *context) +{ + ALOGV("%s: ctxt %p, density: %d", __func__, context, + context->reverb_settings.density); + return context->reverb_settings.density; +} + +void reverb_set_density(reverb_context_t *context, int16_t density) +{ + ALOGV("%s: ctxt %p, density: %d", __func__, context, density); + context->reverb_settings.density = density; + offload_reverb_set_density(&(context->offload_reverb), density); + if (context->ctl) + offload_reverb_send_params(context->ctl, context->offload_reverb, + OFFLOAD_SEND_REVERB_ENABLE_FLAG | + OFFLOAD_SEND_REVERB_DENSITY); +} + +void reverb_set_preset(reverb_context_t *context, int16_t preset) +{ + bool enable; + ALOGV("%s: ctxt %p, preset: %d", __func__, context, preset); + context->next_preset = preset; + offload_reverb_set_preset(&(context->offload_reverb), preset); + + enable = (preset == REVERB_PRESET_NONE) ? false: true; + offload_reverb_set_enable_flag(&(context->offload_reverb), enable); + + if (context->ctl) + offload_reverb_send_params(context->ctl, context->offload_reverb, + OFFLOAD_SEND_REVERB_ENABLE_FLAG | + OFFLOAD_SEND_REVERB_PRESET); +} + +void reverb_set_all_properties(reverb_context_t *context, + reverb_settings_t *reverb_settings) +{ + ALOGV("%s: ctxt %p", __func__, context); + context->reverb_settings.roomLevel = reverb_settings->roomLevel; + context->reverb_settings.roomHFLevel = reverb_settings->roomHFLevel; + context->reverb_settings.decayTime = reverb_settings->decayTime; + context->reverb_settings.decayHFRatio = reverb_settings->decayHFRatio; + context->reverb_settings.reverbLevel = reverb_settings->reverbLevel; + context->reverb_settings.diffusion = reverb_settings->diffusion; + context->reverb_settings.density = reverb_settings->density; + if (context->ctl) + offload_reverb_send_params(context->ctl, context->offload_reverb, + OFFLOAD_SEND_REVERB_ENABLE_FLAG | + OFFLOAD_SEND_REVERB_ROOM_LEVEL | + OFFLOAD_SEND_REVERB_ROOM_HF_LEVEL | + OFFLOAD_SEND_REVERB_DECAY_TIME | + OFFLOAD_SEND_REVERB_DECAY_HF_RATIO | + OFFLOAD_SEND_REVERB_LEVEL | + OFFLOAD_SEND_REVERB_DIFFUSION | + OFFLOAD_SEND_REVERB_DENSITY); +} + +void reverb_load_preset(reverb_context_t *context) +{ + context->cur_preset = context->next_preset; + + if (context->cur_preset != REVERB_PRESET_NONE) { + const reverb_settings_t *preset = &reverb_presets[context->cur_preset]; + reverb_set_room_level(context, preset->roomLevel); + reverb_set_room_hf_level(context, preset->roomHFLevel); + reverb_set_decay_time(context, preset->decayTime); + reverb_set_decay_hf_ratio(context, preset->decayHFRatio); + reverb_set_reverb_level(context, preset->reverbLevel); + reverb_set_diffusion(context, preset->diffusion); + reverb_set_density(context, preset->density); + } +} + +int reverb_get_parameter(effect_context_t *context, effect_param_t *p, + uint32_t *size) +{ + reverb_context_t *reverb_ctxt = (reverb_context_t *)context; + int voffset = ((p->psize - 1) / sizeof(int32_t) + 1) * sizeof(int32_t); + int32_t *param_tmp = (int32_t *)p->data; + int32_t param = *param_tmp++; + void *value = p->data + voffset; + reverb_settings_t *reverb_settings; + int i; + + ALOGV("%s: ctxt %p, param %d", __func__, reverb_ctxt, param); + + p->status = 0; + + if (reverb_ctxt->preset) { + if (param != REVERB_PARAM_PRESET || p->vsize < sizeof(uint16_t)) + return -EINVAL; + *(uint16_t *)value = reverb_ctxt->next_preset; + ALOGV("get REVERB_PARAM_PRESET, preset %d", reverb_ctxt->next_preset); + return 0; + } + switch (param) { + case REVERB_PARAM_ROOM_LEVEL: + if (p->vsize < sizeof(uint16_t)) + p->status = -EINVAL; + p->vsize = sizeof(uint16_t); + break; + case REVERB_PARAM_ROOM_HF_LEVEL: + if (p->vsize < sizeof(uint16_t)) + p->status = -EINVAL; + p->vsize = sizeof(uint16_t); + break; + case REVERB_PARAM_DECAY_TIME: + if (p->vsize < sizeof(uint32_t)) + p->status = -EINVAL; + p->vsize = sizeof(uint32_t); + break; + case REVERB_PARAM_DECAY_HF_RATIO: + if (p->vsize < sizeof(uint16_t)) + p->status = -EINVAL; + p->vsize = sizeof(uint16_t); + break; + case REVERB_PARAM_REFLECTIONS_LEVEL: + if (p->vsize < sizeof(uint16_t)) + p->status = -EINVAL; + p->vsize = sizeof(uint16_t); + break; + case REVERB_PARAM_REFLECTIONS_DELAY: + if (p->vsize < sizeof(uint32_t)) + p->status = -EINVAL; + p->vsize = sizeof(uint32_t); + break; + case REVERB_PARAM_REVERB_LEVEL: + if (p->vsize < sizeof(uint16_t)) + p->status = -EINVAL; + p->vsize = sizeof(uint16_t); + break; + case REVERB_PARAM_REVERB_DELAY: + if (p->vsize < sizeof(uint32_t)) + p->status = -EINVAL; + p->vsize = sizeof(uint32_t); + break; + case REVERB_PARAM_DIFFUSION: + if (p->vsize < sizeof(uint16_t)) + p->status = -EINVAL; + p->vsize = sizeof(uint16_t); + break; + case REVERB_PARAM_DENSITY: + if (p->vsize < sizeof(uint16_t)) + p->status = -EINVAL; + p->vsize = sizeof(uint16_t); + break; + case REVERB_PARAM_PROPERTIES: + if (p->vsize < sizeof(reverb_settings_t)) + p->status = -EINVAL; + p->vsize = sizeof(reverb_settings_t); + break; + default: + p->status = -EINVAL; + } + + *size = sizeof(effect_param_t) + voffset + p->vsize; + + if (p->status != 0) + return 0; + + switch (param) { + case REVERB_PARAM_PROPERTIES: + reverb_settings = (reverb_settings_t *)value; + reverb_settings->roomLevel = reverb_get_room_level(reverb_ctxt); + reverb_settings->roomHFLevel = reverb_get_room_hf_level(reverb_ctxt); + reverb_settings->decayTime = reverb_get_decay_time(reverb_ctxt); + reverb_settings->decayHFRatio = reverb_get_decay_hf_ratio(reverb_ctxt); + reverb_settings->reflectionsLevel = 0; + reverb_settings->reflectionsDelay = 0; + reverb_settings->reverbDelay = 0; + reverb_settings->reverbLevel = reverb_get_reverb_level(reverb_ctxt); + reverb_settings->diffusion = reverb_get_diffusion(reverb_ctxt); + reverb_settings->density = reverb_get_density(reverb_ctxt); + break; + case REVERB_PARAM_ROOM_LEVEL: + *(int16_t *)value = reverb_get_room_level(reverb_ctxt); + break; + case REVERB_PARAM_ROOM_HF_LEVEL: + *(int16_t *)value = reverb_get_room_hf_level(reverb_ctxt); + break; + case REVERB_PARAM_DECAY_TIME: + *(uint32_t *)value = reverb_get_decay_time(reverb_ctxt); + break; + case REVERB_PARAM_DECAY_HF_RATIO: + *(int16_t *)value = reverb_get_decay_hf_ratio(reverb_ctxt); + break; + case REVERB_PARAM_REVERB_LEVEL: + *(int16_t *)value = reverb_get_reverb_level(reverb_ctxt); + break; + case REVERB_PARAM_DIFFUSION: + *(int16_t *)value = reverb_get_diffusion(reverb_ctxt); + break; + case REVERB_PARAM_DENSITY: + *(int16_t *)value = reverb_get_density(reverb_ctxt); + break; + case REVERB_PARAM_REFLECTIONS_LEVEL: + *(uint16_t *)value = 0; + break; + case REVERB_PARAM_REFLECTIONS_DELAY: + *(uint32_t *)value = 0; + break; + case REVERB_PARAM_REVERB_DELAY: + *(uint32_t *)value = 0; + break; + default: + p->status = -EINVAL; + break; + } + + return 0; +} + +int reverb_set_parameter(effect_context_t *context, effect_param_t *p, + uint32_t size __unused) +{ + reverb_context_t *reverb_ctxt = (reverb_context_t *)context; + int voffset = ((p->psize - 1) / sizeof(int32_t) + 1) * sizeof(int32_t); + void *value = p->data + voffset; + int32_t *param_tmp = (int32_t *)p->data; + int32_t param = *param_tmp++; + reverb_settings_t *reverb_settings; + int16_t level; + int16_t ratio; + uint32_t time; + + ALOGV("%s: ctxt %p, param %d", __func__, reverb_ctxt, param); + + p->status = 0; + + if (reverb_ctxt->preset) { + if (param != REVERB_PARAM_PRESET) + return -EINVAL; + uint16_t preset = *(uint16_t *)value; + ALOGV("set REVERB_PARAM_PRESET, preset %d", preset); + if (preset > REVERB_PRESET_LAST) { + return -EINVAL; + } + reverb_set_preset(reverb_ctxt, preset); + return 0; + } + switch (param) { + case REVERB_PARAM_PROPERTIES: + reverb_settings = (reverb_settings_t *)value; + break; + case REVERB_PARAM_ROOM_LEVEL: + level = *(int16_t *)value; + reverb_set_room_level(reverb_ctxt, level); + break; + case REVERB_PARAM_ROOM_HF_LEVEL: + level = *(int16_t *)value; + reverb_set_room_hf_level(reverb_ctxt, level); + break; + case REVERB_PARAM_DECAY_TIME: + time = *(uint32_t *)value; + reverb_set_decay_time(reverb_ctxt, time); + break; + case REVERB_PARAM_DECAY_HF_RATIO: + ratio = *(int16_t *)value; + reverb_set_decay_hf_ratio(reverb_ctxt, ratio); + break; + case REVERB_PARAM_REVERB_LEVEL: + level = *(int16_t *)value; + reverb_set_reverb_level(reverb_ctxt, level); + break; + case REVERB_PARAM_DIFFUSION: + ratio = *(int16_t *)value; + reverb_set_diffusion(reverb_ctxt, ratio); + break; + case REVERB_PARAM_DENSITY: + ratio = *(int16_t *)value; + reverb_set_density(reverb_ctxt, ratio); + break; + case REVERB_PARAM_REFLECTIONS_LEVEL: + case REVERB_PARAM_REFLECTIONS_DELAY: + case REVERB_PARAM_REVERB_DELAY: + break; + default: + p->status = -EINVAL; + break; + } + + return 0; +} + +int reverb_set_device(effect_context_t *context, uint32_t device) +{ + reverb_context_t *reverb_ctxt = (reverb_context_t *)context; + + ALOGV("%s: ctxt %p, device: 0x%x", __func__, reverb_ctxt, device); + reverb_ctxt->device = device; + offload_reverb_set_device(&(reverb_ctxt->offload_reverb), device); + return 0; +} + +int reverb_reset(effect_context_t *context) +{ + reverb_context_t *reverb_ctxt = (reverb_context_t *)context; + + return 0; +} + +int reverb_init(effect_context_t *context) +{ + reverb_context_t *reverb_ctxt = (reverb_context_t *)context; + + ALOGV("%s: ctxt %p", __func__, reverb_ctxt); + context->config.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ; + /* + FIXME: channel mode is mono for auxiliary. is it needed for offload ? + If so, this set config needs to be updated accordingly + */ + context->config.inputCfg.channels = AUDIO_CHANNEL_OUT_STEREO; + context->config.inputCfg.format = AUDIO_FORMAT_PCM_16_BIT; + context->config.inputCfg.samplingRate = 44100; + context->config.inputCfg.bufferProvider.getBuffer = NULL; + context->config.inputCfg.bufferProvider.releaseBuffer = NULL; + context->config.inputCfg.bufferProvider.cookie = NULL; + context->config.inputCfg.mask = EFFECT_CONFIG_ALL; + context->config.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_ACCUMULATE; + context->config.outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO; + context->config.outputCfg.format = AUDIO_FORMAT_PCM_16_BIT; + context->config.outputCfg.samplingRate = 44100; + context->config.outputCfg.bufferProvider.getBuffer = NULL; + context->config.outputCfg.bufferProvider.releaseBuffer = NULL; + context->config.outputCfg.bufferProvider.cookie = NULL; + context->config.outputCfg.mask = EFFECT_CONFIG_ALL; + + set_config(context, &context->config); + + memset(&(reverb_ctxt->reverb_settings), 0, sizeof(reverb_settings_t)); + memset(&(reverb_ctxt->offload_reverb), 0, sizeof(struct reverb_params)); + + if (reverb_ctxt->preset && + reverb_ctxt->next_preset != reverb_ctxt->cur_preset) + reverb_load_preset(reverb_ctxt); + + return 0; +} + +int reverb_enable(effect_context_t *context) +{ + reverb_context_t *reverb_ctxt = (reverb_context_t *)context; + + ALOGV("%s: ctxt %p", __func__, reverb_ctxt); + + if (!offload_reverb_get_enable_flag(&(reverb_ctxt->offload_reverb))) + offload_reverb_set_enable_flag(&(reverb_ctxt->offload_reverb), true); + return 0; +} + +int reverb_disable(effect_context_t *context) +{ + reverb_context_t *reverb_ctxt = (reverb_context_t *)context; + + ALOGV("%s: ctxt %p", __func__, reverb_ctxt); + if (offload_reverb_get_enable_flag(&(reverb_ctxt->offload_reverb))) { + offload_reverb_set_enable_flag(&(reverb_ctxt->offload_reverb), false); + if (reverb_ctxt->ctl) + offload_reverb_send_params(reverb_ctxt->ctl, + reverb_ctxt->offload_reverb, + OFFLOAD_SEND_REVERB_ENABLE_FLAG); + } + return 0; +} + +int reverb_start(effect_context_t *context, output_context_t *output) +{ + reverb_context_t *reverb_ctxt = (reverb_context_t *)context; + + ALOGV("%s: ctxt %p, ctl %p", __func__, reverb_ctxt, output->ctl); + reverb_ctxt->ctl = output->ctl; + if (offload_reverb_get_enable_flag(&(reverb_ctxt->offload_reverb))) { + if (reverb_ctxt->ctl && reverb_ctxt->preset) { + offload_reverb_send_params(reverb_ctxt->ctl, reverb_ctxt->offload_reverb, + OFFLOAD_SEND_REVERB_ENABLE_FLAG | + OFFLOAD_SEND_REVERB_PRESET); + } + } + + return 0; +} + +int reverb_stop(effect_context_t *context, output_context_t *output __unused) +{ + reverb_context_t *reverb_ctxt = (reverb_context_t *)context; + + ALOGV("%s: ctxt %p", __func__, reverb_ctxt); + reverb_ctxt->ctl = NULL; + return 0; +} + diff --git a/msm8909/post_proc/reverb.h b/msm8909/post_proc/reverb.h new file mode 100644 index 00000000..63192eb0 --- /dev/null +++ b/msm8909/post_proc/reverb.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Not a Contribution. + * + * Copyright (C) 2013 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. + */ + +#ifndef OFFLOAD_REVERB_H_ +#define OFFLOAD_REVERB_H_ + +#include "bundle.h" + +#define REVERB_DEFAULT_PRESET REVERB_PRESET_NONE + +extern const effect_descriptor_t aux_env_reverb_descriptor; +extern const effect_descriptor_t ins_env_reverb_descriptor; +extern const effect_descriptor_t aux_preset_reverb_descriptor; +extern const effect_descriptor_t ins_preset_reverb_descriptor; + +typedef struct reverb_settings_s { + int16_t roomLevel; + int16_t roomHFLevel; + uint32_t decayTime; + int16_t decayHFRatio; + int16_t reflectionsLevel; + uint32_t reflectionsDelay; + int16_t reverbLevel; + uint32_t reverbDelay; + int16_t diffusion; + int16_t density; +} reverb_settings_t; + +typedef struct reverb_context_s { + effect_context_t common; + + // Offload vars + struct mixer_ctl *ctl; + bool auxiliary; + bool preset; + uint16_t cur_preset; + uint16_t next_preset; + reverb_settings_t reverb_settings; + uint32_t device; + struct reverb_params offload_reverb; +} reverb_context_t; + + +void reverb_auxiliary_init(reverb_context_t *context); + +void reverb_preset_init(reverb_context_t *context); + +int reverb_get_parameter(effect_context_t *context, effect_param_t *p, + uint32_t *size); + +int reverb_set_parameter(effect_context_t *context, effect_param_t *p, + uint32_t size); + +int reverb_set_device(effect_context_t *context, uint32_t device); + +int reverb_reset(effect_context_t *context); + +int reverb_init(effect_context_t *context); + +int reverb_enable(effect_context_t *context); + +int reverb_disable(effect_context_t *context); + +int reverb_start(effect_context_t *context, output_context_t *output); + +int reverb_stop(effect_context_t *context, output_context_t *output); + +#endif /* OFFLOAD_REVERB_H_ */ diff --git a/msm8909/post_proc/virtualizer.c b/msm8909/post_proc/virtualizer.c new file mode 100644 index 00000000..dcddfe70 --- /dev/null +++ b/msm8909/post_proc/virtualizer.c @@ -0,0 +1,503 @@ +/* + * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. + * Not a Contribution. + * + * Copyright (C) 2013 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 "offload_effect_virtualizer" +#define LOG_NDEBUG 0 + +#include <cutils/list.h> +#include <cutils/log.h> +#include <tinyalsa/asoundlib.h> +#include <sound/audio_effects.h> +#include <audio_effects/effect_virtualizer.h> + +#include "effect_api.h" +#include "virtualizer.h" + +/* Offload Virtualizer UUID: 509a4498-561a-4bea-b3b1-0002a5d5c51b */ +const effect_descriptor_t virtualizer_descriptor = { + {0x37cc2c00, 0xdddd, 0x11db, 0x8577, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, + {0x509a4498, 0x561a, 0x4bea, 0xb3b1, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // uuid + EFFECT_CONTROL_API_VERSION, + (EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_DEVICE_IND | EFFECT_FLAG_HW_ACC_TUNNEL), + 0, /* TODO */ + 1, + "MSM offload virtualizer", + "The Android Open Source Project", +}; + +/* + * Virtualizer operations + */ + +int virtualizer_get_strength(virtualizer_context_t *context) +{ + ALOGV("%s: ctxt %p, strength: %d", __func__, context, context->strength); + return context->strength; +} + +int virtualizer_set_strength(virtualizer_context_t *context, uint32_t strength) +{ + ALOGV("%s: ctxt %p, strength: %d", __func__, context, strength); + context->strength = strength; + + offload_virtualizer_set_strength(&(context->offload_virt), strength); + if (context->ctl) + offload_virtualizer_send_params(context->ctl, context->offload_virt, + OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG | + OFFLOAD_SEND_VIRTUALIZER_STRENGTH); + return 0; +} + +/* + * Check if an audio device is supported by this implementation + * + * [in] + * device device that is intented for processing (e.g. for binaural vs transaural) + * [out] + * false device is not applicable for effect + * true device is applicable for effect + */ +bool virtualizer_is_device_supported(audio_devices_t device) { + switch (device) { + case AUDIO_DEVICE_OUT_SPEAKER: + case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT: + case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER: +#ifdef AFE_PROXY_ENABLED + case AUDIO_DEVICE_OUT_PROXY: +#endif + case AUDIO_DEVICE_OUT_AUX_DIGITAL: + case AUDIO_DEVICE_OUT_USB_ACCESSORY: + case AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET: + return false; + default : + return true; + } +} + +/* + * Check if a channel mask + audio device is supported by this implementation + * + * [in] + * channel_mask channel mask of input buffer + * device device that is intented for processing (e.g. for binaural vs transaural) + * [out] + * false if the configuration is not supported or it is unknown + * true if the configuration is supported + */ +bool virtualizer_is_configuration_supported(audio_channel_mask_t channel_mask, + audio_devices_t device) { + uint32_t channelCount = audio_channel_count_from_out_mask(channel_mask); + if ((channelCount == 0) || (channelCount > 2)) { + return false; + } + + return virtualizer_is_device_supported(device); +} + +/* + * Force the virtualization mode to that of the given audio device + * + * [in] + * context effect engine context + * forced_device device whose virtualization mode we'll always use + * [out] + * -EINVAL if the device is not supported or is unknown + * 0 if the device is supported and the virtualization mode forced + */ +int virtualizer_force_virtualization_mode(virtualizer_context_t *context, + audio_devices_t forced_device) { + virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)context; + int status = 0; + bool use_virt = false; + int is_virt_enabled = + offload_virtualizer_get_enable_flag(&(virt_ctxt->offload_virt)); + + ALOGV("%s: ctxt %p, forcedDev=0x%x enabled=%d tmpDisabled=%d", __func__, virt_ctxt, + forced_device, is_virt_enabled, virt_ctxt->temp_disabled); + + if (virtualizer_is_device_supported(forced_device) == false) { + if (forced_device != AUDIO_DEVICE_NONE) { + //forced device is not supported, make it behave as a reset of forced mode + forced_device = AUDIO_DEVICE_NONE; + // but return an error + status = -EINVAL; + } + } + + if (forced_device == AUDIO_DEVICE_NONE) { + // disabling forced virtualization mode: + // verify whether the virtualization should be enabled or disabled + if (virtualizer_is_device_supported(virt_ctxt->device)) { + use_virt = (is_virt_enabled == true); + } + virt_ctxt->forced_device = AUDIO_DEVICE_NONE; + } else { + // forcing virtualization mode: + // TODO: we assume device is supported, so hard coded a fixed one. + virt_ctxt->forced_device = AUDIO_DEVICE_OUT_WIRED_HEADPHONE; + // TODO: only enable for a supported mode, when the effect is enabled + use_virt = (is_virt_enabled == true); + } + + if (use_virt) { + if (virt_ctxt->temp_disabled == true) { + if (effect_is_active(&virt_ctxt->common)) { + offload_virtualizer_set_enable_flag(&(virt_ctxt->offload_virt), true); + if (virt_ctxt->ctl) + offload_virtualizer_send_params(virt_ctxt->ctl, + virt_ctxt->offload_virt, + OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG); + } + ALOGV("%s: re-enable VIRTUALIZER", __func__); + virt_ctxt->temp_disabled = false; + } else { + ALOGV("%s: leaving VIRTUALIZER enabled", __func__); + } + } else { + if (virt_ctxt->temp_disabled == false) { + if (effect_is_active(&virt_ctxt->common)) { + offload_virtualizer_set_enable_flag(&(virt_ctxt->offload_virt), false); + if (virt_ctxt->ctl) + offload_virtualizer_send_params(virt_ctxt->ctl, + virt_ctxt->offload_virt, + OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG); + } + ALOGV("%s: disable VIRTUALIZER", __func__); + virt_ctxt->temp_disabled = true; + } else { + ALOGV("%s: leaving VIRTUALIZER disabled", __func__); + } + } + + ALOGV("after %s: ctxt %p, enabled=%d tmpDisabled=%d", __func__, virt_ctxt, + is_virt_enabled, virt_ctxt->temp_disabled); + + return status; +} + +/* + * Get the virtual speaker angles for a channel mask + audio device configuration + * which is guaranteed to be supported by this implementation + * + * [in] + * channel_mask the channel mask of the input to virtualize + * device the type of device that affects the processing (e.g. for binaural vs transaural) + * [in/out] + * speaker_angles the array of integer where each speaker angle is written as a triplet in the + * following format: + * int32_t a bit mask with a single value selected for each speaker, following + * the convention of the audio_channel_mask_t type + * int32_t a value in degrees expressing the speaker azimuth, where 0 is in front + * of the user, 180 behind, -90 to the left, 90 to the right of the user + * int32_t a value in degrees expressing the speaker elevation, where 0 is the + * horizontal plane, +90 is directly above the user, -90 below + * + */ +void virtualizer_get_speaker_angles(audio_channel_mask_t channel_mask __unused, + audio_devices_t device __unused, int32_t *speaker_angles) { + // the channel count is guaranteed to be 1 or 2 + // the device is guaranteed to be of type headphone + // this virtualizer is always 2in with speakers at -90 and 90deg of azimuth, 0deg of elevation + *speaker_angles++ = (int32_t) AUDIO_CHANNEL_OUT_FRONT_LEFT; + *speaker_angles++ = -90; // azimuth + *speaker_angles++ = 0; // elevation + *speaker_angles++ = (int32_t) AUDIO_CHANNEL_OUT_FRONT_RIGHT; + *speaker_angles++ = 90; // azimuth + *speaker_angles = 0; // elevation +} + +/* + * Retrieve the current device whose processing mode is used by this effect + * + * [out] + * AUDIO_DEVICE_NONE if the effect is not virtualizing + * or the device type if the effect is virtualizing + */ +audio_devices_t virtualizer_get_virtualization_mode(virtualizer_context_t *context) { + virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)context; + audio_devices_t device = AUDIO_DEVICE_NONE; + + if ((offload_virtualizer_get_enable_flag(&(virt_ctxt->offload_virt))) + && (virt_ctxt->temp_disabled == false)) { + if (virt_ctxt->forced_device != AUDIO_DEVICE_NONE) { + // virtualization mode is forced, return that device + device = virt_ctxt->forced_device; + } else { + // no forced mode, return the current device + device = virt_ctxt->device; + } + } + ALOGV("%s: returning 0x%x", __func__, device); + return device; +} + +int virtualizer_get_parameter(effect_context_t *context, effect_param_t *p, + uint32_t *size) +{ + virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)context; + int voffset = ((p->psize - 1) / sizeof(int32_t) + 1) * sizeof(int32_t); + int32_t *param_tmp = (int32_t *)p->data; + int32_t param = *param_tmp++; + void *value = p->data + voffset; + int i; + + ALOGV("%s: ctxt %p, param %d", __func__, virt_ctxt, param); + + p->status = 0; + + switch (param) { + case VIRTUALIZER_PARAM_STRENGTH_SUPPORTED: + if (p->vsize < sizeof(uint32_t)) + p->status = -EINVAL; + p->vsize = sizeof(uint32_t); + break; + case VIRTUALIZER_PARAM_STRENGTH: + if (p->vsize < sizeof(int16_t)) + p->status = -EINVAL; + p->vsize = sizeof(int16_t); + break; + case VIRTUALIZER_PARAM_VIRTUAL_SPEAKER_ANGLES: + // return value size can only be interpreted as relative to input value, + // deferring validity check to below + break; + case VIRTUALIZER_PARAM_VIRTUALIZATION_MODE: + if (p->vsize != sizeof(uint32_t)) + p->status = -EINVAL; + p->vsize = sizeof(uint32_t); + break; + default: + p->status = -EINVAL; + } + + *size = sizeof(effect_param_t) + voffset + p->vsize; + + if (p->status != 0) + return 0; + + switch (param) { + case VIRTUALIZER_PARAM_STRENGTH_SUPPORTED: + *(uint32_t *)value = 1; + break; + + case VIRTUALIZER_PARAM_STRENGTH: + *(int16_t *)value = virtualizer_get_strength(virt_ctxt); + break; + + case VIRTUALIZER_PARAM_VIRTUAL_SPEAKER_ANGLES: + { + const audio_channel_mask_t channel_mask = (audio_channel_mask_t) *param_tmp++; + const audio_devices_t device = (audio_devices_t) *param_tmp; + uint32_t channel_cnt = audio_channel_count_from_out_mask(channel_mask); + + if (p->vsize < 3 * channel_cnt * sizeof(int32_t)){ + p->status = -EINVAL; + break; + } + // verify the configuration is supported + if(virtualizer_is_configuration_supported(channel_mask, device)) { + // configuration is supported, get the angles + virtualizer_get_speaker_angles(channel_mask, device, (int32_t *)value); + } else { + p->status = -EINVAL; + } + + break; + } + + case VIRTUALIZER_PARAM_VIRTUALIZATION_MODE: + *(uint32_t *)value = (uint32_t) virtualizer_get_virtualization_mode(virt_ctxt); + break; + + default: + p->status = -EINVAL; + break; + } + + return 0; +} + +int virtualizer_set_parameter(effect_context_t *context, effect_param_t *p, + uint32_t size __unused) +{ + virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)context; + int voffset = ((p->psize - 1) / sizeof(int32_t) + 1) * sizeof(int32_t); + void *value = p->data + voffset; + int32_t *param_tmp = (int32_t *)p->data; + int32_t param = *param_tmp++; + uint32_t strength; + + ALOGV("%s: ctxt %p, param %d", __func__, virt_ctxt, param); + + p->status = 0; + + switch (param) { + case VIRTUALIZER_PARAM_STRENGTH: + strength = (uint32_t)(*(int16_t *)value); + virtualizer_set_strength(virt_ctxt, strength); + break; + case VIRTUALIZER_PARAM_FORCE_VIRTUALIZATION_MODE: + { + const audio_devices_t device = *(audio_devices_t *)value; + if (0 != virtualizer_force_virtualization_mode(virt_ctxt, device)) { + p->status = -EINVAL; + } + break; + } + default: + p->status = -EINVAL; + break; + } + + return 0; +} + +int virtualizer_set_device(effect_context_t *context, uint32_t device) +{ + virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)context; + + ALOGV("%s: ctxt %p, device: 0x%x", __func__, virt_ctxt, device); + virt_ctxt->device = device; + + if (virt_ctxt->forced_device == AUDIO_DEVICE_NONE) { + // default case unless configuration is forced + if (virtualizer_is_device_supported(device) == false) { + if (!virt_ctxt->temp_disabled) { + if (effect_is_active(&virt_ctxt->common)) { + offload_virtualizer_set_enable_flag(&(virt_ctxt->offload_virt), false); + if (virt_ctxt->ctl) + offload_virtualizer_send_params(virt_ctxt->ctl, + virt_ctxt->offload_virt, + OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG); + } + ALOGI("%s: ctxt %p, disabled based on device", __func__, virt_ctxt); + virt_ctxt->temp_disabled = true; + } + } else { + if (virt_ctxt->temp_disabled) { + if (effect_is_active(&virt_ctxt->common)) { + offload_virtualizer_set_enable_flag(&(virt_ctxt->offload_virt), true); + if (virt_ctxt->ctl) + offload_virtualizer_send_params(virt_ctxt->ctl, + virt_ctxt->offload_virt, + OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG); + } + virt_ctxt->temp_disabled = false; + } + } + } + // else virtualization mode is forced to a certain device, nothing to do + + offload_virtualizer_set_device(&(virt_ctxt->offload_virt), device); + return 0; +} + +int virtualizer_reset(effect_context_t *context) +{ + virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)context; + + return 0; +} + +int virtualizer_init(effect_context_t *context) +{ + ALOGV("%s: ctxt %p", __func__, context); + virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)context; + + context->config.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ; + context->config.inputCfg.channels = AUDIO_CHANNEL_OUT_STEREO; + context->config.inputCfg.format = AUDIO_FORMAT_PCM_16_BIT; + context->config.inputCfg.samplingRate = 44100; + context->config.inputCfg.bufferProvider.getBuffer = NULL; + context->config.inputCfg.bufferProvider.releaseBuffer = NULL; + context->config.inputCfg.bufferProvider.cookie = NULL; + context->config.inputCfg.mask = EFFECT_CONFIG_ALL; + context->config.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_ACCUMULATE; + context->config.outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO; + context->config.outputCfg.format = AUDIO_FORMAT_PCM_16_BIT; + context->config.outputCfg.samplingRate = 44100; + context->config.outputCfg.bufferProvider.getBuffer = NULL; + context->config.outputCfg.bufferProvider.releaseBuffer = NULL; + context->config.outputCfg.bufferProvider.cookie = NULL; + context->config.outputCfg.mask = EFFECT_CONFIG_ALL; + + set_config(context, &context->config); + + virt_ctxt->temp_disabled = false; + virt_ctxt->forced_device = AUDIO_DEVICE_NONE; + virt_ctxt->device = AUDIO_DEVICE_NONE; + memset(&(virt_ctxt->offload_virt), 0, sizeof(struct virtualizer_params)); + + return 0; +} + +int virtualizer_enable(effect_context_t *context) +{ + virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)context; + + ALOGV("%s: ctxt %p, strength %d", __func__, virt_ctxt, virt_ctxt->strength); + + if (!offload_virtualizer_get_enable_flag(&(virt_ctxt->offload_virt)) && + !(virt_ctxt->temp_disabled)) { + offload_virtualizer_set_enable_flag(&(virt_ctxt->offload_virt), true); + if (virt_ctxt->ctl && virt_ctxt->strength) + offload_virtualizer_send_params(virt_ctxt->ctl, + virt_ctxt->offload_virt, + OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG | + OFFLOAD_SEND_BASSBOOST_STRENGTH); + } + return 0; +} + +int virtualizer_disable(effect_context_t *context) +{ + virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)context; + + ALOGV("%s: ctxt %p", __func__, virt_ctxt); + if (offload_virtualizer_get_enable_flag(&(virt_ctxt->offload_virt))) { + offload_virtualizer_set_enable_flag(&(virt_ctxt->offload_virt), false); + if (virt_ctxt->ctl) + offload_virtualizer_send_params(virt_ctxt->ctl, + virt_ctxt->offload_virt, + OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG); + } + return 0; +} + +int virtualizer_start(effect_context_t *context, output_context_t *output) +{ + virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)context; + + ALOGV("%s: ctxt %p, ctl %p", __func__, virt_ctxt, output->ctl); + virt_ctxt->ctl = output->ctl; + if (offload_virtualizer_get_enable_flag(&(virt_ctxt->offload_virt))) + if (virt_ctxt->ctl) + offload_virtualizer_send_params(virt_ctxt->ctl, virt_ctxt->offload_virt, + OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG | + OFFLOAD_SEND_VIRTUALIZER_STRENGTH); + return 0; +} + +int virtualizer_stop(effect_context_t *context, output_context_t *output __unused) +{ + virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)context; + + ALOGV("%s: ctxt %p", __func__, virt_ctxt); + virt_ctxt->ctl = NULL; + return 0; +} diff --git a/msm8909/post_proc/virtualizer.h b/msm8909/post_proc/virtualizer.h new file mode 100644 index 00000000..21bc2547 --- /dev/null +++ b/msm8909/post_proc/virtualizer.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. + * Not a Contribution. + * + * Copyright (C) 2013 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. + */ + +#ifndef OFFLOAD_VIRTUALIZER_H_ +#define OFFLOAD_VIRTUALIZER_H_ + +#include "bundle.h" + +extern const effect_descriptor_t virtualizer_descriptor; + +typedef struct virtualizer_context_s { + effect_context_t common; + + int strength; + + // Offload vars + struct mixer_ctl *ctl; + bool temp_disabled; + audio_devices_t forced_device; + audio_devices_t device; + struct virtualizer_params offload_virt; +} virtualizer_context_t; + +int virtualizer_get_parameter(effect_context_t *context, effect_param_t *p, + uint32_t *size); + +int virtualizer_set_parameter(effect_context_t *context, effect_param_t *p, + uint32_t size); + +int virtualizer_set_device(effect_context_t *context, uint32_t device); + +int virtualizer_reset(effect_context_t *context); + +int virtualizer_init(effect_context_t *context); + +int virtualizer_enable(effect_context_t *context); + +int virtualizer_disable(effect_context_t *context); + +int virtualizer_start(effect_context_t *context, output_context_t *output); + +int virtualizer_stop(effect_context_t *context, output_context_t *output); + +#endif /* OFFLOAD_VIRTUALIZER_H_ */ |