Merge "audio: add bt-sco and speaker-safe path" into pi-dev
diff --git a/hal/Android.mk b/hal/Android.mk
index 9b1f4e6..3ce2d2b 100644
--- a/hal/Android.mk
+++ b/hal/Android.mk
@@ -51,8 +51,8 @@
 ifneq ($(filter sdm845,$(TARGET_BOARD_PLATFORM)),)
   LOCAL_CFLAGS := -DPLATFORM_SDM845
   LOCAL_CFLAGS += -DMAX_TARGET_SPECIFIC_CHANNEL_CNT="4"
-  LOCAL_CFLAGS += -DKPI_OPTIMIZE_ENABLED
   LOCAL_CFLAGS += -DINCALL_MUSIC_ENABLED
+  LOCAL_CFLAGS += -DINCALL_STEREO_CAPTURE_ENABLED
   MULTIPLE_HW_VARIANTS_ENABLED := true
 endif
 endif
@@ -193,6 +193,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/audio_extn/a2dp.c b/hal/audio_extn/a2dp.c
index 8dc4a26..bb44172 100644
--- a/hal/audio_extn/a2dp.c
+++ b/hal/audio_extn/a2dp.c
@@ -1370,7 +1370,6 @@
         ALOGD("%s: calling Bluetooth module stream start", __func__);
         /* This call indicates Bluetooth IPC lib to start playback */
         ret =  a2dp.audio_stream_start();
-        ALOGE("%s: Bluetooth controller start return = %d", __func__, ret);
         if (ret != 0 ) {
            ALOGE("%s: Bluetooth controller start failed", __func__);
            a2dp.a2dp_started = false;
@@ -1423,6 +1422,30 @@
     return ret;
 }
 
+static int reset_a2dp_dec_config_params()
+{
+    struct mixer_ctl *ctl_dec_data = NULL;
+    struct abr_dec_cfg_t dummy_reset_cfg;
+    int ret = 0;
+
+    if (a2dp.abr_config.is_abr_enabled) {
+        ctl_dec_data = mixer_get_ctl_by_name(a2dp.adev->mixer, MIXER_DEC_CONFIG_BLOCK);
+        if (!ctl_dec_data) {
+            ALOGE("%s: ERROR A2DP decoder config mixer control not identifed", __func__);
+            return -EINVAL;
+        }
+        memset(&dummy_reset_cfg, 0x0, sizeof(dummy_reset_cfg));
+        ret = mixer_ctl_set_array(ctl_dec_data, (void *)&dummy_reset_cfg,
+                                  sizeof(dummy_reset_cfg));
+        if (ret != 0) {
+            ALOGE("%s: Failed to set dummy decoder config", __func__);
+            return ret;
+        }
+    }
+
+    return ret;
+}
+
 int audio_extn_a2dp_stop_playback()
 {
     int ret = 0;
@@ -1446,6 +1469,7 @@
         else
             ALOGV("%s: stop steam to Bluetooth IPC lib successful", __func__);
         reset_a2dp_enc_config_params();
+        reset_a2dp_dec_config_params();
         a2dp_reset_backend_cfg();
         if (a2dp.abr_config.is_abr_enabled && a2dp.abr_config.abr_started)
             stop_abr();
@@ -1457,16 +1481,17 @@
     return 0;
 }
 
-void audio_extn_a2dp_set_parameters(struct str_parms *parms)
+int audio_extn_a2dp_set_parameters(struct str_parms *parms, bool *reconfig)
 {
-     int ret, val;
+     int ret = 0, val;
      char value[32] = {0};
      struct audio_usecase *uc_info;
      struct listnode *node;
 
      if (a2dp.is_a2dp_offload_enabled == false) {
         ALOGV("%s: No supported encoders identified,ignoring A2DP setparam", __func__);
-        return;
+        ret = -EINVAL;
+        goto param_handled;
      }
 
      ret = str_parms_get_str(parms, AUDIO_PARAMETER_DEVICE_CONNECT, value,
@@ -1488,6 +1513,7 @@
          if (audio_is_a2dp_out_device(val)) {
              ALOGV("%s: Received device disconnect request", __func__);
              reset_a2dp_enc_config_params();
+             reset_a2dp_dec_config_params();
              close_a2dp_output();
          }
          goto param_handled;
@@ -1513,6 +1539,7 @@
                     }
                 }
                 reset_a2dp_enc_config_params();
+                reset_a2dp_dec_config_params();
                 if (a2dp.audio_stream_suspend) {
                    a2dp.audio_stream_suspend();
                 }
@@ -1562,8 +1589,20 @@
         }
         goto param_handled;
      }
+
+     ret = str_parms_get_str(parms, AUDIO_PARAMETER_RECONFIG_A2DP, value,
+                         sizeof(value));
+     if (ret >= 0) {
+         if (a2dp.is_a2dp_offload_enabled &&
+                a2dp.bt_state != A2DP_STATE_DISCONNECTED) {
+             *reconfig = true;
+         }
+         goto param_handled;
+     }
+
 param_handled:
      ALOGV("%s: end of A2DP setparam", __func__);
+     return ret;
 }
 
 void audio_extn_a2dp_set_handoff_mode(bool is_on)
@@ -1615,6 +1654,7 @@
   a2dp.is_handoff_in_progress = false;
   a2dp.is_aptx_dual_mono_supported = false;
   reset_a2dp_enc_config_params();
+  reset_a2dp_dec_config_params();
   update_offload_codec_support();
 }
 
@@ -1664,4 +1704,21 @@
     }
     return latency;
 }
+
+int audio_extn_a2dp_get_parameters(struct str_parms *query,
+                                   struct str_parms *reply)
+{
+    int ret, val = 0;
+    char value[32]={0};
+
+    ret = str_parms_get_str(query, AUDIO_PARAMETER_A2DP_RECONFIG_SUPPORTED,
+                            value, sizeof(value));
+    if (ret >= 0) {
+        val = a2dp.is_a2dp_offload_enabled;
+        str_parms_add_int(reply, AUDIO_PARAMETER_A2DP_RECONFIG_SUPPORTED, val);
+        ALOGV("%s: called ... isReconfigA2dpSupported %d", __func__, val);
+    }
+
+    return 0;
+}
 #endif // A2DP_OFFLOAD_ENABLED
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index 054beea..b1c701d 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -147,7 +147,8 @@
 #define audio_extn_a2dp_init(adev)                       (0)
 #define audio_extn_a2dp_start_playback()                 (0)
 #define audio_extn_a2dp_stop_playback()                  (0)
