post_proc: Offload effects combined patchset
* Support effects in DSP for tunnel mode playback
Add interface to support configuring equlaizer, bass boost,
virtualizer and reverb effects in DSP for tunnel mode of
playback.
(cherry-picked from CAF commit 3eedc004e9adf5967f393d65c22b7806d0c63e6c)
* post_proc: Enable effects param in DSP to start effect
-During switch to tunnel playback, offload effects-flags remain
disabled. This stops effects being applied on tunnel playback.
-Send effects enable params to DSP to start effects during switch.
(cherry-picked from CAF commit d02f2cd710334cc2be6a866da537a595256ae623)
* post_proc: disable adsp reverb when preset is 'None'
Audio HAL set corresponding preset id into adsp, but doesn't disabe
reverb explicitly when 'None' preset is chosen. However, preset=0
means custom preset in adsp, so adsp won't stop reverb processing.
(cherry-picked from CAF commit b27e25f062edfeebb6860078013c7b413b8c4301)
* post_proc: send ENABLE_FLAG directly to offload effect driver
Enable flag should be sent directly through offload effect driver to
adsp whenever bundle receives EFFECT_CMD_ENABLE. Otherwise enablement
will only take effect in adsp after subsequent parameters being set, and
that's not expected.
(cherry-picked from CAF commit d45948e2153c03b41f55577debd943408f9c8280)
* post_proc: reverb preset id is not mapped correctly
Array index is not correct and causes uninitialized value being used
when 'Plate' is chosen. Correct index to retrieve the right preset id.
(cherry-picked from CAF commit ca2685b2a0a695a7c4ac78883e750a92dcad0515)
* post_proc: disable Bassboost and Virtualizer for certain devices
WFD, Hdmi and usb audio are not intended to be applied with
SA+ bassboost and virtualizer, so add into invalid device list.
(cherry-picked from CAF ee2ff9621d25d83151ccb24a416f21533fdfbd31)
* post_proc: disable effect immediately when routed to invalid devices
Offload effect is still perceived when invalid output device is
connected. We should send disable command immediately once phone is
routed to unexpected device and forbid effect enablement during
temporary disabled state.
(cherry-picked from CAF commit 95d74c2232721631f3a04f6ccf35760b37b33fea)
* post_proc: Enable reverb in DSP to start effect
During switch to tunnel playback, reverb enable command is not sent to
DSP and causes reverb effect not applied continuously.
Send reverb enable params to DSP to start effects during switch.
(cherry-picked from CAF commit c37c260fa174453f4822261bcd531ddb2706ab2c)
* post_proc: include audio_effects.h from kernel exported headers
Currently, audio_effects.h header file is included with reference
to the absolute path. Instead, reference it from the kernel
exported headers.
(cherry-picked from CAF commit 090a2aa3f38298196ad9f47e3b6578535e1f7e10)
* hal: Add support for audio effects in DSP for tunnel mode playback
Add support to enable or disable audio post processing effects
in DSP for tunnel mode playback.
(cherry-picked from CAF commit 1d0891672175d431e8872dd7dff21e0ce507361a)
Change-Id: I7ead6da4c216fd87e8ca1884811c4e0155053f49
diff --git a/Android.mk b/Android.mk
index e1d4ec2..6dbcccd 100644
--- a/Android.mk
+++ b/Android.mk
@@ -8,6 +8,7 @@
include $(MY_LOCAL_PATH)/hal/Android.mk
include $(MY_LOCAL_PATH)/voice_processing/Android.mk
include $(MY_LOCAL_PATH)/visualizer/Android.mk
+include $(MY_LOCAL_PATH)/post_proc/Android.mk
endif
endif
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 9eddfb6..6299455 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -933,9 +933,12 @@
return -EINVAL;
}
- if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD &&
- adev->visualizer_stop_output != NULL)
- adev->visualizer_stop_output(out->handle);
+ if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
+ if (adev->visualizer_stop_output != NULL)
+ adev->visualizer_stop_output(out->handle, out->pcm_device_id);
+ if (adev->offload_effects_stop_output != NULL)
+ adev->offload_effects_stop_output(out->handle, out->pcm_device_id);
+ }
/* 1. Get and set stream specific mixer controls */
disable_audio_route(adev, uc_info);
@@ -1013,7 +1016,9 @@
compress_nonblock(out->compr, out->non_blocking);
if (adev->visualizer_start_output != NULL)
- adev->visualizer_start_output(out->handle);
+ adev->visualizer_start_output(out->handle, out->pcm_device_id);
+ if (adev->offload_effects_start_output != NULL)
+ adev->offload_effects_start_output(out->handle, out->pcm_device_id);
}
ALOGV("%s: exit", __func__);
return 0;
@@ -1343,7 +1348,6 @@
const char *mixer_ctl_name = "Compress Playback Volume";
struct audio_device *adev = out->dev;
struct mixer_ctl *ctl;
-
ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
if (!ctl) {
/* try with the control based on device id */
@@ -2515,14 +2519,31 @@
} else {
ALOGV("%s: DLOPEN successful for %s", __func__, VISUALIZER_LIBRARY_PATH);
adev->visualizer_start_output =
- (int (*)(audio_io_handle_t))dlsym(adev->visualizer_lib,
+ (int (*)(audio_io_handle_t, int))dlsym(adev->visualizer_lib,
"visualizer_hal_start_output");
adev->visualizer_stop_output =
- (int (*)(audio_io_handle_t))dlsym(adev->visualizer_lib,
+ (int (*)(audio_io_handle_t, int))dlsym(adev->visualizer_lib,
"visualizer_hal_stop_output");
}
}
+ if (access(OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH, R_OK) == 0) {
+ adev->offload_effects_lib = dlopen(OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH, RTLD_NOW);
+ if (adev->offload_effects_lib == NULL) {
+ ALOGE("%s: DLOPEN failed for %s", __func__,
+ OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH);
+ } else {
+ ALOGV("%s: DLOPEN successful for %s", __func__,
+ OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH);
+ adev->offload_effects_start_output =
+ (int (*)(audio_io_handle_t, int))dlsym(adev->offload_effects_lib,
+ "offload_effects_bundle_hal_start_output");
+ adev->offload_effects_stop_output =
+ (int (*)(audio_io_handle_t, int))dlsym(adev->offload_effects_lib,
+ "offload_effects_bundle_hal_stop_output");
+ }
+ }
+
adev->bt_wb_speech_enabled = false;
*device = &adev->device.common;
diff --git a/hal/audio_hw.h b/hal/audio_hw.h
index 62bc100..b70696d 100644
--- a/hal/audio_hw.h
+++ b/hal/audio_hw.h
@@ -28,6 +28,7 @@
#include "voice.h"
#define VISUALIZER_LIBRARY_PATH "/system/lib/soundfx/libqcomvisualizer.so"
+#define OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH "/system/lib/soundfx/libqcompostprocbundle.so"
/* Flags used to initialize acdb_settings variable that goes to ACDB library */
#define DMIC_FLAG 0x00000002
@@ -206,8 +207,8 @@
void *platform;
void *visualizer_lib;
- int (*visualizer_start_output)(audio_io_handle_t);
- int (*visualizer_stop_output)(audio_io_handle_t);
+ int (*visualizer_start_output)(audio_io_handle_t, int);
+ int (*visualizer_stop_output)(audio_io_handle_t, int);
/* The pcm_params use_case_table is loaded by adev_verify_devices() upon
* calling adev_open().
@@ -216,6 +217,9 @@
* or other capabilities are present for the device corresponding to that usecase.
*/
struct pcm_params *use_case_table[AUDIO_USECASE_MAX];
+ void *offload_effects_lib;
+ int (*offload_effects_start_output)(audio_io_handle_t, int);
+ int (*offload_effects_stop_output)(audio_io_handle_t, int);
};
int pcm_ioctl(void *pcm, int request, ...);
diff --git a/post_proc/Android.mk b/post_proc/Android.mk
new file mode 100644
index 0000000..01e3c68
--- /dev/null
+++ b/post_proc/Android.mk
@@ -0,0 +1,33 @@
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+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_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/soundfx
+LOCAL_MODULE:= libqcompostprocbundle
+
+LOCAL_C_INCLUDES := \
+ external/tinyalsa/include \
+ $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include \
+ $(call include-path-for, audio-effects)
+
+LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/post_proc/bass_boost.c b/post_proc/bass_boost.c
new file mode 100644
index 0000000..183f2f1
--- /dev/null
+++ b/post_proc/bass_boost.c
@@ -0,0 +1,275 @@
+/*
+ * Copyright (C) 2014 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: strength: %d", __func__, context->strength);
+ return context->strength;
+}
+
+int bassboost_set_strength(bassboost_context_t *context, uint32_t strength)
+{
+ ALOGV("%s: strength: %d", __func__, 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", __func__);
+
+ 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:
+ ALOGV("%s: BASSBOOST_PARAM_STRENGTH_SUPPORTED", __func__);
+ *(uint32_t *)value = 1;
+ break;
+
+ case BASSBOOST_PARAM_STRENGTH:
+ ALOGV("%s: BASSBOOST_PARAM_STRENGTH", __func__);
+ *(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)
+{
+ 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", __func__);
+
+ p->status = 0;
+
+ switch (param) {
+ case BASSBOOST_PARAM_STRENGTH:
+ ALOGV("%s BASSBOOST_PARAM_STRENGTH", __func__);
+ 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: device: %d", __func__, 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) ||
+ (device == AUDIO_DEVICE_OUT_PROXY) ||
+ (device == AUDIO_DEVICE_OUT_AUX_DIGITAL) ||
+ (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;
+ }
+ } 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", __func__);
+ 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", __func__);
+
+ 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", __func__);
+ 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", __func__);
+ bass_ctxt->ctl = output->ctl;
+ ALOGV("output->ctl: %p", 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)
+{
+ bassboost_context_t *bass_ctxt = (bassboost_context_t *)context;
+
+ ALOGV("%s", __func__);
+ bass_ctxt->ctl = NULL;
+ return 0;
+}
diff --git a/post_proc/bass_boost.h b/post_proc/bass_boost.h
new file mode 100644
index 0000000..7717b12
--- /dev/null
+++ b/post_proc/bass_boost.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2014 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/post_proc/bundle.c b/post_proc/bundle.c
new file mode 100644
index 0000000..d4aa6d6
--- /dev/null
+++ b/post_proc/bundle.c
@@ -0,0 +1,758 @@
+/*
+ * Copyright (C) 2014 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 "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;
+
+ 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;
+
+ 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));
+ 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));
+ 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));
+ 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));
+ 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));
+ 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_insert_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,
+ audio_buffer_t *outBuffer)
+{
+ effect_context_t * context = (effect_context_t *)self;
+ int status = 0;
+
+ ALOGW("%s Called ?????", __func__);
+
+ 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;
+ }
+
+ 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);
+ ALOGV("%s EFFECT_CMD_ENABLE", __func__);
+ *(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);
+ ALOGV("%s EFFECT_CMD_DISABLE", __func__);
+ *(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;
+ ALOGV("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;
+ ALOGV("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;
+ ALOGV("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)) {
+ ALOGV("%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 Android Open Source Project",
+ create_effect : effect_lib_create,
+ release_effect : effect_lib_release,
+ get_descriptor : effect_lib_get_descriptor,
+};
diff --git a/post_proc/bundle.h b/post_proc/bundle.h
new file mode 100644
index 0000000..70a06d4
--- /dev/null
+++ b/post_proc/bundle.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2014 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/post_proc/effect_api.c b/post_proc/effect_api.c
new file mode 100644
index 0000000..cf3968b
--- /dev/null
+++ b/post_proc/effect_api.c
@@ -0,0 +1,599 @@
+/*
+ * Copyright (C) 2014 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_api"
+//#define LOG_NDEBUG 0
+
+#include <stdbool.h>
+#include <cutils/log.h>
+#include <tinyalsa/asoundlib.h>
+#include <sound/audio_effects.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)
+{
+ ALOGV("%s", __func__);
+ bassboost->device = device;
+}
+
+void offload_bassboost_set_enable_flag(struct bass_boost_params *bassboost,
+ bool enable)
+{
+ ALOGV("%s", __func__);
+ bassboost->enable_flag = enable;
+}
+
+int offload_bassboost_get_enable_flag(struct bass_boost_params *bassboost)
+{
+ ALOGV("%s", __func__);
+ return bassboost->enable_flag;
+}
+
+void offload_bassboost_set_strength(struct bass_boost_params *bassboost,
+ int strength)
+{
+ ALOGV("%s", __func__);
+ bassboost->strength = strength;
+}
+
+void offload_bassboost_set_mode(struct bass_boost_params *bassboost,
+ int mode)
+{
+ ALOGV("%s", __func__);
+ 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", __func__);
+ *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)
+{
+ ALOGV("%s", __func__);
+ virtualizer->device = device;
+}
+
+void offload_virtualizer_set_enable_flag(struct virtualizer_params *virtualizer,
+ bool enable)
+{
+ ALOGV("%s", __func__);
+ virtualizer->enable_flag = enable;
+}
+
+int offload_virtualizer_get_enable_flag(struct virtualizer_params *virtualizer)
+{
+ ALOGV("%s", __func__);
+ return virtualizer->enable_flag;
+}
+
+void offload_virtualizer_set_strength(struct virtualizer_params *virtualizer,
+ int strength)
+{
+ ALOGV("%s", __func__);
+ virtualizer->strength = strength;
+}
+
+void offload_virtualizer_set_out_type(struct virtualizer_params *virtualizer,
+ int out_type)
+{
+ ALOGV("%s", __func__);
+ virtualizer->out_type = out_type;
+}
+
+void offload_virtualizer_set_gain_adjust(struct virtualizer_params *virtualizer,
+ int gain_adjust)
+{
+ ALOGV("%s", __func__);
+ 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", __func__);
+ *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)
+{
+ ALOGV("%s", __func__);
+ eq->device = device;
+}
+
+void offload_eq_set_enable_flag(struct eq_params *eq, bool enable)
+{
+ ALOGV("%s", __func__);
+ eq->enable_flag = enable;
+}
+
+int offload_eq_get_enable_flag(struct eq_params *eq)
+{
+ ALOGV("%s", __func__);
+ return eq->enable_flag;
+}
+
+void offload_eq_set_preset(struct eq_params *eq, int preset)
+{
+ ALOGV("%s", __func__);
+ 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;
+ ALOGV("%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", __func__);
+ if (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)
+{
+ ALOGV("%s", __func__);
+ reverb->device = device;
+}
+
+void offload_reverb_set_enable_flag(struct reverb_params *reverb, bool enable)
+{
+ ALOGV("%s", __func__);
+ reverb->enable_flag = enable;
+}
+
+int offload_reverb_get_enable_flag(struct reverb_params *reverb)
+{
+ ALOGV("%s", __func__);
+ return reverb->enable_flag;
+}
+
+void offload_reverb_set_mode(struct reverb_params *reverb, int mode)
+{
+ ALOGV("%s", __func__);
+ reverb->mode = mode;
+}
+
+void offload_reverb_set_preset(struct reverb_params *reverb, int preset)
+{
+ ALOGV("%s", __func__);
+ 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)
+{
+ ALOGV("%s", __func__);
+ reverb->wet_mix = wet_mix;
+}
+
+void offload_reverb_set_gain_adjust(struct reverb_params *reverb,
+ int gain_adjust)
+{
+ ALOGV("%s", __func__);
+ reverb->gain_adjust = gain_adjust;
+}
+
+void offload_reverb_set_room_level(struct reverb_params *reverb, int room_level)
+{
+ ALOGV("%s", __func__);
+ reverb->room_level = room_level;
+}
+
+void offload_reverb_set_room_hf_level(struct reverb_params *reverb,
+ int room_hf_level)
+{
+ ALOGV("%s", __func__);
+ reverb->room_hf_level = room_hf_level;
+}
+
+void offload_reverb_set_decay_time(struct reverb_params *reverb, int decay_time)
+{
+ ALOGV("%s", __func__);
+ reverb->decay_time = decay_time;
+}
+
+void offload_reverb_set_decay_hf_ratio(struct reverb_params *reverb,
+ int decay_hf_ratio)
+{
+ ALOGV("%s", __func__);
+ reverb->decay_hf_ratio = decay_hf_ratio;
+}
+
+void offload_reverb_set_reflections_level(struct reverb_params *reverb,
+ int reflections_level)
+{
+ ALOGV("%s", __func__);
+ reverb->reflections_level = reflections_level;
+}
+
+void offload_reverb_set_reflections_delay(struct reverb_params *reverb,
+ int reflections_delay)
+{
+ ALOGV("%s", __func__);
+ reverb->reflections_delay = reflections_delay;
+}
+
+void offload_reverb_set_reverb_level(struct reverb_params *reverb,
+ int reverb_level)
+{
+ ALOGV("%s", __func__);
+ reverb->level = reverb_level;
+}
+
+void offload_reverb_set_delay(struct reverb_params *reverb, int delay)
+{
+ ALOGV("%s", __func__);
+ reverb->delay = delay;
+}
+
+void offload_reverb_set_diffusion(struct reverb_params *reverb, int diffusion)
+{
+ ALOGV("%s", __func__);
+ reverb->diffusion = diffusion;
+}
+
+void offload_reverb_set_density(struct reverb_params *reverb, int density)
+{
+ ALOGV("%s", __func__);
+ 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", __func__);
+ *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/post_proc/effect_api.h b/post_proc/effect_api.h
new file mode 100644
index 0000000..b169319
--- /dev/null
+++ b/post_proc/effect_api.h
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2014 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_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/post_proc/equalizer.c b/post_proc/equalizer.c
new file mode 100644
index 0000000..4f8b584
--- /dev/null
+++ b/post_proc/equalizer.c
@@ -0,0 +1,506 @@
+/*
+ * Copyright (C) 2014 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: band: %d level: %d", __func__, 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: band: %d, level: %d", __func__, 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: band: %d", __func__, 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: band: %d", __func__, 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: freq: %d", __func__, 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: preset: %d", __func__, context->preset);
+ return context->preset;
+}
+
+int equalizer_set_preset(equalizer_context_t *context, int preset)
+{
+ int i;
+
+ ALOGV("%s: preset: %d", __func__, 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: preset: %s", __func__, 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: presets_num: %d", __func__,
+ 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", __func__);
+
+ 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:
+ ALOGV("%s: EQ_PARAM_NUM_BANDS", __func__);
+ *(uint16_t *)value = (uint16_t)NUM_EQ_BANDS;
+ break;
+
+ case EQ_PARAM_LEVEL_RANGE:
+ ALOGV("%s: EQ_PARAM_LEVEL_RANGE", __func__);
+ *(int16_t *)value = -1500;
+ *((int16_t *)value + 1) = 1500;
+ break;
+
+ case EQ_PARAM_BAND_LEVEL:
+ ALOGV("%s: EQ_PARAM_BAND_LEVEL", __func__);
+ 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:
+ ALOGV("%s: EQ_PARAM_CENTER_FREQ", __func__);
+ 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:
+ ALOGV("%s: EQ_PARAM_BAND_FREQ_RANGE", __func__);
+ 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:
+ ALOGV("%s: EQ_PARAM_GET_BAND", __func__);
+ param2 = *param_tmp;
+ *(uint16_t *)value = (uint16_t)equalizer_get_band(eq_ctxt, param2);
+ break;
+
+ case EQ_PARAM_CUR_PRESET:
+ ALOGV("%s: EQ_PARAM_CUR_PRESET", __func__);
+ *(uint16_t *)value = (uint16_t)equalizer_get_preset(eq_ctxt);
+ break;
+
+ case EQ_PARAM_GET_NUM_OF_PRESETS:
+ ALOGV("%s: EQ_PARAM_GET_NUM_OF_PRESETS", __func__);
+ *(uint16_t *)value = (uint16_t)equalizer_get_num_presets(eq_ctxt);
+ break;
+
+ case EQ_PARAM_GET_PRESET_NAME:
+ ALOGV("%s: EQ_PARAM_GET_PRESET_NAME", __func__);
+ param2 = *param_tmp;
+ ALOGV("param2: %d", 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: {
+ ALOGV("%s: EQ_PARAM_PROPERTIES", __func__);
+ 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)
+{
+ 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", __func__);
+
+ p->status = 0;
+
+ switch (param) {
+ case EQ_PARAM_CUR_PRESET:
+ ALOGV("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:
+ ALOGV("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: {
+ ALOGV("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: device: %d", __func__, 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", __func__);
+ 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", __func__);
+
+ 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", __func__);
+ 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: %p", __func__, 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)
+{
+ equalizer_context_t *eq_ctxt = (equalizer_context_t *)context;
+
+ ALOGV("%s", __func__);
+ eq_ctxt->ctl = NULL;
+ return 0;
+}
diff --git a/post_proc/equalizer.h b/post_proc/equalizer.h
new file mode 100644
index 0000000..00ad616
--- /dev/null
+++ b/post_proc/equalizer.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2014 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/post_proc/reverb.c b/post_proc/reverb.c
new file mode 100644
index 0000000..5d19041
--- /dev/null
+++ b/post_proc/reverb.c
@@ -0,0 +1,632 @@
+/*
+ * Copyright (C) 2014 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_insert_init(reverb_context_t *context)
+{
+ context->auxiliary = false;
+ context->preset = true;
+ context->cur_preset = REVERB_PRESET_LAST + 1;
+ context->next_preset = REVERB_DEFAULT_PRESET;
+}
+
+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: room level: %d", __func__, context->reverb_settings.roomLevel);
+ return context->reverb_settings.roomLevel;
+}
+
+void reverb_set_room_level(reverb_context_t *context, int16_t room_level)
+{
+ ALOGV("%s: room level: %d", __func__, 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: room hf level: %d", __func__,
+ 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: room hf level: %d", __func__, 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: decay time: %d", __func__, context->reverb_settings.decayTime);
+ return context->reverb_settings.decayTime;
+}
+
+void reverb_set_decay_time(reverb_context_t *context, uint32_t decay_time)
+{
+ ALOGV("%s: decay_time: %d", __func__, 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: decay hf ratio: %d", __func__,
+ 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: decay_hf_ratio: %d", __func__, 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: reverb level: %d", __func__, context->reverb_settings.reverbLevel);
+ return context->reverb_settings.reverbLevel;
+}
+
+void reverb_set_reverb_level(reverb_context_t *context, int16_t reverb_level)
+{
+ ALOGV("%s: reverb level: %d", __func__, 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: diffusion: %d", __func__, context->reverb_settings.diffusion);
+ return context->reverb_settings.diffusion;
+}
+
+void reverb_set_diffusion(reverb_context_t *context, int16_t diffusion)
+{
+ ALOGV("%s: diffusion: %d", __func__, 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: density: %d", __func__, context->reverb_settings.density);
+ return context->reverb_settings.density;
+}
+
+void reverb_set_density(reverb_context_t *context, int16_t density)
+{
+ ALOGV("%s: density: %d", __func__, 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: preset: %d", __func__, 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", __func__);
+ 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", __func__);
+
+ 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:
+ ALOGV("%s: REVERB_PARAM_PROPERTIES", __func__);
+ 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:
+ ALOGV("%s: REVERB_PARAM_ROOM_LEVEL", __func__);
+ *(int16_t *)value = reverb_get_room_level(reverb_ctxt);
+ break;
+ case REVERB_PARAM_ROOM_HF_LEVEL:
+ ALOGV("%s: REVERB_PARAM_ROOM_HF_LEVEL", __func__);
+ *(int16_t *)value = reverb_get_room_hf_level(reverb_ctxt);
+ break;
+ case REVERB_PARAM_DECAY_TIME:
+ ALOGV("%s: REVERB_PARAM_DECAY_TIME", __func__);
+ *(uint32_t *)value = reverb_get_decay_time(reverb_ctxt);
+ break;
+ case REVERB_PARAM_DECAY_HF_RATIO:
+ ALOGV("%s: REVERB_PARAM_DECAY_HF_RATIO", __func__);
+ *(int16_t *)value = reverb_get_decay_hf_ratio(reverb_ctxt);
+ break;
+ case REVERB_PARAM_REVERB_LEVEL:
+ ALOGV("%s: REVERB_PARAM_REVERB_LEVEL", __func__);
+ *(int16_t *)value = reverb_get_reverb_level(reverb_ctxt);
+ break;
+ case REVERB_PARAM_DIFFUSION:
+ ALOGV("%s: REVERB_PARAM_DIFFUSION", __func__);
+ *(int16_t *)value = reverb_get_diffusion(reverb_ctxt);
+ break;
+ case REVERB_PARAM_DENSITY:
+ ALOGV("%s: REVERB_PARAM_DENSITY", __func__);
+ *(int16_t *)value = reverb_get_density(reverb_ctxt);
+ break;
+ case REVERB_PARAM_REFLECTIONS_LEVEL:
+ ALOGV("%s: REVERB_PARAM_REFLECTIONS_LEVEL", __func__);
+ *(uint16_t *)value = 0;
+ break;
+ case REVERB_PARAM_REFLECTIONS_DELAY:
+ ALOGV("%s: REVERB_PARAM_REFLECTIONS_DELAY", __func__);
+ *(uint32_t *)value = 0;
+ break;
+ case REVERB_PARAM_REVERB_DELAY:
+ ALOGV("%s: REVERB_PARAM_REVERB_DELAY", __func__);
+ *(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)
+{
+ 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", __func__);
+
+ 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:
+ ALOGV("%s: REVERB_PARAM_PROPERTIES", __func__);
+ reverb_settings = (reverb_settings_t *)value;
+ break;
+ case REVERB_PARAM_ROOM_LEVEL:
+ ALOGV("%s: REVERB_PARAM_ROOM_LEVEL", __func__);
+ level = *(int16_t *)value;
+ reverb_set_room_level(reverb_ctxt, level);
+ break;
+ case REVERB_PARAM_ROOM_HF_LEVEL:
+ ALOGV("%s: REVERB_PARAM_ROOM_HF_LEVEL", __func__);
+ level = *(int16_t *)value;
+ reverb_set_room_hf_level(reverb_ctxt, level);
+ break;
+ case REVERB_PARAM_DECAY_TIME:
+ ALOGV("%s: REVERB_PARAM_DECAY_TIME", __func__);
+ time = *(uint32_t *)value;
+ reverb_set_decay_time(reverb_ctxt, time);
+ break;
+ case REVERB_PARAM_DECAY_HF_RATIO:
+ ALOGV("%s: REVERB_PARAM_DECAY_HF_RATIO", __func__);
+ ratio = *(int16_t *)value;
+ reverb_set_decay_hf_ratio(reverb_ctxt, ratio);
+ break;
+ case REVERB_PARAM_REVERB_LEVEL:
+ ALOGV("%s: REVERB_PARAM_REVERB_LEVEL", __func__);
+ level = *(int16_t *)value;
+ reverb_set_reverb_level(reverb_ctxt, level);
+ break;
+ case REVERB_PARAM_DIFFUSION:
+ ALOGV("%s: REVERB_PARAM_DIFFUSION", __func__);
+ ratio = *(int16_t *)value;
+ reverb_set_diffusion(reverb_ctxt, ratio);
+ break;
+ case REVERB_PARAM_DENSITY:
+ ALOGV("%s: REVERB_PARAM_DENSITY", __func__);
+ 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: device: %d", __func__, 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;
+
+ 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", __func__);
+
+ 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", __func__);
+ 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", __func__);
+ 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)
+{
+ reverb_context_t *reverb_ctxt = (reverb_context_t *)context;
+
+ ALOGV("%s", __func__);
+ reverb_ctxt->ctl = NULL;
+ return 0;
+}
+
diff --git a/post_proc/reverb.h b/post_proc/reverb.h
new file mode 100644
index 0000000..aba2b27
--- /dev/null
+++ b/post_proc/reverb.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2014 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);
+
+void reverb_insert_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/post_proc/virtualizer.c b/post_proc/virtualizer.c
new file mode 100644
index 0000000..c036c08
--- /dev/null
+++ b/post_proc/virtualizer.c
@@ -0,0 +1,274 @@
+/*
+ * Copyright (C) 2014 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: strength: %d", __func__, context->strength);
+ return context->strength;
+}
+
+int virtualizer_set_strength(virtualizer_context_t *context, uint32_t strength)
+{
+ ALOGV("%s: strength: %d", __func__, 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;
+}
+
+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", __func__);
+
+ 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;
+ 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:
+ ALOGV("%s: VIRTUALIZER_PARAM_STRENGTH_SUPPORTED", __func__);
+ *(uint32_t *)value = 1;
+ break;
+
+ case VIRTUALIZER_PARAM_STRENGTH:
+ ALOGV("%s: VIRTUALIZER_PARAM_STRENGTH", __func__);
+ *(int16_t *)value = virtualizer_get_strength(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)
+{
+ 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", __func__);
+
+ p->status = 0;
+
+ switch (param) {
+ case VIRTUALIZER_PARAM_STRENGTH:
+ ALOGV("%s VIRTUALIZER_PARAM_STRENGTH", __func__);
+ strength = (uint32_t)(*(int16_t *)value);
+ virtualizer_set_strength(virt_ctxt, strength);
+ 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: device: %d", __func__, device);
+ virt_ctxt->device = device;
+ if ((device == AUDIO_DEVICE_OUT_SPEAKER) ||
+ (device == AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT) ||
+ (device == AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER) ||
+ (device == AUDIO_DEVICE_OUT_PROXY) ||
+ (device == AUDIO_DEVICE_OUT_AUX_DIGITAL) ||
+ (device == AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET)) {
+ 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);
+ }
+ 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;
+ }
+ }
+ 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", __func__);
+ 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;
+ 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", __func__);
+
+ 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", __func__);
+ 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", __func__);
+ 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)
+{
+ virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)context;
+
+ ALOGV("%s", __func__);
+ virt_ctxt->ctl = NULL;
+ return 0;
+}
diff --git a/post_proc/virtualizer.h b/post_proc/virtualizer.h
new file mode 100644
index 0000000..978dc86
--- /dev/null
+++ b/post_proc/virtualizer.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2014 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;
+ uint32_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_ */
diff --git a/visualizer/offload_visualizer.c b/visualizer/offload_visualizer.c
index eaa7774..9b11e20 100644
--- a/visualizer/offload_visualizer.c
+++ b/visualizer/offload_visualizer.c
@@ -37,6 +37,7 @@
};
typedef struct effect_context_s effect_context_t;
+typedef struct output_context_s output_context_t;
/* effect specific operations. Only the init() and process() operations must be defined.
* Others are optional.
@@ -47,6 +48,8 @@
int (*reset)(effect_context_t *context);
int (*enable)(effect_context_t *context);
int (*disable)(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 (*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);
@@ -247,6 +250,8 @@
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) {
@@ -257,6 +262,8 @@
effect_context_t,
output_node);
if (fx_ctxt == context) {
+ if (context->ops.stop)
+ context->ops.stop(context, output);
list_remove(&context->output_node);
return;
}
@@ -276,7 +283,7 @@
effect_context_t *fx_ctxt = node_to_item(fx_node,
effect_context_t,
output_node);
- if (fx_ctxt->state == EFFECT_STATE_ACTIVE)
+ if (fx_ctxt->state == EFFECT_STATE_ACTIVE && fx_ctxt->ops.process != NULL)
return true;
}
}
@@ -379,7 +386,8 @@
effect_context_t *fx_ctxt = node_to_item(fx_node,
effect_context_t,
output_node);
- fx_ctxt->ops.process(fx_ctxt, &buf, &buf);
+ if (fx_ctxt->ops.process != NULL)
+ fx_ctxt->ops.process(fx_ctxt, &buf, &buf);
}
}
} else {
@@ -405,11 +413,11 @@
*/
__attribute__ ((visibility ("default")))
-int visualizer_hal_start_output(audio_io_handle_t output) {
+int visualizer_hal_start_output(audio_io_handle_t output, int pcm_id) {
int ret;
struct listnode *node;
- ALOGV("%s", __func__);
+ ALOGV("%s output %d pcm_id %d", __func__, output, pcm_id);
if (lib_init() != 0)
return init_status;
@@ -431,6 +439,8 @@
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);
}
}
@@ -449,12 +459,13 @@
}
__attribute__ ((visibility ("default")))
-int visualizer_hal_stop_output(audio_io_handle_t output) {
+int visualizer_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", __func__);
+ ALOGV("%s output %d pcm_id %d", __func__, output, pcm_id);
if (lib_init() != 0)
return init_status;
@@ -468,7 +479,13 @@
ret = -ENOSYS;
goto exit;
}
-
+ 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);
pthread_cond_signal(&cond);
@@ -917,6 +934,7 @@
context->ops.set_parameter = visualizer_set_parameter;
context->ops.get_parameter = visualizer_get_parameter;
context->ops.command = visualizer_command;
+ context->desc = &visualizer_descriptor;
} else {
return -EINVAL;
}
@@ -924,7 +942,6 @@
context->itfe = &effect_interface;
context->state = EFFECT_STATE_UNINITIALIZED;
context->out_handle = (audio_io_handle_t)ioId;
- context->desc = &visualizer_descriptor;
ret = context->ops.init(context);
if (ret < 0) {
@@ -1177,12 +1194,12 @@
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(offload_param->ioHandle);
if (out_ctxt != NULL)
add_effect_to_output(out_ctxt, context);
- context->out_handle = offload_param->ioHandle;
-
} break;