Merge "hal: Support config selection for playback on speaker"
diff --git a/hal/Android.mk b/hal/Android.mk
index 6d20f7e..1af245a 100644
--- a/hal/Android.mk
+++ b/hal/Android.mk
@@ -146,6 +146,19 @@
     LOCAL_SRC_FILES += audio_extn/dev_arbi.c
 endif
 
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_RECORD_PLAY_CONCURRENCY)),true)
+    LOCAL_CFLAGS += -DRECORD_PLAY_CONCURRENCY
+endif
+
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_DS2_DOLBY_DAP)),true)
+    LOCAL_CFLAGS += -DDS2_DOLBY_DAP_ENABLED
+ifneq ($(strip $(DOLBY_DDP)),true)
+    ifneq ($(strip $(DOLBY_DAP)),true)
+        LOCAL_SRC_FILES += audio_extn/dolby.c
+    endif
+endif
+endif
+
 LOCAL_SHARED_LIBRARIES := \
 	liblog \
 	libcutils \
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index dd6063f..02add40 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -259,22 +259,27 @@
 #define audio_extn_dolby_set_license(adev)              (0)
 #endif
 
-#ifndef DS1_DOLBY_DDP_ENABLED
+#ifndef DS1_DOLBY_DAP_ENABLED
 #define audio_extn_dolby_set_endpoint(adev)                 (0)
 #else
 void audio_extn_dolby_set_endpoint(struct audio_device *adev);
 #endif
 
-#ifndef DS1_DOLBY_DDP_ENABLED
-#define audio_extn_ddp_set_parameters(adev, parms)      (0)
-#define audio_extn_is_dolby_format(format)              (0)
-#define audio_extn_dolby_get_snd_codec_id(adev, out, format)       (0)
-#define audio_extn_dolby_send_ddp_endp_params(adev)     (0)
-#else
+
+#if defined(DS1_DOLBY_DDP_ENABLED) || defined(DS2_DOLBY_DAP_ENABLED)
 bool audio_extn_is_dolby_format(audio_format_t format);
 int audio_extn_dolby_get_snd_codec_id(struct audio_device *adev,
                                       struct stream_out *out,
                                       audio_format_t format);
+#else
+#define audio_extn_is_dolby_format(format)              (0)
+#define audio_extn_dolby_get_snd_codec_id(adev, out, format)       (0)
+#endif
+
+#ifndef DS1_DOLBY_DDP_ENABLED
+#define audio_extn_ddp_set_parameters(adev, parms)      (0)
+#define audio_extn_dolby_send_ddp_endp_params(adev)     (0)
+#else
 void audio_extn_ddp_set_parameters(struct audio_device *adev,
                                    struct str_parms *parms);
 void audio_extn_dolby_send_ddp_endp_params(struct audio_device *adev);
@@ -318,5 +323,39 @@
 int audio_extn_utils_send_app_type_cfg(struct audio_usecase *usecase);
 void audio_extn_utils_send_audio_calibration(struct audio_device *adev,
                                              struct audio_usecase *usecase);
+#ifdef DS2_DOLBY_DAP_ENABLED
+#define LIB_DS2_DAP_HAL "vendor/lib/libhwdaphal.so"
+#define SET_HW_INFO_FUNC "dap_hal_set_hw_info"
+typedef enum {
+    SND_CARD            = 0,
+    HW_ENDPOINT         = 1,
+    DMID                = 2,
+    DEVICE_BE_ID_MAP    = 3,
+    DAP_BYPASS          = 4,
+} dap_hal_hw_info_t;
+typedef int (*dap_hal_set_hw_info_t)(int32_t hw_info, void* data);
+typedef struct {
+     int (*device_id_to_be_id)[2];
+     int len;
+} dap_hal_device_be_id_map_t;
 
+int audio_extn_dap_hal_init(int snd_card);
+int audio_extn_dap_hal_deinit();
+void audio_extn_dolby_ds2_set_endpoint(struct audio_device *adev);
+int audio_extn_ds2_enable(struct audio_device *adev);
+int audio_extn_dolby_set_dap_bypass(struct audio_device *adev, int state);
+#else
+#define audio_extn_dap_hal_init(snd_card)                             (0)
+#define audio_extn_dap_hal_deinit()                                   (0)
+#define audio_extn_dolby_ds2_set_endpoint(adev)                       (0)
+#define audio_extn_ds2_enable(adev)                                   (0)
+#define audio_extn_dolby_set_dap_bypass(adev, state)                  (0)
+#endif
+typedef enum {
+    DAP_STATE_ON = 0,
+    DAP_STATE_BYPASS,
+};
+#ifndef AUDIO_FORMAT_E_AC3_JOC
+#define AUDIO_FORMAT_E_AC3_JOC  0x19000000UL
+#endif
 #endif /* AUDIO_EXTN_H */
diff --git a/hal/audio_extn/dolby.c b/hal/audio_extn/dolby.c
index ddd2380..8670367 100644
--- a/hal/audio_extn/dolby.c
+++ b/hal/audio_extn/dolby.c
@@ -243,7 +243,8 @@
             (usecase->devices & ddp_dev) &&
             (usecase->stream.out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) &&
             ((usecase->stream.out->format == AUDIO_FORMAT_AC3) ||
-             (usecase->stream.out->format == AUDIO_FORMAT_E_AC3))) {
+             (usecase->stream.out->format == AUDIO_FORMAT_E_AC3) ||
+             (usecase->stream.out->format == AUDIO_FORMAT_E_AC3_JOC))) {
             send_ddp_endp_params_stream(usecase->stream.out, ddp_dev,
                                         dev_ch_cap, false /* set cache */);
         }
@@ -260,7 +261,8 @@
             (usecase->devices & AUDIO_DEVICE_OUT_ALL) &&
             (usecase->stream.out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) &&
             ((usecase->stream.out->format == AUDIO_FORMAT_AC3) ||
-             (usecase->stream.out->format == AUDIO_FORMAT_E_AC3))) {
+             (usecase->stream.out->format == AUDIO_FORMAT_E_AC3) ||
+             (usecase->stream.out->format == AUDIO_FORMAT_E_AC3_JOC))) {
             /*
              * Use wfd /hdmi sink channel cap for dolby params if device is wfd
              * or hdmi. Otherwise use stereo configuration
@@ -352,7 +354,9 @@
      */
     send_ddp_endp_params(adev, ddp_dev, dev_ch_cap);
 }
+#endif /* DS1_DOLBY_DDP_ENABLED */
 
+#if defined(DS1_DOLBY_DDP_ENABLED) || defined(DS2_DOLBY_DAP_ENABLED)
 int audio_extn_dolby_get_snd_codec_id(struct audio_device *adev,
                                       struct stream_out *out,
                                       audio_format_t format)
@@ -370,19 +374,20 @@
     switch (format) {
     case AUDIO_FORMAT_AC3:
         id = SND_AUDIOCODEC_AC3;
+#ifdef DS1_DOLBY_DDP_ENABLED
         send_ddp_endp_params_stream(out, out->devices,
                             channel_cap, true /* set_cache */);
-#ifndef DS1_DOLBY_DAP_ENABLED
-        audio_extn_dolby_set_dmid(adev);
 #endif
+        audio_extn_dolby_set_dmid(adev);
         break;
     case AUDIO_FORMAT_E_AC3:
+    case AUDIO_FORMAT_E_AC3_JOC:
         id = SND_AUDIOCODEC_EAC3;
+#ifdef DS1_DOLBY_DDP_ENABLED
         send_ddp_endp_params_stream(out, out->devices,
                             channel_cap, true /* set_cache */);
-#ifndef DS1_DOLBY_DAP_ENABLED
-        audio_extn_dolby_set_dmid(adev);
 #endif
+        audio_extn_dolby_set_dmid(adev);
         break;
     default:
         ALOGE("%s: Unsupported audio format :%x", __func__, format);
@@ -394,13 +399,13 @@
 bool audio_extn_is_dolby_format(audio_format_t format)
 {
     if (format == AUDIO_FORMAT_AC3 ||
-            format == AUDIO_FORMAT_E_AC3)
+            format == AUDIO_FORMAT_E_AC3 ||
+            format == AUDIO_FORMAT_E_AC3_JOC)
         return true;
     else
         return false;
 }
-
-#endif /* DS1_DOLBY_DDP_ENABLED */
+#endif /* DS1_DOLBY_DDP_ENABLED || DS2_DOLBY_DAP_ENABLED */
 
 #ifdef DS1_DOLBY_DAP_ENABLED
 void audio_extn_dolby_set_endpoint(struct audio_device *adev)
@@ -499,3 +504,135 @@
     return;
 }
 #endif /* DS1_DOLBY_DDP_ENABLED || DS1_DOLBY_DAP_ENABLED */
+
+#ifdef DS2_DOLBY_DAP_ENABLED
+struct ds2_extn_module  {
+   void *ds2_handle;
+   dap_hal_set_hw_info_t dap_hal_set_hw_info;
+};
+
+static struct ds2_extn_module ds2extnmod = {
+    .ds2_handle = NULL,
+    .dap_hal_set_hw_info = NULL,
+};
+
+int audio_extn_dap_hal_init(int snd_card) {
+    char c_dmid[128] = {0};
+    void *handle = NULL;
+    int i_dmid, ret = -EINVAL;
+    dap_hal_device_be_id_map_t device_be_id_map;
+
+    ALOGV("%s: opening DAP HAL lib\n", __func__);
+    ds2extnmod.ds2_handle = dlopen(LIB_DS2_DAP_HAL, RTLD_NOW);
+    if (ds2extnmod.ds2_handle == NULL) {
+        ALOGE("%s: DLOPEN failed for %s error %s", __func__, LIB_DS2_DAP_HAL,
+              dlerror());
+        goto ret;
+    }
+    ds2extnmod.dap_hal_set_hw_info = (dap_hal_set_hw_info_t)dlsym(ds2extnmod.ds2_handle, SET_HW_INFO_FUNC);
+    if (ds2extnmod.dap_hal_set_hw_info == NULL) {
+           ALOGE("%s: dlsym error %s for %s", __func__, SET_HW_INFO_FUNC,
+                 dlerror());
+           goto close;
+    }
+    ds2extnmod.dap_hal_set_hw_info(SND_CARD, (void*)(&snd_card));
+    ALOGV("%s Sound card number is:%d",__func__,snd_card);
+
+    property_get("dmid",c_dmid,"0");
+    i_dmid = atoi(c_dmid);
+    ds2extnmod.dap_hal_set_hw_info(DMID, (void*)(&i_dmid));
+    ALOGV("%s Dolby device manufacturer id is:%d",__func__,i_dmid);
+
+    platform_get_device_to_be_id_map(&device_be_id_map.device_id_to_be_id, &device_be_id_map.len);
+    ds2extnmod.dap_hal_set_hw_info(DEVICE_BE_ID_MAP, (void*)(&device_be_id_map));
+    ALOGV("%s Set be id map len:%d",__func__,device_be_id_map.len);
+    ret = 0;
+    goto ret;
+
+close:
+    dlclose(ds2extnmod.ds2_handle);
+    ds2extnmod.ds2_handle = NULL;
+    ds2extnmod.dap_hal_set_hw_info = NULL;
+ret:
+    return ret;
+}
+
+int audio_extn_dap_hal_deinit() {
+    if (ds2extnmod.ds2_handle != NULL) {
+       dlclose(ds2extnmod.ds2_handle);
+       ds2extnmod.ds2_handle = NULL;
+    }
+    ds2extnmod.dap_hal_set_hw_info = NULL;
+    return 0;
+}
+
+void audio_extn_dolby_ds2_set_endpoint(struct audio_device *adev) {
+    struct listnode *node;
+    struct audio_usecase *usecase;
+    struct mixer_ctl *ctl;
+    const char *mixer_ctl_name = "DS1 DAP Endpoint";
+    int endpoint = 0, ret;
+    bool send = false;
+
+    list_for_each(node, &adev->usecase_list) {
+        usecase = node_to_item(node, struct audio_usecase, list);
+        if ((usecase->type == PCM_PLAYBACK) &&
+            (usecase->id != USECASE_AUDIO_PLAYBACK_LOW_LATENCY)) {
+            endpoint |= usecase->devices & AUDIO_DEVICE_OUT_ALL;
+            send = true;
+        }
+    }
+    if (!send)
+        return;
+
+    if (ds2extnmod.dap_hal_set_hw_info) {
+        ds2extnmod.dap_hal_set_hw_info(HW_ENDPOINT, (void*)(&endpoint));
+        ALOGE("%s: Dolby set endpint :0x%x",__func__, endpoint);
+    } else {
+        ALOGE("%s: dap_hal_set_hw_info is NULL",__func__);
+    }
+
+    return;
+}
+
+int audio_extn_ds2_enable(struct audio_device *adev) {
+
+    char value[PROPERTY_VALUE_MAX] = {0};
+    bool ds2_enabled = false;
+    const char *mixer_ctl_name = "DS2 OnOff";
+    struct mixer_ctl *ctl;
+
+    property_get("audio.dolby.ds2.enabled", value, NULL);
+    ds2_enabled = atoi(value) || !strncmp("true", value, 4);
+
+    ALOGV("%s:", __func__);
+    if(ds2_enabled) {
+        ALOGD("%s:ds2_enabled %d", __func__, ds2_enabled);
+        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;
+        }
+
+        if (mixer_ctl_set_value(ctl, 0, ds2_enabled) < 0) {
+            ALOGE("%s: Could not set ds2 enable %d",
+                            __func__, ds2_enabled);
+            return -EINVAL;
+        }
+    }
+    return 0;
+}
+
+int audio_extn_dolby_set_dap_bypass(struct audio_device *adev, int state) {
+
+    ALOGV("%s: state %d", __func__, state);
+    if (ds2extnmod.dap_hal_set_hw_info) {
+        ds2extnmod.dap_hal_set_hw_info(DAP_BYPASS, (void*)(&state));
+        ALOGV("%s: Dolby set bypas :0x%x", __func__, state);
+    } else {
+        ALOGV("%s: dap_hal_set_hw_info is NULL", __func__);
+    }
+    return 0;
+}
+#endif
diff --git a/hal/audio_extn/soundtrigger.c b/hal/audio_extn/soundtrigger.c
index c6d7077..5f4c6ba 100644
--- a/hal/audio_extn/soundtrigger.c
+++ b/hal/audio_extn/soundtrigger.c
@@ -139,12 +139,12 @@
 
     pthread_mutex_lock(&st_dev->lock);
     st_ses_info = get_sound_trigger_info(in->capture_handle);
