Merge "hal: Send voice cal data before routing voice usecases"
diff --git a/Android.mk b/Android.mk
index 4216d51..bc466ed 100644
--- a/Android.mk
+++ b/Android.mk
@@ -1,4 +1,4 @@
-ifneq ($(filter mpq8092 msm8960 msm8226 msm8x26 msm8610 msm8974 msm8x74 apq8084 msm8916 msm8994 ferrum,$(TARGET_BOARD_PLATFORM)),)
+ifneq ($(filter mpq8092 msm8960 msm8226 msm8x26 msm8610 msm8974 msm8x74 apq8084 msm8916 msm8994 msm8909,$(TARGET_BOARD_PLATFORM)),)
 
 MY_LOCAL_PATH := $(call my-dir)
 
diff --git a/hal/Android.mk b/hal/Android.mk
index 227a309..6d20f7e 100644
--- a/hal/Android.mk
+++ b/hal/Android.mk
@@ -26,11 +26,11 @@
 endif
 endif
 
-ifneq ($(filter msm8916 ferrum,$(TARGET_BOARD_PLATFORM)),)
+ifneq ($(filter msm8916 msm8909,$(TARGET_BOARD_PLATFORM)),)
   AUDIO_PLATFORM = msm8916
   MULTIPLE_HW_VARIANTS_ENABLED := true
   LOCAL_CFLAGS := -DPLATFORM_MSM8916
-ifneq ($(filter ferrum,$(TARGET_BOARD_PLATFORM)),)
+ifneq ($(filter msm8909,$(TARGET_BOARD_PLATFORM)),)
   LOCAL_CFLAGS := -DPLATFORM_MSM8909
 endif
 endif
diff --git a/hal/audio_extn/hfp.c b/hal/audio_extn/hfp.c
index 5a68016..a0588a3 100644
--- a/hal/audio_extn/hfp.c
+++ b/hal/audio_extn/hfp.c
@@ -270,10 +270,13 @@
         return -EINVAL;
     }
 
-    /* 2. Get and set stream specific mixer controls */
+    /* 2. Disable echo reference while stopping hfp */
+    platform_set_echo_reference(adev->platform, false);
+
+    /* 3. Get and set stream specific mixer controls */
     disable_audio_route(adev, uc_info);
 
-    /* 3. Disable the rx and tx devices */
+    /* 4. Disable the rx and tx devices */
     disable_snd_device(adev, uc_info->out_snd_device);
     disable_snd_device(adev, uc_info->in_snd_device);
 
diff --git a/hal/audio_extn/utils.c b/hal/audio_extn/utils.c
index aa22193..5287ae8 100644
--- a/hal/audio_extn/utils.c
+++ b/hal/audio_extn/utils.c
@@ -472,6 +472,7 @@
     struct audio_device *adev;
     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;
 
     ALOGV("%s", __func__);
 
@@ -513,13 +514,21 @@
         rc = -EINVAL;
         goto exit_send_app_type_cfg;
     }
+
+    if ((24 == usecase->stream.out->bit_width) &&
+            (AUDIO_DEVICE_OUT_SPEAKER == snd_device)) {
+        sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
+    } else {
+        sample_rate = out->app_type_cfg.sample_rate;
+    }
+
     app_type_cfg[len++] = out->app_type_cfg.app_type;
     app_type_cfg[len++] = acdb_dev_id;
-    app_type_cfg[len++] = out->app_type_cfg.sample_rate;
+    app_type_cfg[len++] = sample_rate;
 
     mixer_ctl_set_array(ctl, app_type_cfg, len);
     ALOGI("%s app_type %d, acdb_dev_id %d, sample_rate %d",
-           __func__, out->app_type_cfg.app_type, acdb_dev_id, out->app_type_cfg.sample_rate);
+           __func__, out->app_type_cfg.app_type, acdb_dev_id, sample_rate);
     rc = 0;
 exit_send_app_type_cfg:
     return rc;
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index d02ec19..6daa1d1 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -821,6 +821,27 @@
     usecase->in_snd_device = in_snd_device;
     usecase->out_snd_device = out_snd_device;
 
