Merge "hal: Fix device selection at start of the voice call"
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index 3e38d2b..c0b6de1 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -421,7 +421,6 @@
                                   audio_format_t format,
                                   uint32_t sample_rate,
                                   uint32_t bit_width,
-                                  audio_channel_mask_t channel_mask,
                                   struct stream_app_type_cfg *app_type_cfg);
 int audio_extn_utils_send_app_type_cfg(struct audio_usecase *usecase);
 void audio_extn_utils_send_audio_calibration(struct audio_device *adev,
diff --git a/hal/audio_extn/dts_eagle.c b/hal/audio_extn/dts_eagle.c
index 52d7abb..7608a61 100644
--- a/hal/audio_extn/dts_eagle.c
+++ b/hal/audio_extn/dts_eagle.c
@@ -39,7 +39,6 @@
 #define STATE_NOTIFY_FILE               "/data/misc/dts/stream"
 #define FADE_NOTIFY_FILE                "/data/misc/dts/fade"
 #define DTS_EAGLE_KEY                   "DTS_EAGLE"
-#define DEVICE_NODE                     "/dev/snd/hwC0D3"
 #define MAX_LENGTH_OF_INTEGER_IN_STRING 13
 #define PARAM_GET_MAX_SIZE              512
 
@@ -117,7 +116,7 @@
     }
 
     if (!sent) {
-        int fd = open(DEVICE_NODE, O_RDWR);
+        int fd = open(GENERIC_AUDIO_DEVICE_NODE, O_RDWR);
 
         if (get) {
             ALOGD("DTS_EAGLE_HAL (%s): no stream opened, attempting to retrieve directly from cache", __func__);
@@ -137,7 +136,7 @@
             }
             close(fd);
         } else {
-            ALOGE("DTS_EAGLE_HAL (%s): couldn't open device %s\n", __func__, DEVICE_NODE);
+            ALOGE("DTS_EAGLE_HAL (%s): couldn't open device %s\n", __func__, GENERIC_AUDIO_DEVICE_NODE);
             ret = -EINVAL;
         }
     }
diff --git a/hal/audio_extn/fm.c b/hal/audio_extn/fm.c
index ed3776c..efc2307 100644
--- a/hal/audio_extn/fm.c
+++ b/hal/audio_extn/fm.c
@@ -243,7 +243,20 @@
         if (ret >= 0) {
             val = atoi(value);
             if(val > 0)
-                select_devices(adev, USECASE_AUDIO_PLAYBACK_FM);
+                /*
+                 * Only when wsa does present and is in analog mode,
+                 * fm will stop/start here.
+                 * To-do: when the kernel codec type query change
+                 * is ready, enum of wsa mode should be checked here.
+                 * Currently, platform_get_wsa_mode will directly return
+                 * 1 when wsa is in analog mode.
+                 */
+                if (platform_get_wsa_mode(adev->platform) == 1) {
+                    fm_stop(adev);
+                    fm_start(adev);
+                } else {
+                    select_devices(adev, USECASE_AUDIO_PLAYBACK_FM);
+                }
         }
     }
     if (fmmod.restart_fm && (fmmod.scard_state == SND_CARD_STATE_ONLINE)) {
diff --git a/hal/audio_extn/utils.c b/hal/audio_extn/utils.c
index dee9d44..75bb336 100644
--- a/hal/audio_extn/utils.c
+++ b/hal/audio_extn/utils.c
@@ -459,14 +459,12 @@
                                   audio_format_t format,
                                   uint32_t sample_rate,
                                   uint32_t bit_width,
-                                  audio_channel_mask_t channel_mask,
                                   struct stream_app_type_cfg *app_type_cfg)
 {
     struct listnode *node_i, *node_j, *node_k;
     struct streams_output_cfg *so_info;
     struct stream_format *sf_info;
     struct stream_sample_rate *ss_info;
-    char value[PROPERTY_VALUE_MAX] = {0};
 
     if ((24 == bit_width) &&
         (devices & AUDIO_DEVICE_OUT_SPEAKER)) {
@@ -477,16 +475,6 @@
         ALOGI("%s Allowing 24-bit playback on speaker ONLY at default sampling rate", __func__);
     }
 
-    property_get("audio.playback.mch.downsample",value,"");
-    if (!strncmp("true", value, sizeof("true"))) {
-        if ((popcount(channel_mask) > 2) &&
-                (sample_rate > CODEC_BACKEND_DEFAULT_SAMPLE_RATE) &&
-                !(flags & AUDIO_OUTPUT_FLAG_COMPRESS_PASSTHROUGH))  {
-                    sample_rate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
-                    ALOGD("%s: MCH session defaulting sample rate to %d",
-                               __func__, sample_rate);
-        }
-    }
     ALOGV("%s: flags: %x, format: %x sample_rate %d",
            __func__, flags, format, sample_rate);
     list_for_each(node_i, streams_output_cfg_list) {
@@ -528,7 +516,6 @@
     struct mixer_ctl *ctl;
     int pcm_device_id, acdb_dev_id, snd_device = usecase->out_snd_device;
     int32_t sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
-    char value[PROPERTY_VALUE_MAX] = {0};
 
     ALOGV("%s", __func__);
 
@@ -582,14 +569,6 @@
         sample_rate = out->app_type_cfg.sample_rate;
     }
 
-    property_get("audio.playback.mch.downsample",value,"");
-    if (!strncmp("true", value, sizeof("true"))) {
-        if ((popcount(out->channel_mask) > 2) &&
-               (out->sample_rate > CODEC_BACKEND_DEFAULT_SAMPLE_RATE) &&
-               !(out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_PASSTHROUGH))
-           sample_rate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
-    }
-
     app_type_cfg[len++] = out->app_type_cfg.app_type;
     app_type_cfg[len++] = acdb_dev_id;
     if (((out->format == AUDIO_FORMAT_E_AC3) ||
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 206fc22..f105007 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -912,6 +912,9 @@
         (usecase->in_snd_device != SND_DEVICE_NONE) &&
         (usecase->out_snd_device != SND_DEVICE_NONE)) {
         status = platform_switch_voice_call_device_pre(adev->platform);
+        /* Disable sidetone only if voice call already exists */
+        if (voice_is_call_state_active(adev))
+            voice_set_sidetone(adev, usecase->out_snd_device, false);
     }
 
     /* Disable current sound devices */
@@ -954,6 +957,9 @@
                                                         out_snd_device,
                                                         in_snd_device);
         enable_audio_route_for_voice_usecases(adev, usecase);
+        /* Enable sidetone only if voice call already exists */
+        if (voice_is_call_state_active(adev))
+            voice_set_sidetone(adev, out_snd_device, true);
     }
 
     usecase->in_snd_device = in_snd_device;
