Merge "hal: add external echo reference to ecns-hfp calls"
diff --git a/hal/audio_extn/audio_extn.c b/hal/audio_extn/audio_extn.c
index 9057016..2d31509 100644
--- a/hal/audio_extn/audio_extn.c
+++ b/hal/audio_extn/audio_extn.c
@@ -5677,6 +5677,7 @@
         auto_hal_init_config.fp_disable_snd_device = disable_snd_device;
         auto_hal_init_config.fp_adev_get_active_input = adev_get_active_input;
         auto_hal_init_config.fp_platform_set_echo_reference = platform_set_echo_reference;
+        auto_hal_init_config.fp_platform_get_eccarstate = platform_get_eccarstate;
         return auto_hal_init(adev, auto_hal_init_config);
     }
     else
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index d282f45..c0e8cf4 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -696,6 +696,7 @@
                                                         struct audio_usecase *);
 typedef int (*fp_audio_extn_auto_hal_stop_hfp_downlink_t)(struct audio_device *,
                                                         struct audio_usecase *);
+typedef bool (*fp_platform_get_eccarstate_t)(void *);
 
 typedef struct hfp_init_config {
     fp_platform_set_mic_mute_t                   fp_platform_set_mic_mute;
@@ -1360,6 +1361,7 @@
     fp_disable_snd_device_t                      fp_disable_snd_device;
     fp_adev_get_active_input_t                   fp_adev_get_active_input;
     fp_platform_set_echo_reference_t             fp_platform_set_echo_reference;
+    fp_platform_get_eccarstate_t                 fp_platform_get_eccarstate;
 } auto_hal_init_config_t;
 // END: AUTO_HAL FEATURE ==================================================
 
diff --git a/hal/audio_extn/auto_hal.c b/hal/audio_extn/auto_hal.c
index b09a9d0..41b3762 100644
--- a/hal/audio_extn/auto_hal.c
+++ b/hal/audio_extn/auto_hal.c
@@ -59,6 +59,7 @@
 static fp_disable_snd_device_t                      fp_disable_snd_device;
 static fp_adev_get_active_input_t                   fp_adev_get_active_input;
 static fp_platform_set_echo_reference_t             fp_platform_set_echo_reference;
+static fp_platform_get_eccarstate_t                 fp_platform_get_eccarstate;
 
 /* Auto hal module struct */
 static struct auto_hal_module *auto_hal = NULL;
@@ -827,7 +828,11 @@
         switch (usecase->id) {
         case USECASE_AUDIO_HFP_SCO:
         case USECASE_AUDIO_HFP_SCO_WB:
-            snd_device = SND_DEVICE_IN_VOICE_SPEAKER_MIC_HFP;
+            if (fp_platform_get_eccarstate((void *) adev->platform)) {
+                snd_device = SND_DEVICE_IN_VOICE_SPEAKER_MIC_HFP_MMSECNS;
+            } else {
+                snd_device = SND_DEVICE_IN_VOICE_SPEAKER_MIC_HFP;
+            }
             if (adev->enable_hfp)
                 fp_platform_set_echo_reference(adev, true, out_device);
             break;
@@ -971,6 +976,7 @@
     fp_disable_snd_device = init_config.fp_disable_snd_device;
     fp_adev_get_active_input = init_config.fp_adev_get_active_input;
     fp_platform_set_echo_reference = init_config.fp_platform_set_echo_reference;
+    fp_platform_get_eccarstate = init_config.fp_platform_get_eccarstate;
 
     return ret;
 }
diff --git a/hal/audio_extn/ext_hw_plugin.c b/hal/audio_extn/ext_hw_plugin.c
index 6e784cb..92f3f30 100644
--- a/hal/audio_extn/ext_hw_plugin.c
+++ b/hal/audio_extn/ext_hw_plugin.c
@@ -286,9 +286,12 @@
             }
         }
 