+    pthread_mutex_unlock(&st_dev->lock);
     if (st_ses_info) {
         event.u.ses_info = st_ses_info->st_ses;
         ALOGV("%s: AUDIO_EVENT_STOP_LAB pcm %p", __func__, st_ses_info->st_ses.pcm);
         st_dev->st_callback(AUDIO_EVENT_STOP_LAB, &event);
     }
-    pthread_mutex_unlock(&st_dev->lock);
 }
 void audio_extn_sound_trigger_check_and_get_session(struct stream_in *in)
 {
@@ -252,7 +252,7 @@
 {
     audio_event_info_t event;
     char value[32];
-    int ret;
+    int ret, val;
 
     if(!st_dev || !params) {
         ALOGE("%s: str_params NULL", __func__);
@@ -287,6 +287,12 @@
         else
             ALOGE("%s: unknown CPE status", __func__);
     }
+
+    ret = str_parms_get_int(params, "SVA_NUM_SESSIONS", &val);
+    if (ret >= 0) {
+        event.u.value = val;
+        st_dev->st_callback(AUDIO_EVENT_NUM_ST_SESSIONS, &event);
+    }
 }
 
 int audio_extn_sound_trigger_init(struct audio_device *adev)
diff --git a/hal/audio_extn/spkr_protection.c b/hal/audio_extn/spkr_protection.c
index 59b46fc..a350198 100644
--- a/hal/audio_extn/spkr_protection.c
+++ b/hal/audio_extn/spkr_protection.c
@@ -753,7 +753,8 @@
         (const pthread_attr_t *) NULL, spkr_calibration_thread, &handle);
     } else {
         ALOGE("%s: thermal_client_request failed", __func__);
-        if (handle.thermal_client_handle)
+        if (handle.thermal_client_handle &&
+            handle.thermal_client_unregister_callback)
             handle.thermal_client_unregister_callback(handle.thermal_client_handle);
         if (handle.thermal_handle)
             dlclose(handle.thermal_handle);
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 05bf132..9e841df 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -60,9 +60,14 @@
 #define COMPRESS_OFFLOAD_PLAYBACK_LATENCY 96
 #define COMPRESS_PLAYBACK_VOLUME_MAX 0x2000
 
+#define PROXY_OPEN_RETRY_COUNT           100
+#define PROXY_OPEN_WAIT_TIME             20
 
 #define USECASE_AUDIO_PLAYBACK_PRIMARY USECASE_AUDIO_PLAYBACK_DEEP_BUFFER
 
+static unsigned int configured_low_latency_capture_period_size =
+        LOW_LATENCY_CAPTURE_PERIOD_SIZE;
+
 struct pcm_config pcm_config_deep_buffer = {
     .channels = 2,
     .rate = DEFAULT_OUTPUT_SAMPLING_RATE,
@@ -102,6 +107,37 @@
     .format = PCM_FORMAT_S16_LE,
 };
 
+#define AFE_PROXY_CHANNEL_COUNT 2
+#define AFE_PROXY_SAMPLING_RATE 48000
+
+#define AFE_PROXY_PLAYBACK_PERIOD_SIZE  768
+#define AFE_PROXY_PLAYBACK_PERIOD_COUNT 4
+
+struct pcm_config pcm_config_afe_proxy_playback = {
+    .channels = AFE_PROXY_CHANNEL_COUNT,
+    .rate = AFE_PROXY_SAMPLING_RATE,
+    .period_size = AFE_PROXY_PLAYBACK_PERIOD_SIZE,
+    .period_count = AFE_PROXY_PLAYBACK_PERIOD_COUNT,
+    .format = PCM_FORMAT_S16_LE,
+    .start_threshold = AFE_PROXY_PLAYBACK_PERIOD_SIZE,
+    .stop_threshold = INT_MAX,
+    .avail_min = AFE_PROXY_PLAYBACK_PERIOD_SIZE,
+};
+
+#define AFE_PROXY_RECORD_PERIOD_SIZE  768
+#define AFE_PROXY_RECORD_PERIOD_COUNT 4
+
+struct pcm_config pcm_config_afe_proxy_record = {
+    .channels = AFE_PROXY_CHANNEL_COUNT,
+    .rate = AFE_PROXY_SAMPLING_RATE,
+    .period_size = AFE_PROXY_RECORD_PERIOD_SIZE,
+    .period_count = AFE_PROXY_RECORD_PERIOD_COUNT,
+    .format = PCM_FORMAT_S16_LE,
+    .start_threshold = AFE_PROXY_RECORD_PERIOD_SIZE,
+    .stop_threshold = INT_MAX,
+    .avail_min = AFE_PROXY_RECORD_PERIOD_SIZE,
+};
+
 const char * const use_case_table[AUDIO_USECASE_MAX] = {
     [USECASE_AUDIO_PLAYBACK_DEEP_BUFFER] = "deep-buffer-playback",
     [USECASE_AUDIO_PLAYBACK_LOW_LATENCY] = "low-latency-playback",
@@ -142,6 +178,9 @@
     [USECASE_INCALL_MUSIC_UPLINK2] = "incall_music_uplink2",
     [USECASE_AUDIO_SPKR_CALIB_RX] = "spkr-rx-calib",
     [USECASE_AUDIO_SPKR_CALIB_TX] = "spkr-vi-record",
+
+    [USECASE_AUDIO_PLAYBACK_AFE_PROXY] = "afe-proxy-playback",
+    [USECASE_AUDIO_RECORD_AFE_PROXY] = "afe-proxy-record",
 };
 
 static const audio_usecase_t offload_usecases[] = {
@@ -171,6 +210,12 @@
     STRING_TO_ENUM(AUDIO_CHANNEL_OUT_7POINT1),
 };
 
+static const struct string_to_enum out_formats_name_to_enum_table[] = {
+    STRING_TO_ENUM(AUDIO_FORMAT_AC3),
+    STRING_TO_ENUM(AUDIO_FORMAT_E_AC3),
+    STRING_TO_ENUM(AUDIO_FORMAT_E_AC3_JOC),
+};
+
 static struct audio_device *adev = NULL;
 static pthread_mutex_t adev_init_lock;
 static unsigned int audio_device_ref_count;
@@ -288,6 +333,19 @@
     return 0;
 }
 