@@ -967,7 +973,6 @@
                                                 usecase->stream.out->format,
                                                 usecase->stream.out->sample_rate,
                                                 usecase->stream.out->bit_width,
-                                                usecase->stream.out->channel_mask,
                                                 &usecase->stream.out->app_type_cfg);
         ALOGI("%s Selected apptype: %d", __func__, usecase->stream.out->app_type_cfg.app_type);
     }
@@ -2992,8 +2997,7 @@
     audio_extn_utils_update_stream_app_type_cfg(adev->platform,
                                                 &adev->streams_output_cfg_list,
                                                 devices, flags, format, out->sample_rate,
-                                                out->bit_width, out->channel_mask,
-                                                &out->app_type_cfg);
+                                                out->bit_width, &out->app_type_cfg);
     if ((out->usecase == USECASE_AUDIO_PLAYBACK_PRIMARY) ||
         (flags & AUDIO_OUTPUT_FLAG_PRIMARY)) {
         /* Ensure the default output is not selected twice */
diff --git a/hal/msm8916/platform.c b/hal/msm8916/platform.c
index 02e9aac..645edcd 100644
--- a/hal/msm8916/platform.c
+++ b/hal/msm8916/platform.c
@@ -2191,7 +2191,7 @@
         goto exit;
     }
 
-    if (popcount(devices) == 2) {
+    if (popcount(devices) == 2 && !voice_is_in_call(adev)) {
         if (devices == (AUDIO_DEVICE_OUT_WIRED_HEADPHONE |
                         AUDIO_DEVICE_OUT_SPEAKER)) {
             if (my_data->external_spk_1)
@@ -4026,10 +4026,15 @@
         ALOGE("%s: Invalid channel mapping used", __func__);
         return -EINVAL;
     }
-    strlcpy(mixer_ctl_name, "Playback Channel Map", sizeof(mixer_ctl_name));
+
+    /*
+     * If snd_id is greater than 0, stream channel mapping
+     * If snd_id is below 0, typically -1, device channel mapping
+     */
     if (snd_id >= 0) {
-        snprintf(device_num, sizeof(device_num), "%d", snd_id);
-        strlcat(mixer_ctl_name, device_num, sizeof(device_num));
+        snprintf(mixer_ctl_name, sizeof(mixer_ctl_name), "Playback Channel Map%d", snd_id);
+    } else {
+        strlcpy(mixer_ctl_name, "Playback Device Channel Map", sizeof(mixer_ctl_name));
     }
 
     ALOGD("%s mixer_ctl_name:%s", __func__, mixer_ctl_name);
@@ -4445,3 +4450,16 @@
 done:
     return ret;
 }
+
+int platform_get_wsa_mode(void *platform)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    char *snd_card_name;
+
+    snd_card_name = mixer_get_name(my_data->adev->mixer);
+    if ((!strcmp(snd_card_name, "msm8952-skum-snd-card")) ||
+        (!strcmp(snd_card_name, "msm8952-snd-card-mtp")))
+        return 1;
+    else
+        return 0;
+}
diff --git a/hal/msm8960/platform.c b/hal/msm8960/platform.c
index 7b86739..6212f23 100644
--- a/hal/msm8960/platform.c
+++ b/hal/msm8960/platform.c
@@ -1175,3 +1175,8 @@
 {
     return -ENOSYS;
 }