-#define audio_extn_a2dp_set_parameters(parms)            (0)
+#define audio_extn_a2dp_set_parameters(parms, reconfig)  (0)
+#define audio_extn_a2dp_get_parameters(query, reply)     (0)
 #define audio_extn_a2dp_is_force_device_switch()         (0)
 #define audio_extn_a2dp_set_handoff_mode(is_on)          (0)
 #define audio_extn_a2dp_get_sample_rate(sample_rate)     (0)
@@ -158,7 +159,9 @@
 void audio_extn_a2dp_init(void *adev);
 int audio_extn_a2dp_start_playback();
 int audio_extn_a2dp_stop_playback();
-void audio_extn_a2dp_set_parameters(struct str_parms *parms);
+int audio_extn_a2dp_set_parameters(struct str_parms *parms, bool *reconfig);
+int audio_extn_a2dp_get_parameters(struct str_parms *query,
+                                   struct str_parms *reply);
 bool audio_extn_a2dp_is_force_device_switch();
 void audio_extn_a2dp_set_handoff_mode(bool is_on);
 void audio_extn_a2dp_get_sample_rate(int *sample_rate);
diff --git a/hal/audio_extn/maxxaudio.c b/hal/audio_extn/maxxaudio.c
index 73bd641..9007da7 100644
--- a/hal/audio_extn/maxxaudio.c
+++ b/hal/audio_extn/maxxaudio.c
@@ -17,40 +17,41 @@
 #define LOG_TAG "audio_hw_waves"
 /*#define LOG_NDEBUG 0*/
 
-#include <stdlib.h>
-#include <dlfcn.h>
-#include <pthread.h>
-#include <unistd.h>
-#include <cutils/str_parms.h>
-#include <log/log.h>
 #include <audio_hw.h>
-#include <system/audio.h>
-#include <platform_api.h>
-#include <string.h>
+#include <cutils/str_parms.h>
+#include <dlfcn.h>
+#include <log/log.h>
 #include <math.h>
+#include <platform_api.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+#include <system/audio.h>
+#include <unistd.h>
+
 #include "audio_extn.h"
 #include "maxxaudio.h"
 
-#define LIB_MA_PARAM "libmaqdspparams.so"
+#define LIB_MA_PARAM "libmaxxaudioqdsp.so"
 #define LIB_MA_PATH "vendor/lib/"
-#define PRESET_PATH "/vendor/etc/default.mps"
+#define PRESET_PATH "/vendor/etc"
+#define MPS_BASE_STRING "default"
 #define USER_PRESET_PATH ""
 #define CONFIG_PATH "/vendor/etc/maxx_conf.ini"
 #define CAL_PRESIST_STR "cal_persist"
 #define CAL_SAMPLERATE_STR "cal_samplerate"
 
-#define MA_QDSP_PARAM_INIT "maxxaudio_qdsp_parameters_initialize"
-#define MA_QDSP_PARAM_DEINIT "maxxaudio_qdsp_parameters_uninitialize"
+#define MA_QDSP_PARAM_INIT "maxxaudio_qdsp_initialize"
+#define MA_QDSP_PARAM_DEINIT "maxxaudio_qdsp_uninitialize"
 #define MA_QDSP_SET_LR_SWAP "maxxaudio_qdsp_set_lr_swap"
 #define MA_QDSP_SET_MODE "maxxaudio_qdsp_set_sound_mode"
 #define MA_QDSP_SET_VOL "maxxaudio_qdsp_set_volume"
 #define MA_QDSP_SET_VOLT "maxxaudio_qdsp_set_volume_table"
 
 #define SUPPORT_DEV "Blackbird"
-#define SUPPORTED_USB  0x01
+#define SUPPORTED_USB 0x01
 
 struct ma_audio_cal_settings {
-    void *platform;
     int app_type;
     audio_devices_t device;
 };
@@ -78,34 +79,30 @@
 } ma_cmd_t;
 
 typedef void *ma_audio_cal_handle_t;
-typedef int (*set_audio_cal_t)(const struct ma_audio_cal_settings *, const char *);
+typedef int (*set_audio_cal_t)(const char *);
 
-typedef bool (*ma_param_init_t)(
-                ma_audio_cal_handle_t *,
-                void *, const char *, const char *,
-                const char *, set_audio_cal_t);
+typedef bool (*ma_param_init_t)(ma_audio_cal_handle_t *, const char *,
+                                const char *, const char *, set_audio_cal_t);
 
-typedef bool (*ma_param_deinit_t)(ma_audio_cal_handle_t);
+typedef bool (*ma_param_deinit_t)(ma_audio_cal_handle_t *);
 
-typedef bool (*ma_set_lr_swap_t)(
-                ma_audio_cal_handle_t,
-                const struct ma_audio_cal_settings *, bool);
+typedef bool (*ma_set_lr_swap_t)(ma_audio_cal_handle_t,
+                                 const struct ma_audio_cal_settings *, bool);
 
-typedef bool (*ma_set_sound_mode_t)(
-                ma_audio_cal_handle_t,
-                const struct ma_audio_cal_settings *, unsigned int);
+typedef bool (*ma_set_sound_mode_t)(ma_audio_cal_handle_t,
+                                    const struct ma_audio_cal_settings *,
+                                    unsigned int);
 
-typedef bool (*ma_set_volume_t)(
-                ma_audio_cal_handle_t,
-                const struct ma_audio_cal_settings *, double);
+typedef bool (*ma_set_volume_t)(ma_audio_cal_handle_t,
+                                const struct ma_audio_cal_settings *, double);
 