+    if (usecase->type == PCM_PLAYBACK) {
+        if ((24 == usecase->stream.out->bit_width) &&
+            (AUDIO_DEVICE_OUT_SPEAKER == usecase->stream.out->devices)) {
+            audio_extn_utils_update_stream_app_type_cfg(adev->platform,
+                                                &adev->streams_output_cfg_list,
+                                                usecase->stream.out->flags,
+                                                usecase->stream.out->format,
+                                                DEFAULT_OUTPUT_SAMPLING_RATE,
+                                                usecase->stream.out->bit_width,
+                                                &usecase->stream.out->app_type_cfg);
+        } else {
+            audio_extn_utils_update_stream_app_type_cfg(adev->platform,
+                                                &adev->streams_output_cfg_list,
+                                                usecase->stream.out->flags,
+                                                usecase->stream.out->format,
+                                                usecase->stream.out->sample_rate,
+                                                usecase->stream.out->bit_width,
+                                                &usecase->stream.out->app_type_cfg);
+        }
+    ALOGI("%s Selected apptype: %d", __func__, usecase->stream.out->app_type_cfg.app_type);
+    }
     enable_audio_route(adev, usecase);
 
     /* Applicable only on the targets that has external modem.
@@ -2406,6 +2427,7 @@
     struct stream_out *out;
     int i, ret = 0;
     audio_format_t format;
+    int32_t sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
 
     *stream_out = NULL;
 
@@ -2591,11 +2613,20 @@
         out->sample_rate = out->config.rate;
     }
 
-    ALOGV("%s flags %x, format %x, out->sample_rate %d, out->bit_width %d",
-           __func__, flags, format, out->sample_rate, out->bit_width);
+    if ((24 == out->bit_width) &&
+        (devices == AUDIO_DEVICE_OUT_SPEAKER)) {
+        sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
+        ALOGI("%s 24-bit playback on Speaker is allowed ONLY at 48khz. Hence changing sample rate to: %d",
+               __func__, sample_rate);
+    } else {
+        sample_rate = out->sample_rate;
+    }
+
+    ALOGV("%s flags %x, format %x, sample_rate %d, out->bit_width %d",
+           __func__, flags, format, sample_rate, out->bit_width);
     audio_extn_utils_update_stream_app_type_cfg(adev->platform,
                                                 &adev->streams_output_cfg_list,
-                                                flags, format, out->sample_rate,
+                                                flags, format, sample_rate,
                                                 out->bit_width, &out->app_type_cfg);
     if ((out->usecase == USECASE_AUDIO_PLAYBACK_PRIMARY) ||
         (flags & AUDIO_OUTPUT_FLAG_PRIMARY)) {
@@ -3040,6 +3071,9 @@
 
     ALOGD("%s: enter:stream_handle(%p)",__func__, in);
 
+    /* Disable echo reference while closing input stream */
+    platform_set_echo_reference(adev->platform, false);
+
     if (in->usecase == USECASE_COMPRESS_VOIP_CALL) {
         pthread_mutex_lock(&adev->lock);
         ret = voice_extn_compress_voip_close_input_stream(&stream->common);
diff --git a/hal/msm8916/platform.c b/hal/msm8916/platform.c
index 2cc923d..7b945cf 100644
--- a/hal/msm8916/platform.c
+++ b/hal/msm8916/platform.c
@@ -124,6 +124,7 @@
     int  fluence_mode;
     bool slowtalk;
     bool hd_voice;
+    bool ec_ref_enabled;
     /* Audio calibration related functions */
     void                       *acdb_handle;
     int                        voice_feature_set;
@@ -472,16 +473,24 @@
     }
 }
 