+
+int platform_get_wsa_mode(void *platform)
+{
+    return 0;
+}
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index 45a5621..8119e52 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -2020,7 +2020,7 @@
         goto exit;
     }
 
-    if (popcount(devices) == 2) {
+    if (popcount(devices) == 2 && !voice_is_in_call(adev)) {
         if (devices == (AUDIO_DEVICE_OUT_WIRED_HEADPHONE |
                         AUDIO_DEVICE_OUT_SPEAKER)) {
             if (my_data->external_spk_1)
@@ -3333,7 +3333,6 @@
 
     ALOGI("%s Codec selected backend: %d current bit width: %d and sample rate: %d",
                __func__, backend_idx, bit_width, sample_rate);
-
     // For voice calls use default configuration
     // force routing is not required here, caller will do it anyway
     if (voice_is_in_call(adev) || adev->mode == AUDIO_MODE_IN_COMMUNICATION) {
@@ -4076,3 +4075,8 @@
 done:
     return ret;
 }
+
+int platform_get_wsa_mode (void *platform)
+{
+    return 0;
+}
diff --git a/hal/platform_api.h b/hal/platform_api.h
index 5542a6d..dbcfec7 100644
--- a/hal/platform_api.h
+++ b/hal/platform_api.h
@@ -119,4 +119,5 @@
                                        const char *spkr_1_tz_name, const char *spkr_2_tz_name);
 const char *platform_get_spkr_1_tz_name(snd_device_t snd_device);
 const char *platform_get_spkr_2_tz_name(snd_device_t snd_device);
+int platform_get_wsa_mode(void *platform);
 #endif // AUDIO_PLATFORM_API_H
diff --git a/hal/voice.c b/hal/voice.c
index 9fc1081..95c4e21 100644
--- a/hal/voice.c
+++ b/hal/voice.c
@@ -55,6 +55,59 @@
     return session;
 }
 
+static bool voice_is_sidetone_device(snd_device_t out_device,
+            char *mixer_path)
+{
+    bool is_sidetone_dev;
+
+    switch (out_device) {
+    case SND_DEVICE_OUT_VOICE_HANDSET:
+        is_sidetone_dev = true;
+        strlcpy(mixer_path, "sidetone-handset", MIXER_PATH_MAX_LENGTH);
+        break;
+    case SND_DEVICE_OUT_VOICE_HEADPHONES:
+    case SND_DEVICE_OUT_VOICE_ANC_HEADSET:
+    case SND_DEVICE_OUT_VOICE_ANC_FB_HEADSET:
+        is_sidetone_dev = true;
+        strlcpy(mixer_path, "sidetone-headphones", MIXER_PATH_MAX_LENGTH);
+        break;
+    default:
+        is_sidetone_dev = false;
+        break;
+    }
+
+    return is_sidetone_dev;
+}
+
+void voice_set_sidetone(struct audio_device *adev,
+        snd_device_t out_snd_device, bool enable)
+{
+    char mixer_path[MIXER_PATH_MAX_LENGTH];
+    bool is_sidetone_dev;
+
+    ALOGD("%s: %s, out_snd_device: %d\n",
+          __func__, (enable ? "enable" : "disable"),
+          out_snd_device);
+
+    is_sidetone_dev = voice_is_sidetone_device(out_snd_device, mixer_path);
+
+    if (!is_sidetone_dev) {
+        ALOGD("%s: device %d does not support sidetone\n",
+              __func__, out_snd_device);
+        return;
+    }
+
+    ALOGD("%s: sidetone out device = %s\n",
+          __func__, mixer_path);
+
+    if (enable)
+        audio_route_apply_and_update_path(adev->audio_route, mixer_path);
+    else
+        audio_route_reset_and_update_path(adev->audio_route, mixer_path);
+
+    return;
+}
+
 int voice_stop_usecase(struct audio_device *adev, audio_usecase_t usecase_id)
 {
     int i, ret = 0;
@@ -69,10 +122,21 @@
         return -EINVAL;
     }
 
+    uc_info = get_usecase_from_list(adev, usecase_id);
+    if (uc_info == NULL) {
+        ALOGE("%s: Could not find the usecase (%d) in the list",
+              __func__, usecase_id);
+        return -EINVAL;
+    }
+
     session->state.current = CALL_INACTIVE;
     if (adev->mode == AUDIO_MODE_NORMAL)
         adev->voice.is_in_call = false;
 
+    /* Disable sidetone only when no calls are active */
+    if (!voice_is_call_state_active(adev))
+        voice_set_sidetone(adev, uc_info->out_snd_device, false);
+
     ret = platform_stop_voice_call(adev->platform, session->vsid);
 
     /* 1. Close the PCM devices */
@@ -85,13 +149,6 @@
         session->pcm_tx = NULL;
     }
 