-typedef bool (*ma_set_volume_table_t)(
-                ma_audio_cal_handle_t,
-                const struct ma_audio_cal_settings *,
-                size_t, struct ma_state *);
+typedef bool (*ma_set_volume_table_t)(ma_audio_cal_handle_t,
+                                      const struct ma_audio_cal_settings *,
+                                      size_t, struct ma_state *);
 
 struct ma_platform_data {
     void *waves_handle;
+    void *platform;
     pthread_mutex_t lock;
     ma_param_init_t          ma_param_init;
     ma_param_deinit_t        ma_param_deinit;
@@ -120,49 +117,42 @@
 static struct ma_state ma_cur_state_table[STREAM_MAX_TYPES];
 static struct ma_platform_data *my_data = NULL;
 
-static int set_audio_cal(
-        const struct ma_audio_cal_settings *audio_cal_settings,
-        const char *audio_cal)
-
+static int set_audio_cal(const char *audio_cal)
 {
     ALOGV("set_audio_cal: %s", audio_cal);
 
-    return platform_set_parameters(audio_cal_settings->platform,
+    return platform_set_parameters(my_data->platform,
                                    str_parms_create_str(audio_cal));
 }
 
 static bool ma_set_lr_swap_l(
-        const struct ma_audio_cal_settings *audio_cal_settings,
-        bool swap)
+    const struct ma_audio_cal_settings *audio_cal_settings, bool swap)
 {
-    return my_data->ma_set_lr_swap(g_ma_audio_cal_handle, audio_cal_settings, swap);
+    return my_data->ma_set_lr_swap(g_ma_audio_cal_handle,
+                                   audio_cal_settings, swap);
 }
 
 static bool ma_set_sound_mode_l(
-        const struct ma_audio_cal_settings *audio_cal_settings,
-        int sound_mode)
+    const struct ma_audio_cal_settings *audio_cal_settings, int sound_mode)
 {
     return my_data->ma_set_sound_mode(g_ma_audio_cal_handle,
-                                        audio_cal_settings, sound_mode);
+                                      audio_cal_settings, sound_mode);
 }
 
 static bool ma_set_volume_l(
-        const struct ma_audio_cal_settings *audio_cal_settings,
-        double volume)
+    const struct ma_audio_cal_settings *audio_cal_settings, double volume)
 {
-    return my_data->ma_set_volume(g_ma_audio_cal_handle, audio_cal_settings, volume);
+    return my_data->ma_set_volume(g_ma_audio_cal_handle, audio_cal_settings,
+                                  volume);
 }
 
 static bool ma_set_volume_table_l(
-        const struct ma_audio_cal_settings *audio_cal_settings,
-        size_t num_streams, struct ma_state *volume_table)
+    const struct ma_audio_cal_settings *audio_cal_settings,
+    size_t num_streams, struct ma_state *volume_table)
 {
-    return my_data->ma_set_volume_table(
-                     g_ma_audio_cal_handle,
-                     audio_cal_settings,
-                     num_streams,
-                     volume_table);
-
+    return my_data->ma_set_volume_table(g_ma_audio_cal_handle,
+                                        audio_cal_settings, num_streams,
+                                        volume_table);
 }
 
 static inline bool valid_usecase(struct audio_usecase *usecase)
@@ -175,7 +165,7 @@
         /* support devices */
         ((usecase->devices & AUDIO_DEVICE_OUT_SPEAKER) ||
          (usecase->devices & AUDIO_DEVICE_OUT_SPEAKER_SAFE) ||
-         (usecase->devices & AUDIO_DEVICE_OUT_ALL_A2DP) ||
+         /* TODO: enable A2DP when it is ready */
          (usecase->devices & AUDIO_DEVICE_OUT_ALL_USB)))
 
         return true;
@@ -219,7 +209,6 @@
     list_for_each(node, &adev->usecase_list) {
         usecase = node_to_item(node, struct audio_usecase, list);
         if (valid_usecase(usecase)) {
-            ma_cal->platform = adev->platform;
             ma_cal->app_type = usecase->stream.out->app_type_cfg.app_type;
             ma_cal->device = usecase->stream.out->devices;
             ALOGV("%s: send usecase(%d) app_type(%d) device(%d)",
@@ -228,7 +217,7 @@
             switch (cmd) {
                 case MA_CMD_VOL:
                     ret = ma_set_volume_table_l(ma_cal, STREAM_MAX_TYPES,
-                                                  ma_cur_state_table);
+                                                ma_cur_state_table);
                     if (ret)
                         ALOGV("Waves: ma_set_volume_table_l success");
                     else
@@ -236,9 +225,9 @@
 
                     ALOGV("%s: send volume table === Start", __func__);
                     for (i = 0; i < STREAM_MAX_TYPES; i++)
-                        ALOGV("%s: stream(%d) volume(%f) active(%s)", __func__, i,
-                            ma_cur_state_table[i].vol,
-                            ma_cur_state_table[i].active ? "T" : "F");
+                        ALOGV("%s: stream(%d) volume(%f) active(%s)", __func__,
+                              i, ma_cur_state_table[i].vol,
+                              ma_cur_state_table[i].active ? "T" : "F");
                     ALOGV("%s: send volume table === End", __func__);
                     break;
                 case MA_CMD_SWAP_ENABLE:
@@ -258,7 +247,6 @@
                 default:
                     ALOGE("%s: unsupported cmd %d", __func__, cmd);
             }
-
         }
     }
     free(ma_cal);
@@ -294,10 +282,14 @@
 
 static void ma_set_swap_l(struct audio_device *adev, bool enable)
 {
+    // do platform LR swap if it enables on Waves effect
+    // but there is no Waves implementation
     if (!my_data) {
-        ALOGE("%s: maxxaudio isn't initialized.", __func__);
+        platform_check_and_set_swap_lr_channels(adev, enable);
+        ALOGV("%s: maxxaudio isn't initialized.", __func__);
         return;
     }
+
     if (enable)
         check_and_send_all_audio_cal(adev, MA_CMD_SWAP_ENABLE);
     else
@@ -316,7 +308,7 @@
         ret = snprintf(path, sizeof(path), "/proc/asound/card%u/id", card);
         if (ret < 0) {
             ALOGE("%s: failed on snprintf (%d) to path %s\n",
-              __func__, ret, path);
+                  __func__, ret, path);
             goto done;
         }
         fd = open(path, O_RDONLY);
