Merge "hal: Add tx pcm device id for speaker protection usecase"
diff --git a/audiod/Android.mk b/audiod/Android.mk
index c382c9d..c89b3cd 100644
--- a/audiod/Android.mk
+++ b/audiod/Android.mk
@@ -1,7 +1,10 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
+
+ifneq (,$(findstring $(PLATFORM_VERSION), 5.0 5.1 5.1.1))
include external/stlport/libstlport.mk
+endif
LOCAL_SRC_FILES:= \
audiod_main.cpp \
@@ -13,8 +16,11 @@
libcutils \
libutils \
libbinder \
- libmedia \
- libstlport
+ libmedia
+
+ifneq (,$(findstring $(PLATFORM_VERSION), 5.0 5.1 5.1.1))
+LOCAL_SHARED_LIBRARIES += libstlport
+endif
LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
diff --git a/audiod/AudioDaemon.cpp b/audiod/AudioDaemon.cpp
index b4857c4..6f38218 100644
--- a/audiod/AudioDaemon.cpp
+++ b/audiod/AudioDaemon.cpp
@@ -125,6 +125,7 @@
struct dirent* in_file;
int fd;
String8 path;
+ String8 d_name;
if ((dp = opendir(events_dir)) == NULL) {
ALOGE("Cannot open switch directory to get list of audio events %s", events_dir);
@@ -148,8 +149,9 @@
if (fd == -1) {
ALOGE("Open %s failed : %s", path.string(), strerror(errno));
} else {
- mAudioEvents.push_back(std::make_pair(in_file->d_name, fd));
- mAudioEventsStatus.push_back(std::make_pair(in_file->d_name, 0));
+ d_name = in_file->d_name;
+ mAudioEvents.push_back(std::make_pair(d_name, fd));
+ mAudioEventsStatus.push_back(std::make_pair(d_name, 0));
ALOGD("event status mAudioEventsStatus= %s",
mAudioEventsStatus[0].first.string());
}
diff --git a/hal/Android.mk b/hal/Android.mk
index e0149f9..315aab2 100644
--- a/hal/Android.mk
+++ b/hal/Android.mk
@@ -53,6 +53,7 @@
LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
ifeq ($(strip $(AUDIO_FEATURE_ENABLED_HDMI_EDID)),true)
+ LOCAL_CFLAGS += -DHDMI_EDID
LOCAL_SRC_FILES += edid.c
endif
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index 7bbe2f8..e443f06 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -46,6 +46,9 @@
#define AUDIO_FORMAT_PCM_24_BIT_OFFLOAD (AUDIO_FORMAT_PCM_OFFLOAD | AUDIO_FORMAT_PCM_SUB_8_24_BIT)
#define AUDIO_OFFLOAD_CODEC_FORMAT "music_offload_codec_format"
#define audio_is_offload_pcm(format) (0)
+#define OFFLOAD_USE_SMALL_BUFFER false
+#else
+#define OFFLOAD_USE_SMALL_BUFFER (info->use_small_bufs)
#endif
#ifndef AFE_PROXY_ENABLED
@@ -316,6 +319,9 @@
void audio_extn_dolby_set_dmid(struct audio_device *adev);
#else
#define audio_extn_dolby_set_dmid(adev) (0)
+#define AUDIO_CHANNEL_OUT_PENTA (AUDIO_CHANNEL_OUT_QUAD | AUDIO_CHANNEL_OUT_FRONT_CENTER)
+#define AUDIO_CHANNEL_OUT_SURROUND (AUDIO_CHANNEL_OUT_FRONT_LEFT | AUDIO_CHANNEL_OUT_FRONT_RIGHT | \
+ AUDIO_CHANNEL_OUT_FRONT_CENTER | AUDIO_CHANNEL_OUT_BACK_CENTER)
#endif
diff --git a/hal/audio_extn/spkr_protection.c b/hal/audio_extn/spkr_protection.c
index 5ea5a43..e703b13 100644
--- a/hal/audio_extn/spkr_protection.c
+++ b/hal/audio_extn/spkr_protection.c
@@ -485,6 +485,7 @@
enable_audio_route(adev, uc_info_tx);
pcm_dev_tx_id = platform_get_pcm_device_id(uc_info_tx->id, PCM_CAPTURE);
+ ALOGV("%s: pcm device id %d", __func__, pcm_dev_tx_id);
if (pcm_dev_tx_id < 0) {
ALOGE("%s: Invalid pcm device for usecase (%d)",
__func__, uc_info_tx->id);
@@ -647,6 +648,7 @@
char wsa_path[MAX_PATH] = {0};
int spk_1_tzn, spk_2_tzn;
char buf[32] = {0};
+ int ret;
/* If the value of this persist.spkr.cal.duration is 0
* then it means it will take 30min to calibrate
@@ -756,13 +758,17 @@
thermal_fd = open(wsa_path, O_RDONLY);
if (thermal_fd > 0) {
for (i = 0; i < NUM_ATTEMPTS; i++) {
- if (read(thermal_fd, buf, sizeof(buf))) {
+ if ((ret = read(thermal_fd, buf, sizeof(buf))) >= 0) {
t0_spk_1 = atoi(buf);
- if (i > 0 && (t0_spk_1 != t0_spk_prior))
+ if (i > 0 && (t0_spk_1 != t0_spk_prior)) {
+ ALOGE("%s: spkr1 curr temp: %d, prev temp: %d\n",
+ __func__, t0_spk_1, t0_spk_prior);
break;
+ }
t0_spk_prior = t0_spk_1;
+ sleep(1);
} else {
- ALOGE("%s: read fail for %s\n", __func__, wsa_path);
+ ALOGE("%s: read fail for %s err:%d\n", __func__, wsa_path, ret);
break;
}
}
@@ -773,26 +779,30 @@
if (i == NUM_ATTEMPTS) {
/*Convert temp into q6 format*/
t0_spk_1 = (t0_spk_1 * (1 << 6));
- ALOGE("%s: temp T0 for spkr1 %d\n", __func__, t0_spk_1);
+ ALOGD("%s: temp T0 for spkr1 %d\n", __func__, t0_spk_1);
} else {
- ALOGE("%s: thermal equilibrium failed for spkr1 in %d readings\n",
- __func__, NUM_ATTEMPTS);
+ ALOGD("%s: thermal equilibrium failed for spkr1 in %d/%d readings\n",
+ __func__, i, NUM_ATTEMPTS);
t0_spk_1 = SAFE_SPKR_TEMP_Q6;
}
}
if (spk_2_tzn >= 0) {
snprintf(wsa_path, MAX_PATH, TZ_WSA, spk_2_tzn);
- ALOGE("%s: wsa_path: %s\n", __func__, wsa_path);
+ ALOGD("%s: wsa_path: %s\n", __func__, wsa_path);
thermal_fd = open(wsa_path, O_RDONLY);
if (thermal_fd > 0) {
for (i = 0; i < NUM_ATTEMPTS; i++) {
- if (read(thermal_fd, buf, sizeof(buf))) {
+ if ((ret = read(thermal_fd, buf, sizeof(buf))) >= 0) {
t0_spk_2 = atoi(buf);
- if (i > 0 && (t0_spk_2 != t0_spk_prior))
+ if (i > 0 && (t0_spk_2 != t0_spk_prior)) {
+ ALOGE("%s: spkr2 curr temp: %d, prev temp: %d\n",
+ __func__, t0_spk_2, t0_spk_prior);
break;
+ }
t0_spk_prior = t0_spk_2;
+ sleep(1);
} else {
- ALOGE("%s: read fail for %s\n", __func__, wsa_path);
+ ALOGE("%s: read fail for %s err:%d\n", __func__, wsa_path, ret);
break;
}
}
@@ -803,10 +813,10 @@
if (i == NUM_ATTEMPTS) {
/*Convert temp into q6 format*/
t0_spk_2 = (t0_spk_2 * (1 << 6));
- ALOGE("%s: temp T0 for spkr2 %d\n", __func__, t0_spk_2);
+ ALOGD("%s: temp T0 for spkr2 %d\n", __func__, t0_spk_2);
} else {
- ALOGE("%s: thermal equilibrium failed for spkr2 in %d readings\n",
- __func__, NUM_ATTEMPTS);
+ ALOGE("%s: thermal equilibrium failed for spkr2 in %d/%d readings\n",
+ __func__, i, NUM_ATTEMPTS);
t0_spk_2 = SAFE_SPKR_TEMP_Q6;
}
}
diff --git a/hal/audio_extn/utils.c b/hal/audio_extn/utils.c
index 3dbf159..7ad4811 100644
--- a/hal/audio_extn/utils.c
+++ b/hal/audio_extn/utils.c
@@ -71,7 +71,9 @@
#ifdef COMPRESS_VOIP_ENABLED
STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_VOIP_RX),
#endif
+#ifdef HDMI_PASSTHROUGH_ENABLED
STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_COMPRESS_PASSTHROUGH),
+#endif
};
const struct string_to_enum s_format_name_to_enum_table[] = {
@@ -566,8 +568,11 @@
app_type_cfg[len++] = out->app_type_cfg.app_type;
app_type_cfg[len++] = acdb_dev_id;
if (((out->format == AUDIO_FORMAT_E_AC3) ||
- (out->format == AUDIO_FORMAT_E_AC3_JOC)) &&
- (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_PASSTHROUGH))
+ (out->format == AUDIO_FORMAT_E_AC3_JOC))
+#ifdef HDMI_PASSTHROUGH_ENABLED
+ && (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_PASSTHROUGH)
+#endif
+ )
app_type_cfg[len++] = sample_rate * 4;
else
app_type_cfg[len++] = sample_rate;
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index daafa77..c67f210 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -252,6 +252,26 @@
static int set_voice_volume_l(struct audio_device *adev, float volume);
+__attribute__ ((visibility ("default")))
+bool audio_hw_send_gain_dep_calibration(int level) {
+ bool ret_val = false;
+ ALOGV("%s: called ... ", __func__);
+
+ pthread_mutex_lock(&adev_init_lock);
+
+ if (adev != NULL && adev->platform != NULL) {
+ pthread_mutex_lock(&adev->lock);
+ ret_val = platform_send_gain_dep_cal(adev->platform, level);
+ pthread_mutex_unlock(&adev->lock);
+ } else {
+ ALOGE("%s: %s is NULL", __func__, adev == NULL ? "adev" : "adev->platform");
+ }
+
+ pthread_mutex_unlock(&adev_init_lock);
+
+ return ret_val;
+}
+
static int check_and_set_gapless_mode(struct audio_device *adev) {
@@ -2182,7 +2202,7 @@
if (ret != 0) {
if (out->pcm)
- ALOGE("%s: error %ld - %s", __func__, ret, pcm_get_error(out->pcm));
+ ALOGE("%s: error %zu - %s", __func__, ret, pcm_get_error(out->pcm));
if (out->usecase == USECASE_COMPRESS_VOIP_CALL) {
pthread_mutex_lock(&adev->lock);
voice_extn_compress_voip_close_output_stream(&out->stream.common);
@@ -2921,7 +2941,7 @@
if (flags & AUDIO_OUTPUT_FLAG_NON_BLOCKING)
out->non_blocking = 1;
- if (config->offload_info.use_small_bufs) {
+ if (platform_use_small_buffer(&config->offload_info)) {
//this flag is set from framework only if its for PCM formats
//no need to check for PCM format again
out->non_blocking = 0;
diff --git a/hal/audio_hw.h b/hal/audio_hw.h
index 67f5279..5e61d36 100644
--- a/hal/audio_hw.h
+++ b/hal/audio_hw.h
@@ -38,6 +38,7 @@
#ifndef QCOM_AUDIO_HW_H
#define QCOM_AUDIO_HW_H
+#include <stdlib.h>
#include <cutils/list.h>
#include <hardware/audio.h>
#include <tinyalsa/asoundlib.h>
diff --git a/hal/edid.h b/hal/edid.h
index ec83ec8..0d7fbe6 100644
--- a/hal/edid.h
+++ b/hal/edid.h
@@ -92,5 +92,9 @@
int channel_allocation;
} edid_audio_info;
+#ifndef HDMI_EDID
+#define edid_get_sink_caps(info, edid_data) (0)
+#else
bool edid_get_sink_caps(edid_audio_info* info, char *edid_data);
+#endif
#endif /* EDID_H */
diff --git a/hal/msm8916/platform.c b/hal/msm8916/platform.c
index 8d47a8b..c2805f9 100644
--- a/hal/msm8916/platform.c
+++ b/hal/msm8916/platform.c
@@ -3292,6 +3292,11 @@
return fragment_size;
}
+bool platform_use_small_buffer(audio_offload_info_t* info)
+{
+ return OFFLOAD_USE_SMALL_BUFFER;
+}
+
int platform_set_codec_backend_cfg(struct audio_device* adev,
unsigned int bit_width, unsigned int sample_rate)
{
diff --git a/hal/msm8916/platform.h b/hal/msm8916/platform.h
index 3ce4c57..74c8e9b 100644
--- a/hal/msm8916/platform.h
+++ b/hal/msm8916/platform.h
@@ -189,8 +189,8 @@
* We should take care of returning proper size when AudioFlinger queries for
* the buffer size of an input/output stream
*/
-#define DEEP_BUFFER_OUTPUT_PERIOD_SIZE 960
-#define DEEP_BUFFER_OUTPUT_PERIOD_COUNT 5
+#define DEEP_BUFFER_OUTPUT_PERIOD_SIZE 1920
+#define DEEP_BUFFER_OUTPUT_PERIOD_COUNT 2
#define LOW_LATENCY_OUTPUT_PERIOD_SIZE 240
#define LOW_LATENCY_OUTPUT_PERIOD_COUNT 2
diff --git a/hal/msm8960/platform.c b/hal/msm8960/platform.c
index 5fab099..861790e 100644
--- a/hal/msm8960/platform.c
+++ b/hal/msm8960/platform.c
@@ -1098,6 +1098,11 @@
return 0;
}
+bool platform_use_small_buffer(audio_offload_info_t* info)
+{
+ return false;
+}
+
int platform_get_edid_info(void *platform __unused)
{
return -ENOSYS;
@@ -1166,3 +1171,9 @@
{
return -ENOSYS;
}
+
+bool platform_send_gain_dep_cal(void *platform __unused,
+ int level __unused)
+{
+ return 0;
+}
diff --git a/hal/msm8974/hw_info.c b/hal/msm8974/hw_info.c
index c96d11e..7849644 100644
--- a/hal/msm8974/hw_info.c
+++ b/hal/msm8974/hw_info.c
@@ -134,6 +134,10 @@
SND_DEVICE_IN_HANDSET_MIC_EXTERNAL
};
+static const snd_device_t tasha_DB_variant_devices[] = {
+ SND_DEVICE_OUT_SPEAKER
+};
+
static const snd_device_t taiko_apq8084_sbc_variant_devices[] = {
SND_DEVICE_IN_HANDSET_MIC,
SND_DEVICE_IN_SPEAKER_MIC,
@@ -278,6 +282,12 @@
hw_info->snd_devices = (snd_device_t *)tomtom_liquid_variant_devices;
hw_info->num_snd_devices = ARRAY_SIZE(tomtom_liquid_variant_devices);
strlcpy(hw_info->dev_extn, "-liquid", sizeof(hw_info->dev_extn));
+ } else if (!strcmp(snd_card_name, "msm8996-tasha-db-snd-card")) {
+ strlcpy(hw_info->type, " dragon-board", sizeof(hw_info->type));
+ strlcpy(hw_info->name, "msm8996", sizeof(hw_info->name));
+ hw_info->snd_devices = (snd_device_t *)tasha_DB_variant_devices;
+ hw_info->num_snd_devices = ARRAY_SIZE(tasha_DB_variant_devices);
+ strlcpy(hw_info->dev_extn, "-db", sizeof(hw_info->dev_extn));
} else {
ALOGW("%s: Not a 8996 device", __func__);
}
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index fc81443..3339f3f 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -54,6 +54,7 @@
#define PLATFORM_INFO_XML_PATH "/system/etc/audio_platform_info.xml"
#define PLATFORM_INFO_XML_PATH_I2S "/system/etc/audio_platform_info_i2s.xml"
+#include <linux/msm_audio.h>
#define LIB_ACDB_LOADER "libacdbloader.so"
#define AUDIO_DATA_BLOCK_MIXER_CTL "HDMI EDID"
@@ -156,6 +157,12 @@
uint32_t param_id;
} acdb_audio_cal_cfg_t;
+enum {
+ CAL_MODE_SEND = 0x1,
+ CAL_MODE_PERSIST = 0x2,
+ CAL_MODE_RTAC = 0x4
+};
+
/* Audio calibration related functions */
typedef void (*acdb_deallocate_t)();
typedef int (*acdb_init_t)(const char *, char *, int);
@@ -180,6 +187,7 @@
bool ui_na_prop_enabled;
} native_audio_prop;
static native_audio_prop na_props = {0, 0};
+typedef int (*acdb_send_gain_dep_cal_t)(int, int, int, int, int);
struct platform_data {
struct audio_device *adev;
@@ -210,6 +218,7 @@
acdb_get_default_app_type_t acdb_get_default_app_type;
void *hw_info;
+ acdb_send_gain_dep_cal_t acdb_send_gain_dep_cal;
struct csd_data *csd;
void *edid_info;
bool edid_valid;
@@ -705,6 +714,55 @@
#define DEEP_BUFFER_PLATFORM_DELAY (29*1000LL)
#define LOW_LATENCY_PLATFORM_DELAY (13*1000LL)
+bool platform_send_gain_dep_cal(void *platform, int level) {
+ bool ret_val = false;
+ struct platform_data *my_data = (struct platform_data *)platform;
+ struct audio_device *adev = my_data->adev;
+ int acdb_dev_id, app_type;
+ int acdb_dev_type = MSM_SNDDEV_CAP_RX;
+ int mode = CAL_MODE_RTAC;
+ struct listnode *node;
+ struct audio_usecase *usecase;
+
+ if (my_data->acdb_send_gain_dep_cal == NULL) {
+ ALOGE("%s: dlsym error for acdb_send_gain_dep_cal", __func__);
+ return ret_val;
+ }
+
+ if (!voice_is_in_call(adev)) {
+ ALOGV("%s: Not Voice call usecase, apply new cal for level %d",
+ __func__, level);
+
+ // find the current active sound device
+ list_for_each(node, &adev->usecase_list) {
+ usecase = node_to_item(node, struct audio_usecase, list);
+
+ if (usecase != NULL &&
+ usecase->type == PCM_PLAYBACK &&
+ (usecase->stream.out->devices == AUDIO_DEVICE_OUT_SPEAKER ||
+ usecase->stream.out->devices == AUDIO_DEVICE_OUT_SPEAKER_SAFE)) {
+
+ ALOGV("%s: out device is %d", __func__, usecase->out_snd_device);
+ app_type = usecase->stream.out->app_type_cfg.app_type;
+ acdb_dev_id = acdb_device_table[usecase->out_snd_device];
+ if (!my_data->acdb_send_gain_dep_cal(acdb_dev_id, app_type,
+ acdb_dev_type, mode, level)) {
+ // set ret_val true if at least one calibration is set successfully
+ ret_val = true;
+ } else {
+ ALOGE("%s: my_data->acdb_send_gain_dep_cal failed ", __func__);
+ }
+ } else {
+ ALOGW("%s: Usecase list is empty", __func__);
+ }
+ }
+ } else {
+ ALOGW("%s: Voice call in progress .. ignore setting new cal",
+ __func__);
+ }
+ return ret_val;
+}
+
void platform_set_echo_reference(void *platform, bool enable)
{
struct platform_data *my_data = (struct platform_data *)platform;
@@ -1257,6 +1315,12 @@
ALOGE("%s: Could not find the symbol acdb_get_default_app_type from %s",
__func__, LIB_ACDB_LOADER);
+ my_data->acdb_send_gain_dep_cal = (acdb_send_gain_dep_cal_t)dlsym(my_data->acdb_handle,
+ "acdb_loader_send_gain_dep_cal");
+ if (!my_data->acdb_send_gain_dep_cal)
+ ALOGV("%s: Could not find the symbol acdb_loader_send_gain_dep_cal from %s",
+ __func__, LIB_ACDB_LOADER);
+
my_data->acdb_init = (acdb_init_t)dlsym(my_data->acdb_handle,
"acdb_loader_init_v2");
if (my_data->acdb_init == NULL) {
@@ -3197,6 +3261,11 @@
return fragment_size;
}
+bool platform_use_small_buffer(audio_offload_info_t* info)
+{
+ return OFFLOAD_USE_SMALL_BUFFER;
+}
+
int platform_set_codec_backend_cfg(struct audio_device* adev,
snd_device_t snd_device,
unsigned int bit_width, unsigned int sample_rate)
diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h
index 14ae2a7..2247933 100644
--- a/hal/msm8974/platform.h
+++ b/hal/msm8974/platform.h
@@ -185,8 +185,8 @@
* We should take care of returning proper size when AudioFlinger queries for
* the buffer size of an input/output stream
*/
-#define DEEP_BUFFER_OUTPUT_PERIOD_SIZE 960
-#define DEEP_BUFFER_OUTPUT_PERIOD_COUNT 5
+#define DEEP_BUFFER_OUTPUT_PERIOD_SIZE 1920
+#define DEEP_BUFFER_OUTPUT_PERIOD_COUNT 2
#define LOW_LATENCY_OUTPUT_PERIOD_SIZE 240
#define LOW_LATENCY_OUTPUT_PERIOD_COUNT 2
diff --git a/hal/platform_api.h b/hal/platform_api.h
index 5542a6d..f8749e7 100644
--- a/hal/platform_api.h
+++ b/hal/platform_api.h
@@ -30,6 +30,7 @@
int platform_get_snd_device_name_extn(void *platform, snd_device_t snd_device,
char *device_name);
void platform_add_backend_name(char *mixer_path, snd_device_t snd_device);
+bool platform_send_gain_dep_cal(void *platform, int level);
int platform_get_pcm_device_id(audio_usecase_t usecase, int device_type);
int platform_get_snd_device_index(char *snd_device_index_name);
int platform_set_fluence_type(void *platform, char *value);
@@ -92,6 +93,7 @@
struct audio_offload_info_t;
uint32_t platform_get_compress_offload_buffer_size(audio_offload_info_t* info);
uint32_t platform_get_pcm_offload_buffer_size(audio_offload_info_t* info);
+bool platform_use_small_buffer(audio_offload_info_t* info);
uint32_t platform_get_compress_passthrough_buffer_size(audio_offload_info_t* info);
bool platform_check_and_set_codec_backend_cfg(struct audio_device* adev,
diff --git a/mm-audio/aenc-aac/qdsp6/src/omx_aac_aenc.cpp b/mm-audio/aenc-aac/qdsp6/src/omx_aac_aenc.cpp
index 6af9269..4cfee1b 100644
--- a/mm-audio/aenc-aac/qdsp6/src/omx_aac_aenc.cpp
+++ b/mm-audio/aenc-aac/qdsp6/src/omx_aac_aenc.cpp
@@ -4208,6 +4208,16 @@
buffer->nOffset = 0;
buffer->nTimeStamp = nTimestamp;
frame_done_cb((OMX_BUFFERHEADERTYPE *)buffer);
+
+ if (errno == ENETRESET)
+ {
+ ALOGE("In SSR, return error to close the session");
+ m_cb.EventHandler(&m_cmp,
+ m_app_data,
+ OMX_EventError,
+ OMX_ErrorHardware,
+ 0, NULL );
+ }
return OMX_ErrorNone;
}
}
diff --git a/post_proc/Android.mk b/post_proc/Android.mk
index be70166..192320a 100644
--- a/post_proc/Android.mk
+++ b/post_proc/Android.mk
@@ -14,8 +14,12 @@
virtualizer.c \
reverb.c \
effect_api.c \
- effect_util.c \
- hw_accelerator.c
+ effect_util.c
+
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_HW_ACCELERATED_EFFECTS)),true)
+ LOCAL_CFLAGS += -DHW_ACCELERATED_EFFECTS
+ LOCAL_SRC_FILES += hw_accelerator.c
+endif
LOCAL_CFLAGS+= -O2 -fvisibility=hidden
@@ -68,3 +72,32 @@
include $(BUILD_STATIC_LIBRARY)
endif
+
+
+################################################################################
+
+ifneq ($(filter msm8992 msm8994 msm8996 msm8952,$(TARGET_BOARD_PLATFORM)),)
+
+include $(CLEAR_VARS)
+
+LOCAL_CFLAGS := -DLIB_AUDIO_HAL="/system/lib/hw/audio.primary."$(TARGET_BOARD_PLATFORM)".so"
+
+LOCAL_SRC_FILES:= \
+ volume_listener.c
+
+LOCAL_CFLAGS+= -O2 -fvisibility=hidden
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ liblog \
+ libdl
+
+LOCAL_MODULE_RELATIVE_PATH := soundfx
+LOCAL_MODULE:= libvolumelistener
+
+LOCAL_C_INCLUDES := \
+ $(call include-path-for, audio-effects)
+
+include $(BUILD_SHARED_LIBRARY)
+
+endif
diff --git a/post_proc/bundle.c b/post_proc/bundle.c
index e38a41c..6f1bdfa 100644
--- a/post_proc/bundle.c
+++ b/post_proc/bundle.c
@@ -38,6 +38,7 @@
#define LOG_TAG "offload_effect_bundle"
//#define LOG_NDEBUG 0
+#include <stdlib.h>
#include <cutils/list.h>
#include <cutils/log.h>
#include <system/thread_defs.h>
@@ -69,7 +70,9 @@
&ins_env_reverb_descriptor,
&aux_preset_reverb_descriptor,
&ins_preset_reverb_descriptor,
+#ifdef HW_ACCELERATED_EFFECTS
&hw_accelerator_descriptor,
+#endif
NULL,
};
@@ -302,9 +305,6 @@
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,
@@ -313,6 +313,9 @@
fx_ctxt->ops.stop(fx_ctxt, out_ctxt);
}
+ if (out_ctxt->mixer)
+ mixer_close(out_ctxt->mixer);
+
list_remove(&out_ctxt->outputs_list_node);
#ifdef DTS_EAGLE
@@ -604,6 +607,7 @@
reverb_preset_init(reverb_ctxt);
}
reverb_ctxt->ctl = NULL;
+#ifdef HW_ACCELERATED_EFFECTS
} else if (memcmp(uuid, &hw_accelerator_descriptor.uuid,
sizeof(effect_uuid_t)) == 0) {
hw_accelerator_context_t *hw_acc_ctxt = (hw_accelerator_context_t *)
@@ -625,6 +629,7 @@
context->ops.process = hw_accelerator_process;
context->desc = &hw_accelerator_descriptor;
+#endif
} else {
return -EINVAL;
}
@@ -911,6 +916,7 @@
} break;
+#ifdef HW_ACCELERATED_EFFECTS
case EFFECT_CMD_HW_ACC: {
ALOGV("EFFECT_CMD_HW_ACC cmdSize %d pCmdData %p, *replySize %d, pReplyData %p",
cmdSize, pCmdData, *replySize, pReplyData);
@@ -925,6 +931,7 @@
context->hw_acc_enabled = (value > 0) ? true : false;
break;
}
+#endif
default:
if (cmdCode >= EFFECT_CMD_FIRST_PROPRIETARY && context->ops.command)
status = context->ops.command(context, cmdCode, cmdSize,
diff --git a/post_proc/effect_api.c b/post_proc/effect_api.c
index e15db17..16c370b 100644
--- a/post_proc/effect_api.c
+++ b/post_proc/effect_api.c
@@ -55,6 +55,7 @@
#endif
#include <stdbool.h>
+#include <errno.h>
#include <cutils/log.h>
#include <tinyalsa/asoundlib.h>
#include <sound/audio_effects.h>
diff --git a/post_proc/effect_util.c b/post_proc/effect_util.c
index 8f7a604..52f623d 100644
--- a/post_proc/effect_util.c
+++ b/post_proc/effect_util.c
@@ -16,6 +16,7 @@
#include <utils/Log.h>
#include <stdlib.h>
+#include <string.h>
#include "effect_util.h"
#ifdef LOG_TAG
diff --git a/post_proc/volume_listener.c b/post_proc/volume_listener.c
new file mode 100644
index 0000000..51f8803
--- /dev/null
+++ b/post_proc/volume_listener.c
@@ -0,0 +1,769 @@
+/*
+ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define LOG_TAG "volume_listener"
+//#define LOG_NDEBUG 0
+#include <stdlib.h>
+#include <dlfcn.h>
+
+#include <cutils/list.h>
+#include <cutils/log.h>
+#include <hardware/audio_effect.h>
+#include <cutils/properties.h>
+
+#define PRIMARY_HAL_PATH XSTR(LIB_AUDIO_HAL)
+#define XSTR(x) STR(x)
+#define STR(x) #x
+
+#define VOL_FLAG ( EFFECT_FLAG_TYPE_INSERT | \
+ EFFECT_FLAG_VOLUME_IND | \
+ EFFECT_FLAG_DEVICE_IND | \
+ EFFECT_FLAG_OFFLOAD_SUPPORTED)
+
+#define PRINT_STREAM_TYPE(i) ALOGV("descriptor found and is of stream type %s ",\
+ i == MUSIC?"MUSIC": \
+ i == RING?"RING": \
+ i == ALARM?"ALARM": \
+ i == VOICE_CALL?"Voice_call": \
+ i == NOTIFICATION?"Notification":\
+ "--INVALID--"); \
+
+#define MAX_GAIN_LEVELS 5
+
+#define AHAL_GAIN_DEPENDENT_INTERFACE_FUNCTION "audio_hw_send_gain_dep_calibration"
+
+enum {
+ VOL_LISTENER_STATE_UNINITIALIZED,
+ VOL_LISTENER_STATE_INITIALIZED,
+ VOL_LISTENER_STATE_ACTIVE,
+};
+
+typedef struct vol_listener_context_s vol_listener_context_t;
+static const struct effect_interface_s effect_interface;
+
+/* flag to avoid multiple initialization */
+static bool initialized = false;
+
+/* current gain dep cal level that was pushed succesfully */
+static int current_gain_dep_cal_level = -1;
+
+enum STREAM_TYPE {
+ MUSIC,
+ RING,
+ ALARM,
+ VOICE_CALL,
+ NOTIFICATION,
+ MAX_STREAM_TYPES,
+};
+
+struct vol_listener_context_s {
+ const struct effect_interface_s *itfe;
+ struct listnode effect_list_node;
+ effect_config_t config;
+ const effect_descriptor_t *desc;
+ uint32_t stream_type;
+ uint32_t session_id;
+ uint32_t state;
+ uint32_t dev_id;
+ float left_vol;
+ float right_vol;
+};
+
+/* volume listener, music UUID: 08b8b058-0590-11e5-ac71-0025b32654a0 */
+const effect_descriptor_t vol_listener_music_descriptor = {
+ { 0x08b8b058, 0x0590, 0x11e5, 0xac71, { 0x00, 0x25, 0xb3, 0x26, 0x54, 0xa0 } }, // type
+ { 0x08b8b058, 0x0590, 0x11e5, 0xac71, { 0x00, 0x25, 0xb3, 0x26, 0x54, 0xa0 } }, // uuid
+ EFFECT_CONTROL_API_VERSION,
+ VOL_FLAG,
+ 0, /* TODO */
+ 1,
+ "Volume listener for Music",
+ "Qualcomm Technologies Inc.",
+};
+
+/* volume listener, ring UUID: 0956df94-0590-11e5-bdbe-0025b32654a0 */
+const effect_descriptor_t vol_listener_ring_descriptor = {
+ { 0x0956df94, 0x0590, 0x11e5, 0xbdbe, { 0x00, 0x25, 0xb3, 0x26, 0x54, 0xa0 } }, // type
+ { 0x0956df94, 0x0590, 0x11e5, 0xbdbe, { 0x00, 0x25, 0xb3, 0x26, 0x54, 0xa0 } }, // uuid
+ EFFECT_CONTROL_API_VERSION,
+ VOL_FLAG,
+ 0, /* TODO */
+ 1,
+ "Volume listener for ring",
+ "Qualcomm Technologies Inc",
+};
+
+/* volume listener, alarm UUID: 09f303e2-0590-11e5-8fdb-0025b32654a0 */
+const effect_descriptor_t vol_listener_alarm_descriptor = {
+ { 0x09f303e2, 0x0590, 0x11e5, 0x8fdb, { 0x00, 0x25, 0xb3, 0x26, 0x54, 0xa0 } }, // type
+ { 0x09f303e2, 0x0590, 0x11e5, 0x8fdb, { 0x00, 0x25, 0xb3, 0x26, 0x54, 0xa0 } }, // uuid
+ EFFECT_CONTROL_API_VERSION,
+ VOL_FLAG,
+ 0, /* TODO */
+ 1,
+ "Volume listener for alarm",
+ "Qualcomm Technologies Inc",
+};
+
+/* volume listener, voice call UUID: 0ace5c08-0590-11e5-ae9e-0025b32654a0 */
+const effect_descriptor_t vol_listener_voice_call_descriptor = {
+ { 0x0ace5c08, 0x0590, 0x11e5, 0xae9e, { 0x00, 0x25, 0xb3, 0x26, 0x54, 0xa0 } }, // type
+ { 0x0ace5c08, 0x0590, 0x11e5, 0xae9e, { 0x00, 0x25, 0xb3, 0x26, 0x54, 0xa0 } }, // uuid
+ EFFECT_CONTROL_API_VERSION,
+ VOL_FLAG,
+ 0, /* TODO */
+ 1,
+ "Volume listener for voice call",
+ "Qualcomm Technologies Inc",
+};
+
+/* volume listener, notification UUID: 0b776dde-0590-11e5-81ba-0025b32654a0 */
+const effect_descriptor_t vol_listener_notification_descriptor = {
+ { 0x0b776dde, 0x0590, 0x11e5, 0x81ba, { 0x00, 0x25, 0xb3, 0x26, 0x54, 0xa0 } }, // type
+ { 0x0b776dde, 0x0590, 0x11e5, 0x81ba, { 0x00, 0x25, 0xb3, 0x26, 0x54, 0xa0 } }, // uuid
+ EFFECT_CONTROL_API_VERSION,
+ VOL_FLAG,
+ 0, /* TODO */
+ 1,
+ "Volume listener for notification",
+ "Qualcomm Technologies Inc",
+};
+
+struct amp_db_and_gain_table {
+ float amp;
+ float db;
+ uint32_t level;
+} amp_to_dBLevel_table;
+
+// using gain level for non-drc volume curve
+static const struct amp_db_and_gain_table volume_curve_gain_mapping_table[MAX_GAIN_LEVELS] = {
+ /* Level 0 in the calibration database contains default calibration */
+ { 0.001774, -55, 5 },
+ { 0.501187, -6, 4 },
+ { 0.630957, -4, 3 },
+ { 0.794328, -2, 2 },
+ { 1.0, 0, 1 },
+};
+
+static const effect_descriptor_t *descriptors[] = {
+ &vol_listener_music_descriptor,
+ &vol_listener_ring_descriptor,
+ &vol_listener_alarm_descriptor,
+ &vol_listener_voice_call_descriptor,
+ &vol_listener_notification_descriptor,
+ NULL,
+};
+
+pthread_once_t once = PTHREAD_ONCE_INIT;
+/* flag to indicate if init was success */
+static int init_status;
+
+/* current volume level for which gain dep cal level was selected */
+static float current_vol = 0.0;
+
+/* HAL interface to send calibration */
+static bool (*send_gain_dep_cal)(int);
+
+/* if dumping allowed */
+static bool dumping_enabled = false;
+
+/* list of created effects. */
+struct listnode vol_effect_list;
+
+/* lock must be held when modifying or accessing created_effects_list */
+pthread_mutex_t vol_listner_init_lock;
+
+/*
+ * Local functions
+ */
+static void dump_list_l()
+{
+ struct listnode *node;
+ vol_listener_context_t *context;
+
+ ALOGW("DUMP_START :: ===========");
+
+ list_for_each(node, &vol_effect_list) {
+ context = node_to_item(node, struct vol_listener_context_s, effect_list_node);
+ // dump stream_type / Device / session_id / left / righ volume
+ ALOGW("%s: streamType [%s] Device [%d] state [%d] sessionID [%d] volume (L/R) [%f / %f] ",
+ __func__,
+ context->stream_type == MUSIC ? "MUSIC" :
+ context->stream_type == RING ? "RING" :
+ context->stream_type == ALARM ? "ALARM" :
+ context->stream_type == VOICE_CALL ? "VOICE_CALL" :
+ context->stream_type == NOTIFICATION ? "NOTIFICATION" : "--INVALID--",
+ context->dev_id, context->state, context->session_id, context->left_vol,context->right_vol);
+ }
+
+ ALOGW("DUMP_END :: ===========");
+}
+
+static void check_and_set_gain_dep_cal()
+{
+ // iterate through list and make decision to set new gain dep cal level for speaker device
+ // 1. find all usecase active on speaker
+ // 2. find average of left and right for each usecase
+ // 3. find the highest of all the active usecase
+ // 4. if new value is different than the current value then load new calibration
+
+ struct listnode *node = NULL;
+ float new_vol = 0.0;
+ int max_level = 0;
+ vol_listener_context_t *context = NULL;
+ if (dumping_enabled) {
+ dump_list_l();
+ }
+
+ ALOGV("%s ==> Start ...", __func__);
+
+ // select the highest volume on speaker device
+ list_for_each(node, &vol_effect_list) {
+ context = node_to_item(node, struct vol_listener_context_s, effect_list_node);
+ if ((context->state == VOL_LISTENER_STATE_ACTIVE) &&
+ (context->dev_id & AUDIO_DEVICE_OUT_SPEAKER) &&
+ (new_vol < (context->left_vol + context->right_vol) / 2)) {
+ new_vol = (context->left_vol + context->right_vol) / 2;
+ }
+ }
+
+ if (new_vol != current_vol) {
+ ALOGV("%s:: Change in decision :: current volume is %f new volume is %f",
+ __func__, current_vol, new_vol);
+
+ if (send_gain_dep_cal != NULL) {
+ // send Gain dep cal level
+ int gain_dep_cal_level = -1;
+
+ if (new_vol >= 1) { // max amplitude, use highest DRC level
+ gain_dep_cal_level = volume_curve_gain_mapping_table[MAX_GAIN_LEVELS - 1].level;
+ } else if (new_vol <= 0) {
+ gain_dep_cal_level = volume_curve_gain_mapping_table[0].level;
+ } else {
+ for (max_level = 0; max_level + 1 < MAX_GAIN_LEVELS; max_level++) {
+ if (new_vol < volume_curve_gain_mapping_table[max_level + 1].amp &&
+ new_vol >= volume_curve_gain_mapping_table[max_level].amp) {
+ gain_dep_cal_level = volume_curve_gain_mapping_table[max_level].level;
+ ALOGV("%s: volume(%f), gain dep cal selcetd %d ",
+ __func__, current_vol, gain_dep_cal_level);
+ break;
+ }
+ }
+ }
+
+ // check here if previous gain dep cal level was not same
+ if (gain_dep_cal_level != -1) {
+ if (gain_dep_cal_level != current_gain_dep_cal_level) {
+ // decision made .. send new level now
+ if (!send_gain_dep_cal(gain_dep_cal_level)) {
+ ALOGE("%s: Failed to set gain dep cal level", __func__);
+ } else {
+ // Success in setting the gain dep cal level, store new level and Volume
+ if (dumping_enabled) {
+ ALOGW("%s: (old/new) Volume (%f/%f) (old/new) level (%d/%d)",
+ __func__, current_vol, new_vol, current_gain_dep_cal_level,
+ gain_dep_cal_level);
+ } else {
+ ALOGV("%s: Change in Cal::(old/new) Volume (%f/%f) (old/new) level (%d/%d)",
+ __func__, current_vol, new_vol, current_gain_dep_cal_level,
+ gain_dep_cal_level);
+ }
+ current_gain_dep_cal_level = gain_dep_cal_level;
+ current_vol = new_vol;
+ }
+ } else {
+ if (dumping_enabled) {
+ ALOGW("%s: volume changed but gain dep cal level is still the same",
+ __func__);
+ } else {
+ ALOGV("%s: volume changed but gain dep cal level is still the same",
+ __func__);
+ }
+ }
+ } else {
+ ALOGW("%s: Failed to find gain dep cal level for volume %f", __func__, new_vol);
+ }
+ } else {
+ ALOGE("%s: not able to send calibration, NULL function pointer",
+ __func__);
+ }
+ } else {
+ ALOGV("%s:: volume not changed, stick to same config ..... ", __func__);
+ }
+
+ ALOGV("check_and_set_gain_dep_cal ==> End ");
+}
+
+/*
+ * Effect Control Interface Implementation
+ */
+
+static int vol_effect_process(effect_handle_t self,
+ audio_buffer_t *in_buffer,
+ audio_buffer_t *out_buffer)
+{
+ int status = 0;
+ ALOGV("%s Called ", __func__);
+
+ vol_listener_context_t *context = (vol_listener_context_t *)self;
+ pthread_mutex_lock(&vol_listner_init_lock);
+
+ if (context->state != VOL_LISTENER_STATE_ACTIVE) {
+ ALOGE("%s: state is not active .. return error", __func__);
+ status = -EINVAL;
+ goto exit;
+ }
+
+ // calculation based on channel count 2
+ if (in_buffer->raw != out_buffer->raw) {
+ memcpy(out_buffer->raw, in_buffer->raw, out_buffer->frameCount * 2 * sizeof(int16_t));
+ } else {
+ ALOGW("%s: something wrong, didn't handle in_buffer and out_buffer same address case",
+ __func__);
+ }
+
+exit:
+ pthread_mutex_unlock(&vol_listner_init_lock);
+ return status;
+}
+
+
+static int vol_effect_command(effect_handle_t self,
+ uint32_t cmd_code, uint32_t cmd_size,
+ void *p_cmd_data, uint32_t *reply_size,
+ void *p_reply_data)
+{
+ vol_listener_context_t *context = (vol_listener_context_t *)self;
+ int status = 0;
+
+ ALOGV("%s Called ", __func__);
+ pthread_mutex_lock(&vol_listner_init_lock);
+
+ if (context == NULL || context->state == VOL_LISTENER_STATE_UNINITIALIZED) {
+ ALOGE("%s: %s is NULL", __func__, (context == NULL) ?
+ "context" : "context->state");
+ status = -EINVAL;
+ goto exit;
+ }
+
+ switch (cmd_code) {
+ case EFFECT_CMD_INIT:
+ ALOGV("%s :: cmd called EFFECT_CMD_INIT", __func__);
+ if (p_reply_data == NULL || *reply_size != sizeof(int)) {
+ ALOGE("%s: EFFECT_CMD_INIT: %s, sending -EINVAL", __func__,
+ (p_reply_data == NULL) ? "p_reply_data is NULL" :
+ "*reply_size != sizeof(int)");
+ return -EINVAL;
+ }
+ *(int *)p_reply_data = 0;
+ break;
+
+ case EFFECT_CMD_SET_CONFIG:
+ ALOGV("%s :: cmd called EFFECT_CMD_SET_CONFIG", __func__);
+ break;
+
+ case EFFECT_CMD_GET_CONFIG:
+ ALOGV("%s :: cmd called EFFECT_CMD_GET_CONFIG", __func__);
+ break;
+
+ case EFFECT_CMD_RESET:
+ ALOGV("%s :: cmd called EFFECT_CMD_RESET", __func__);
+ break;
+
+ case EFFECT_CMD_SET_AUDIO_MODE:
+ ALOGV("%s :: cmd called EFFECT_CMD_SET_AUDIO_MODE", __func__);
+ break;
+
+ case EFFECT_CMD_OFFLOAD:
+ ALOGV("%s :: cmd called EFFECT_CMD_OFFLOAD", __func__);
+ if (p_reply_data == NULL || *reply_size != sizeof(int)) {
+ ALOGE("%s: EFFECT_CMD_OFFLOAD: %s, sending -EINVAL", __func__,
+ (p_reply_data == NULL) ? "p_reply_data is NULL" :
+ "*reply_size != sizeof(int)");
+ return -EINVAL;
+ }
+ *(int *)p_reply_data = 0;
+ break;
+
+ case EFFECT_CMD_ENABLE:
+ ALOGV("%s :: cmd called EFFECT_CMD_ENABLE", __func__);
+ if (p_reply_data == NULL || *reply_size != sizeof(int)) {
+ ALOGE("%s: EFFECT_CMD_ENABLE: %s, sending -EINVAL", __func__,
+ (p_reply_data == NULL) ? "p_reply_data is NULL" :
+ "*reply_size != sizeof(int)");
+ status = -EINVAL;
+ goto exit;
+ }
+
+ if (context->state != VOL_LISTENER_STATE_INITIALIZED) {
+ ALOGE("%s: EFFECT_CMD_ENABLE : state not INITIALIZED", __func__);
+ status = -ENOSYS;
+ goto exit;
+ }
+
+ context->state = VOL_LISTENER_STATE_ACTIVE;
+ *(int *)p_reply_data = 0;
+
+ // After changing the state and if device is speaker
+ // recalculate gain dep cal level
+ if (context->dev_id & AUDIO_DEVICE_OUT_SPEAKER) {
+ check_and_set_gain_dep_cal();
+ }
+
+ break;
+
+ case EFFECT_CMD_DISABLE:
+ ALOGV("%s :: cmd called EFFECT_CMD_DISABLE", __func__);
+ if (p_reply_data == NULL || *reply_size != sizeof(int)) {
+ ALOGE("%s: EFFECT_CMD_DISABLE: %s, sending -EINVAL", __func__,
+ (p_reply_data == NULL) ? "p_reply_data is NULL" :
+ "*reply_size != sizeof(int)");
+ status = -EINVAL;
+ goto exit;
+ }
+
+ if (context->state != VOL_LISTENER_STATE_ACTIVE) {
+ ALOGE("%s: EFFECT_CMD_ENABLE : state not ACTIVE", __func__);
+ status = -ENOSYS;
+ goto exit;
+ }
+
+ context->state = VOL_LISTENER_STATE_INITIALIZED;
+ *(int *)p_reply_data = 0;
+
+ // After changing the state and if device is speaker
+ // recalculate gain dep cal level
+ if (context->dev_id & AUDIO_DEVICE_OUT_SPEAKER) {
+ check_and_set_gain_dep_cal();
+ }
+
+ break;
+
+ case EFFECT_CMD_GET_PARAM:
+ ALOGV("%s :: cmd called EFFECT_CMD_GET_PARAM", __func__);
+ break;
+
+ case EFFECT_CMD_SET_PARAM:
+ ALOGV("%s :: cmd called EFFECT_CMD_SET_PARAM", __func__);
+ break;
+
+ case EFFECT_CMD_SET_DEVICE:
+ {
+ uint32_t new_device;
+ bool recompute_gain_dep_cal_Level = false;
+ ALOGV("cmd called EFFECT_CMD_SET_DEVICE ");
+
+ if (p_cmd_data == NULL) {
+ ALOGE("%s: EFFECT_CMD_SET_DEVICE: cmd data NULL", __func__);
+ status = -EINVAL;
+ goto exit;
+ }
+
+ new_device = *(uint32_t *)p_cmd_data;
+ ALOGV("%s :: EFFECT_CMD_SET_DEVICE: (current/new) device (0x%x / 0x%x)",
+ __func__, context->dev_id, new_device);
+
+ // check if old or new device is speaker
+ if ((context->dev_id & AUDIO_DEVICE_OUT_SPEAKER) ||
+ (new_device & AUDIO_DEVICE_OUT_SPEAKER)) {
+ recompute_gain_dep_cal_Level = true;
+ }
+
+ context->dev_id = new_device;
+
+ if (recompute_gain_dep_cal_Level) {
+ check_and_set_gain_dep_cal();
+ }
+ }
+ break;
+
+ case EFFECT_CMD_SET_VOLUME:
+ {
+ float left_vol = 0, right_vol = 0;
+ bool recompute_gain_dep_cal_Level = false;
+
+ ALOGV("cmd called EFFECT_CMD_SET_VOLUME");
+ if (p_cmd_data == NULL || cmd_size != 2 * sizeof(uint32_t)) {
+ ALOGE("%s: EFFECT_CMD_SET_VOLUME: %s", __func__, (p_cmd_data == NULL) ?
+ "p_cmd_data is NULL" : "cmd_size issue");
+ status = -EINVAL;
+ goto exit;
+ }
+
+ if (context->dev_id & AUDIO_DEVICE_OUT_SPEAKER) {
+ recompute_gain_dep_cal_Level = true;
+ }
+
+ left_vol = (float)(*(uint32_t *)p_cmd_data) / (1 << 24);
+ right_vol = (float)(*((uint32_t *)p_cmd_data + 1)) / (1 << 24);
+ ALOGV("Current Volume (%f / %f ) new Volume (%f / %f)", context->left_vol,
+ context->right_vol, left_vol, right_vol);
+
+ context->left_vol = left_vol;
+ context->right_vol = right_vol;
+
+ // recompute gan dep cal level only if volume changed on speaker device
+ if (recompute_gain_dep_cal_Level) {
+ check_and_set_gain_dep_cal();
+ }
+ }
+ break;
+
+ default:
+ ALOGW("volume_listener_command invalid command %d", cmd_code);
+ status = -ENOSYS;
+ break;
+ }
+
+exit:
+ pthread_mutex_unlock(&vol_listner_init_lock);
+ return status;
+}
+
+/* Effect Control Interface Implementation: get_descriptor */
+static int vol_effect_get_descriptor(effect_handle_t self,
+ effect_descriptor_t *descriptor)
+{
+ vol_listener_context_t *context = (vol_listener_context_t *)self;
+ ALOGV("%s Called ", __func__);
+
+ if (descriptor == NULL) {
+ ALOGE("%s: descriptor is NULL", __func__);
+ return -EINVAL;
+ }
+
+ *descriptor = *context->desc;
+ return 0;
+}
+
+static void init_once()
+{
+ int i = 0;
+ if (initialized) {
+ ALOGV("%s : already init .. do nothing", __func__);
+ return;
+ }
+
+ ALOGD("%s Called ", __func__);
+ pthread_mutex_init(&vol_listner_init_lock, NULL);
+
+ // get hal function pointer
+ if (access(PRIMARY_HAL_PATH, R_OK) == 0) {
+ void *hal_lib_pointer = dlopen(PRIMARY_HAL_PATH, RTLD_NOW);
+ if (hal_lib_pointer == NULL) {
+ ALOGE("%s: DLOPEN failed for %s", __func__, PRIMARY_HAL_PATH);
+ send_gain_dep_cal = NULL;
+ } else {
+ ALOGV("%s: DLOPEN of %s Succes .. next get HAL entry function", __func__, PRIMARY_HAL_PATH);
+ send_gain_dep_cal = (bool (*)(int))dlsym(hal_lib_pointer, AHAL_GAIN_DEPENDENT_INTERFACE_FUNCTION);
+ if (send_gain_dep_cal == NULL) {
+ ALOGE("Couldnt able to get the function symbol");
+ }
+ }
+ } else {
+ ALOGE("%s: not able to acces lib %s ", __func__, PRIMARY_HAL_PATH);
+ send_gain_dep_cal = NULL;
+ }
+
+ // check system property to see if dumping is required
+ char check_dump_val[PROPERTY_VALUE_MAX];
+ property_get("audio.volume.listener.dump", check_dump_val, "0");
+ if (atoi(check_dump_val)) {
+ dumping_enabled = true;
+ }
+
+ init_status = 0;
+ list_init(&vol_effect_list);
+ initialized = true;
+}
+
+static int lib_init()
+{
+ pthread_once(&once, init_once);
+ ALOGV("%s Called ", __func__);
+ return init_status;
+}
+
+static int vol_prc_lib_create(const effect_uuid_t *uuid,
+ int32_t session_id,
+ int32_t io_id,
+ effect_handle_t *p_handle)
+{
+ int itt = 0;
+ vol_listener_context_t *context = NULL;
+
+ ALOGV("volume_prc_lib_create .. called ..");
+
+ if (lib_init() != 0) {
+ return init_status;
+ }
+
+ if (p_handle == NULL || uuid == NULL) {
+ ALOGE("%s: %s is NULL", __func__, (p_handle == NULL) ? "p_handle" : "uuid");
+ return -EINVAL;
+ }
+
+ context = (vol_listener_context_t *)calloc(1, sizeof(vol_listener_context_t));
+
+ if (context == NULL) {
+ ALOGE("%s: failed to allocate for context .. oops !!", __func__);
+ return -EINVAL;
+ }
+
+ // check if UUID is supported
+ for (itt = 0; descriptors[itt] != NULL; itt++) {
+ if (memcmp(uuid, &descriptors[itt]->uuid, sizeof(effect_uuid_t)) == 0) {
+ // check if this correct .. very imp
+ context->desc = descriptors[itt];
+ context->stream_type = itt;
+ PRINT_STREAM_TYPE(itt)
+ break;
+ }
+ }
+
+ if (descriptors[itt] == NULL) {
+ ALOGE("%s .. couldnt find passed uuid, something wrong", __func__);
+ free(context);
+ return -EINVAL;
+ }
+
+ ALOGV("%s CREATED_CONTEXT %p", __func__, context);
+
+ context->itfe = &effect_interface;
+ context->state = VOL_LISTENER_STATE_INITIALIZED;
+ context->dev_id = AUDIO_DEVICE_NONE;
+ context->session_id = session_id;
+
+ // Add this to master list
+ pthread_mutex_lock(&vol_listner_init_lock);
+ list_add_tail(&vol_effect_list, &context->effect_list_node);
+ if (dumping_enabled) {
+ dump_list_l();
+ }
+ pthread_mutex_unlock(&vol_listner_init_lock);
+
+ *p_handle = (effect_handle_t)context;
+ return 0;
+}
+
+static int vol_prc_lib_release(effect_handle_t handle)
+{
+ struct listnode *node = NULL;
+ vol_listener_context_t *context = NULL;
+ vol_listener_context_t *recv_contex = (vol_listener_context_t *)handle;
+ int status = -1;
+ bool recompute_flag = false;
+ int active_stream_count = 0;
+ ALOGV("%s context %p", __func__, handle);
+ pthread_mutex_lock(&vol_listner_init_lock);
+
+ // check if the handle/context provided is valid
+ list_for_each(node, &vol_effect_list) {
+ context = node_to_item(node, struct vol_listener_context_s, effect_list_node);
+ if ((memcmp(&(context->desc->uuid), &(recv_contex->desc->uuid), sizeof(effect_uuid_t)) == 0)
+ && (context->session_id == recv_contex->session_id)
+ && (context->stream_type == recv_contex->stream_type)) {
+ ALOGV("--- Found something to remove ---");
+ list_remove(&context->effect_list_node);
+ PRINT_STREAM_TYPE(context->stream_type);
+ if (context->dev_id && AUDIO_DEVICE_OUT_SPEAKER) {
+ recompute_flag = true;
+ }
+ free(context);
+ status = 0;
+ } else {
+ ++active_stream_count;
+ }
+ }
+
+ if (status != 0) {
+ ALOGE("something wrong ... <<<--- Found NOTHING to remove ... ???? --->>>>>");
+ }
+
+ // if there are no active streams, reset cal and volume level
+ if (active_stream_count == 0) {
+ current_gain_dep_cal_level = -1;
+ current_vol = 0.0;
+ }
+
+ if (recompute_flag) {
+ check_and_set_gain_dep_cal();
+ }
+
+ if (dumping_enabled) {
+ dump_list_l();
+ }
+ pthread_mutex_unlock(&vol_listner_init_lock);
+ return status;
+}
+
+static int vol_prc_lib_get_descriptor(const effect_uuid_t *uuid,
+ effect_descriptor_t *descriptor)
+{
+ int i = 0;
+ ALOGV("%s Called ", __func__);
+ if (lib_init() != 0) {
+ return init_status;
+ }
+
+ if (descriptor == NULL || uuid == NULL) {
+ ALOGE("%s: %s is NULL", __func__, (descriptor == NULL) ? "descriptor" : "uuid");
+ 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;
+ }
+ }
+
+ ALOGE("%s: couldnt found uuid passed, oops", __func__);
+ return -EINVAL;
+}
+
+
+/* effect_handle_t interface implementation for volume listener effect */
+static const struct effect_interface_s effect_interface = {
+ vol_effect_process,
+ vol_effect_command,
+ vol_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 = "Volume Listener Effect Library",
+ .implementor = "Qualcomm Technologies Inc.",
+ .create_effect = vol_prc_lib_create,
+ .release_effect = vol_prc_lib_release,
+ .get_descriptor = vol_prc_lib_get_descriptor,
+};
diff --git a/voice_processing/voice_processing.c b/voice_processing/voice_processing.c
index 1d18a3d..72e4d84 100644
--- a/voice_processing/voice_processing.c
+++ b/voice_processing/voice_processing.c
@@ -16,6 +16,7 @@
#define LOG_TAG "voice_processing"
/*#define LOG_NDEBUG 0*/
+#include <stdlib.h>
#include <dlfcn.h>
#include <cutils/log.h>
#include <cutils/list.h>