+int pcm_ioctl(struct pcm *pcm, int request, ...)
+{
+    va_list ap;
+    void * arg;
+    int pcm_fd = *(int*)pcm;
+
+    va_start(ap, request);
+    arg = va_arg(ap, void *);
+    va_end(ap);
+
+    return ioctl(pcm_fd, request, arg);
+}
+
 int enable_audio_route(struct audio_device *adev,
                        struct audio_usecase *usecase)
 {
@@ -308,6 +366,7 @@
     audio_extn_dolby_set_dmid(adev);
     audio_extn_dolby_set_endpoint(adev);
 #endif
+    audio_extn_dolby_ds2_set_endpoint(adev);
     audio_extn_sound_trigger_update_stream_status(usecase, ST_EVENT_STREAM_BUSY);
     audio_extn_listen_update_stream_status(usecase, LISTEN_EVENT_STREAM_BUSY);
     audio_extn_utils_send_audio_calibration(adev, usecase);
@@ -571,7 +630,8 @@
         usecase = node_to_item(node, struct audio_usecase, list);
         if (usecase->type != PCM_PLAYBACK &&
                 usecase != uc_info &&
-                usecase->in_snd_device != snd_device) {
+                usecase->in_snd_device != snd_device &&
+                (usecase->id != USECASE_AUDIO_SPKR_CALIB_TX)) {
             ALOGV("%s: Usecase (%s) is active on (%s) - disabling ..",
                   __func__, use_case_table[usecase->id],
                   platform_get_snd_device_name(usecase->in_snd_device));
@@ -704,7 +764,7 @@
          * usecase. This is to avoid switching devices for voice call when
          * check_usecases_codec_backend() is called below.
          */
-        if (adev->voice.in_call && adev->mode == AUDIO_MODE_IN_CALL) {
+        if (voice_is_in_call(adev) && adev->mode == AUDIO_MODE_IN_CALL) {
             vc_usecase = get_usecase_from_list(adev,
                                                get_voice_usecase_id_from_list(adev));
             if ((vc_usecase) && ((vc_usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) ||
@@ -744,14 +804,14 @@
             usecase->devices = usecase->stream.in->device;
             out_snd_device = SND_DEVICE_NONE;
             if (in_snd_device == SND_DEVICE_NONE) {
+                audio_devices_t out_device = AUDIO_DEVICE_NONE;
                 if (adev->active_input->source == AUDIO_SOURCE_VOICE_COMMUNICATION &&
                         adev->primary_output && !adev->primary_output->standby) {
-                    in_snd_device = platform_get_input_snd_device(adev->platform,
-                                        adev->primary_output->devices);
-                } else {
-                    in_snd_device = platform_get_input_snd_device(adev->platform,
-                                                                  AUDIO_DEVICE_NONE);
+                    out_device = adev->primary_output->devices;
+                } else if (usecase->id == USECASE_AUDIO_RECORD_AFE_PROXY) {
+                    out_device = AUDIO_DEVICE_OUT_TELEPHONY_TX;
                 }
+                in_snd_device = platform_get_input_snd_device(adev->platform, out_device);
             }
         }
     }
@@ -934,16 +994,33 @@
     select_devices(adev, in->usecase);
 
     ALOGV("%s: Opening PCM device card_id(%d) device_id(%d), channels %d",
-          __func__, adev->snd_card,
-          in->pcm_device_id, in->config.channels);
-    in->pcm = pcm_open(adev->snd_card,
-                       in->pcm_device_id, PCM_IN, &in->config);
-    if (in->pcm && !pcm_is_ready(in->pcm)) {
-        ALOGE("%s: %s", __func__, pcm_get_error(in->pcm));
-        pcm_close(in->pcm);
-        in->pcm = NULL;
-        ret = -EIO;
-        goto error_open;
+          __func__, adev->snd_card, in->pcm_device_id, in->config.channels);
+
+    unsigned int flags = PCM_IN;
+    unsigned int pcm_open_retry_count = 0;
+
+    if (in->usecase == USECASE_AUDIO_RECORD_AFE_PROXY) {
+        flags |= PCM_MMAP | PCM_NOIRQ;
+        pcm_open_retry_count = PROXY_OPEN_RETRY_COUNT;
+    }
+
+    while (1) {
+        in->pcm = pcm_open(adev->snd_card, in->pcm_device_id,
+                           flags, &in->config);
+        if (in->pcm == NULL || !pcm_is_ready(in->pcm)) {
+            ALOGE("%s: %s", __func__, pcm_get_error(in->pcm));
+            if (in->pcm != NULL) {
+                pcm_close(in->pcm);
+                in->pcm = NULL;
+            }
+            if (pcm_open_retry_count-- == 0) {
+                ret = -EIO;
+                goto error_open;
+            }
+            usleep(PROXY_OPEN_WAIT_TIME * 1000);
+            continue;
+        }
+        break;
     }
 
     ALOGV("%s: exit", __func__);
@@ -1345,18 +1422,34 @@
 
     select_devices(adev, out->usecase);
 
-    ALOGV("%s: Opening PCM device card_id(%d) device_id(%d)",
-          __func__, 0, out->pcm_device_id);
+    ALOGV("%s: Opening PCM device card_id(%d) device_id(%d) format(%#x)",
+          __func__, adev->snd_card, out->pcm_device_id, out->config.format);
     if (!is_offload_usecase(out->usecase)) {
-        out->pcm = pcm_open(adev->snd_card,
-                            out->pcm_device_id,
-                            PCM_OUT | PCM_MONOTONIC, &out->config);
-        if (out->pcm && !pcm_is_ready(out->pcm)) {
-            ALOGE("%s: %s", __func__, pcm_get_error(out->pcm));
-            pcm_close(out->pcm);
-            out->pcm = NULL;
-            ret = -EIO;
-            goto error_open;
+        unsigned int flags = PCM_OUT;
+        unsigned int pcm_open_retry_count = 0;
+        if (out->usecase == USECASE_AUDIO_PLAYBACK_AFE_PROXY) {
+            flags |= PCM_MMAP | PCM_NOIRQ;
+            pcm_open_retry_count = PROXY_OPEN_RETRY_COUNT;
+        } else
+            flags |= PCM_MONOTONIC;
+
+        while (1) {
+            out->pcm = pcm_open(adev->snd_card, out->pcm_device_id,
+                               flags, &out->config);
+            if (out->pcm == NULL || !pcm_is_ready(out->pcm)) {
+                ALOGE("%s: %s", __func__, pcm_get_error(out->pcm));
+                if (out->pcm != NULL) {
+                    pcm_close(out->pcm);
+                    out->pcm = NULL;
+                }
+                if (pcm_open_retry_count-- == 0) {
+                    ret = -EIO;
+                    goto error_open;
+                }
+                usleep(PROXY_OPEN_WAIT_TIME * 1000);
+                continue;
+            }
+            break;
         }
     } else {
         out->pcm = NULL;
@@ -1430,7 +1523,8 @@
 
 static size_t get_input_buffer_size(uint32_t sample_rate,
                                     audio_format_t format,
-                                    int channel_count)
+                                    int channel_count,
+                                    bool is_low_latency)
 {
     size_t size = 0;
 
@@ -1438,13 +1532,19 @@
         return 0;
 
     size = (sample_rate * AUDIO_CAPTURE_PERIOD_DURATION_MSEC) / 1000;
+    if (is_low_latency)
+        size = configured_low_latency_capture_period_size;
     /* ToDo: should use frame_size computed based on the format and
        channel_count here. */
     size *= sizeof(short) * channel_count;
 
-    /* make sure the size is multiple of 64 */
-    size += 0x3f;
-    size &= ~0x3f;
+    /* make sure the size is multiple of 32 bytes
+     * At 48 kHz mono 16-bit PCM:
+     *  5.000 ms = 240 frames = 15*16*1*2 = 480, a whole multiple of 32 (15)
+     *  3.333 ms = 160 frames = 10*16*1*2 = 320, a whole multiple of 32 (10)
+     */
+    size += 0x1f;
+    size &= ~0x1f;
 
     return size;
 }
@@ -1621,6 +1721,10 @@
     return 0;
 }
 
+static bool output_drives_call(struct audio_device *adev, struct stream_out *out)
+{
+    return out == adev->primary_output || out == adev->voice_tx_output;
+}
 
 static int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
 {
@@ -1681,23 +1785,19 @@
             if (!out->standby)
                 select_devices(adev, out->usecase);
 
-            if ((adev->mode == AUDIO_MODE_IN_CALL) &&
-                !adev->voice.in_call &&
-                (out == adev->primary_output)) {
-                ret = voice_start_call(adev);
-            } else if ((adev->mode == AUDIO_MODE_IN_CALL) &&
-                       adev->voice.in_call &&
-                       (out == adev->primary_output)) {
-                voice_update_devices_for_all_voice_usecases(adev);
+            if (output_drives_call(adev, out)) {
+                if(!voice_is_in_call(adev)) {
+                    if (adev->mode == AUDIO_MODE_IN_CALL) {
+                        adev->current_call_output = out;
+                        ret = voice_start_call(adev);
+                    }
+                } else {
+                    adev->current_call_output = out;
+                    voice_update_devices_for_all_voice_usecases(adev);
+                }
             }
         }
 
-        if ((adev->mode == AUDIO_MODE_NORMAL) &&
-                adev->voice.in_call &&
-                (out == adev->primary_output)) {
-            ret = voice_stop_call(adev);
-        }
-
         pthread_mutex_unlock(&adev->lock);
         pthread_mutex_unlock(&out->lock);
     }
@@ -1886,7 +1986,10 @@
             if (out->muted)
                 memset((void *)buffer, 0, bytes);
             ALOGVV("%s: writing buffer (%d bytes) to pcm device", __func__, bytes);
-            ret = pcm_write(out->pcm, (void *)buffer, bytes);
+            if (out->usecase == USECASE_AUDIO_PLAYBACK_AFE_PROXY)
+                ret = pcm_mmap_write(out->pcm, (void *)buffer, bytes);
+            else
+                ret = pcm_write(out->pcm, (void *)buffer, bytes);
             if (ret < 0)
                 ret = -errno;
             else if (ret == 0)
@@ -2234,7 +2337,7 @@
     err = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING, value, sizeof(value));
     if (err >= 0) {
         val = atoi(value);
-        if ((in->device != val) && (val != 0)) {
+        if (((int)in->device != val) && (val != 0)) {
             in->device = val;
             /* If recording is in progress, change the tx device to new device */
             if (!in->standby && !in->is_st_session)
@@ -2323,6 +2426,8 @@
             ret = audio_extn_ssr_read(stream, buffer, bytes);
         else if (audio_extn_compr_cap_usecase_supported(in->usecase))
             ret = audio_extn_compr_cap_read(in, buffer, bytes);
+        else if (in->usecase == USECASE_AUDIO_RECORD_AFE_PROXY)
+            ret = pcm_mmap_read(in->pcm, buffer, bytes);
         else
             ret = pcm_read(in->pcm, buffer, bytes);
         if (ret < 0)
@@ -2567,11 +2672,6 @@
             out->compr_config.codec->format = SNDRV_PCM_FORMAT_S24_LE;
         }
 
-        if (out->bit_width == 24 && !platform_check_24_bit_support()) {
-            ALOGW("24 bit support is not enabled, using 16 bit backend");
-            out->compr_config.codec->format = SNDRV_PCM_FORMAT_S16_LE;
-        }
-
         if (config->offload_info.format == AUDIO_FORMAT_FLAC)
             out->compr_config.codec->options.flac_dec.sample_size = PCM_OUTPUT_BIT_WIDTH;
 
@@ -2596,6 +2696,28 @@
                   __func__, ret);
             goto error_open;
         }
+    } else  if (out->devices == AUDIO_DEVICE_OUT_TELEPHONY_TX) {
+        if (config->sample_rate == 0)
+            config->sample_rate = AFE_PROXY_SAMPLING_RATE;
+        if (config->sample_rate != 48000 && config->sample_rate != 16000 &&
+                config->sample_rate != 8000) {
+            config->sample_rate = AFE_PROXY_SAMPLING_RATE;
+            ret = -EINVAL;
+            goto error_open;
+        }
+        out->sample_rate = config->sample_rate;
+        out->config.rate = config->sample_rate;
+        if (config->format == AUDIO_FORMAT_DEFAULT)
+            config->format = AUDIO_FORMAT_PCM_16_BIT;
+        if (config->format != AUDIO_FORMAT_PCM_16_BIT) {
+            config->format = AUDIO_FORMAT_PCM_16_BIT;
+            ret = -EINVAL;
+            goto error_open;
+        }
+        out->format = config->format;
+        out->usecase = USECASE_AUDIO_PLAYBACK_AFE_PROXY;
+        out->config = pcm_config_afe_proxy_playback;
+        adev->voice_tx_output = out;
     } else if (out->flags & AUDIO_OUTPUT_FLAG_FAST) {
         format = AUDIO_FORMAT_PCM_16_BIT;
         out->usecase = USECASE_AUDIO_PLAYBACK_LOW_LATENCY;
@@ -2706,6 +2828,10 @@
         if (out->compr_config.codec != NULL)
             free(out->compr_config.codec);
     }
+
+    if (adev->voice_tx_output == out)
+        adev->voice_tx_output = NULL;
+
     pthread_cond_destroy(&out->cond);
     pthread_mutex_destroy(&out->lock);
     free(stream);
@@ -2919,10 +3045,16 @@
 static int adev_set_mode(struct audio_hw_device *dev, audio_mode_t mode)
 {
     struct audio_device *adev = (struct audio_device *)dev;
+
     pthread_mutex_lock(&adev->lock);
     if (adev->mode != mode) {
-        ALOGD("%s mode %d\n", __func__, mode);
+        ALOGD("%s: mode %d\n", __func__, mode);
         adev->mode = mode;
+        if ((mode == AUDIO_MODE_NORMAL || mode == AUDIO_MODE_IN_COMMUNICATION) &&
+                voice_is_in_call(adev)) {
+            voice_stop_call(adev);
+            adev->current_call_output = NULL;
+        }
     }
     pthread_mutex_unlock(&adev->lock);
     return 0;
@@ -2951,7 +3083,8 @@
 {
     int channel_count = audio_channel_count_from_in_mask(config->channel_mask);
 
-    return get_input_buffer_size(config->sample_rate, config->format, channel_count);
+    return get_input_buffer_size(config->sample_rate, config->format, channel_count,
+            false /* is_low_latency: since we don't know, be conservative */);
 }
 
 static int adev_open_input_stream(struct audio_hw_device *dev,
@@ -2967,7 +3100,7 @@
     struct stream_in *in;
     int ret = 0, buffer_size, frame_size;
     int channel_count = audio_channel_count_from_in_mask(config->channel_mask);
-
+    bool is_low_latency = false;
 
     *stream_in = NULL;
     if (check_input_parameters(config->sample_rate, config->format, channel_count) != 0)
@@ -3011,11 +3144,39 @@
 
     /* Update config params with the requested sample rate and channels */
     in->usecase = USECASE_AUDIO_RECORD;
+    if (config->sample_rate == LOW_LATENCY_CAPTURE_SAMPLE_RATE &&
+            (flags & AUDIO_INPUT_FLAG_FAST) != 0) {
+        is_low_latency = true;
+#if LOW_LATENCY_CAPTURE_USE_CASE
+        in->usecase = USECASE_AUDIO_RECORD_LOW_LATENCY;
+#endif
+    }
     in->config = pcm_config_audio_capture;
     in->config.rate = config->sample_rate;
     in->format = config->format;
 
-    if (channel_count == 6) {
+    if (in->device == AUDIO_DEVICE_IN_TELEPHONY_RX) {
+        if (config->sample_rate == 0)
+            config->sample_rate = AFE_PROXY_SAMPLING_RATE;
+        if (config->sample_rate != 48000 && config->sample_rate != 16000 &&
+                config->sample_rate != 8000) {
+            config->sample_rate = AFE_PROXY_SAMPLING_RATE;
+            ret = -EINVAL;
+            goto err_open;
+        }
+        if (config->format == AUDIO_FORMAT_DEFAULT)
+            config->format = AUDIO_FORMAT_PCM_16_BIT;
+        if (config->format != AUDIO_FORMAT_PCM_16_BIT) {
+            config->format = AUDIO_FORMAT_PCM_16_BIT;
+            ret = -EINVAL;
+            goto err_open;
+        }
+
+        in->usecase = USECASE_AUDIO_RECORD_AFE_PROXY;
+        in->config = pcm_config_afe_proxy_record;
+        in->config.channels = channel_count;
+        in->config.rate = config->sample_rate;
+    } else if (channel_count == 6) {
         if(audio_extn_ssr_get_enabled()) {
             if(audio_extn_ssr_init(in)) {
                 ALOGE("%s: audio_extn_ssr_init failed", __func__);
@@ -3034,7 +3195,8 @@
         frame_size = audio_stream_in_frame_size(&in->stream);
         buffer_size = get_input_buffer_size(config->sample_rate,
                                             config->format,
-                                            channel_count);
+                                            channel_count,
+                                            is_low_latency);
         in->config.period_size = buffer_size / frame_size;
     }
 
@@ -3116,6 +3278,23 @@
     return 0;
 }
 
+/* This returns 1 if the input parameter looks at all plausible as a low latency period size,
+ * or 0 otherwise.  A return value of 1 doesn't mean the value is guaranteed to work,
+ * just that it _might_ work.
+ */
+static int period_size_is_plausible_for_low_latency(int period_size)
+{
+    switch (period_size) {
+    case 160:
+    case 240:
+    case 320:
+    case 480:
+        return 1;
+    default:
+        return 0;
+    }
+}
+
 static int adev_open(const hw_module_t *module, const char *name,
                      hw_device_t **device)
 {
@@ -3233,31 +3412,38 @@
 
     adev->bt_wb_speech_enabled = false;
 
+    audio_extn_ds2_enable(adev);
     *device = &adev->device.common;
 
     audio_extn_utils_update_streams_output_cfg_list(adev->platform, adev->mixer,
                                                     &adev->streams_output_cfg_list);
 
     audio_device_ref_count++;
+
+    char value[PROPERTY_VALUE_MAX];
+    int trial;
+    if (property_get("audio_hal.period_size", value, NULL) > 0) {
+        trial = atoi(value);
+        if (period_size_is_plausible_for_low_latency(trial)) {
+            pcm_config_low_latency.period_size = trial;
+            pcm_config_low_latency.start_threshold = trial / 4;
+            pcm_config_low_latency.avail_min = trial / 4;
+            configured_low_latency_capture_period_size = trial;
+        }
+    }
+    if (property_get("audio_hal.in_period_size", value, NULL) > 0) {
+        trial = atoi(value);
+        if (period_size_is_plausible_for_low_latency(trial)) {
+            configured_low_latency_capture_period_size = trial;
+        }
+    }
+
     pthread_mutex_unlock(&adev_init_lock);
 
     ALOGV("%s: exit", __func__);
     return 0;
 }
 
-int pcm_ioctl(struct pcm *pcm, int request, ...)
-{
-    va_list ap;
-    void * arg;
-    int pcm_fd = *(int*)pcm;
-
-    va_start(ap, request);
-    arg = va_arg(ap, void *);
-    va_end(ap);
-
-    return ioctl(pcm_fd, request, arg);
-}
-
 static struct hw_module_methods_t hal_module_methods = {
     .open = adev_open,
 };
diff --git a/hal/audio_hw.h b/hal/audio_hw.h
index bdb9aae..d05f743 100644
--- a/hal/audio_hw.h
+++ b/hal/audio_hw.h
@@ -32,9 +32,6 @@
 #define VISUALIZER_LIBRARY_PATH "/system/lib/soundfx/libqcomvisualizer.so"
 #define OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH "/system/lib/soundfx/libqcompostprocbundle.so"
 
-#define BT_SCO_SAMPLE_RATE "bt-sco-samplerate"
-#define BT_SCO_WB_SAMPLE_RATE "bt-sco-wb-samplerate"
-
 /* Flags used to initialize acdb_settings variable that goes to ACDB library */
 #define NONE_FLAG            0x00000000
 #define ANC_FLAG	     0x00000001
@@ -114,6 +111,10 @@
 
     USECASE_AUDIO_SPKR_CALIB_RX,
     USECASE_AUDIO_SPKR_CALIB_TX,
+
+    USECASE_AUDIO_PLAYBACK_AFE_PROXY,
+    USECASE_AUDIO_RECORD_AFE_PROXY,
+
     AUDIO_USECASE_MAX
 };
 
@@ -203,7 +204,7 @@
     int standby;
     int source;
     int pcm_device_id;
-    int device;
+    audio_devices_t device;
     audio_channel_mask_t channel_mask;
     audio_usecase_t usecase;
     bool enable_aec;
@@ -269,6 +270,8 @@
     audio_devices_t out_device;
     struct stream_in *active_input;
     struct stream_out *primary_output;
+    struct stream_out *voice_tx_output;
+    struct stream_out *current_call_output;
     bool bluetooth_nrec;
     bool screen_off;
     int *snd_dev_ref_cnt;
diff --git a/hal/msm8916/platform.c b/hal/msm8916/platform.c
index b4476f5..cf64878 100644
--- a/hal/msm8916/platform.c
+++ b/hal/msm8916/platform.c
@@ -23,6 +23,7 @@
 
 #include <stdlib.h>
 #include <dlfcn.h>
+#include <fcntl.h>
 #include <sys/ioctl.h>
 #include <cutils/log.h>
 #include <cutils/properties.h>
@@ -32,6 +33,8 @@
 #include "platform.h"
 #include "audio_extn.h"
 #include "voice_extn.h"
+#include "sound/msmcal-hwdep.h"
+#define SOUND_TRIGGER_DEVICE_HANDSET_MONO_LOW_POWER_ACDB_ID (100)
 
 #define MIXER_XML_PATH "/system/etc/mixer_paths.xml"
 #define MIXER_XML_PATH_MTP "/system/etc/mixer_paths_mtp.xml"
@@ -93,6 +96,15 @@
 #define AUDIO_PARAMETER_KEY_SLOWTALK      "st_enable"
 #define AUDIO_PARAMETER_KEY_HD_VOICE      "hd_voice"
 #define AUDIO_PARAMETER_KEY_VOLUME_BOOST  "volume_boost"
+#define MAX_CAL_NAME 20
+
+char cal_name_info[WCD9XXX_MAX_CAL][MAX_CAL_NAME] = {
+        [WCD9XXX_ANC_CAL] = "anc_cal",
+        [WCD9XXX_MBHC_CAL] = "mbhc_cal",
+        [WCD9XXX_MAD_CAL] = "mad_cal",
+};
+
+#define AUDIO_PARAMETER_KEY_REC_PLAY_CONC "rec_play_conc_on"
 
 enum {
 	VOICE_FEATURE_SET_DEFAULT,
@@ -112,6 +124,8 @@
 typedef void (*acdb_send_voice_cal_t)(int, int);
 typedef int (*acdb_reload_vocvoltable_t)(int);
 typedef int  (*acdb_get_default_app_type_t)(void);
+typedef int (*acdb_loader_get_calibration_t)(char *attr, int size, void *data);
+acdb_loader_get_calibration_t acdb_loader_get_calibration;
 
 struct platform_data {
     struct audio_device *adev;
@@ -134,7 +148,9 @@
     acdb_send_voice_cal_t      acdb_send_voice_cal;
     acdb_reload_vocvoltable_t  acdb_reload_vocvoltable;
     acdb_get_default_app_type_t acdb_get_default_app_type;
-
+#ifdef RECORD_PLAY_CONCURRENCY
+    bool rec_play_conc_set;
+#endif
     void *hw_info;
     struct csd_data *csd;
 };
@@ -213,6 +229,11 @@
     [SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET] = "speaker-and-anc-headphones",
     [SND_DEVICE_OUT_ANC_HANDSET] = "anc-handset",
     [SND_DEVICE_OUT_SPEAKER_PROTECTED] = "speaker-protected",
+#ifdef RECORD_PLAY_CONCURRENCY
+    [SND_DEVICE_OUT_VOIP_HANDSET] = "voip-handset",
+    [SND_DEVICE_OUT_VOIP_SPEAKER] = "voip-speaker",
+    [SND_DEVICE_OUT_VOIP_HEADPHONES] = "voip-headphones",
+#endif
 
     /* Capture sound devices */
     [SND_DEVICE_IN_HANDSET_MIC] = "handset-mic",
@@ -294,6 +315,11 @@
     [SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET] = 26,
     [SND_DEVICE_OUT_ANC_HANDSET] = 103,
     [SND_DEVICE_OUT_SPEAKER_PROTECTED] = 101,
+#ifdef RECORD_PLAY_CONCURRENCY
+    [SND_DEVICE_OUT_VOIP_HANDSET] = 133,
+    [SND_DEVICE_OUT_VOIP_SPEAKER] = 132,
+    [SND_DEVICE_OUT_VOIP_HEADPHONES] = 134,
+#endif
 
     [SND_DEVICE_IN_HANDSET_MIC] = 4,
     [SND_DEVICE_IN_HANDSET_MIC_AEC] = 106,
@@ -380,6 +406,11 @@
     {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_ANC_HANDSET)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_PROTECTED)},
+#ifdef RECORD_PLAY_CONCURRENCY
+    {TO_NAME_INDEX(SND_DEVICE_OUT_VOIP_HANDSET)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_VOIP_SPEAKER)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_VOIP_HEADPHONES)},
+#endif
     {TO_NAME_INDEX(SND_DEVICE_IN_HANDSET_MIC)},
     {TO_NAME_INDEX(SND_DEVICE_IN_HANDSET_MIC_AEC)},
     {TO_NAME_INDEX(SND_DEVICE_IN_HANDSET_MIC_NS)},
@@ -425,6 +456,64 @@
     {TO_NAME_INDEX(SND_DEVICE_IN_CAPTURE_VI_FEEDBACK)},
 };
 