@@ -350,7 +342,10 @@
 {
     ma_stream_type_t i = 0;
     int ret = 0;
-    char lib_path[256];
+    char lib_path[128] = {0};
+    char mps_path[128] = {0};
+    struct snd_card_split *snd_split_handle = NULL;
+    snd_split_handle = audio_extn_get_snd_card_split();
 
     if (platform == NULL) {
         ALOGE("%s: platform is NULL", __func__);
@@ -366,6 +361,7 @@
 
     pthread_mutex_init(&my_data->lock, NULL);
 
+    my_data->platform = platform;
     ret = snprintf(lib_path, sizeof(lib_path), "%s/%s", LIB_MA_PATH, LIB_MA_PARAM);
     if (ret < 0) {
         ALOGE("%s: snprintf failed for lib %s, ret %d", __func__, LIB_MA_PARAM, ret);
@@ -380,53 +376,64 @@
          ALOGV("%s: DLOPEN successful for %s", __func__, LIB_MA_PARAM);
 
          my_data->ma_param_init = (ma_param_init_t)dlsym(my_data->waves_handle,
-                                     MA_QDSP_PARAM_INIT);
+                                   MA_QDSP_PARAM_INIT);
          if (!my_data->ma_param_init) {
              ALOGE("%s: dlsym error %s for ma_param_init", __func__, dlerror());
              goto error;
          }
 
-         my_data->ma_param_deinit = (ma_param_deinit_t)dlsym(my_data->waves_handle,
-                                       MA_QDSP_PARAM_DEINIT);
+         my_data->ma_param_deinit = (ma_param_deinit_t)dlsym(
+                                     my_data->waves_handle, MA_QDSP_PARAM_DEINIT);
          if (!my_data->ma_param_deinit) {
              ALOGE("%s: dlsym error %s for ma_param_deinit", __func__, dlerror());
              goto error;
          }
 
          my_data->ma_set_lr_swap = (ma_set_lr_swap_t)dlsym(my_data->waves_handle,
-                                      MA_QDSP_SET_LR_SWAP);
+                                    MA_QDSP_SET_LR_SWAP);
          if (!my_data->ma_set_lr_swap) {
              ALOGE("%s: dlsym error %s for ma_set_lr_swap", __func__, dlerror());
              goto error;
          }
 
-         my_data->ma_set_sound_mode = (ma_set_sound_mode_t)dlsym(my_data->waves_handle,
-                                         MA_QDSP_SET_MODE);
+         my_data->ma_set_sound_mode = (ma_set_sound_mode_t)dlsym(
+                                       my_data->waves_handle, MA_QDSP_SET_MODE);
          if (!my_data->ma_set_sound_mode) {
              ALOGE("%s: dlsym error %s for ma_set_sound_mode", __func__, dlerror());
              goto error;
          }
 
          my_data->ma_set_volume = (ma_set_volume_t)dlsym(my_data->waves_handle,
-                                     MA_QDSP_SET_VOL);
+                                   MA_QDSP_SET_VOL);
          if (!my_data->ma_set_volume) {
              ALOGE("%s: dlsym error %s for ma_set_volume", __func__, dlerror());
              goto error;
          }
 
-         my_data->ma_set_volume_table = (ma_set_volume_table_t)dlsym(my_data->waves_handle,
-                                           MA_QDSP_SET_VOLT);
+         my_data->ma_set_volume_table = (ma_set_volume_table_t)dlsym(
+                                         my_data->waves_handle, MA_QDSP_SET_VOLT);
          if (!my_data->ma_set_volume_table) {
              ALOGE("%s: dlsym error %s for ma_set_volume_table", __func__, dlerror());
              goto error;
          }
     }
 
-    /* check file */
-    if (access(PRESET_PATH, F_OK) < 0) {
-        ALOGW("%s: file %s isn't existed.", __func__, PRESET_PATH);
-        goto error;
+    /* get preset table */
+    if (snd_split_handle == NULL) {
+        snprintf(mps_path, sizeof(mps_path), "%s/%s.mps",
+                 PRESET_PATH, MPS_BASE_STRING);
+    } else {
+        snprintf(mps_path, sizeof(mps_path), "%s/%s_%s.mps",
+                 PRESET_PATH, MPS_BASE_STRING, snd_split_handle->form_factor);
     }
+
+    /* check file */
+    if (access(mps_path, F_OK) < 0) {
+        ALOGW("%s: file %s isn't existed.", __func__, mps_path);
+        goto error;
+    } else
+        ALOGD("%s: Loading mps file: %s", __func__, mps_path);
+
     /* TODO: check user preset table once the feature is enabled
     if (access(USER_PRESET_PATH, F_OK) < 0 ){
         ALOGW("%s: file %s isn't existed.", __func__, USER_PRESET_PATH);
@@ -440,11 +447,10 @@
 
     /* init ma parameter */
     if (my_data->ma_param_init(&g_ma_audio_cal_handle,
-                                  platform, /* TODO: remove this on next version*/
-                                  PRESET_PATH,
-                                  USER_PRESET_PATH, /* useless */
-                                  CONFIG_PATH,
-                                  &set_audio_cal)) {
+                               mps_path,
+                               USER_PRESET_PATH, /* unused */
+                               CONFIG_PATH,
+                               &set_audio_cal)) {
         if (!g_ma_audio_cal_handle) {
             ALOGE("%s: ma parameters initialize failed", __func__);
             my_data->ma_param_deinit(&g_ma_audio_cal_handle);
@@ -487,8 +493,8 @@
 }
 
 // adev_init and adev lock held
-bool audio_extn_ma_set_state(
-        struct audio_device *adev, int stream_type, float vol, bool active)
+bool audio_extn_ma_set_state(struct audio_device *adev, int stream_type,
+                             float vol, bool active)
 {
     bool ret = false;
     ma_stream_type_t stype = (ma_stream_type_t)stream_type;
@@ -497,7 +503,7 @@
           __func__, stream_type, vol, active ? "true" : "false");
 
     if (!my_data) {
-        ALOGE("%s: maxxaudio isn't initialized.", __func__);
+        ALOGV("%s: maxxaudio isn't initialized.", __func__);
         return ret;
     }
 
@@ -505,7 +511,7 @@
     // 1. start track: active and volume isn't zero
     // 2. stop track: no tracks are active
     if ((active && vol != 0) ||
-         (!active)) {
+        (!active)) {
         pthread_mutex_lock(&my_data->lock);
 
         ma_cur_state_table[stype].vol = vol;
@@ -519,7 +525,7 @@
     return ret;
 }
 
-void audio_extn_ma_set_device(struct audio_device *adev, struct audio_usecase *usecase)
+void audio_extn_ma_set_device(struct audio_usecase *usecase)
 {
     int i = 0;
     int u_index = -1;
@@ -540,7 +546,6 @@
 
     /* update audio_cal and send it */
     if (ma_cal != NULL){
-        ma_cal->platform = adev->platform;
         ma_cal->app_type = usecase->stream.out->app_type_cfg.app_type;
         ma_cal->device = usecase->stream.out->devices;
         ALOGV("%s: send usecase(%d) app_type(%d) device(%d)",
@@ -557,8 +562,8 @@
             ALOGV("%s: send volume table === End", __func__);
 
             if (!ma_set_volume_table_l(ma_cal,
-                                         STREAM_MAX_TYPES,
-                                         ma_cur_state_table))
+                                       STREAM_MAX_TYPES,
+                                       ma_cur_state_table))
                 ALOGE("Waves: ma_set_volume_table_l %f returned with error.", vol);
             else
                 ALOGV("Waves: ma_set_volume_table_l success");
@@ -571,7 +576,8 @@
     }
 }
 
