summaryrefslogtreecommitdiffstats
path: root/msm8909/post_proc
diff options
context:
space:
mode:
Diffstat (limited to 'msm8909/post_proc')
-rw-r--r--msm8909/post_proc/Android.mk34
-rw-r--r--msm8909/post_proc/bass_boost.c280
-rw-r--r--msm8909/post_proc/bass_boost.h59
-rw-r--r--msm8909/post_proc/bundle.c780
-rw-r--r--msm8909/post_proc/bundle.h92
-rw-r--r--msm8909/post_proc/effect_api.c620
-rw-r--r--msm8909/post_proc/effect_api.h151
-rw-r--r--msm8909/post_proc/equalizer.c497
-rw-r--r--msm8909/post_proc/equalizer.h63
-rw-r--r--msm8909/post_proc/reverb.c613
-rw-r--r--msm8909/post_proc/reverb.h84
-rw-r--r--msm8909/post_proc/virtualizer.c503
-rw-r--r--msm8909/post_proc/virtualizer.h60
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_ */