audio: Add support to enable audio over bg

Add support for BG sound card. Add changes to send BG
codec cal stored in ACDB.

Bug: 73666907
Test: Compile test for 8974 platform, manual test for audio
playback/capture on BG.

Change-Id: I425224efdc2e3d43662f4d4bd521c436daa40ee9
diff --git a/hal/Android.mk b/hal/Android.mk
index cbee1d4..aa6a9b5 100644
--- a/hal/Android.mk
+++ b/hal/Android.mk
@@ -194,6 +194,10 @@
     LOCAL_SRC_FILES += audio_extn/maxxaudio.c
 endif
 
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_BG_CAL)),true)
+    LOCAL_CFLAGS += -DBG_CODEC_CAL
+endif
+
 LOCAL_SHARED_LIBRARIES += libbase libhidlbase libhwbinder libutils android.hardware.power@1.2 liblog
 
 LOCAL_SRC_FILES += audio_perf.cpp
diff --git a/hal/acdb.h b/hal/acdb.h
index 24dcb8f..e6410d6 100644
--- a/hal/acdb.h
+++ b/hal/acdb.h
@@ -33,6 +33,7 @@
 typedef int  (*acdb_init_t)();
 typedef void (*acdb_send_audio_cal_t)(int, int);
 typedef void (*acdb_send_voice_cal_t)(int, int);
+typedef int (*acdb_get_audio_cal_t) (void *, void *, uint32_t*);
 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);
diff --git a/hal/msm8916/hw_info.c b/hal/msm8916/hw_info.c
index e5ef549..0afb510 100644
--- a/hal/msm8916/hw_info.c
+++ b/hal/msm8916/hw_info.c
@@ -47,6 +47,8 @@
     } else if (!strcmp(snd_card_name, "msm8909-snd-card") ||
                !strcmp(snd_card_name, "msm8909-pm8916-snd-card")) {
         strlcpy(hw_info->name, "msm8909", sizeof(hw_info->name));
+    } else if (!strcmp(snd_card_name, "msm-bg-snd-card")) {
+        strlcpy(hw_info->name, "msm8909", sizeof(hw_info->name));
     }  else if (!strcmp(snd_card_name, "msm8952-snd-card") ||
                 !strcmp(snd_card_name, "msm8952-snd-card-mtp")) {
         strlcpy(hw_info->name, "msm8952", sizeof(hw_info->name));
@@ -68,7 +70,8 @@
     }
 
     if (strstr(snd_card_name, "msm8x16") || strstr(snd_card_name, "msm8909")
-        || strstr(snd_card_name, "msm8952")) {
+        || strstr(snd_card_name, "msm8952") ||
+        strstr(snd_card_name, "msm-bg-snd-card")) {
         ALOGV("8x16 - variant soundcard");
 
         strlcpy(hw_info->type, "", sizeof(hw_info->type));
diff --git a/hal/msm8916/platform.c b/hal/msm8916/platform.c
index 61260b8..c9851d4 100644
--- a/hal/msm8916/platform.c
+++ b/hal/msm8916/platform.c
@@ -29,6 +29,7 @@
 #include <platform_api.h>
 #include "platform.h"
 #include "audio_extn.h"
+#include "acdb.h"
 #include "voice_extn.h"
 #include "sound/msmcal-hwdep.h"
 #include "audio_extn/tfa_98xx.h"
@@ -37,6 +38,7 @@
 #define MIXER_XML_PATH "mixer_paths.xml"
 #define MIXER_XML_PATH_MTP "mixer_paths_mtp.xml"
 #define MIXER_XML_PATH_MSM8909_PM8916 "mixer_paths_msm8909_pm8916.xml"
+#define MIXER_XML_PATH_BG "mixer_paths_bg.xml"
 #define MIXER_XML_PATH_L9300 "mixer_paths_l9300.xml"
 
 #define LIB_ACDB_LOADER "libacdbloader.so"
@@ -89,6 +91,19 @@
     int length;
 };
 