-void audio_extn_ma_set_parameters(struct audio_device *adev, struct str_parms *parms)
+void audio_extn_ma_set_parameters(struct audio_device *adev,
+                                  struct str_parms *parms)
 {
     int ret;
     bool ret_b;
@@ -594,7 +600,8 @@
     }
 
     // check connect status
-    ret = str_parms_get_str(parms, AUDIO_PARAMETER_DEVICE_CONNECT, value, sizeof(value));
+    ret = str_parms_get_str(parms, AUDIO_PARAMETER_DEVICE_CONNECT, value,
+                            sizeof(value));
     if (ret >= 0) {
         audio_devices_t device = (audio_devices_t)strtoul(value, NULL, 10);
         if (audio_is_usb_out_device(device)) {
@@ -607,7 +614,8 @@
     }
 
     // check disconnect status
-    ret = str_parms_get_str(parms, AUDIO_PARAMETER_DEVICE_DISCONNECT, value, sizeof(value));
+    ret = str_parms_get_str(parms, AUDIO_PARAMETER_DEVICE_DISCONNECT, value,
+                            sizeof(value));
     if (ret >= 0) {
         audio_devices_t device = (audio_devices_t)strtoul(value, NULL, 10);
         if (audio_is_usb_out_device(device)) {
diff --git a/hal/audio_extn/maxxaudio.h b/hal/audio_extn/maxxaudio.h
index a2ebaed..4c91107 100644
--- a/hal/audio_extn/maxxaudio.h
+++ b/hal/audio_extn/maxxaudio.h
@@ -18,18 +18,20 @@
 #define MAXXAUDIO_H_
 
 #ifndef MAXXAUDIO_QDSP_ENABLED
-#define audio_extn_ma_init(platform)                                      (0)
-#define audio_extn_ma_deinit()                                            (0)
-#define audio_extn_ma_set_state(adev, type, vol, active)                  (false)
-#define audio_extn_ma_set_device(adev, usecase)                           (0)
-#define audio_extn_ma_set_parameters(adev, param)                         (0)
-#define audio_extn_ma_supported_usb()                                     (false)
+#define audio_extn_ma_init(platform)                                (0)
+#define audio_extn_ma_deinit()                                      (0)
+#define audio_extn_ma_set_state(adev, type, vol, active)            (false)
+#define audio_extn_ma_set_device(usecase)                           (0)
+#define audio_extn_ma_set_parameters(adev, param)                   (0)
+#define audio_extn_ma_supported_usb()                               (false)
 #else
 void audio_extn_ma_init(void *platform);
 void audio_extn_ma_deinit();
-bool audio_extn_ma_set_state(struct audio_device *adev, int stream_type, float vol, bool active);
-void audio_extn_ma_set_device(struct audio_device *adev, struct audio_usecase *usecase);
-void audio_extn_ma_set_parameters(struct audio_device *adev, struct str_parms *parms);
+bool audio_extn_ma_set_state(struct audio_device *adev, int stream_type,
+                             float vol, bool active);
+void audio_extn_ma_set_device(struct audio_usecase *usecase);
+void audio_extn_ma_set_parameters(struct audio_device *adev,
+                                  struct str_parms *parms);
 bool audio_extn_ma_supported_usb();
 #endif /* MAXXAUDIO_QDSP_ENABLED */
 
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 8a2562f..b104319 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -678,12 +678,6 @@
 
     audio_extn_dsm_feedback_enable(adev, snd_device, true);
 
-    if (is_a2dp_device(snd_device) &&
-        (audio_extn_a2dp_start_playback() < 0)) {
-           ALOGE("%s: failed to configure A2DP control path", __func__);
-           goto on_error;
-    }
-
     if ((snd_device == SND_DEVICE_OUT_SPEAKER ||
         snd_device == SND_DEVICE_OUT_SPEAKER_SAFE ||
         snd_device == SND_DEVICE_OUT_SPEAKER_REVERSE ||
@@ -711,6 +705,13 @@
         }
 
         ALOGD("%s: snd_device(%d: %s)", __func__, snd_device, device_name);
+
+        if (is_a2dp_device(snd_device) &&
+            (audio_extn_a2dp_start_playback() < 0)) {
+               ALOGE("%s: failed to configure A2DP control path", __func__);
+               goto on_error;
+        }
+
         audio_route_apply_and_update_path(adev->audio_route, device_name);
     }
 on_success:
@@ -907,7 +908,8 @@
      * with new AFE encoder format based on a2dp state
      */
     if ((SND_DEVICE_OUT_BT_A2DP == snd_device ||
-         SND_DEVICE_OUT_SPEAKER_AND_BT_A2DP == snd_device) &&
+         SND_DEVICE_OUT_SPEAKER_AND_BT_A2DP == snd_device ||
+         SND_DEVICE_OUT_SPEAKER_SAFE_AND_BT_A2DP == snd_device) &&
          audio_extn_a2dp_is_force_device_switch()) {
          force_routing = true;
     }
@@ -1361,7 +1363,8 @@
           return 0;
     }
 
-    if ((out_snd_device == SND_DEVICE_OUT_SPEAKER_AND_BT_A2DP) &&
+    if ((out_snd_device == SND_DEVICE_OUT_SPEAKER_AND_BT_A2DP ||
+         out_snd_device == SND_DEVICE_OUT_SPEAKER_SAFE_AND_BT_A2DP) &&
         (!audio_extn_a2dp_is_ready())) {
         ALOGW("%s: A2DP profile is not ready, routing to speaker only", __func__);
         out_snd_device = SND_DEVICE_OUT_SPEAKER;
@@ -1461,7 +1464,7 @@
 
     enable_audio_route(adev, usecase);
 
-    audio_extn_ma_set_device(adev, usecase);
+    audio_extn_ma_set_device(usecase);
 
     /* Applicable only on the targets that has external modem.
      * Enable device command should be sent to modem only after
@@ -2599,7 +2602,7 @@
             out->devices = new_dev;
 
             if (output_drives_call(adev, out)) {
-                if (!voice_is_in_call(adev)) {
+                if (!voice_is_call_state_active(adev)) {
                     if (adev->mode == AUDIO_MODE_IN_CALL) {
                         adev->current_call_output = out;
                         ret = voice_start_call(adev);
@@ -4643,6 +4646,7 @@
     int val;
     int ret;
     int status = 0;
+    bool a2dp_reconfig = false;
 
     ALOGV("%s: enter: %s", __func__, kvpairs);
 
@@ -4741,18 +4745,16 @@
     }
 
     audio_extn_hfp_set_parameters(adev, parms);
-    audio_extn_a2dp_set_parameters(parms);
     audio_extn_ma_set_parameters(adev, parms);
 
-    // reconfigure should be done only after updating A2DP state in audio extension
-    ret = str_parms_get_str(parms,"reconfigA2dp", value, sizeof(value));
-    if (ret >= 0) {
+    status = audio_extn_a2dp_set_parameters(parms, &a2dp_reconfig);
+    if (status >= 0 && a2dp_reconfig) {
         struct audio_usecase *usecase;
         struct listnode *node;
         list_for_each(node, &adev->usecase_list) {
             usecase = node_to_item(node, struct audio_usecase, list);
             if ((usecase->type == PCM_PLAYBACK) &&
-                (usecase->devices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP)) {
+                (usecase->devices & AUDIO_DEVICE_OUT_ALL_A2DP)) {
                 ALOGD("%s: reconfigure A2DP... forcing device switch", __func__);
 
                 pthread_mutex_unlock(&adev->lock);
@@ -4786,6 +4788,8 @@
     pthread_mutex_lock(&adev->lock);
 
     voice_get_parameters(adev, query, reply);
+    audio_extn_a2dp_get_parameters(query, reply);
+
     str = str_parms_to_str(reply);
     str_parms_destroy(query);
     str_parms_destroy(reply);
@@ -5006,6 +5010,18 @@
     in->capture_handle = handle;
     in->flags = flags;
 
+    ALOGV("%s: source = %d, config->channel_mask = %d", __func__, source, config->channel_mask);
+    if (source == AUDIO_SOURCE_VOICE_UPLINK ||
+         source == AUDIO_SOURCE_VOICE_DOWNLINK) {
+        /* Force channel config requested to mono if incall
+           record is being requested for only uplink/downlink */
+        if (config->channel_mask != AUDIO_CHANNEL_IN_MONO) {
+            config->channel_mask = AUDIO_CHANNEL_IN_MONO;
+            ret = -EINVAL;
+            goto err_open;
+        }
+    }
+
     if (is_usb_dev && may_use_hifi_record) {
         /* HiFi record selects an appropriate format, channel, rate combo
            depending on sink capabilities*/
@@ -5660,6 +5676,8 @@
         }
     }
 
+    adev->mic_break_enabled = property_get_bool("vendor.audio.mic_break", false);
+
     // commented as full set of app type cfg is sent from platform
     // audio_extn_utils_send_default_app_type_cfg(adev->platform, adev->mixer);
     audio_device_ref_count++;
diff --git a/hal/audio_hw.h b/hal/audio_hw.h
index a42a458..921c249 100644
--- a/hal/audio_hw.h
+++ b/hal/audio_hw.h
@@ -328,6 +328,7 @@
     bool mic_muted;
     bool enable_voicerx;
     bool enable_hfp;
+    bool mic_break_enabled;
 
     int snd_card;
     void *platform;
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 5c528d7..d92243e 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] = {
@@ -213,6 +227,7 @@
     [SND_DEVICE_OUT_BT_SCO_WB] = "bt-sco-headset-wb",
     [SND_DEVICE_OUT_BT_A2DP] = "bt-a2dp",
     [SND_DEVICE_OUT_SPEAKER_AND_BT_A2DP] = "speaker-and-bt-a2dp",
+    [SND_DEVICE_OUT_SPEAKER_SAFE_AND_BT_A2DP] = "speaker-safe-and-bt-a2dp",
     [SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES] = "voice-tty-full-headphones",
     [SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES] = "voice-tty-vco-headphones",
     [SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET] = "voice-tty-hco-handset",
@@ -306,6 +321,7 @@
     [SND_DEVICE_OUT_BT_SCO_WB] = 39,
     [SND_DEVICE_OUT_BT_A2DP] = 20,
     [SND_DEVICE_OUT_SPEAKER_AND_BT_A2DP] = 14,
+    [SND_DEVICE_OUT_SPEAKER_SAFE_AND_BT_A2DP] = 14,
     [SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES] = 17,
     [SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES] = 17,
     [SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET] = 37,
@@ -406,6 +422,7 @@
     {TO_NAME_INDEX(SND_DEVICE_OUT_BT_SCO_WB)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_BT_A2DP)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_AND_BT_A2DP)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_SAFE_AND_BT_A2DP)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET)},
