audio: Add API to set audio calibration
- add API of setting audio calibration only on platform
Bug: 74360112
Test: manual test
Change-Id: Ie0520f31cd1834fcb6faa1205b839336e9233678
Signed-off-by: jasmine cha <chajasmine@android.com>
diff --git a/hal/acdb.h b/hal/acdb.h
index 08026fb..24dcb8f 100644
--- a/hal/acdb.h
+++ b/hal/acdb.h
@@ -36,6 +36,7 @@
typedef int (*acdb_reload_vocvoltable_t)(int);
typedef int (*acdb_send_gain_dep_cal_t)(int, int, int, int, int);
typedef int (*acdb_send_custom_top_t) (void);
+typedef int (*acdb_set_audio_cal_t) (void *, void *, uint32_t);
struct meta_key_list {
struct listnode list;
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index c80f994..b8755b8 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -34,6 +34,8 @@
#include <sound/devdep_params.h>
#endif
+#include <resolv.h>
+
#define MIXER_XML_DEFAULT_PATH "mixer_paths.xml"
#define MIXER_XML_BASE_STRING "mixer_paths"
#define TOMTOM_8226_SND_CARD_NAME "msm8226-tomtom-snd-card"
@@ -105,6 +107,21 @@
static struct listnode operator_info_list;
static struct listnode *operator_specific_device_table[SND_DEVICE_MAX];
+#define AUDIO_PARAMETER_KEY_AUD_CALDATA "cal_data"
+
+typedef struct acdb_audio_cal_cfg {
+ uint32_t persist;
+ uint32_t snd_dev_id;
+ audio_devices_t dev_id;
+ int32_t acdb_dev_id;
+ uint32_t app_type;
+ uint32_t topo_id;
+ uint32_t sampling_rate;
+ uint32_t cal_type;
+ uint32_t module_id;
+ uint32_t param_id;
+} acdb_audio_cal_cfg_t;
+
/* Audio calibration related functions */
typedef void (*acdb_send_audio_cal_v3_t)(int, int, int, int, int);
@@ -130,6 +147,7 @@
acdb_deallocate_t acdb_deallocate;
acdb_send_audio_cal_t acdb_send_audio_cal;
acdb_send_audio_cal_v3_t acdb_send_audio_cal_v3;
+ acdb_set_audio_cal_t acdb_set_audio_cal;
acdb_send_voice_cal_t acdb_send_voice_cal;
acdb_reload_vocvoltable_t acdb_reload_vocvoltable;
acdb_send_gain_dep_cal_t acdb_send_gain_dep_cal;
@@ -741,6 +759,139 @@
#endif
}
+static int parse_audiocal_cfg(struct str_parms *parms, acdb_audio_cal_cfg_t *cal)
+{
+ int err;
+ char value[64];
+ int ret = 0;
+
+ if (parms == NULL || cal == NULL)
+ return ret;
+
+ err = str_parms_get_str(parms, "cal_persist", value, sizeof(value));
+ if (err >= 0) {
+ str_parms_del(parms, "cal_persist");
+ cal->persist = (uint32_t)strtoul(value, NULL, 0);
+ ret = ret | 0x1;
+ }
+ err = str_parms_get_str(parms, "cal_apptype", value, sizeof(value));
+ if (err >= 0) {
+ str_parms_del(parms, "cal_apptype");
+ cal->app_type = (uint32_t)strtoul(value, NULL, 0);
+ ret = ret | 0x2;
+ }
+ err = str_parms_get_str(parms, "cal_caltype", value, sizeof(value));
+ if (err >= 0) {
+ str_parms_del(parms, "cal_caltype");
+ cal->cal_type = (uint32_t)strtoul(value, NULL, 0);
+ ret = ret | 0x4;
+ }
+ err = str_parms_get_str(parms, "cal_samplerate", value, sizeof(value));
+ if (err >= 0) {
+ str_parms_del(parms, "cal_samplerate");
+ cal->sampling_rate = (uint32_t)strtoul(value, NULL, 0);
+ ret = ret | 0x8;
+ }
+ err = str_parms_get_str(parms, "cal_devid", value, sizeof(value));
+ if (err >= 0) {
+ str_parms_del(parms, "cal_devid");
+ cal->dev_id = (uint32_t)strtoul(value, NULL, 0);
+ ret = ret | 0x10;
+ }
+ err = str_parms_get_str(parms, "cal_snddevid", value, sizeof(value));
+ if (err >= 0) {
+ str_parms_del(parms, "cal_snddevid");
+ cal->snd_dev_id = (uint32_t)strtoul(value, NULL, 0);
+ ret = ret | 0x20;
+ }
+ err = str_parms_get_str(parms, "cal_topoid", value, sizeof(value));
+ if (err >= 0) {
+ str_parms_del(parms, "cal_topoid");
+ cal->topo_id = (uint32_t)strtoul(value, NULL, 0);
+ ret = ret | 0x40;
+ }
+ err = str_parms_get_str(parms, "cal_moduleid", value, sizeof(value));
+ if (err >= 0) {
+ str_parms_del(parms, "cal_moduleid");
+ cal->module_id = (uint32_t)strtoul(value, NULL, 0);
+ ret = ret | 0x80;
+ }
+ err = str_parms_get_str(parms, "cal_paramid", value, sizeof(value));
+ if (err >= 0) {
+ str_parms_del(parms, "cal_paramid");
+ cal->param_id = (uint32_t)strtoul(value, NULL, 0);
+ ret = ret | 0x100;
+ }
+ return ret;
+}
+
+static void set_audiocal(void *platform, struct str_parms *parms, char *value, int len)
+{
+ struct platform_data *my_data = (struct platform_data *)platform;
+ acdb_audio_cal_cfg_t cal;
+ uint8_t *dptr = NULL;
+ int32_t dlen = 0;
+ int err ,ret;
+
+ if (value == NULL || platform == NULL || parms == NULL) {
+ ALOGE("[%s] received null pointer, failed", __func__);
+ goto done_key_audcal;
+ }
+
+ memset(&cal, 0, sizeof(acdb_audio_cal_cfg_t));
+ /* parse audio calibration keys */
+ ret = parse_audiocal_cfg(parms, &cal);
+
+ /* handle audio calibration data now */
+ err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_AUD_CALDATA, value, len);
+ if (err >= 0) {
+ str_parms_del(parms, AUDIO_PARAMETER_KEY_AUD_CALDATA);
+ dlen = strlen(value);
+ if (dlen <= 0) {
+ ALOGE("[%s] null data received", __func__);
+ goto done_key_audcal;
+ }
+ /*
+ The base64 encoded string is always larger than the binary data,
+ so b64_pton will always output less data than provided (around 1/3
+ less than the input data). That's why we can allocate input buffer
+ length and then get function work.
+ */
+ dptr = (uint8_t *)calloc(dlen, sizeof(uint8_t));
+ if (dptr == NULL) {
+ ALOGE("[%s] memory allocation failed for %d", __func__, dlen);
+ goto done_key_audcal;
+ }
+ dlen = b64_pton(value, dptr, dlen);
+ if (dlen <= 0) {
+ ALOGE("[%s] data decoding failed %d", __func__, dlen);
+ goto done_key_audcal;
+ }
+
+ if (cal.dev_id) {
+ if (audio_is_input_device(cal.dev_id)) {
+ cal.snd_dev_id = platform_get_input_snd_device(platform, cal.dev_id);
+ } else {
+ cal.snd_dev_id = platform_get_output_snd_device(platform, cal.dev_id);
+ }
+ }
+ cal.acdb_dev_id = platform_get_snd_device_acdb_id(cal.snd_dev_id);
+ ALOGD("Setting audio calibration for snd_device(%d) acdb_id(%d)",
+ cal.snd_dev_id, cal.acdb_dev_id);
+ if (cal.acdb_dev_id == -EINVAL) {
+ ALOGE("[%s] Invalid acdb_device id %d for snd device id %d",
+ __func__, cal.acdb_dev_id, cal.snd_dev_id);
+ goto done_key_audcal;
+ }
+ if (my_data->acdb_set_audio_cal) {
+ ret = my_data->acdb_set_audio_cal((void *)&cal, (void *)dptr, dlen);
+ }
+ }
+done_key_audcal:
+ if (dptr != NULL)
+ free(dptr);
+}
+
bool platform_send_gain_dep_cal(void *platform, int level)
{
bool ret_val = false;
@@ -1598,6 +1749,12 @@
ALOGE("%s: Could not find the symbol acdb_get_default_app_type from %s",
__func__, LIB_ACDB_LOADER);
+ my_data->acdb_set_audio_cal = (acdb_set_audio_cal_t)dlsym(my_data->acdb_handle,
+ "acdb_loader_set_audio_cal_v2");
+ if (!my_data->acdb_set_audio_cal)
+ ALOGE("%s: Could not find the symbol acdb_set_audio_cal_v2 from %s",
+ __func__, LIB_ACDB_LOADER);
+
int result = acdb_init(adev->snd_card);
if (!result) {
my_data->acdb_initialized = true;
@@ -3139,8 +3296,9 @@
int platform_set_parameters(void *platform, struct str_parms *parms)
{
struct platform_data *my_data = (struct platform_data *)platform;
- char value[128];
+ char *value = NULL;
char *kv_pairs = str_parms_to_str(parms);
+ int len;
int ret = 0, err;
if (kv_pairs == NULL) {
@@ -3151,8 +3309,16 @@
ALOGV("%s: enter: %s", __func__, kv_pairs);
+ len = strlen(kv_pairs);
+ value = (char*)calloc(len+1, sizeof(char));
+ if (value == NULL) {
+ ret = -ENOMEM;
+ ALOGE("[%s] failed to allocate memory",__func__);
+ goto done;
+ }
+
err = str_parms_get_str(parms, PLATFORM_CONFIG_KEY_SOUNDCARD_NAME,
- value, sizeof(value));
+ value, len);
if (err >= 0) {
str_parms_del(parms, PLATFORM_CONFIG_KEY_SOUNDCARD_NAME);
my_data->snd_card_name = strdup(value);
@@ -3160,7 +3326,7 @@
}
err = str_parms_get_str(parms, PLATFORM_CONFIG_KEY_OPERATOR_INFO,
- value, sizeof(value));
+ value, len);
if (err >= 0) {
struct operator_info *info;
char *str = value;
@@ -3178,19 +3344,24 @@
memset(value, 0, sizeof(value));
err = str_parms_get_str(parms, PLATFORM_CONFIG_KEY_MAX_MIC_COUNT,
- value, sizeof(value));
+ value, len);
if (err >= 0) {
str_parms_del(parms, PLATFORM_CONFIG_KEY_MAX_MIC_COUNT);
my_data->max_mic_count = atoi(value);
ALOGV("%s: max_mic_count %s/%d", __func__, value, my_data->max_mic_count);
}
+ /* handle audio calibration parameters */
+ set_audiocal(platform, parms, value, len);
+
// to-do: disable setting sidetone gain, will revist this later
// audio_extn_usb_set_sidetone_gain(parms, value, len);
done:
ALOGV("%s: exit with code(%d)", __func__, ret);
if (kv_pairs != NULL)
free(kv_pairs);
+ if (value != NULL)
+ free(value);
return ret;
}