-        if ((usecase->type == PCM_CAPTURE) &&
-            (usecase->id ==  USECASE_AUDIO_RECORD) &&
-            (usecase->in_snd_device == SND_DEVICE_IN_SPEAKER_QMIC_AEC)) {
+        if (((usecase->type == PCM_CAPTURE) &&
+            (usecase->id == USECASE_AUDIO_RECORD) &&
+            (usecase->in_snd_device == SND_DEVICE_IN_SPEAKER_QMIC_AEC)) ||
+            ((usecase->type == PCM_HFP_CALL) &&
+            ((usecase->id == USECASE_AUDIO_HFP_SCO) || (usecase->id == USECASE_AUDIO_HFP_SCO_WB)) &&
+            (usecase->in_snd_device == SND_DEVICE_IN_VOICE_SPEAKER_MIC_HFP_MMSECNS))) {
             audio_hal_plugin_codec_enable_t codec_enable_ec = {0,};
             codec_enable_ec.snd_dev = usecase->in_snd_device;
             // TODO - below should be related with in_snd_dev
diff --git a/hal/audio_extn/hfp.c b/hal/audio_extn/hfp.c
index 62eb9e6..e646bc1 100644
--- a/hal/audio_extn/hfp.c
+++ b/hal/audio_extn/hfp.c
@@ -83,6 +83,7 @@
     struct pcm *hfp_sco_tx;
     struct pcm *hfp_pcm_rx;
     struct pcm *hfp_pcm_tx;
+    struct pcm *hfp_ext_ec_tx;
     bool is_hfp_running;
     float hfp_volume;
     int32_t hfp_pcm_dev_id;
@@ -96,6 +97,7 @@
     .hfp_sco_tx = NULL,
     .hfp_pcm_rx = NULL,
     .hfp_pcm_tx = NULL,
+    .hfp_ext_ec_tx = NULL,
     .is_hfp_running = 0,
     .hfp_volume = 0,
     .hfp_pcm_dev_id = HFP_ASM_RX_TX,
@@ -288,6 +290,7 @@
     int32_t ret = 0;
     struct audio_usecase *uc_info;
     int32_t pcm_dev_rx_id, pcm_dev_tx_id, pcm_dev_asm_rx_id, pcm_dev_asm_tx_id;
+    int32_t pcm_ext_ec_ref_id;
 
     ALOGD("%s: enter", __func__);
 
@@ -396,6 +399,27 @@
         goto exit;
     }
 
+#ifdef PLATFORM_AUTO
+    /* echo reference path for single-mic/multi-mic surround ECNS hfp calls */
+    pcm_ext_ec_ref_id = HFP_EXT_EC_REF_TX;
+    ALOGD("%s: Opening PCM capture device card_id(%d) device_id(%d)",
+            __func__, adev->snd_card, pcm_ext_ec_ref_id);
+    hfpmod.hfp_ext_ec_tx = pcm_open(adev->snd_card,
+                                    pcm_ext_ec_ref_id,
+                                    PCM_IN, &pcm_config_hfp);
+    if (hfpmod.hfp_ext_ec_tx && !pcm_is_ready(hfpmod.hfp_ext_ec_tx)) {
+        ALOGE("%s: %s", __func__, pcm_get_error(hfpmod.hfp_ext_ec_tx));
+        ret = -EIO;
+        goto exit;
+    }
+
+    if (pcm_start(hfpmod.hfp_ext_ec_tx) < 0) {
+        ALOGE("%s: pcm start for hfp ext ec tx failed", __func__);
+        ret = -EINVAL;
+        goto exit;
+    }
+#endif
+
     hfpmod.is_hfp_running = true;
     hfp_set_volume(adev, hfpmod.hfp_volume);
 
@@ -438,6 +462,14 @@
         hfpmod.hfp_pcm_tx = NULL;
     }
 
+#ifdef PLATFORM_AUTO
+    /* echo reference path for single-mic/multi-mic surround ECNS hfp calls */
+    if (hfpmod.hfp_ext_ec_tx) {
+        pcm_close(hfpmod.hfp_ext_ec_tx);
+        hfpmod.hfp_ext_ec_tx = NULL;
+    }
+#endif
+
     uc_info = fp_get_usecase_from_list(adev, hfpmod.ucid);
     if (uc_info == NULL) {
         ALOGE("%s: Could not find the usecase (%d) in the list",
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 89228ec..968fac5 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -1128,7 +1128,9 @@
                 in->ec_opened = true;
             }
         }