@@ -513,6 +530,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,
@@ -680,6 +701,8 @@
     backend_table[SND_DEVICE_OUT_BT_SCO_WB] = strdup("bt-sco-wb");
     backend_table[SND_DEVICE_OUT_BT_A2DP] = strdup("bt-a2dp");
     backend_table[SND_DEVICE_OUT_SPEAKER_AND_BT_A2DP] = strdup("speaker-and-bt-a2dp");
+    backend_table[SND_DEVICE_OUT_SPEAKER_SAFE_AND_BT_A2DP] =
+        strdup("speaker-safe-and-bt-a2dp");
     backend_table[SND_DEVICE_OUT_HDMI] = strdup("hdmi");
     backend_table[SND_DEVICE_OUT_SPEAKER_AND_HDMI] = strdup("speaker-and-hdmi");
     backend_table[SND_DEVICE_OUT_VOICE_TX] = strdup("afe-proxy");
@@ -748,8 +771,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 +856,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 +926,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 +941,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 +1122,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 +1152,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 +1176,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 +1451,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);
@@ -1457,6 +1621,11 @@
     return 0;
 }
 
+int platform_set_mic_break_det(void *platform __unused, bool enable __unused)
+{
+    return 0;
+}
+
 int platform_get_sample_rate(void *platform __unused, uint32_t *rate __unused)
 {
     return 0;
@@ -1634,6 +1803,9 @@
         } else if ((devices & AUDIO_DEVICE_OUT_SPEAKER) &&
                    (devices & AUDIO_DEVICE_OUT_ALL_A2DP)) {
             snd_device = SND_DEVICE_OUT_SPEAKER_AND_BT_A2DP;
+        } else if ((devices & AUDIO_DEVICE_OUT_SPEAKER_SAFE) &&
+                   (devices & AUDIO_DEVICE_OUT_ALL_A2DP)) {
+            snd_device = SND_DEVICE_OUT_SPEAKER_SAFE_AND_BT_A2DP;
         } else {
             ALOGE("%s: Invalid combo device(%#x)", __func__, devices);
             goto exit;
@@ -2146,6 +2318,13 @@
     return ret;
 }
 