-static void set_echo_reference(struct audio_device *adev, bool enable)
+void platform_set_echo_reference(void *platform, bool enable)
 {
-    int ret = 0;
+    struct platform_data *my_data = (struct platform_data *)platform;
+    struct audio_device *adev = my_data->adev;
 
-    if (enable)
-        ret = audio_route_apply_and_update_path(adev->audio_route, "echo-reference");
-    else
-        ret = audio_route_reset_and_update_path(adev->audio_route, "echo-reference");
+    if (enable) {
+        my_data->ec_ref_enabled = enable;
+        audio_route_apply_and_update_path(adev->audio_route, "echo-reference");
+    } else {
+        if (my_data->ec_ref_enabled) {
+            audio_route_reset_and_update_path(adev->audio_route, "echo-reference");
+            my_data->ec_ref_enabled = enable;
+        } else {
+            ALOGV("EC reference is already disabled : %d", my_data->ec_ref_enabled);
+        }
+    }
 
-    ALOGV("Setting EC Reference: %d ret: %d", enable, ret);
+    ALOGV("Setting EC Reference: %d", enable);
 }
 
 static struct csd_data *open_csd_client()
@@ -1474,14 +1483,16 @@
             } else if (my_data->fluence_type == FLUENCE_NONE ||
                 my_data->fluence_in_voice_call == false) {
                 snd_device = SND_DEVICE_IN_HANDSET_MIC;
-                set_echo_reference(adev, true);
+                if (audio_extn_hfp_is_active(adev))
+                    platform_set_echo_reference(adev->platform, true);
             } else {
                 snd_device = SND_DEVICE_IN_VOICE_DMIC;
                 adev->acdb_settings |= DMIC_FLAG;
             }
         } else if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
             snd_device = SND_DEVICE_IN_VOICE_HEADSET_MIC;
-            set_echo_reference(adev, true);
+               if (audio_extn_hfp_is_active(adev))
+                   platform_set_echo_reference(adev->platform, true);
         } else if (out_device & AUDIO_DEVICE_OUT_ALL_SCO) {
             if (adev->bt_wb_speech_enabled) {
                 if (adev->bluetooth_nrec)
@@ -1510,7 +1521,8 @@
                 }
             } else {
                 snd_device = SND_DEVICE_IN_VOICE_SPEAKER_MIC;
-                set_echo_reference(adev, true);
+                if (audio_extn_hfp_is_active(adev))
+                    platform_set_echo_reference(adev->platform, true);
             }
         }
     } else if (source == AUDIO_SOURCE_CAMCORDER) {
@@ -1562,7 +1574,7 @@
                 } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) {
                     snd_device = SND_DEVICE_IN_HEADSET_MIC_FLUENCE;
                 }
-                set_echo_reference(adev, true);
+                platform_set_echo_reference(adev->platform, true);
             } else if (adev->active_input->enable_aec) {
                 if (in_device & AUDIO_DEVICE_IN_BACK_MIC) {
                     if (my_data->fluence_type & FLUENCE_DUAL_MIC &&
@@ -1583,7 +1595,7 @@
                 } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) {
                     snd_device = SND_DEVICE_IN_HEADSET_MIC_FLUENCE;
                 }
-                set_echo_reference(adev, true);
+                platform_set_echo_reference(adev->platform, true);
             } else if (adev->active_input->enable_ns) {
                 if (in_device & AUDIO_DEVICE_IN_BACK_MIC) {
                     if (my_data->fluence_type & FLUENCE_DUAL_MIC &&
@@ -1604,9 +1616,9 @@
                 } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) {
                     snd_device = SND_DEVICE_IN_HEADSET_MIC_FLUENCE;
                 }
-                set_echo_reference(adev, false);
+                platform_set_echo_reference(adev->platform,false);
             } else