+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;
+
 enum {
     CAL_MODE_SEND           = 0x1,
     CAL_MODE_PERSIST        = 0x2,
@@ -119,14 +134,10 @@
 static struct listnode *operator_specific_device_table[SND_DEVICE_MAX];
 
 /* Audio calibration related functions */
-typedef void (*acdb_deallocate_t)();
-typedef int  (*acdb_init_v2_cvd_t)(const char *, char *, int);
-typedef void (*acdb_send_audio_cal_t)(int, int);
 typedef void (*acdb_send_audio_cal_v3_t)(int, int, int , int, int);
-typedef void (*acdb_send_voice_cal_t)(int, int);
-typedef int (*acdb_reload_vocvoltable_t)(int);
 typedef int (*acdb_loader_get_calibration_t)(char *attr, int size, void *data);
 acdb_loader_get_calibration_t acdb_loader_get_calibration;
+static int platform_get_meta_info_key_from_list(void *platform, char *mod_name);
 
 struct platform_data {
     struct audio_device *adev;
@@ -140,10 +151,12 @@
     bool gsm_mode_enabled;
     /* Audio calibration related functions */
     void                       *acdb_handle;
+    acdb_init_v3_t             acdb_init_v3;
     acdb_init_v2_cvd_t         acdb_init;
     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_get_audio_cal_t       acdb_get_audio_cal;
     acdb_send_voice_cal_t      acdb_send_voice_cal;
     acdb_reload_vocvoltable_t  acdb_reload_vocvoltable;
     void *hw_info;
@@ -151,6 +164,7 @@
     bool speaker_lr_swap;
 
     int max_vol_index;
+    struct listnode acdb_meta_key_list;
 };
 
 int pcm_device_table[AUDIO_USECASE_MAX][2] = {
@@ -513,6 +527,10 @@
                  sizeof("msm8909-pm8916-snd-card"))) {
         strlcpy(mixer_xml_path, MIXER_XML_PATH_MSM8909_PM8916,
                 sizeof(MIXER_XML_PATH_MSM8909_PM8916));
+    } else if (!strncmp(snd_card_name, "msm-bg-snd-card",
+                sizeof("msm-bg-snd-card"))) {
+        strlcpy(mixer_xml_path, MIXER_XML_PATH_BG,
+                sizeof(MIXER_XML_PATH_BG));
     } else if (!strncmp(snd_card_name, "msm8952-snd-card-mtp",
                  sizeof("msm8952-snd-card-mtp"))) {
         strlcpy(mixer_xml_path, MIXER_XML_PATH_MTP,
@@ -748,8 +766,84 @@
     void   *buff;
 };
 
+static int send_bg_cal(struct platform_data *plat_data,
+                        int type, int fd)
+{
+    /*
+     * This is done to avoid compiler failure due to unused varialbes
+     * if both the below #defines are not present
+     */
+    (void)plat_data;
+    (void)type;
+    (void)fd;
+
+#ifdef BG_CAL_SUPPORT
+    if ((type == BG_CODEC_MIC_CAL) ||
+        (type == BG_CODEC_SPEAKER_CAL)) {
+#ifdef BG_CODEC_CAL
+        int ret = 0, key = 0;
+        uint32_t param_len;
+        uint8_t *dptr = NULL;
+        struct wcdcal_ioctl_buffer codec_buffer;
+        acdb_audio_cal_cfg_t cal;
+
+        memset(&cal, 0, sizeof(cal));
+        cal.persist = 1;
+        cal.cal_type = AUDIO_CORE_METAINFO_CAL_TYPE;
+        param_len = MAX_SET_CAL_BYTE_SIZE;
+        dptr = (unsigned char*) calloc(param_len, sizeof(unsigned char*));
+        if (dptr == NULL) {
+            ALOGE("%s Memory allocation failed for length %d",
+                    __func__, param_len);
+            return 0;
+        }
+        if (type == BG_CODEC_MIC_CAL) {
+            key = platform_get_meta_info_key_from_list(plat_data,
+                                                       "bg_miccal");
+            if (!key) {
+                ALOGE("%s Failed to fetch mic metakey info", __func__);
+                goto done;
+            }
+            ALOGV("%s BG mic with key:0x%x", __func__, key);
+            codec_buffer.cal_type = BG_CODEC_MIC_CAL;
+        } else if (type == BG_CODEC_SPEAKER_CAL) {
+            key = platform_get_meta_info_key_from_list(plat_data,
+                                                       "bg_speakercal");
+            if (!key) {
+                ALOGE("%s Failed to fetch metakey info", __func__);
+                goto done;
+            }
+            ALOGV("%s BG speaker with key:0x%x", __func__, key);
+            codec_buffer.cal_type = BG_CODEC_SPEAKER_CAL;
+        }
+        cal.acdb_dev_id = key;
+        ret = plat_data->acdb_get_audio_cal((void*)&cal, (void*)dptr,
+                                            &param_len);
+        if (ret) {
+            ALOGE("%s failed to get meta info for key 0x%x error %d",
+                    __func__, key, ret);
+            goto done;
+        }
+        codec_buffer.buffer = dptr;
+        codec_buffer.size = param_len;
+
+        if (ioctl(fd, SNDRV_CTL_IOCTL_HWDEP_CAL_TYPE, &codec_buffer) < 0)
+            ALOGE("Failed to call ioctl  for mic err=%d calib.size=%d",
+                    errno, codec_buffer.size);
+        else
+            ALOGD("%s cal sent for %d calib.size=%d",
+                    __func__, cal.acdb_dev_id, codec_buffer.size);
+    done:
+        free(dptr);
+#endif /* #ifdef BG_CODEC_CAL */
+        return 0;
+    } else
+#endif /* #ifdef BG_CAL_SUPPORT */
+      return -1;
+}
+
 static int send_codec_cal(acdb_loader_get_calibration_t acdb_loader_get_calibration,
-                          struct platform_data *plat_data __unused, int fd)
+                          struct platform_data *plat_data , int fd)
 {
     int ret = 0, type;
 
@@ -757,6 +851,9 @@
         struct wcdcal_ioctl_buffer codec_buffer;
         struct param_data calib;
 
+        if (send_bg_cal(plat_data, type, fd) == 0)
+            continue;
+
         if (type != WCD9XXX_MBHC_CAL)
             continue;
 
@@ -824,8 +921,11 @@
     char *cvd_version = NULL;
     int key = 0;
     const char *snd_card_name;
-    int result;
+    int result = 0;
     char value[PROPERTY_VALUE_MAX];
+    struct listnode *node;
+    struct meta_key_list *key_info;
+
     cvd_version = calloc(1, MAX_CVD_VERSION_STRING_SIZE);
     if (!cvd_version)
         ALOGE("Failed to allocate cvd version");
@@ -836,7 +936,12 @@
     key = atoi(value);
     snd_card_name = mixer_get_name(my_data->adev->mixer);
 
-    result = my_data->acdb_init(snd_card_name, cvd_version, key);
+    if (my_data->acdb_init_v3) {
+        result = my_data->acdb_init_v3(snd_card_name, cvd_version,
+                                           &my_data->acdb_meta_key_list);
+    } else if (my_data->acdb_init) {
+        result = my_data->acdb_init((char *)snd_card_name, cvd_version, key);
+    }
 
     if (cvd_version)
         free(cvd_version);
@@ -1012,6 +1117,13 @@
         acdb_device_table[SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET] = 131;
     }
 