+#define NO_COLS 2
+static int msm_be_id_array_len;
+static int (*msm_device_to_be_id)[];
+
+/* Below table lists output device to BE_ID mapping*/
+/* Update the table based on the board configuration*/
+
+static int msm_device_to_be_id_internal_codec [][NO_COLS] = {
+       {AUDIO_DEVICE_OUT_EARPIECE                       ,       34},
+       {AUDIO_DEVICE_OUT_SPEAKER                        ,       34},
+       {AUDIO_DEVICE_OUT_WIRED_HEADSET                  ,       34},
+       {AUDIO_DEVICE_OUT_WIRED_HEADPHONE                ,       34},
+       {AUDIO_DEVICE_OUT_BLUETOOTH_SCO                  ,       11},
+       {AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET          ,       11},
+       {AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT           ,       11},
+       {AUDIO_DEVICE_OUT_BLUETOOTH_A2DP                 ,       -1},
+       {AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES      ,       -1},
+       {AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER         ,       -1},
+       {AUDIO_DEVICE_OUT_AUX_DIGITAL                    ,       4},
+       {AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET              ,       9},
+       {AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET              ,       9},
+       {AUDIO_DEVICE_OUT_USB_ACCESSORY                  ,       -1},
+       {AUDIO_DEVICE_OUT_USB_DEVICE                     ,       -1},
+       {AUDIO_DEVICE_OUT_REMOTE_SUBMIX                  ,       9},
+       {AUDIO_DEVICE_OUT_PROXY                          ,       9},
+       {AUDIO_DEVICE_OUT_FM                             ,       7},
+       {AUDIO_DEVICE_OUT_FM_TX                          ,       8},
+       {AUDIO_DEVICE_OUT_ALL                            ,      -1},
+       {AUDIO_DEVICE_NONE                               ,      -1},
+       {AUDIO_DEVICE_OUT_DEFAULT                        ,      -1},
+};
+
+static int msm_device_to_be_id_external_codec [][NO_COLS] = {
+       {AUDIO_DEVICE_OUT_EARPIECE                       ,       2},
+       {AUDIO_DEVICE_OUT_SPEAKER                        ,       2},
+       {AUDIO_DEVICE_OUT_WIRED_HEADSET                  ,       2},
+       {AUDIO_DEVICE_OUT_WIRED_HEADPHONE                ,       2},
+       {AUDIO_DEVICE_OUT_BLUETOOTH_SCO                  ,       11},
+       {AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET          ,       11},
+       {AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT           ,       11},
+       {AUDIO_DEVICE_OUT_BLUETOOTH_A2DP                 ,       -1},
+       {AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES      ,       -1},
+       {AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER         ,       -1},
+       {AUDIO_DEVICE_OUT_AUX_DIGITAL                    ,       4},
+       {AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET              ,       9},
+       {AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET              ,       9},
+       {AUDIO_DEVICE_OUT_USB_ACCESSORY                  ,       -1},
+       {AUDIO_DEVICE_OUT_USB_DEVICE                     ,       -1},
+       {AUDIO_DEVICE_OUT_REMOTE_SUBMIX                  ,       9},
+       {AUDIO_DEVICE_OUT_PROXY                          ,       9},
+       {AUDIO_DEVICE_OUT_FM                             ,       7},
+       {AUDIO_DEVICE_OUT_FM_TX                          ,       8},
+       {AUDIO_DEVICE_OUT_ALL                            ,      -1},
+       {AUDIO_DEVICE_NONE                               ,      -1},
+       {AUDIO_DEVICE_OUT_DEFAULT                        ,      -1},
+};
+
+
 #define DEEP_BUFFER_PLATFORM_DELAY (29*1000LL)
 #define LOW_LATENCY_PLATFORM_DELAY (13*1000LL)
 