-    } else if (usecase->type == TRANSCODE_LOOPBACK_TX) {
+    } else if ((usecase->type == TRANSCODE_LOOPBACK_TX) || ((usecase->type == PCM_HFP_CALL) &&
+        ((usecase->id == USECASE_AUDIO_HFP_SCO) || (usecase->id == USECASE_AUDIO_HFP_SCO_WB)) &&
+        (usecase->in_snd_device == SND_DEVICE_IN_VOICE_SPEAKER_MIC_HFP_MMSECNS))) {
         snd_device = usecase->in_snd_device;
     } else {
         snd_device = usecase->out_snd_device;
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index 264c6f6..aded977 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -149,6 +149,7 @@
 #define AUDIO_PARAMETER_KEY_VOLUME_BOOST  "volume_boost"
 #define AUDIO_PARAMETER_KEY_AUD_CALDATA   "cal_data"
 #define AUDIO_PARAMETER_KEY_AUD_CALRESULT "cal_result"
+#define AUDIO_PARAMETER_KEY_EC_CAR_STATE  "ec_car_state"
 
 #define AUDIO_PARAMETER_KEY_MONO_SPEAKER "mono_speaker"
 
@@ -302,6 +303,7 @@
     bool hifi_audio;
     bool is_i2s_ext_modem;
     bool is_acdb_initialized;
+    bool ec_car_state;
     /* Vbat monitor related flags */
     bool is_vbat_speaker;
     bool is_bcl_speaker;
@@ -656,6 +658,7 @@
     [SND_DEVICE_IN_VOICE_SPEAKER_TMIC] = "voice-speaker-tmic",
     [SND_DEVICE_IN_VOICE_SPEAKER_QMIC] = "voice-speaker-qmic",
     [SND_DEVICE_IN_VOICE_SPEAKER_MIC_HFP] = "voice-speaker-mic-hfp",
+    [SND_DEVICE_IN_VOICE_SPEAKER_MIC_HFP_MMSECNS] = "voice-speaker-mic-hfp-mmsecns",
     [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",
@@ -906,6 +909,7 @@
     [SND_DEVICE_IN_VOICE_SPEAKER_MIC] = 11,
     [SND_DEVICE_IN_VOICE_SPEAKER_MIC_SB] = 171,
     [SND_DEVICE_IN_VOICE_SPEAKER_MIC_HFP] = 11,
+    [SND_DEVICE_IN_VOICE_SPEAKER_MIC_HFP_MMSECNS] = 131,
     [SND_DEVICE_IN_VOICE_HEADSET_MIC] = 8,
     [SND_DEVICE_IN_SPDIF] = 143,
     [SND_DEVICE_IN_HDMI_MIC] = 143,
@@ -1142,6 +1146,7 @@
     {TO_NAME_INDEX(SND_DEVICE_IN_VOICE_SPEAKER_MIC)},
     {TO_NAME_INDEX(SND_DEVICE_IN_VOICE_SPEAKER_MIC_SB)},
     {TO_NAME_INDEX(SND_DEVICE_IN_VOICE_SPEAKER_MIC_HFP)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_VOICE_SPEAKER_MIC_HFP_MMSECNS)},
     {TO_NAME_INDEX(SND_DEVICE_IN_VOICE_HEADSET_MIC)},
     {TO_NAME_INDEX(SND_DEVICE_IN_SPDIF)},
     {TO_NAME_INDEX(SND_DEVICE_IN_HDMI_MIC)},
@@ -1893,6 +1898,9 @@
         else if (out_device & AUDIO_DEVICE_OUT_USB_HEADSET)
             strlcat(ec_ref_mixer_path, " usb-headphones",
                     MIXER_PATH_MAX_LENGTH);
+        else if (out_device & AUDIO_DEVICE_OUT_BUS)
+            strlcpy(ec_ref_mixer_path, "multi-mic-echo-reference",
+                    MIXER_PATH_MAX_LENGTH);
 
         if (audio_route_apply_and_update_path(adev->audio_route,
                                               ec_ref_mixer_path) == 0)
@@ -2184,6 +2192,7 @@
     backend_tag_table[SND_DEVICE_OUT_VOICE_SPEAKER_STEREO_AND_VOICE_ANC_HEADSET] = strdup("speaker-and-headphones");
     backend_tag_table[SND_DEVICE_OUT_VOICE_SPEAKER_STEREO_AND_VOICE_ANC_FB_HEADSET] = strdup("speaker-and-headphones");
     backend_tag_table[SND_DEVICE_OUT_VOICE_HEARING_AID] = strdup("hearing-aid");
+    backend_tag_table[SND_DEVICE_IN_VOICE_SPEAKER_MIC_HFP_MMSECNS] = strdup("bt-sco-mmsecns");
 
     hw_interface_table[SND_DEVICE_OUT_HANDSET] = strdup("SLIMBUS_0_RX");
     hw_interface_table[SND_DEVICE_OUT_SPEAKER] = strdup("SLIMBUS_0_RX");
@@ -2341,6 +2350,7 @@
     hw_interface_table[SND_DEVICE_IN_VOICE_SPEAKER_DMIC] = strdup("SLIMBUS_0_TX");
     hw_interface_table[SND_DEVICE_IN_VOICE_SPEAKER_DMIC_SB] = strdup("SLIMBUS_0_TX");
     hw_interface_table[SND_DEVICE_IN_VOICE_SPEAKER_MIC_HFP] = strdup("SLIMBUS_0_TX");
+    hw_interface_table[SND_DEVICE_IN_VOICE_SPEAKER_MIC_HFP_MMSECNS] = strdup("SLIMBUS_0_TX");
     hw_interface_table[SND_DEVICE_IN_VOICE_SPEAKER_TMIC] = strdup("SLIMBUS_0_TX");
     hw_interface_table[SND_DEVICE_IN_VOICE_SPEAKER_QMIC] = strdup("SLIMBUS_0_TX");
     hw_interface_table[SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC] = strdup("SLIMBUS_0_TX");
@@ -3103,6 +3113,7 @@
     my_data->spkr_ch_map = NULL;
     my_data->use_sprk_default_sample_rate = true;
     my_data->fluence_in_voice_comm = false;
+    my_data->ec_car_state = false;
     platform_reset_edid_info(my_data);
 
     //set max volume step for voice call
@@ -7280,6 +7291,21 @@
     return ret;
 }
 