-    uc_info = get_usecase_from_list(adev, usecase_id);
-    if (uc_info == NULL) {
-        ALOGE("%s: Could not find the usecase (%d) in the list",
-              __func__, usecase_id);
-        return -EINVAL;
-    }
-
     /* 2. Get and set stream specific mixer controls */
     disable_audio_route(adev, uc_info);
 
@@ -159,6 +216,17 @@
 
     voice_set_mic_mute(adev, adev->voice.mic_mute);
 
+    ALOGV("%s: Opening PCM capture device card_id(%d) device_id(%d)",
+          __func__, adev->snd_card, pcm_dev_tx_id);
+    session->pcm_tx = pcm_open(adev->snd_card,
+                               pcm_dev_tx_id,
+                               PCM_IN, &voice_config);
+    if (session->pcm_tx && !pcm_is_ready(session->pcm_tx)) {
+        ALOGE("%s: %s", __func__, pcm_get_error(session->pcm_tx));
+        ret = -EIO;
+        goto error_start_voice;
+    }
+
     ALOGV("%s: Opening PCM playback device card_id(%d) device_id(%d)",
           __func__, adev->snd_card, pcm_dev_rx_id);
     session->pcm_rx = pcm_open(adev->snd_card,
@@ -170,18 +238,12 @@
         goto error_start_voice;
     }
 
-    ALOGV("%s: Opening PCM capture device card_id(%d) device_id(%d)",
-          __func__, adev->snd_card, pcm_dev_tx_id);
-    session->pcm_tx = pcm_open(adev->snd_card,
-                               pcm_dev_tx_id,
-                               PCM_IN, &voice_config);
-    if (session->pcm_tx && !pcm_is_ready(session->pcm_tx)) {
-        ALOGE("%s: %s", __func__, pcm_get_error(session->pcm_tx));
-        ret = -EIO;
-        goto error_start_voice;
-    }
-    pcm_start(session->pcm_rx);
     pcm_start(session->pcm_tx);
+    pcm_start(session->pcm_rx);
+
+    /* Enable sidetone only when no calls are already active */
+    if (!voice_is_call_state_active(adev))
+        voice_set_sidetone(adev, uc_info->out_snd_device, true);
 
     voice_set_volume(adev, adev->voice.volume);
 
diff --git a/hal/voice.h b/hal/voice.h
index 5a9cce1..139a8c8 100644
--- a/hal/voice.h
+++ b/hal/voice.h
@@ -95,4 +95,8 @@
                                             struct stream_in *in);
 void voice_update_devices_for_all_voice_usecases(struct audio_device *adev);
 snd_device_t voice_get_incall_rec_snd_device(snd_device_t in_snd_device);
+void voice_set_sidetone(struct audio_device *adev,
+                       snd_device_t out_snd_device,
+                       bool enable);
+bool voice_is_call_state_active(struct audio_device *adev);
 #endif //VOICE_H
diff --git a/post_proc/bundle.c b/post_proc/bundle.c
index e38a41c..bb21f7e 100644
--- a/post_proc/bundle.c
+++ b/post_proc/bundle.c
@@ -302,9 +302,6 @@
         goto exit;
     }
 
-    if (out_ctxt->mixer)
-        mixer_close(out_ctxt->mixer);
-
     list_for_each(fx_node, &out_ctxt->effects_list) {
         effect_context_t *fx_ctxt = node_to_item(fx_node,
                                                  effect_context_t,
@@ -313,6 +310,9 @@
             fx_ctxt->ops.stop(fx_ctxt, out_ctxt);
     }
 
+    if (out_ctxt->mixer)
+        mixer_close(out_ctxt->mixer);
+
     list_remove(&out_ctxt->outputs_list_node);
 
 #ifdef DTS_EAGLE