+int platform_set_incall_recording_session_channels(void *platform __unused,
+                                             uint32_t channel_count __unused)
+{
+    return 0;
+}
+
+
 int platform_stop_incall_recording_usecase(void *platform __unused)
 {
     return 0;
diff --git a/hal/msm8916/platform.h b/hal/msm8916/platform.h
index d828f6b..b69b6c9 100644
--- a/hal/msm8916/platform.h
+++ b/hal/msm8916/platform.h
@@ -73,6 +73,7 @@
     SND_DEVICE_OUT_BT_SCO_WB,
     SND_DEVICE_OUT_BT_A2DP,
     SND_DEVICE_OUT_SPEAKER_AND_BT_A2DP,
+    SND_DEVICE_OUT_SPEAKER_SAFE_AND_BT_A2DP,
     SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES,
     SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES,
     SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET,
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 cbc8a09..429291c 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -263,6 +263,7 @@
     [SND_DEVICE_OUT_BT_SCO_WB] = "bt-sco-headset-wb",
     [SND_DEVICE_OUT_BT_A2DP] = "bt-a2dp",
     [SND_DEVICE_OUT_SPEAKER_AND_BT_A2DP] = "speaker-and-bt-a2dp",
+    [SND_DEVICE_OUT_SPEAKER_SAFE_AND_BT_A2DP] = "speaker-safe-and-bt-a2dp",
     [SND_DEVICE_OUT_VOICE_HANDSET_TMUS] = "voice-handset-tmus",
     [SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES] = "voice-tty-full-headphones",
     [SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES] = "voice-tty-vco-headphones",
@@ -384,6 +385,7 @@
     [SND_DEVICE_OUT_SPEAKER_SAFE_AND_BT_SCO_WB] = 14,
     [SND_DEVICE_OUT_BT_A2DP] = 20,
     [SND_DEVICE_OUT_SPEAKER_AND_BT_A2DP] = 14,
+    [SND_DEVICE_OUT_SPEAKER_SAFE_AND_BT_A2DP] = 14,
     [SND_DEVICE_OUT_VOICE_HANDSET_TMUS] = ACDB_ID_VOICE_HANDSET_TMUS,
     [SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES] = 17,
     [SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES] = 17,
@@ -509,6 +511,7 @@
     {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_SAFE_AND_BT_SCO_WB)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_BT_A2DP)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_AND_BT_A2DP)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_SAFE_AND_BT_A2DP)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_HANDSET_TMUS)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_HAC_HANDSET)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES)},
@@ -1220,6 +1223,7 @@
     backend_tag_table[SND_DEVICE_IN_USB_HEADSET_MIC_AEC] = strdup("usb-headset-mic");
     backend_tag_table[SND_DEVICE_OUT_BT_A2DP] = strdup("bt-a2dp");
     backend_tag_table[SND_DEVICE_OUT_SPEAKER_AND_BT_A2DP] = strdup("speaker-and-bt-a2dp");
+    backend_tag_table[SND_DEVICE_OUT_SPEAKER_SAFE_AND_BT_A2DP] = strdup("speaker-safe-and-bt-a2dp");
     backend_tag_table[SND_DEVICE_OUT_USB_HEADSET_SPEC] = strdup("usb-headset");
 
     hw_interface_table[SND_DEVICE_OUT_HANDSET] = strdup("SLIMBUS_0_RX");
@@ -1244,6 +1248,8 @@
     hw_interface_table[SND_DEVICE_OUT_BT_A2DP] = strdup("SLIMBUS_7_RX");
     hw_interface_table[SND_DEVICE_OUT_SPEAKER_AND_BT_A2DP] =
         strdup("SLIMBUS_0_RX-and-SLIMBUS_7_RX");
+    hw_interface_table[SND_DEVICE_OUT_SPEAKER_SAFE_AND_BT_A2DP] =
+        strdup("SLIMBUS_0_RX-and-SLIMBUS_7_RX");
     hw_interface_table[SND_DEVICE_OUT_VOICE_HANDSET_TMUS] = strdup("SLIMBUS_0_RX");
     hw_interface_table[SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES] = strdup("SLIMBUS_0_RX");
     hw_interface_table[SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES] = strdup("SLIMBUS_0_RX");
@@ -1501,7 +1507,7 @@
     const char* setting5 = "ADC1";
     const char* ctl6 = "DEC2 Volume";
     int setting6 = 84;
-    const char* ctl7 = "MultiMedia2 Mixer SLIM_1_TX";
+    const char* ctl7 = "MultiMedia9 Mixer SLIM_1_TX";
     int setting7 = 1;
     const char* ctl8 = "SLIM_1_TX SampleRate";
     const char* setting8 = "KHZ_8";
@@ -1905,6 +1911,7 @@
         hw_info_append_hw_type(my_data->hw_info, snd_device, device_name);
     } else {
         strlcpy(device_name, "none", DEVICE_NAME_MAX_SIZE);
+        return -EINVAL;
     }
 
     return 0;
@@ -2316,6 +2323,26 @@
     return ret;
 }
 