+bool platform_get_eccarstate(void *platform)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    return my_data->ec_car_state;
+}
+
+static int platform_set_eccarstate(struct platform_data *my_data, bool state)
+{
+    int ret = 0;
+    ALOGD("Setting EC Car state: %d", state);
+    my_data->ec_car_state = state;
+
+    return ret;
+}
+
 static int update_external_device_status(struct platform_data *my_data,
                                  char* event_name, bool status)
 {
@@ -7713,6 +7739,18 @@
         }
     }
 
+    err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_EC_CAR_STATE,
+                            value, len);
+    if (err >= 0) {
+        bool state = false;
+        if (!strncmp("true", value, sizeof("true"))) {
+            state = true;
+            ALOGD("%s: Value of EC CAR STATE set to true!", __func__);
+        }
+        str_parms_del(parms, AUDIO_PARAMETER_KEY_EC_CAR_STATE);
+        platform_set_eccarstate(my_data, state);
+    }
+
     err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_RELOAD_ACDB,
                             value, len);
     if (err >= 0) {
@@ -8081,6 +8119,13 @@
         str_parms_add_str(reply, AUDIO_PARAMETER_KEY_VOLUME_BOOST, value);
     }
 
+    ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_EC_CAR_STATE,
+                            value, sizeof(value));
+    if (ret >= 0) {
+        str_parms_add_str(reply, AUDIO_PARAMETER_KEY_EC_CAR_STATE,
+                          my_data->ec_car_state? "true" : "false");
+    }
+
     ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_DP_FOR_VOICE_USECASE,
                             value, sizeof(value));
 
diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h
index f9d4198..1777ec3 100644
--- a/hal/msm8974/platform.h
+++ b/hal/msm8974/platform.h
@@ -231,6 +231,7 @@
     SND_DEVICE_IN_VOICE_SPEAKER_MIC,
     SND_DEVICE_IN_VOICE_SPEAKER_MIC_SB,
     SND_DEVICE_IN_VOICE_SPEAKER_MIC_HFP,
+    SND_DEVICE_IN_VOICE_SPEAKER_MIC_HFP_MMSECNS,
     SND_DEVICE_IN_VOICE_HEADSET_MIC,
     SND_DEVICE_IN_SPDIF,
     SND_DEVICE_IN_HDMI_MIC,
@@ -643,6 +644,7 @@
 #elif PLATFORM_AUTO
 #define HFP_SCO_RX 29
 #define HFP_ASM_RX_TX 36
+#define HFP_EXT_EC_REF_TX 1
 #elif defined (PLATFORM_MSMFALCON) || defined (PLATFORM_MSM8937)
 #define HFP_SCO_RX 17
 #define HFP_ASM_RX_TX 18
diff --git a/hal/platform_api.h b/hal/platform_api.h
index bb8c558..2ffead8 100644
--- a/hal/platform_api.h
+++ b/hal/platform_api.h
@@ -374,6 +374,7 @@
                                     size_t *mic_count);
 
 int platform_get_license_by_product(void *platform, const char* product_name, int *product_id, char* product_license);
+bool platform_get_eccarstate(void *platform);
 int platform_get_haptics_pcm_device_id();
 int platform_set_qtime(void *platform, int audio_pcm_device_id,
                        int haptic_pcm_device_id);