+    list_init(&my_data->acdb_meta_key_list);
+    set_platform_defaults();
+    /* Initialize ACDB and PCM ID's */
+    strlcpy(platform_info_path, PLATFORM_INFO_XML_PATH, MAX_MIXER_XML_PATH);
+    resolve_config_file(platform_info_path);
+    platform_info_init(platform_info_path, my_data);
+
     my_data->acdb_handle = dlopen(LIB_ACDB_LOADER, RTLD_NOW);
     if (my_data->acdb_handle == NULL) {
         ALOGE("%s: DLOPEN failed for %s", __func__, LIB_ACDB_LOADER);
@@ -1035,6 +1147,12 @@
             ALOGE("%s: Could not find the symbol acdb_send_audio_cal from %s",
                   __func__, LIB_ACDB_LOADER);
 
+        my_data->acdb_get_audio_cal = (acdb_get_audio_cal_t)dlsym(my_data->acdb_handle,
+                                                  "acdb_loader_get_audio_cal_v2");
+        if (!my_data->acdb_get_audio_cal)
+            ALOGE("%s: Could not find the symbol acdb_get_audio_cal_v2 from %s",
+                  __func__, LIB_ACDB_LOADER);
+
         my_data->acdb_send_voice_cal = (acdb_send_voice_cal_t)dlsym(my_data->acdb_handle,
                                                     "acdb_loader_send_voice_cal");
         if (!my_data->acdb_send_voice_cal)
@@ -1053,18 +1171,17 @@
             ALOGE("%s: dlsym error %s for acdb_loader_init_v2", __func__, dlerror());
             goto acdb_init_fail;
         }