-                set_echo_reference(adev, false);
+                platform_set_echo_reference(adev->platform, false);
         }
     } else if (source == AUDIO_SOURCE_MIC) {
         if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC &&
diff --git a/hal/msm8960/platform.c b/hal/msm8960/platform.c
index 3274888..e2c30f4 100644
--- a/hal/msm8960/platform.c
+++ b/hal/msm8960/platform.c
@@ -80,6 +80,7 @@
     bool fluence_in_voice_rec;
     int  fluence_type;
     int  dualmic_config;
+    bool ec_ref_enabled;
 
     /* Audio calibration related functions */
     void *acdb_handle;
@@ -201,12 +202,22 @@
 #define DEEP_BUFFER_PLATFORM_DELAY (29*1000LL)
 #define LOW_LATENCY_PLATFORM_DELAY (13*1000LL)
 
-static void set_echo_reference(struct audio_device *adev, bool enable)
+void platform_set_echo_reference(void *platform, bool enable)
 {
-    if (enable)
+    struct platform_data *my_data = (struct platform_data *)platform;
+    struct audio_device *adev = my_data->adev;
+
+    if (enable) {
+        my_data->ec_ref_enabled = enable;
         audio_route_apply_and_update_path(adev->audio_route, "echo-reference");
-    else
-        audio_route_reset_and_update_path(adev->audio_route, "echo-reference");
+    } else {
+        if (my_data->ec_ref_enabled) {
+            audio_route_reset_and_update_path(adev->audio_route, "echo-reference");
+            my_data->ec_ref_enabled = enable;
+        } else {
+            ALOGV("EC Reference is already disabled: %d", my_data->ec_ref_enabled);
+        }
+    }
 
     ALOGV("Setting EC Reference: %d", enable);
 }
@@ -809,9 +820,9 @@
                 } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) {
                     snd_device = SND_DEVICE_IN_HEADSET_MIC_AEC;
                 }
-                set_echo_reference(adev, true);
+                platform_set_echo_reference(adev->platform, true);
             } else
-                set_echo_reference(adev, false);
+                platform_set_echo_reference(adev->platform, false);
         }
     } else if (source == AUDIO_SOURCE_DEFAULT) {
         goto exit;
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index cf26f68..ff9076e 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -132,6 +132,7 @@
     char fluence_cap[PROPERTY_VALUE_MAX];
     bool slowtalk;
     bool hd_voice;
+    bool ec_ref_enabled;
     bool is_i2s_ext_modem;
     /* Audio calibration related functions */
     void                       *acdb_handle;
@@ -497,12 +498,22 @@
 #define DEEP_BUFFER_PLATFORM_DELAY (29*1000LL)
 #define LOW_LATENCY_PLATFORM_DELAY (13*1000LL)
 
-static void set_echo_reference(struct audio_device *adev, bool enable)
+void platform_set_echo_reference(void *platform, bool enable)
 {
-    if (enable)
-        audio_route_apply_and_update_path(adev->audio_route, "echo-reference");
-    else
-        audio_route_reset_and_update_path(adev->audio_route, "echo-reference");
+    struct platform_data *my_data = (struct platform_data *)platform;
+    struct audio_device *adev = my_data->adev;
+
+    if (enable) {
+         my_data->ec_ref_enabled = enable;
+         audio_route_apply_and_update_path(adev->audio_route, "echo-reference");
+    } else {
+         if (my_data->ec_ref_enabled) {
+             audio_route_reset_and_update_path(adev->audio_route, "echo-reference");
+             my_data->ec_ref_enabled = enable;
+         } else {
+             ALOGV("EC Reference is already disabled: %d", my_data->ec_ref_enabled);
+         }
+    }
 
     ALOGV("Setting EC Reference: %d", enable);
 }
@@ -1656,13 +1667,15 @@
             } else if (my_data->fluence_type == FLUENCE_NONE ||
                 my_data->fluence_in_voice_call == false) {
                 snd_device = SND_DEVICE_IN_HANDSET_MIC;
-                set_echo_reference(adev, true);
+                if (audio_extn_hfp_is_active(adev))
+                    platform_set_echo_reference(adev->platform, true);
             } else {
                 snd_device = SND_DEVICE_IN_VOICE_DMIC;
             }
         } else if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
             snd_device = SND_DEVICE_IN_VOICE_HEADSET_MIC;