+int platform_set_mic_break_det(void *platform, bool enable)
+{
+    int ret = 0;
+    struct platform_data *my_data = (struct platform_data *)platform;
+    struct audio_device *adev = my_data->adev;
+    const char *mixer_ctl_name = "Voice Mic Break Enable";
+    struct mixer_ctl *ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+    if (!ctl) {
+        ALOGE("%s: Could not get ctl for mixer cmd - %s",
+              __func__, mixer_ctl_name);
+        return -EINVAL;
+    }
+
+    ret = mixer_ctl_set_value(ctl, 0, enable);
+    if(ret)
+        ALOGE("%s: Failed to set mixer ctl: %s", __func__, mixer_ctl_name);
+
+    return ret;
+}
+
 int platform_get_sample_rate(void *platform, uint32_t *rate)
 {
     struct platform_data *my_data = (struct platform_data *)platform;
@@ -2583,6 +2610,13 @@
         new_snd_devices[0] = SND_DEVICE_OUT_SPEAKER;
         new_snd_devices[1] = SND_DEVICE_OUT_BT_A2DP;
         ret = 0;
+    } else if (SND_DEVICE_OUT_SPEAKER_SAFE_AND_BT_A2DP == snd_device &&
+               !platform_check_backends_match(SND_DEVICE_OUT_SPEAKER_SAFE,
+                                              SND_DEVICE_OUT_BT_A2DP)) {
+        *num_devices = 2;
+        new_snd_devices[0] = SND_DEVICE_OUT_SPEAKER_SAFE;
+        new_snd_devices[1] = SND_DEVICE_OUT_BT_A2DP;
+        ret = 0;
     }
 
     return ret;
@@ -2645,6 +2679,9 @@
         } else if ((devices & AUDIO_DEVICE_OUT_SPEAKER) &&
                    (devices & AUDIO_DEVICE_OUT_ALL_A2DP)) {
             snd_device = SND_DEVICE_OUT_SPEAKER_AND_BT_A2DP;
+        }  else if ((devices & AUDIO_DEVICE_OUT_SPEAKER_SAFE) &&
+                   (devices & AUDIO_DEVICE_OUT_ALL_A2DP)) {
+            snd_device = SND_DEVICE_OUT_SPEAKER_SAFE_AND_BT_A2DP;
         } else {
             ALOGE("%s: Invalid combo device(%#x)", __func__, devices);
             goto exit;
@@ -3290,6 +3327,35 @@
     return ret;
 }
 
+int platform_set_incall_recording_session_channels(void *platform,
+                                             uint32_t channel_count)
+{
+    int ret = 0;
+    struct platform_data *my_data = (struct platform_data *)platform;
+    struct audio_device *adev = my_data->adev;
+    const char *mixer_ctl_name = "Voc Rec Config";
+    int num_ctl_values;
+    int i;
+    struct mixer_ctl *ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+
+    if (!ctl) {
+        ALOGE("%s: Could not get ctl for mixer cmd - %s",
+              __func__, mixer_ctl_name);
+        ret = -EINVAL;
+    } else {
+        num_ctl_values = mixer_ctl_get_num_values(ctl);
+        for (i = 0; i < num_ctl_values; i++) {
+            if (mixer_ctl_set_value(ctl, i, channel_count)) {
+                ALOGE("Error: invalid channel count: %x", channel_count);
+                ret = -EINVAL;
+                break;
+            }
+        }
+    }
+
+    return ret;
+}
+
 int platform_stop_incall_recording_usecase(void *platform)
 {
     int ret = 0;
@@ -4705,3 +4771,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/msm8974/platform.h b/hal/msm8974/platform.h
index 32191ec..2c7eebf 100644
--- a/hal/msm8974/platform.h
+++ b/hal/msm8974/platform.h
@@ -80,6 +80,7 @@
     SND_DEVICE_OUT_BT_SCO_WB,
     SND_DEVICE_OUT_BT_A2DP,
     SND_DEVICE_OUT_SPEAKER_AND_BT_A2DP,
+    SND_DEVICE_OUT_SPEAKER_SAFE_AND_BT_A2DP,
     SND_DEVICE_OUT_VOICE_HANDSET_TMUS,
     SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES,
     SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES,
diff --git a/hal/platform_api.h b/hal/platform_api.h
index 5c7d81f..1a7d2c3 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,
@@ -72,6 +73,7 @@
                                                   snd_device_t in_snd_device);
 int platform_start_voice_call(void *platform, uint32_t vsid);
 int platform_stop_voice_call(void *platform, uint32_t vsid);
+int platform_set_mic_break_det(void *platform, bool enable);
 int platform_set_voice_volume(void *platform, int volume);
 void platform_set_speaker_gain_in_combo(struct audio_device *adev,
                                         snd_device_t snd_device,
@@ -104,6 +106,8 @@
 
 int platform_set_incall_recording_session_id(void *platform,
                                              uint32_t session_id, int rec_mode);
+int platform_set_incall_recording_session_channels(void *platform,
+                                                   uint32_t session_channels);
 int platform_stop_incall_recording_usecase(void *platform);
 int platform_start_incall_music_usecase(void *platform);
 int platform_stop_incall_music_usecase(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;
     }
 }
 
diff --git a/hal/voice.c b/hal/voice.c
index f3b69b8..f456ce1 100644
--- a/hal/voice.c
+++ b/hal/voice.c
@@ -207,6 +207,9 @@
         goto error_start_voice;
     }
 
+    if (adev->mic_break_enabled)
+        platform_set_mic_break_det(adev->platform, true);
+
     pcm_start(session->pcm_tx);
     pcm_start(session->pcm_rx);
 
@@ -309,6 +312,10 @@
         session_id = voice_get_active_session_id(adev);
         ret = platform_set_incall_recording_session_id(adev->platform,
                                                        session_id, rec_mode);
+#ifdef INCALL_STEREO_CAPTURE_ENABLED
+        ret = platform_set_incall_recording_session_channels(adev->platform,
+                                                        in->config.channels);
+#endif
         ALOGV("%s: Update usecase to %d",__func__, in->usecase);
     } else {
         ALOGV("%s: voice call not active", __func__);
diff --git a/hal/voice_extn/voice_extn.c b/hal/voice_extn/voice_extn.c
index c36a450..c4b8cff 100644
--- a/hal/voice_extn/voice_extn.c
+++ b/hal/voice_extn/voice_extn.c
@@ -162,7 +162,6 @@
     struct voice_session *session = NULL;
     int fd = 0;
     int ret = 0;
-    bool is_voice_sess_active = false;
 
     ALOGD("%s: enter:", __func__);
 
@@ -223,12 +222,6 @@
                           __func__, usecase_id);
                 } else {
                     session->state.current = session->state.new;
-
-                    // The flag is not reset if another voice session is active as routing/mode is
-                    // set globally instead of per session.
-                    voice_extn_is_call_state_active(adev, &is_voice_sess_active);
-                    if (!is_voice_sess_active)
-                        adev->voice.in_call = false;
                 }
                 break;