+
+        my_data->acdb_init_v3 = (acdb_init_v3_t)dlsym(my_data->acdb_handle,
+                                                   "acdb_loader_init_v3");
+        if (my_data->acdb_init_v3 == NULL) {
+            ALOGI("%s: dlsym error %s for acdb_loader_init_v3", __func__, dlerror());
+        }
         platform_acdb_init(my_data);
     }
 
 acdb_init_fail:
 
-    set_platform_defaults();
-
-    /* Initialize ACDB and PCM ID's */
-    strlcpy(platform_info_path, PLATFORM_INFO_XML_PATH, MAX_MIXER_XML_PATH);
-    resolve_config_file(platform_info_path);
-    platform_info_init(platform_info_path, my_data);
-
     /*init a2dp*/
     audio_extn_a2dp_init(adev);
 
@@ -1329,6 +1446,48 @@
     return ret;
 }
 
+int platform_set_acdb_metainfo_key(void *platform, char *name, int key)
+{
+    struct meta_key_list *key_info;
+    struct platform_data *pdata = (struct platform_data *)platform;
+
+    if (key < 0) {
+        ALOGE("%s: Incorrect Meta key\n", __func__);
+        return -EINVAL;
+    }
+    key_info = (struct meta_key_list *)calloc(1, sizeof(struct meta_key_list));
+    if (!key_info) {
+        ALOGE("%s: Could not allocate memory for key %d", __func__, key);
+        return -ENOMEM;
+    }
+
+    key_info->cal_info.nKey = key;
+    strlcpy(key_info->name, name, sizeof(key_info->name));
+    list_add_tail(&pdata->acdb_meta_key_list, &key_info->list);
+    ALOGD("%s: successfully added module %s and key %d to the list", __func__,
+                   key_info->name, key_info->cal_info.nKey);
+    return 0;
+}
+
+static int platform_get_meta_info_key_from_list(void *platform, char *mod_name)
+{
+    struct listnode *node;
+    struct meta_key_list *key_info;
+    struct platform_data *pdata = (struct platform_data *)platform;
+    int key = 0;
+
+    ALOGV("%s: for module %s", __func__, mod_name);
+    list_for_each(node, &pdata->acdb_meta_key_list) {
+        key_info = node_to_item(node, struct meta_key_list, list);
+        if (strcmp(key_info->name, mod_name) == 0) {
+            key = key_info->cal_info.nKey;
+            ALOGD("%s: Found key %d for module %s", __func__, key, mod_name);
+            break;
+        }
+    }
+    return key;
+}
+
 int platform_get_default_app_type_v2(void *platform, usecase_type_t type, int *app_type)
 {
     ALOGV("%s: platform: %p, type: %d", __func__, platform, type);
diff --git a/hal/msm8960/platform.c b/hal/msm8960/platform.c
index 6095ea6..9e06a0c 100644
--- a/hal/msm8960/platform.c
+++ b/hal/msm8960/platform.c
@@ -1375,3 +1375,9 @@
 {
     return -1;
 }
+
+int platform_set_acdb_metainfo_key(void *platform __unused,
+                                   char *name __unused,
+                                   int key __unused) {
+    return -ENOSYS;
+}
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index 2955d6b..6d0a6cf 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -4703,3 +4703,10 @@
     return -1;
 #endif
 }