-            set_echo_reference(adev, true);
+            if (audio_extn_hfp_is_active(adev))
+                platform_set_echo_reference(adev->platform, true);
         } else if (out_device & AUDIO_DEVICE_OUT_ALL_SCO) {
             if (adev->bt_wb_speech_enabled) {
                 if (adev->bluetooth_nrec)
@@ -1690,7 +1703,8 @@
                 }
             } else {
                 snd_device = SND_DEVICE_IN_VOICE_SPEAKER_MIC;
-                set_echo_reference(adev, true);
+                if (audio_extn_hfp_is_active(adev))
+                    platform_set_echo_reference(adev->platform, true);
             }
         }
     } else if (source == AUDIO_SOURCE_CAMCORDER) {
@@ -1734,7 +1748,7 @@
                 } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) {
                     snd_device = SND_DEVICE_IN_HEADSET_MIC_FLUENCE;
                 }
-                set_echo_reference(adev, true);
+                platform_set_echo_reference(adev->platform, true);
             } else if (adev->active_input->enable_aec) {
                 if (in_device & AUDIO_DEVICE_IN_BACK_MIC) {
                     if (my_data->fluence_type & FLUENCE_DUAL_MIC &&
@@ -1753,7 +1767,7 @@
                 } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) {
                     snd_device = SND_DEVICE_IN_HEADSET_MIC_FLUENCE;
                 }
-                set_echo_reference(adev, true);
+                platform_set_echo_reference(adev->platform, true);
             } else if (adev->active_input->enable_ns) {
                 if (in_device & AUDIO_DEVICE_IN_BACK_MIC) {
                     if (my_data->fluence_type & FLUENCE_DUAL_MIC &&
@@ -1772,9 +1786,9 @@
                 } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) {
                     snd_device = SND_DEVICE_IN_HEADSET_MIC_FLUENCE;
                 }
-                set_echo_reference(adev, false);
+                platform_set_echo_reference(adev->platform, false);
             } else
-                set_echo_reference(adev, false);
+                platform_set_echo_reference(adev->platform, false);
         }
     } else if (source == AUDIO_SOURCE_MIC) {
         if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC &&
@@ -1782,7 +1796,7 @@
             if(my_data->fluence_type & FLUENCE_DUAL_MIC &&
                     my_data->fluence_in_audio_rec) {
                 snd_device = SND_DEVICE_IN_HANDSET_DMIC;
-                set_echo_reference(adev, true);
+                platform_set_echo_reference(adev->platform, true);
             }
         }
     } else if (source == AUDIO_SOURCE_FM_RX ||
@@ -2546,8 +2560,10 @@
     }
 
     // 16 bit playbacks is allowed through 16 bit/48 khz backend only
-    if (16 == bit_width)
+    if ((16 == bit_width) ||
+        ((24 == bit_width) && (SND_DEVICE_OUT_SPEAKER == usecase->devices))) {
         sample_rate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
+    }
     // Force routing if the expected bitwdith or samplerate
     // is not same as current backend comfiguration
     if ((bit_width != adev->cur_codec_backend_bit_width) ||
diff --git a/hal/platform_api.h b/hal/platform_api.h
index 6b75fce..b11a0c7 100644
--- a/hal/platform_api.h
+++ b/hal/platform_api.h
@@ -92,5 +92,6 @@
 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);
 
 #endif // AUDIO_PLATFORM_API_H
diff --git a/hal/voice_extn/compress_voip.c b/hal/voice_extn/compress_voip.c
index 4ab141d..26636db 100644
--- a/hal/voice_extn/compress_voip.c
+++ b/hal/voice_extn/compress_voip.c
@@ -287,6 +287,7 @@
            __func__, voip_data.out_stream_count, voip_data.in_stream_count);
 
     if (!voip_data.out_stream_count && !voip_data.in_stream_count) {
+        voip_data.sample_rate = 0;
         uc_info = get_usecase_from_list(adev, USECASE_COMPRESS_VOIP_CALL);
         if (uc_info == NULL) {
             ALOGE("%s: Could not find the usecase (%d) in the list",
@@ -313,7 +314,6 @@
 
         list_remove(&uc_info->list);
         free(uc_info);
-        voip_data.sample_rate = 0;
     } else
         ALOGV("%s: NO-OP because out_stream_count=%d, in_stream_count=%d",
                __func__, voip_data.out_stream_count, voip_data.in_stream_count);