@@ -435,41 +524,89 @@
                  sizeof("msm8x16-snd-card-mtp"))) {
         strlcpy(mixer_xml_path, MIXER_XML_PATH_MTP,
                 sizeof(MIXER_XML_PATH_MTP));
+
+        msm_device_to_be_id = msm_device_to_be_id_internal_codec;
+        msm_be_id_array_len  =
+            sizeof(msm_device_to_be_id_internal_codec) / sizeof(msm_device_to_be_id_internal_codec[0]);
+
     } else if (!strncmp(snd_card_name, "msm8x16-skuh-snd-card",
                  sizeof("msm8x16-skuh-snd-card"))) {
         strlcpy(mixer_xml_path, MIXER_XML_PATH_QRD_SKUH,
                 sizeof(MIXER_XML_PATH_QRD_SKUH));
+
+        msm_device_to_be_id = msm_device_to_be_id_internal_codec;
+        msm_be_id_array_len  =
+            sizeof(msm_device_to_be_id_internal_codec) / sizeof(msm_device_to_be_id_internal_codec[0]);
+
     } else if (!strncmp(snd_card_name, "msm8x16-skui-snd-card",
                  sizeof("msm8x16-skui-snd-card"))) {
         strlcpy(mixer_xml_path, MIXER_XML_PATH_QRD_SKUI,
                 sizeof(MIXER_XML_PATH_QRD_SKUI));
+
+        msm_device_to_be_id = msm_device_to_be_id_internal_codec;
+        msm_be_id_array_len  =
+            sizeof(msm_device_to_be_id_internal_codec) / sizeof(msm_device_to_be_id_internal_codec[0]);
+
     } else if (!strncmp(snd_card_name, "msm8x16-skuhf-snd-card",
                  sizeof("msm8x16-skuhf-snd-card"))) {
         strlcpy(mixer_xml_path, MIXER_XML_PATH_QRD_SKUHF,
                 sizeof(MIXER_XML_PATH_QRD_SKUHF));
+
+        msm_device_to_be_id = msm_device_to_be_id_internal_codec;
+        msm_be_id_array_len  =
+            sizeof(msm_device_to_be_id_internal_codec) / sizeof(msm_device_to_be_id_internal_codec[0]);
+
     } else if (!strncmp(snd_card_name, "msm8939-snd-card-mtp",
                  sizeof("msm8939-snd-card-mtp"))) {
         strlcpy(mixer_xml_path, MIXER_XML_PATH_MTP,
                 sizeof(MIXER_XML_PATH_MTP));
+
+        msm_device_to_be_id = msm_device_to_be_id_internal_codec;
+        msm_be_id_array_len  =
+            sizeof(msm_device_to_be_id_internal_codec) / sizeof(msm_device_to_be_id_internal_codec[0]);
+
     } else if (!strncmp(snd_card_name, "msm8939-snd-card-skuk",
                  sizeof("msm8939-snd-card-skuk"))) {
         strlcpy(mixer_xml_path, MIXER_XML_PATH_SKUK,
                 sizeof(MIXER_XML_PATH_SKUK));
+        msm_device_to_be_id = msm_device_to_be_id_internal_codec;
+        msm_be_id_array_len  =
+            sizeof(msm_device_to_be_id_internal_codec) / sizeof(msm_device_to_be_id_internal_codec[0]);
+
     } else if (!strncmp(snd_card_name, "msm8939-tapan-snd-card",
                  sizeof("msm8939-tapan-snd-card"))) {
         strlcpy(mixer_xml_path, MIXER_XML_PATH_WCD9306,
                 sizeof(MIXER_XML_PATH_WCD9306));
+        msm_device_to_be_id = msm_device_to_be_id_external_codec;
+        msm_be_id_array_len  =
+            sizeof(msm_device_to_be_id_external_codec) / sizeof(msm_device_to_be_id_external_codec[0]);
+
     } else if (!strncmp(snd_card_name, "msm8939-tapan9302-snd-card",
                  sizeof("msm8939-tapan9302-snd-card"))) {
         strlcpy(mixer_xml_path, MIXER_XML_PATH_WCD9306,
                 sizeof(MIXER_XML_PATH_WCD9306));
+
+        msm_device_to_be_id = msm_device_to_be_id_external_codec;
+        msm_be_id_array_len  =
+            sizeof(msm_device_to_be_id_external_codec) / sizeof(msm_device_to_be_id_external_codec[0]);
+
     } else if (!strncmp(snd_card_name, "msm8939-tomtom9330-snd-card",
                  sizeof("msm8939-tomtom9330-snd-card"))) {
         strlcpy(mixer_xml_path, MIXER_XML_PATH_WCD9330,
                 sizeof(MIXER_XML_PATH_WCD9330));
+
+        msm_device_to_be_id = msm_device_to_be_id_external_codec;
+        msm_be_id_array_len  =
+            sizeof(msm_device_to_be_id_external_codec) / sizeof(msm_device_to_be_id_external_codec[0]);
+
     } else {
         strlcpy(mixer_xml_path, MIXER_XML_PATH,
                 sizeof(MIXER_XML_PATH));
+
+        msm_device_to_be_id = msm_device_to_be_id_internal_codec;
+        msm_be_id_array_len  =
+            sizeof(msm_device_to_be_id_internal_codec) / sizeof(msm_device_to_be_id_internal_codec[0]);
+
     }
 }
 
@@ -658,6 +795,92 @@
     return;
 }
 
+static int hw_util_open(int card_no)
+{
+    int fd = -1;
+    char dev_name[256];
+
+    snprintf(dev_name, sizeof(dev_name), "/dev/snd/hwC%uD%u",
+                               card_no, WCD9XXX_CODEC_HWDEP_NODE);
+    ALOGD("%s Opening device %s\n", __func__, dev_name);
+    fd = open(dev_name, O_WRONLY);
+    if (fd < 0) {
+        ALOGE("%s: cannot open device '%s'\n", __func__, dev_name);
+        return fd;
+    }
+    ALOGD("%s success", __func__);
+    return fd;
+}
+
+struct param_data {
+    int    use_case;
+    int    acdb_id;
+    int    get_size;
+    int    buff_size;
+    int    data_size;
+    void   *buff;
+};
+
+static int send_codec_cal(acdb_loader_get_calibration_t acdb_loader_get_calibration, int fd)
+{
+    int ret = 0, type;
+
+    for (type = WCD9XXX_ANC_CAL; type < WCD9XXX_MAX_CAL; type++) {
+        struct wcdcal_ioctl_buffer codec_buffer;
+        struct param_data calib;
+
+        if (!strcmp(cal_name_info[type], "mad_cal"))
+            calib.acdb_id = SOUND_TRIGGER_DEVICE_HANDSET_MONO_LOW_POWER_ACDB_ID;
+        calib.get_size = 1;
+        ret = acdb_loader_get_calibration(cal_name_info[type], sizeof(struct param_data),
+                                                                 &calib);
+        if (ret < 0) {
+            ALOGE("%s get_calibration failed\n", __func__);
+            return ret;
+        }
+        calib.get_size = 0;
+        calib.buff = malloc(calib.buff_size);
+        ret = acdb_loader_get_calibration(cal_name_info[type],
+                              sizeof(struct param_data), &calib);
+        if (ret < 0) {
+            ALOGE("%s get_calibration failed\n", __func__);
+            free(calib.buff);
+            return ret;
+        }
+        codec_buffer.buffer = calib.buff;
+        codec_buffer.size = calib.data_size;
+        codec_buffer.cal_type = type;
+        if (ioctl(fd, SNDRV_CTL_IOCTL_HWDEP_CAL_TYPE, &codec_buffer) < 0)
+            ALOGE("Failed to call ioctl  for %s err=%d",
+                                  cal_name_info[type], errno);
+        ALOGD("%s cal sent for %s", __func__, cal_name_info[type]);
+        free(calib.buff);
+    }
+    return ret;
+}
+
+static void audio_hwdep_send_cal(struct platform_data *plat_data)
+{
+    int fd;
+
+    fd = hw_util_open(plat_data->adev->snd_card);
+    if (fd == -1) {
+        ALOGE("%s error open\n", __func__);
+        return;
+    }
+
+    acdb_loader_get_calibration = (acdb_loader_get_calibration_t)
+          dlsym(plat_data->acdb_handle, "acdb_loader_get_calibration");
+
+    if (acdb_loader_get_calibration == NULL) {
+        ALOGE("%s: ERROR. dlsym Error:%s acdb_loader_get_calibration", __func__,
+           dlerror());
+        return;
+    }
+    if (send_codec_cal(acdb_loader_get_calibration, fd) < 0)
+        ALOGE("%s: Could not send anc cal", __FUNCTION__);
+}
+
 void *platform_init(struct audio_device *adev)
 {
     char platform[PROPERTY_VALUE_MAX];
@@ -666,7 +889,7 @@
     struct platform_data *my_data = NULL;
     int retry_num = 0, snd_card_num = 0;
     const char *snd_card_name;
-    char mixer_xml_path[100];
+    char mixer_xml_path[100],ffspEnable[PROPERTY_VALUE_MAX];
     char *cvd_version = NULL;
 
     my_data = calloc(1, sizeof(struct platform_data));
@@ -768,7 +991,13 @@
             my_data->fluence_mode = FLUENCE_BROADSIDE;
         }
     }
-
+    property_get("persist.audio.FFSP.enable", ffspEnable, "");
+    if (!strncmp("true", ffspEnable, sizeof("true"))) {
+        acdb_device_table[SND_DEVICE_OUT_SPEAKER] = 131;
+        acdb_device_table[SND_DEVICE_OUT_SPEAKER_REVERSE] = 131;
+        acdb_device_table[SND_DEVICE_OUT_SPEAKER_AND_HDMI] = 131;
+        acdb_device_table[SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET] = 131;
+    }
     my_data->voice_feature_set = VOICE_FEATURE_SET_DEFAULT;
     my_data->acdb_handle = dlopen(LIB_ACDB_LOADER, RTLD_NOW);
     if (my_data->acdb_handle == NULL) {
@@ -838,6 +1067,7 @@
     audio_extn_spkr_prot_init(adev);
 
     audio_extn_dolby_set_license(adev);
+    audio_hwdep_send_cal(my_data);
 
     return my_data;
 }