+
+int platform_set_acdb_metainfo_key(void *platform __unused,
+                                   char *name __unused,
+                                   int key __unused)
+{
+    return -ENOSYS;
+}
diff --git a/hal/platform_api.h b/hal/platform_api.h
index 44305a1..1967233 100644
--- a/hal/platform_api.h
+++ b/hal/platform_api.h
@@ -59,6 +59,7 @@
 int platform_send_audio_calibration(void *platform, snd_device_t snd_device);
 int platform_send_audio_calibration_v2(void *platform, struct audio_usecase *usecase,
                                        int app_type, int sample_rate);
+int platform_set_acdb_metainfo_key(void *platform, char *name, int key);
 int platform_get_default_app_type_v2(void *platform, enum usecase_type_t type, int *app_type);
 int platform_switch_voice_call_device_pre(void *platform);
 int platform_switch_voice_call_enable_device_config(void *platform,
diff --git a/hal/platform_info.c b/hal/platform_info.c
index 181460e..f5fbe3f 100644
--- a/hal/platform_info.c
+++ b/hal/platform_info.c
@@ -41,6 +41,7 @@
     INPUT_SND_DEVICE_TO_MIC_MAPPING,
     SND_DEV,
     MIC_INFO,
+    ACDB_METAINFO_KEY,
 } section_t;
 
 typedef void (* section_process_fn)(const XML_Char **attr);
@@ -56,6 +57,7 @@
 static void process_microphone_characteristic(const XML_Char **attr);
 static void process_snd_dev(const XML_Char **attr);
 static void process_mic_info(const XML_Char **attr);
+static void process_acdb_metainfo_key(const XML_Char **attr);
 
 static section_process_fn section_table[] = {
     [ROOT] = process_root,
@@ -69,6 +71,7 @@
     [MICROPHONE_CHARACTERISTIC] = process_microphone_characteristic,
     [SND_DEV] = process_snd_dev,
     [MIC_INFO] = process_mic_info,
+    [ACDB_METAINFO_KEY] = process_acdb_metainfo_key,
 };
 
 static set_parameters_fn set_parameters = &platform_set_parameters;
@@ -737,6 +740,28 @@
     return;
 }
 
+/* process acdb meta info key value */
+static void process_acdb_metainfo_key(const XML_Char **attr)
+{
+    if (strcmp(attr[0], "name") != 0) {
+        ALOGE("%s: 'name' not found", __func__);
+        goto done;
+    }
+    if (strcmp(attr[2], "value") != 0) {
+        ALOGE("%s: 'value' not found", __func__);
+        goto done;
+    }
+
+    int key = atoi((char *)attr[3]);
+    if (platform_set_acdb_metainfo_key(my_data.platform,
+                                       (char*)attr[1], key) < 0) {
+        ALOGE("%s: key %d was not set!", __func__, key);
+    }
+
+done:
+    return;
+}
+
 static void start_tag(void *userdata __unused, const XML_Char *tag_name,
                       const XML_Char **attr)
 {
@@ -764,6 +789,8 @@
             section = MICROPHONE_CHARACTERISTIC;
         } else if (strcmp(tag_name, "snd_devices") == 0) {
             section = SND_DEVICES;
+        } else if(strcmp(tag_name, "acdb_metainfo_key") == 0) {
+            section = ACDB_METAINFO_KEY;
         } else if (strcmp(tag_name, "device") == 0) {
             if ((section != ACDB) && (section != BACKEND_NAME) && (section != OPERATOR_SPECIFIC)) {
                 ALOGE("device tag only supported for acdb/backend names");
@@ -782,7 +809,7 @@
             section_process_fn fn = section_table[PCM_ID];
             fn(attr);
         } else if (strcmp(tag_name, "param") == 0) {
-            if (section != CONFIG_PARAMS) {
+            if ((section != CONFIG_PARAMS) && (section != ACDB_METAINFO_KEY)) {
                 ALOGE("param tag only supported with CONFIG_PARAMS section");
                 return;
             }
@@ -884,6 +911,8 @@
         section = SND_DEVICES;
     } else if (strcmp(tag_name, "input_snd_device_mic_mapping") == 0) {
         section = INPUT_SND_DEVICE;
+    } else if (strcmp(tag_name, "acdb_metainfo_key") == 0) {
+        section = ROOT;
     }
 }