@@ -1079,7 +1309,7 @@
     int ret = 0;
 
     if (my_data->csd != NULL &&
-        my_data->adev->mode == AUDIO_MODE_IN_CALL) {
+        voice_is_in_call(my_data->adev)) {
         /* This must be called before disabling mixer controls on APQ side */
         ret = my_data->csd->disable_device();
         if (ret < 0) {
@@ -1308,6 +1538,18 @@
     struct audio_device *adev = my_data->adev;
     audio_mode_t mode = adev->mode;
     snd_device_t snd_device = SND_DEVICE_NONE;
+#ifdef RECORD_PLAY_CONCURRENCY
+    bool use_voip_out_devices = false;
+    bool prop_rec_play_enabled = false;
+    char recConcPropValue[PROPERTY_VALUE_MAX];
+
+    if (property_get("rec.playback.conc.disabled", recConcPropValue, NULL)) {
+        prop_rec_play_enabled = atoi(recConcPropValue) || !strncmp("true", recConcPropValue, 4);
+    }
+    use_voip_out_devices =  prop_rec_play_enabled &&
+                        (my_data->rec_play_conc_set || adev->mode == AUDIO_MODE_IN_COMMUNICATION);
+    ALOGV("platform_get_output_snd_device use_voip_out_devices : %d",use_voip_out_devices);
+#endif
 
     audio_channel_mask_t channel_mask = (adev->active_input == NULL) ?
                                 AUDIO_CHANNEL_IN_MONO : adev->active_input->channel_mask;
@@ -1350,8 +1592,7 @@
         goto exit;
     }
 
-    if ((mode == AUDIO_MODE_IN_CALL) ||
-        voice_extn_compress_voip_is_active(adev)) {
+    if (voice_is_in_call(adev) || voice_extn_compress_voip_is_active(adev)) {
         if (devices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
             devices & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
             if ((adev->voice.tty_mode != TTY_MODE_OFF) &&
@@ -1405,18 +1646,38 @@
         devices & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
         if (devices & AUDIO_DEVICE_OUT_WIRED_HEADSET
             && audio_extn_get_anc_enabled()) {
-            if (audio_extn_should_use_fb_anc())
-                snd_device = SND_DEVICE_OUT_ANC_FB_HEADSET;
+#ifdef RECORD_PLAY_CONCURRENCY
+            if (use_voip_out_devices) {
+                // ANC should be disabled for voip concurrency
+                snd_device = SND_DEVICE_OUT_VOIP_HEADPHONES;
+            } else
+#endif
+            {
+                if (audio_extn_should_use_fb_anc())
+                    snd_device = SND_DEVICE_OUT_ANC_FB_HEADSET;
+                else
+                    snd_device = SND_DEVICE_OUT_ANC_HEADSET;
+            }
+        } else {
+#ifdef RECORD_PLAY_CONCURRENCY
+            if (use_voip_out_devices)
+                snd_device = SND_DEVICE_OUT_VOIP_HEADPHONES;
             else
-                snd_device = SND_DEVICE_OUT_ANC_HEADSET;
+#endif
+                snd_device = SND_DEVICE_OUT_HEADPHONES;
         }
-        else
-            snd_device = SND_DEVICE_OUT_HEADPHONES;
     } else if (devices & AUDIO_DEVICE_OUT_SPEAKER) {
-        if (adev->speaker_lr_swap)
-            snd_device = SND_DEVICE_OUT_SPEAKER_REVERSE;
-        else
-            snd_device = SND_DEVICE_OUT_SPEAKER;
+#ifdef RECORD_PLAY_CONCURRENCY
+        if (use_voip_out_devices) {
+            snd_device = SND_DEVICE_OUT_VOIP_SPEAKER;
+        } else
+#endif
+        {
+            if (adev->speaker_lr_swap)
+                snd_device = SND_DEVICE_OUT_SPEAKER_REVERSE;
+            else
+                snd_device = SND_DEVICE_OUT_SPEAKER;
+        }
     } else if (devices & AUDIO_DEVICE_OUT_ALL_SCO) {
         if (adev->bt_wb_speech_enabled)
             snd_device = SND_DEVICE_OUT_BT_SCO_WB;
@@ -1432,7 +1693,12 @@
     } else if (devices & AUDIO_DEVICE_OUT_FM_TX) {
         snd_device = SND_DEVICE_OUT_TRANSMISSION_FM;
     } else if (devices & AUDIO_DEVICE_OUT_EARPIECE) {
-        snd_device = SND_DEVICE_OUT_HANDSET;
+#ifdef RECORD_PLAY_CONCURRENCY
+        if (use_voip_out_devices)
+            snd_device = SND_DEVICE_OUT_VOIP_HANDSET;
+        else
+#endif
+            snd_device = SND_DEVICE_OUT_HANDSET;
     } else if (devices & AUDIO_DEVICE_OUT_PROXY) {
         channel_count = audio_extn_get_afe_proxy_channel_count();
         ALOGD("%s: setting sink capability(%d) for Proxy", __func__, channel_count);
@@ -1464,7 +1730,7 @@
 
     ALOGV("%s: enter: out_device(%#x) in_device(%#x)",
           __func__, out_device, in_device);
-    if ((out_device != AUDIO_DEVICE_NONE) && ((mode == AUDIO_MODE_IN_CALL) ||
+    if ((out_device != AUDIO_DEVICE_NONE) && (voice_is_in_call(adev) ||
         voice_extn_compress_voip_is_active(adev) || audio_extn_hfp_is_active(adev))) {
         if ((adev->voice.tty_mode != TTY_MODE_OFF) &&
             !voice_extn_compress_voip_is_active(adev)) {
@@ -1934,6 +2200,19 @@
         }
     }
 
+#ifdef RECORD_PLAY_CONCURRENCY
+    err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_REC_PLAY_CONC, value, sizeof(value));
+    if (err >= 0) {
+        if (!strncmp("true", value, sizeof("true"))) {
+            ALOGD("setting record playback concurrency to true");
+            my_data->rec_play_conc_set = true;
+        } else {
+            ALOGD("setting record playback concurrency to false");
+            my_data->rec_play_conc_set = false;
+        }
+        str_parms_del(parms, AUDIO_PARAMETER_KEY_REC_PLAY_CONC);
+    }
+#endif
     ALOGV("%s: exit with code(%d)", __func__, ret);
     return ret;
 }
@@ -2287,6 +2566,12 @@
     return fragment_size;
 }
 
+void platform_get_device_to_be_id_map(int **device_to_be_id, int *length)
+{
+     *device_to_be_id = msm_device_to_be_id;
+     *length = msm_be_id_array_len;
+}
+
 bool platform_check_24_bit_support() {
     return false;
 }
diff --git a/hal/msm8916/platform.h b/hal/msm8916/platform.h
index dec9eda..5eeea60 100644
--- a/hal/msm8916/platform.h
+++ b/hal/msm8916/platform.h
@@ -77,6 +77,11 @@
     SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET,
     SND_DEVICE_OUT_ANC_HANDSET,
     SND_DEVICE_OUT_SPEAKER_PROTECTED,
+#ifdef RECORD_PLAY_CONCURRENCY
+    SND_DEVICE_OUT_VOIP_HANDSET,
+    SND_DEVICE_OUT_VOIP_SPEAKER,
+    SND_DEVICE_OUT_VOIP_HEADPHONES,
+#endif
     SND_DEVICE_OUT_END,
 
     /*
@@ -164,6 +169,10 @@
 #define LOW_LATENCY_OUTPUT_PERIOD_SIZE 240
 #define LOW_LATENCY_OUTPUT_PERIOD_COUNT 2
 
+#define LOW_LATENCY_CAPTURE_SAMPLE_RATE 48000
+#define LOW_LATENCY_CAPTURE_PERIOD_SIZE 240
+#define LOW_LATENCY_CAPTURE_USE_CASE 0
+
 #define HDMI_MULTI_PERIOD_SIZE  336
 #define HDMI_MULTI_PERIOD_COUNT 8
 #define HDMI_MULTI_DEFAULT_CHANNEL_COUNT 6
diff --git a/hal/msm8960/platform.c b/hal/msm8960/platform.c
index 87ce2cd..941d39f 100644
--- a/hal/msm8960/platform.c
+++ b/hal/msm8960/platform.c
@@ -505,7 +505,8 @@
     struct platform_data *my_data = (struct platform_data *)platform;
     int ret = 0;
 
-    if (my_data->csd_client != NULL) {
+    if (my_data->csd_client != NULL &&
+        voice_is_in_call(my_data->adev)) {
         /* This must be called before disabling the mixer controls on APQ side */
         if (my_data->csd_disable_device == NULL) {
             ALOGE("%s: dlsym error for csd_disable_device", __func__);
@@ -656,7 +657,7 @@
         goto exit;
     }
 
-    if (mode == AUDIO_MODE_IN_CALL) {
+    if (voice_is_in_call(adev)) {
         if (devices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
             devices & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
             if (adev->voice.tty_mode == TTY_MODE_FULL)
@@ -748,11 +749,7 @@
 
     ALOGV("%s: enter: out_device(%#x) in_device(%#x)",
           __func__, out_device, in_device);
-    if (mode == AUDIO_MODE_IN_CALL) {
-        if (out_device == AUDIO_DEVICE_NONE) {
-            ALOGE("%s: No output device set for voice call", __func__);
-            goto exit;
-        }
+    if ((out_device != AUDIO_DEVICE_NONE) && voice_is_in_call(adev)) {
         if (adev->voice.tty_mode != TTY_MODE_OFF) {
             if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
                 out_device & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
@@ -1042,10 +1039,6 @@
     return false;
 }
 
-bool platform_check_24_bit_support() {
-    return false;
-}
-
 bool platform_check_and_set_codec_backend_cfg(struct audio_device* adev __unused,
                                               struct audio_usecase *usecase __unused)
 {
diff --git a/hal/msm8960/platform.h b/hal/msm8960/platform.h
index 20984d8..950ea84 100644
--- a/hal/msm8960/platform.h
+++ b/hal/msm8960/platform.h
@@ -138,4 +138,11 @@
 /* Define macro for Internal FM volume mixer */
 #define FM_RX_VOLUME "Internal FM RX Volume"
 
+#define LOW_LATENCY_CAPTURE_SAMPLE_RATE 48000
+#define LOW_LATENCY_CAPTURE_PERIOD_SIZE 240
+#define LOW_LATENCY_CAPTURE_USE_CASE 0
+
+#define AFE_PROXY_PLAYBACK_PCM_DEVICE 7
+#define AFE_PROXY_RECORD_PCM_DEVICE 8
+
 #endif // QCOM_AUDIO_PLATFORM_H
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index 66c7731..e0d8a39 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -23,6 +23,7 @@
 
 #include <stdlib.h>
 #include <dlfcn.h>
+#include <fcntl.h>
 #include <sys/ioctl.h>
 #include <cutils/log.h>
 #include <cutils/properties.h>
@@ -33,7 +34,9 @@
 #include "audio_extn.h"
 #include "voice_extn.h"
 #include "sound/compress_params.h"
+#include "sound/msmcal-hwdep.h"
 
+#define SOUND_TRIGGER_DEVICE_HANDSET_MONO_LOW_POWER_ACDB_ID (100)
 #define MIXER_XML_PATH "/system/etc/mixer_paths.xml"
 #define MIXER_XML_PATH_AUXPCM "/system/etc/mixer_paths_auxpcm.xml"
 #define MIXER_XML_PATH_I2S "/system/etc/mixer_paths_i2s.xml"
@@ -98,6 +101,13 @@
 #define EVENT_EXTERNAL_SPK_1 "qc_ext_spk_1"
 #define EVENT_EXTERNAL_SPK_2 "qc_ext_spk_2"
 #define EVENT_EXTERNAL_MIC   "qc_ext_mic"
+#define MAX_CAL_NAME 20
+
+char cal_name_info[WCD9XXX_MAX_CAL][MAX_CAL_NAME] = {
+        [WCD9XXX_ANC_CAL] = "anc_cal",
+        [WCD9XXX_MBHC_CAL] = "mbhc_cal",
+        [WCD9XXX_MAD_CAL] = "mad_cal",
+};
 
 enum {
 	VOICE_FEATURE_SET_DEFAULT,
@@ -117,6 +127,8 @@
 typedef void (*acdb_send_voice_cal_t)(int, int);
 typedef int (*acdb_reload_vocvoltable_t)(int);
 typedef int  (*acdb_get_default_app_type_t)(void);
+typedef int (*acdb_loader_get_calibration_t)(char *attr, int size, void *data);
+acdb_loader_get_calibration_t acdb_loader_get_calibration;
 
 struct platform_data {
     struct audio_device *adev;
@@ -208,6 +220,12 @@
                                       INCALL_MUSIC_UPLINK2_PCM_DEVICE},
     [USECASE_AUDIO_SPKR_CALIB_RX] = {SPKR_PROT_CALIB_RX_PCM_DEVICE, -1},
     [USECASE_AUDIO_SPKR_CALIB_TX] = {-1, SPKR_PROT_CALIB_TX_PCM_DEVICE},
+
+    [USECASE_AUDIO_PLAYBACK_AFE_PROXY] = {AFE_PROXY_PLAYBACK_PCM_DEVICE,
+                                          AFE_PROXY_RECORD_PCM_DEVICE},
+    [USECASE_AUDIO_RECORD_AFE_PROXY] = {AFE_PROXY_PLAYBACK_PCM_DEVICE,
+                                        AFE_PROXY_RECORD_PCM_DEVICE},
+
 };
 
 /* Array to store sound devices */
@@ -233,6 +251,7 @@
     [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",
+    [SND_DEVICE_OUT_VOICE_TX] = "voice-tx",
     [SND_DEVICE_OUT_AFE_PROXY] = "afe-proxy",
     [SND_DEVICE_OUT_USB_HEADSET] = "usb-headphones",
     [SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET] = "speaker-and-usb-headphones",
@@ -280,6 +299,8 @@
     [SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC] = "voice-tty-full-headset-mic",
     [SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC] = "voice-tty-vco-handset-mic",
     [SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC] = "voice-tty-hco-headset-mic",
+    [SND_DEVICE_IN_VOICE_RX] = "voice-rx",
+
     [SND_DEVICE_IN_VOICE_REC_MIC] = "voice-rec-mic",
     [SND_DEVICE_IN_VOICE_REC_MIC_NS] = "voice-rec-mic",
     [SND_DEVICE_IN_VOICE_REC_DMIC_STEREO] = "voice-rec-dmic-ef",
@@ -323,6 +344,7 @@
     [SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES] = 17,
     [SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES] = 17,
     [SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET] = 37,
+    [SND_DEVICE_OUT_VOICE_TX] = 45,
     [SND_DEVICE_OUT_AFE_PROXY] = 0,
     [SND_DEVICE_OUT_USB_HEADSET] = 45,
     [SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET] = 14,
@@ -369,6 +391,8 @@
     [SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC] = 16,
     [SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC] = 36,
     [SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC] = 16,
+    [SND_DEVICE_IN_VOICE_RX] = 44,
+
     [SND_DEVICE_IN_VOICE_REC_MIC] = 4,
     [SND_DEVICE_IN_VOICE_REC_MIC_NS] = 107,
     [SND_DEVICE_IN_VOICE_REC_DMIC_STEREO] = 34,
@@ -498,6 +522,67 @@
     {TO_NAME_INDEX(USECASE_AUDIO_HFP_SCO)},
 };
 
+#define NO_COLS 2
+#ifdef PLATFORM_APQ8084
+static int msm_device_to_be_id [][NO_COLS] = {
+       {AUDIO_DEVICE_OUT_EARPIECE                       ,       2},
+       {AUDIO_DEVICE_OUT_SPEAKER                        ,       2},
+       {AUDIO_DEVICE_OUT_WIRED_HEADSET                  ,       2},
+       {AUDIO_DEVICE_OUT_WIRED_HEADPHONE                ,       2},
+       {AUDIO_DEVICE_OUT_BLUETOOTH_SCO                  ,       11},
+       {AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET          ,       11},
+       {AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT           ,       11},
+       {AUDIO_DEVICE_OUT_BLUETOOTH_A2DP                 ,       -1},
+       {AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES      ,       -1},
+       {AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER         ,       -1},
+       {AUDIO_DEVICE_OUT_AUX_DIGITAL                    ,       4},
+       {AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET              ,       9},
+       {AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET              ,       9},
+       {AUDIO_DEVICE_OUT_USB_ACCESSORY                  ,       -1},
+       {AUDIO_DEVICE_OUT_USB_DEVICE                     ,       -1},
+       {AUDIO_DEVICE_OUT_REMOTE_SUBMIX                  ,       9},
+       {AUDIO_DEVICE_OUT_PROXY                          ,       9},
+       {AUDIO_DEVICE_OUT_FM                             ,       7},
+       {AUDIO_DEVICE_OUT_FM_TX                          ,       8},
+       {AUDIO_DEVICE_OUT_ALL                            ,      -1},
+       {AUDIO_DEVICE_NONE                               ,      -1},
+       {AUDIO_DEVICE_OUT_DEFAULT                        ,      -1},
+};
+#elif PLATFORM_MSM8994
+static int msm_device_to_be_id [][NO_COLS] = {
+       {AUDIO_DEVICE_OUT_EARPIECE                       ,       2},
+       {AUDIO_DEVICE_OUT_SPEAKER                        ,       2},
+       {AUDIO_DEVICE_OUT_WIRED_HEADSET                  ,       2},
+       {AUDIO_DEVICE_OUT_WIRED_HEADPHONE                ,       2},
+       {AUDIO_DEVICE_OUT_BLUETOOTH_SCO                  ,       38},
+       {AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET          ,       38},
+       {AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT           ,       38},
+       {AUDIO_DEVICE_OUT_BLUETOOTH_A2DP                 ,       -1},
+       {AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES      ,       -1},
+       {AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER         ,       -1},
+       {AUDIO_DEVICE_OUT_AUX_DIGITAL                    ,       4},
+       {AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET              ,       9},
+       {AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET              ,       9},
+       {AUDIO_DEVICE_OUT_USB_ACCESSORY                  ,       -1},
+       {AUDIO_DEVICE_OUT_USB_DEVICE                     ,       -1},
+       {AUDIO_DEVICE_OUT_REMOTE_SUBMIX                  ,       9},
+       {AUDIO_DEVICE_OUT_PROXY                          ,       9},
+/* Add the correct be ids */
+       {AUDIO_DEVICE_OUT_FM                             ,       7},
+       {AUDIO_DEVICE_OUT_FM_TX                          ,       8},
+       {AUDIO_DEVICE_OUT_ALL                            ,      -1},
+       {AUDIO_DEVICE_NONE                               ,      -1},
+       {AUDIO_DEVICE_OUT_DEFAULT                        ,      -1},
+};
+#else
+static int msm_device_to_be_id [][NO_COLS] = {
+    {AUDIO_DEVICE_NONE, -1},
+};
+#endif
+static int msm_be_id_array_len  =
+    sizeof(msm_device_to_be_id) / sizeof(msm_device_to_be_id[0]);
+
+
 #define DEEP_BUFFER_PLATFORM_DELAY (29*1000LL)
 #define LOW_LATENCY_PLATFORM_DELAY (13*1000LL)
 
@@ -710,6 +795,9 @@
     backend_table[SND_DEVICE_OUT_BT_SCO_WB] = strdup("bt-sco-wb");
     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");
+    backend_table[SND_DEVICE_IN_VOICE_RX] = strdup("afe-proxy");
+
     backend_table[SND_DEVICE_OUT_AFE_PROXY] = strdup("afe-proxy");
     backend_table[SND_DEVICE_OUT_USB_HEADSET] = strdup("usb-headphones");
     backend_table[SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET] =
@@ -746,6 +834,92 @@
     return;
 }
 
+static int hw_util_open(int card_no)
+{
+    int fd = -1;
+    char dev_name[256];
+
+    snprintf(dev_name, sizeof(dev_name), "/dev/snd/hwC%uD%u",
+                               card_no, WCD9XXX_CODEC_HWDEP_NODE);
+    ALOGD("%s Opening device %s\n", __func__, dev_name);
+    fd = open(dev_name, O_WRONLY);
+    if (fd < 0) {
+        ALOGE("%s: cannot open device '%s'\n", __func__, dev_name);
+        return fd;
+    }
+    ALOGD("%s success", __func__);
+    return fd;
+}
+
+struct param_data {
+    int    use_case;
+    int    acdb_id;
+    int    get_size;
+    int    buff_size;
+    int    data_size;
+    void   *buff;
+};
+
+static int send_codec_cal(acdb_loader_get_calibration_t acdb_loader_get_calibration, int fd)
+{
+    int ret = 0, type;
+
+    for (type = WCD9XXX_ANC_CAL; type < WCD9XXX_MAX_CAL; type++) {
+        struct wcdcal_ioctl_buffer codec_buffer;
+        struct param_data calib;
+
+        if (!strcmp(cal_name_info[type], "mad_cal"))
+            calib.acdb_id = SOUND_TRIGGER_DEVICE_HANDSET_MONO_LOW_POWER_ACDB_ID;
+        calib.get_size = 1;
+        ret = acdb_loader_get_calibration(cal_name_info[type], sizeof(struct param_data),
+                                                                 &calib);
+        if (ret < 0) {
+            ALOGE("%s get_calibration failed\n", __func__);
+            return ret;
+        }
+        calib.get_size = 0;
+        calib.buff = malloc(calib.buff_size);
+        ret = acdb_loader_get_calibration(cal_name_info[type],
+                              sizeof(struct param_data), &calib);
+        if (ret < 0) {
+            ALOGE("%s get_calibration failed\n", __func__);
+            free(calib.buff);
+            return ret;
+        }
+        codec_buffer.buffer = calib.buff;
+        codec_buffer.size = calib.data_size;
+        codec_buffer.cal_type = type;
+        if (ioctl(fd, SNDRV_CTL_IOCTL_HWDEP_CAL_TYPE, &codec_buffer) < 0)
+            ALOGE("Failed to call ioctl  for %s err=%d",
+                                  cal_name_info[type], errno);
+        ALOGD("%s cal sent for %s", __func__, cal_name_info[type]);
+        free(calib.buff);
+    }
+    return ret;
+}
+
+static void audio_hwdep_send_cal(struct platform_data *plat_data)
+{
+    int fd;
+
+    fd = hw_util_open(plat_data->adev->snd_card);
+    if (fd == -1) {
+        ALOGE("%s error open\n", __func__);
+        return;
+    }
+
+    acdb_loader_get_calibration = (acdb_loader_get_calibration_t)
+          dlsym(plat_data->acdb_handle, "acdb_loader_get_calibration");
+
+    if (acdb_loader_get_calibration == NULL) {
+        ALOGE("%s: ERROR. dlsym Error:%s acdb_loader_get_calibration", __func__,
+           dlerror());
+        return;
+    }
+    if (send_codec_cal(acdb_loader_get_calibration, fd) < 0)
+        ALOGE("%s: Could not send anc cal", __FUNCTION__);
+}
+
 void *platform_init(struct audio_device *adev)
 {
     char platform[PROPERTY_VALUE_MAX];
@@ -949,11 +1123,15 @@
     /* update sound cards appropriately */
     audio_extn_usb_set_proxy_sound_card(adev->snd_card);
 
+    /* init dap hal */
+    audio_extn_dap_hal_init(adev->snd_card);
+
     /* Read one time ssr property */
     audio_extn_ssr_update_enabled();
     audio_extn_spkr_prot_init(adev);
 
     audio_extn_dolby_set_license(adev);
+    audio_hwdep_send_cal(my_data);
 
     /* init audio device arbitration */
     audio_extn_dev_arbi_init();
@@ -982,6 +1160,7 @@
     free(platform);
     /* deinit usb */
     audio_extn_usb_deinit();
+    audio_extn_dap_hal_deinit();
 }
 
 const char *platform_get_snd_device_name(snd_device_t snd_device)
@@ -1227,7 +1406,7 @@
     int ret = 0;
 
     if (my_data->csd != NULL &&
-        my_data->adev->mode == AUDIO_MODE_IN_CALL) {
+        voice_is_in_call(my_data->adev)) {
         /* This must be called before disabling mixer controls on APQ side */
         ret = my_data->csd->disable_device();
         if (ret < 0) {
@@ -1535,7 +1714,7 @@
         goto exit;
     }
 
-    if ((mode == AUDIO_MODE_IN_CALL) ||
+    if (voice_is_in_call(adev) ||
         voice_extn_compress_voip_is_active(adev)) {
         if (devices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
             devices & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
@@ -1580,7 +1759,9 @@
                 snd_device = SND_DEVICE_OUT_ANC_HANDSET;
             else
                 snd_device = SND_DEVICE_OUT_VOICE_HANDSET;
-        }
+        } else if (devices & AUDIO_DEVICE_OUT_TELEPHONY_TX)
+            snd_device = SND_DEVICE_OUT_VOICE_TX;
+
         if (snd_device != SND_DEVICE_NONE) {
             goto exit;
         }
@@ -1653,7 +1834,7 @@
     ALOGV("%s: enter: out_device(%#x) in_device(%#x)",
           __func__, out_device, in_device);
     if (my_data->external_mic) {
-        if (((out_device != AUDIO_DEVICE_NONE) && (mode == AUDIO_MODE_IN_CALL)) ||
+        if ((out_device != AUDIO_DEVICE_NONE && voice_is_in_call(adev)) ||
             voice_extn_compress_voip_is_active(adev) || audio_extn_hfp_is_active(adev)) {
             if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
                out_device & AUDIO_DEVICE_OUT_EARPIECE ||
@@ -1668,7 +1849,7 @@
     if (snd_device != AUDIO_DEVICE_NONE)
         goto exit;
 
-    if ((out_device != AUDIO_DEVICE_NONE) && ((mode == AUDIO_MODE_IN_CALL) ||
+    if ((out_device != AUDIO_DEVICE_NONE) && ((voice_is_in_call(adev)) ||
         voice_extn_compress_voip_is_active(adev) || audio_extn_hfp_is_active(adev))) {
         if ((adev->voice.tty_mode != TTY_MODE_OFF) &&
             !voice_extn_compress_voip_is_active(adev)) {
@@ -1690,7 +1871,8 @@
                 goto exit;
             }
         }
-        if (out_device & AUDIO_DEVICE_OUT_EARPIECE) {
+        if (out_device & AUDIO_DEVICE_OUT_EARPIECE ||
+            out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE) {
             if (out_device & AUDIO_DEVICE_OUT_EARPIECE &&
                 audio_extn_should_use_handset_anc(channel_count)) {
                 snd_device = SND_DEVICE_IN_AANC_HANDSET_MIC;
@@ -1719,8 +1901,7 @@
                 else
                     snd_device = SND_DEVICE_IN_BT_SCO_MIC;
             }
-        } else if (out_device & AUDIO_DEVICE_OUT_SPEAKER ||
-                   out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE) {
+        } else if (out_device & AUDIO_DEVICE_OUT_SPEAKER) {
             if (my_data->fluence_type != FLUENCE_NONE &&
                 my_data->fluence_in_voice_call &&
                 my_data->fluence_in_spkr_mode) {
@@ -1737,7 +1918,8 @@
                 if (audio_extn_hfp_is_active(adev))
                     platform_set_echo_reference(adev->platform, true);
             }
-        }
+        } else if (out_device & AUDIO_DEVICE_OUT_TELEPHONY_TX)
+            snd_device = SND_DEVICE_IN_VOICE_RX;
     } else if (source == AUDIO_SOURCE_CAMCORDER) {
         if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC ||
             in_device & AUDIO_DEVICE_IN_BACK_MIC) {
@@ -1886,12 +2068,13 @@
             snd_device = SND_DEVICE_IN_HANDSET_MIC;
         } else if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
             snd_device = SND_DEVICE_IN_HEADSET_MIC;
-        } else if (out_device & AUDIO_DEVICE_OUT_SPEAKER ||
-                   out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE) {
+        } else if (out_device & AUDIO_DEVICE_OUT_SPEAKER) {
             if (channel_count == 2)
                 snd_device = SND_DEVICE_IN_SPEAKER_STEREO_DMIC;
             else
                 snd_device = SND_DEVICE_IN_SPEAKER_MIC;
+        } else if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE) {
+            snd_device = SND_DEVICE_IN_HANDSET_MIC;
         } else if (out_device & AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET) {
             if (adev->bt_wb_speech_enabled) {
                 if (adev->bluetooth_nrec)
@@ -2451,17 +2634,6 @@
     return fragment_size;
 }
 
-bool platform_check_24_bit_support() {
-
-    char value[PROPERTY_VALUE_MAX] = {0};
-    property_get("audio.offload.24bit.enable", value, "0");
-    if (atoi(value)) {
-        ALOGW("Property audio.offload.24bit.enable is set");
-        return true;
-    }
-    return false;
-}
-
 int platform_set_codec_backend_cfg(struct audio_device* adev,
                          unsigned int bit_width, unsigned int sample_rate)
 {
@@ -2554,24 +2726,20 @@
 
     // For voice calls use default configuration
     // force routing is not required here, caller will do it anyway
-    if (adev->mode == AUDIO_MODE_IN_CALL ||
-        adev->mode == AUDIO_MODE_IN_COMMUNICATION) {
+    if (voice_is_in_call(adev) || adev->mode == AUDIO_MODE_IN_COMMUNICATION) {
         ALOGW("%s:Use default bw and sr for voice/voip calls ",__func__);
-        *new_bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
-        *new_sample_rate =  CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
-        backend_change = true;
-    }
-
-    /*
-     * The backend should be configured at highest bit width and/or
-     * sample rate amongst all playback usecases.
-     * If the selected sample rate and/or bit width differ with
-     * current backend sample rate and/or bit width, then, we set the
-     * backend re-configuration flag.
-     *
-     * Exception: 16 bit playbacks is allowed through 16 bit/48 khz backend only
-     */
-    if (!backend_change) {
+        bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
+        sample_rate =  CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
+    } else {
+        /*
+         * The backend should be configured at highest bit width and/or
+         * sample rate amongst all playback usecases.
+         * If the selected sample rate and/or bit width differ with
+         * current backend sample rate and/or bit width, then, we set the
+         * backend re-configuration flag.
+         *
+         * Exception: 16 bit playbacks is allowed through 16 bit/48 khz backend only
+         */
         list_for_each(node, &adev->usecase_list) {
             struct audio_usecase *curr_usecase;
             curr_usecase = node_to_item(node, struct audio_usecase, list);
@@ -2617,12 +2785,6 @@
 
 bool platform_check_and_set_codec_backend_cfg(struct audio_device* adev, struct audio_usecase *usecase)
 {
-    // check if 24bit configuration is enabled first
-    if (!platform_check_24_bit_support()) {
-        ALOGW("24bit not enable, no need to check for backend change");
-        return false;
-    }
-
     ALOGV("platform_check_and_set_codec_backend_cfg usecase = %d",usecase->id );
 
     unsigned int new_bit_width, old_bit_width;
@@ -2677,3 +2839,9 @@
 done:
     return ret;
 }
+
+void platform_get_device_to_be_id_map(int **device_to_be_id, int *length)
+{
+     *device_to_be_id = msm_device_to_be_id;
+     *length = msm_be_id_array_len;
+}
diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h
index 62aa40a..831ee58 100644
--- a/hal/msm8974/platform.h
+++ b/hal/msm8974/platform.h
@@ -70,6 +70,7 @@
     SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES,
     SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES,
     SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET,
+    SND_DEVICE_OUT_VOICE_TX,
     SND_DEVICE_OUT_AFE_PROXY,
     SND_DEVICE_OUT_USB_HEADSET,
     SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET,
@@ -127,6 +128,7 @@
     SND_DEVICE_IN_VOICE_REC_MIC_NS,
     SND_DEVICE_IN_VOICE_REC_DMIC_STEREO,
     SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE,
+    SND_DEVICE_IN_VOICE_RX,
     SND_DEVICE_IN_USB_HEADSET_MIC,
     SND_DEVICE_IN_CAPTURE_FM,
     SND_DEVICE_IN_AANC_HANDSET_MIC,
@@ -178,6 +180,10 @@
 #define AUDIO_CAPTURE_PERIOD_DURATION_MSEC 20
 #define AUDIO_CAPTURE_PERIOD_COUNT 2
 
+#define LOW_LATENCY_CAPTURE_SAMPLE_RATE 48000
+#define LOW_LATENCY_CAPTURE_PERIOD_SIZE 240
+#define LOW_LATENCY_CAPTURE_USE_CASE 1
+
 #define DEVICE_NAME_MAX_SIZE 128
 #define HW_INFO_ARRAY_MAX_SIZE 32
 
@@ -278,6 +284,9 @@
 #define VOWLAN_CALL_PCM_DEVICE 36
 #endif
 
+#define AFE_PROXY_PLAYBACK_PCM_DEVICE 7
+#define AFE_PROXY_RECORD_PCM_DEVICE 8
+
 #ifdef PLATFORM_MSM8x26
 #define HFP_SCO_RX 28
 #define HFP_ASM_RX_TX 29
diff --git a/hal/platform_api.h b/hal/platform_api.h
index 534630c..368677b 100644
--- a/hal/platform_api.h
+++ b/hal/platform_api.h
@@ -91,9 +91,9 @@
 uint32_t platform_get_pcm_offload_buffer_size(audio_offload_info_t* info);
 
 bool platform_check_and_set_codec_backend_cfg(struct audio_device* adev, struct audio_usecase *usecase);
-bool platform_check_24_bit_support();
 int platform_get_usecase_index(const char * usecase);
 int platform_set_usecase_pcm_id(audio_usecase_t usecase, int32_t type, int32_t pcm_id);
 void platform_set_echo_reference(void *platform, bool enable);
+void platform_get_device_to_be_id_map(int **be_id_map, int *length);
 
 #endif // AUDIO_PLATFORM_API_H
diff --git a/hal/voice.c b/hal/voice.c
index ecad7a7..53e3033 100644
--- a/hal/voice.c
+++ b/hal/voice.c
@@ -131,8 +131,8 @@
 
     uc_info->id = usecase_id;
     uc_info->type = VOICE_CALL;
-    uc_info->stream.out = adev->primary_output;
-    uc_info->devices = adev->primary_output->devices;
+    uc_info->stream.out = adev->current_call_output ;
+    uc_info->devices = adev->current_call_output ->devices;
     uc_info->in_snd_device = SND_DEVICE_NONE;
     uc_info->out_snd_device = SND_DEVICE_NONE;
 
@@ -213,6 +213,11 @@
     return call_state;
 }
 
+bool voice_is_in_call(struct audio_device *adev)
+{
+    return adev->voice.in_call;
+}
+
 bool voice_is_in_call_rec_stream(struct stream_in *in)
 {
     bool in_call_rec = false;
@@ -368,11 +373,11 @@
 {
     int ret = 0;
 
+    adev->voice.in_call = true;
     ret = voice_extn_start_call(adev);
     if (ret == -ENOSYS) {
         ret = voice_start_usecase(adev, USECASE_VOICE_CALL);
     }
-    adev->voice.in_call = true;
 
     return ret;
 }
@@ -494,6 +499,7 @@
         if (usecase->type == VOICE_CALL) {
             ALOGV("%s: updating device for usecase:%s", __func__,
                   use_case_table[usecase->id]);
+            usecase->stream.out = adev->current_call_output;
             select_devices(adev, usecase->id);
         }
     }
diff --git a/hal/voice_extn/voice_extn.c b/hal/voice_extn/voice_extn.c
index 8952522..e5b979f 100644
--- a/hal/voice_extn/voice_extn.c
+++ b/hal/voice_extn/voice_extn.c
@@ -299,7 +299,8 @@
          * occured, otherwise voice calls will be started unintendedly on
          * speaker.
          */
-        if (is_call_active || adev->voice.in_call) {
+        if (is_call_active ||
+                (adev->voice.in_call && adev->mode == AUDIO_MODE_IN_CALL)) {
             /* Device routing is not triggered for voice calls on the subsequent
              * subs, Hence update the call states if voice call is already
              * active on other sub.