hal: changes to support 24 bit record

-Changes to support 24 bit record if input format request is
 AUDIO_FORMAT_PCM_8_24_BIT or AUDIO_FORMAT_PCM_24_BIT_PACKED

Change-Id: I68076524ccccbf9f0be3c88bb01180ae7e4fd8b1
diff --git a/configs/msm8996/audio_policy.conf b/configs/msm8996/audio_policy.conf
index eaf896f..453aca4 100644
--- a/configs/msm8996/audio_policy.conf
+++ b/configs/msm8996/audio_policy.conf
@@ -99,6 +99,12 @@
         formats AUDIO_FORMAT_PCM_16_BIT|AUDIO_FORMAT_AMR_NB|AUDIO_FORMAT_AMR_WB|AUDIO_FORMAT_QCELP|AUDIO_FORMAT_EVRC|AUDIO_FORMAT_EVRCB|AUDIO_FORMAT_EVRCWB|AUDIO_FORMAT_EVRCNW
         devices AUDIO_DEVICE_IN_WIRED_HEADSET|AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET|AUDIO_DEVICE_IN_FM_TUNER|AUDIO_DEVICE_IN_VOICE_CALL
       }
+      float {
+        sampling_rates 8000|11025|12000|16000|22050|24000|32000|44100|48000|96000|192000
+        channel_masks AUDIO_CHANNEL_IN_MONO|AUDIO_CHANNEL_IN_STEREO|AUDIO_CHANNEL_IN_FRONT_BACK
+        formats AUDIO_FORMAT_PCM_24_BIT_PACKED
+        devices AUDIO_DEVICE_IN_BUILTIN_MIC|AUDIO_DEVICE_IN_BACK_MIC|AUDIO_DEVICE_IN_WIRED_HEADSET
+      }
       surround_sound {
         sampling_rates 8000|11025|12000|16000|22050|24000|32000|44100|48000
         channel_masks AUDIO_CHANNEL_IN_5POINT1|AUDIO_CHANNEL_IN_MONO|AUDIO_CHANNEL_IN_STEREO|AUDIO_CHANNEL_IN_FRONT_BACK
diff --git a/hal/audio_extn/ssr.c b/hal/audio_extn/ssr.c
index 6534385..f55f3ce 100644
--- a/hal/audio_extn/ssr.c
+++ b/hal/audio_extn/ssr.c
@@ -344,7 +344,8 @@
     if (audio_extn_ssr_get_enabled() &&
            ((channel_count == 2) || (channel_count == 6)) &&
            ((AUDIO_SOURCE_MIC == source) || (AUDIO_SOURCE_CAMCORDER == source)) &&
-           ((AUDIO_DEVICE_IN_BUILTIN_MIC == devices) || (AUDIO_DEVICE_IN_BACK_MIC == devices))) {
+           ((AUDIO_DEVICE_IN_BUILTIN_MIC == devices) || (AUDIO_DEVICE_IN_BACK_MIC == devices)) &&
+           (in->format == AUDIO_FORMAT_PCM_16_BIT)) {
 
         ALOGD("%s: Found SSR use case starting SSR lib with channel_count :%d",
                       __func__, channel_count);
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index aa1bc05..8486e18 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -751,7 +751,7 @@
     }
 }
 
-static void check_and_route_capture_usecases(struct audio_device *adev,
+static void check_usecases_capture_codec_backend(struct audio_device *adev,
                                              struct audio_usecase *uc_info,
                                              snd_device_t snd_device)
 {
@@ -760,6 +760,9 @@
     bool switch_device[AUDIO_USECASE_MAX];
     int i, num_uc_to_switch = 0;
 
+    bool force_routing = platform_check_and_set_capture_codec_backend_cfg(adev, uc_info,
+                         snd_device);
+    ALOGD("%s:becf: force routing %d", __func__, force_routing);
     /*
      * This function is to make sure that all the active capture usecases
      * are always routed to the same input sound device.
@@ -777,7 +780,7 @@
         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 || force_routing) &&
                 ((uc_info->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) &&
                  (((usecase->devices & ~AUDIO_DEVICE_BIT_IN) & AUDIO_DEVICE_IN_ALL_CODEC_BACKEND) ||
                   (usecase->type == VOICE_CALL))) &&
@@ -1149,7 +1152,7 @@
     }
 
     if (in_snd_device != SND_DEVICE_NONE) {
-        check_and_route_capture_usecases(adev, usecase, in_snd_device);
+        check_usecases_capture_codec_backend(adev, usecase, in_snd_device);
         enable_snd_device(adev, in_snd_device);
     }
 
@@ -1291,8 +1294,8 @@
                                  adev->perf_lock_opts_size);
     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);
+    ALOGV("%s: Opening PCM device card_id(%d) device_id(%d), channels %d format %d",
+          __func__, adev->snd_card, in->pcm_device_id, in->config.channels, in->config.format);
 
     unsigned int flags = PCM_IN;
     unsigned int pcm_open_retry_count = 0;
@@ -1996,9 +1999,11 @@
 {
     int ret = 0;
 
-    if ((format != AUDIO_FORMAT_PCM_16_BIT) &&
+    if (((format != AUDIO_FORMAT_PCM_16_BIT) && (format != AUDIO_FORMAT_PCM_8_24_BIT) &&
+        (format != AUDIO_FORMAT_PCM_24_BIT_PACKED) && (format != AUDIO_FORMAT_PCM_32_BIT) &&
+        (format != AUDIO_FORMAT_PCM_FLOAT)) &&
         !voice_extn_compress_voip_is_format_supported(format) &&
-            !audio_extn_compr_cap_format_supported(format))  ret = -EINVAL;
+        !audio_extn_compr_cap_format_supported(format))  ret = -EINVAL;
 
     switch (channel_count) {
     case 1:
@@ -2019,6 +2024,8 @@
     case 32000:
     case 44100:
     case 48000:
+    case 96000:
+    case 192000:
         break;
     default:
         ret = -EINVAL;
@@ -2040,9 +2047,8 @@
     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;
+
+    size *= audio_bytes_per_sample(format) * channel_count;
 
     /* make sure the size is multiple of 32 bytes
      * At 48 kHz mono 16-bit PCM:
@@ -3033,6 +3039,7 @@
     struct audio_device *adev = in->dev;
     int ret = -1;
     int snd_scard_state = get_snd_card_state(adev);
+    int *int_buf_stream = NULL;
 
     lock_input_stream(in);
 
@@ -3069,16 +3076,30 @@
         adev->adm_request_focus(adev->adm_data, in->capture_handle);
 
     if (in->pcm) {
-        if (audio_extn_ssr_get_stream() == in)
+        if (audio_extn_ssr_get_stream() == in) {
             ret = audio_extn_ssr_read(stream, buffer, bytes);
-        else if (audio_extn_compr_cap_usecase_supported(in->usecase))
+        } 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)
+        } else if (in->usecase == USECASE_AUDIO_RECORD_AFE_PROXY) {
             ret = pcm_mmap_read(in->pcm, buffer, bytes);
-        else
+        } else {
             ret = pcm_read(in->pcm, buffer, bytes);
-        if (ret < 0)
-            ret = -errno;
+            if ( !ret && bytes > 0 && (in->format == AUDIO_FORMAT_PCM_8_24_BIT)) {
+                if (bytes % 4 == 0) {
+                    /* data from DSP comes in 24_8 format, convert it to 8_24 */
+                    int_buf_stream = buffer;
+                    for (size_t itt=0; itt < bytes/4 ; itt++) {
+                        int_buf_stream[itt] >>= 8;
+                    }
+                } else {
+                    ALOGE("%s: !!! something wrong !!! ... data not 32 bit aligned ", __func__);
+                    ret = -EINVAL;
+                    goto exit;
+                }
+            } if (ret < 0) {
+                ret = -errno;
+            }
+        }
     }
 
     if (adev->adm_abandon_focus)
@@ -3921,9 +3942,8 @@
     }
 
     ALOGD("%s: enter: sample_rate(%d) channel_mask(%#x) devices(%#x)\
-        stream_handle(%p) io_handle(%d) source(%d)",__func__, config->sample_rate, config->channel_mask,
-        devices, &in->stream, handle, source);
-
+        stream_handle(%p) io_handle(%d) source(%d) format %x",__func__, config->sample_rate,
+        config->channel_mask, devices, &in->stream, handle, source, config->format);
     pthread_mutex_init(&in->lock, (const pthread_mutexattr_t *) NULL);
     pthread_mutex_init(&in->pre_lock, (const pthread_mutexattr_t *) NULL);
 
@@ -3963,6 +3983,8 @@
     in->config = pcm_config_audio_capture;
     in->config.rate = config->sample_rate;
     in->format = config->format;
+    in->bit_width = 16;
+    in->sample_rate = config->sample_rate;
 
     if (in->device == AUDIO_DEVICE_IN_TELEPHONY_RX) {
         if (adev->mode != AUDIO_MODE_IN_CALL) {
@@ -3989,6 +4011,7 @@
         in->config = pcm_config_afe_proxy_record;
         in->config.channels = channel_count;
         in->config.rate = config->sample_rate;
+        in->sample_rate = config->sample_rate;
     } else if (!audio_extn_ssr_check_and_set_usecase(in)) {
         ALOGD("%s: created surround sound session succesfully",__func__);
     } else if (audio_extn_compr_cap_enabled() &&
@@ -3996,6 +4019,48 @@
             (in->dev->mode != AUDIO_MODE_IN_COMMUNICATION)) {
         audio_extn_compr_cap_init(in);
     } else {
+        /* restrict 24 bit capture for unprocessed source only
+         * for other sources if 24 bit requested reject 24 and set 16 bit capture only
+         */
+        if (config->format == AUDIO_FORMAT_DEFAULT) {
+            config->format = AUDIO_FORMAT_PCM_16_BIT;
+        } else if ((config->format == AUDIO_FORMAT_PCM_FLOAT) ||
+                (config->format == AUDIO_FORMAT_PCM_32_BIT) ||
+                (config->format == AUDIO_FORMAT_PCM_24_BIT_PACKED) ||
+                (config->format == AUDIO_FORMAT_PCM_8_24_BIT)) {
+            bool ret_error = false;
+            in->bit_width = 24;
+            /* 24 bit is restricted to UNPROCESSED source only,also format supported
+               from HAL is 24_packed and 8_24
+             *> In case of UNPROCESSED source, for 24 bit, if format requested is other than
+             24_packed return error indicating supported format is 24_packed
+             *> In case of any other source requesting 24 bit or float return error
+             indicating format supported is 16 bit only.
+
+             on error flinger will retry with supported format passed
+             */
+            if ((source != AUDIO_SOURCE_UNPROCESSED) &&
+                (source != AUDIO_SOURCE_CAMCORDER)) {
+                config->format = AUDIO_FORMAT_PCM_16_BIT;
+                if( config->sample_rate > 48000)
+                    config->sample_rate = 48000;
+                ret_error = true;
+            } else if (config->format == AUDIO_FORMAT_PCM_24_BIT_PACKED) {
+                in->config.format = PCM_FORMAT_S24_3LE;
+            } else if (config->format == AUDIO_FORMAT_PCM_8_24_BIT) {
+                in->config.format = PCM_FORMAT_S24_LE;
+            } else {
+                config->format = AUDIO_FORMAT_PCM_24_BIT_PACKED;
+                ret_error = true;
+            }
+
+            if (ret_error) {
+                ret = -EINVAL;
+                goto err_open;
+            }
+        }
+
+        in->format = config->format;
         in->config.channels = channel_count;
         frame_size = audio_stream_in_frame_size(&in->stream);
         buffer_size = get_input_buffer_size(config->sample_rate,
diff --git a/hal/audio_hw.h b/hal/audio_hw.h
index a1d69a6..31184d5 100644
--- a/hal/audio_hw.h
+++ b/hal/audio_hw.h
@@ -247,7 +247,8 @@
     audio_input_flags_t flags;
     bool is_st_session;
     bool is_st_session_active;
-
+    int sample_rate;
+    int bit_width;
     struct audio_device *dev;
 };
 
diff --git a/hal/msm8916/platform.c b/hal/msm8916/platform.c
index 8f27e80..857d9e1 100644
--- a/hal/msm8916/platform.c
+++ b/hal/msm8916/platform.c
@@ -252,6 +252,7 @@
     void *edid_info;
     bool edid_valid;
     codec_backend_cfg_t current_backend_cfg[MAX_CODEC_BACKENDS];
+    codec_backend_cfg_t current_tx_backend_cfg[MAX_CODEC_TX_BACKENDS];
     char ec_ref_mixer_path[64];
     char codec_version[CODEC_VERSION_MAX_LENGTH];
     int hw_dep_fd;
@@ -1809,6 +1810,11 @@
         my_data->current_backend_cfg[idx].bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
     }
 
+    my_data->current_tx_backend_cfg[DEFAULT_CODEC_BACKEND].sample_rate =
+                                               CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
+    my_data->current_tx_backend_cfg[DEFAULT_CODEC_BACKEND].bit_width =
+                                               CODEC_BACKEND_DEFAULT_BIT_WIDTH;
+
     if (is_external_codec) {
         my_data->current_backend_cfg[DEFAULT_CODEC_BACKEND].bitwidth_mixer_ctl =
             strdup("SLIM_0_RX Format");
@@ -1824,11 +1830,21 @@
             strdup("SLIM_6_RX Format");
         my_data->current_backend_cfg[HEADPHONE_BACKEND].samplerate_mixer_ctl =
             strdup("SLIM_6_RX SampleRate");
+
+        my_data->current_tx_backend_cfg[DEFAULT_CODEC_BACKEND].bitwidth_mixer_ctl =
+            strdup("SLIM_0_TX Format");
+        my_data->current_tx_backend_cfg[DEFAULT_CODEC_BACKEND].samplerate_mixer_ctl =
+            strdup("SLIM_0_TX SampleRate");
     } else {
         my_data->current_backend_cfg[DEFAULT_CODEC_BACKEND].bitwidth_mixer_ctl =
             strdup("MI2S_RX Format");
         my_data->current_backend_cfg[DEFAULT_CODEC_BACKEND].samplerate_mixer_ctl =
             strdup("MI2S_RX SampleRate");
+
+        my_data->current_tx_backend_cfg[DEFAULT_CODEC_BACKEND].bitwidth_mixer_ctl =
+            strdup("MI2S_TX Format");
+        my_data->current_tx_backend_cfg[DEFAULT_CODEC_BACKEND].samplerate_mixer_ctl =
+            strdup("MI2S_TX SampleRate");
     }
 
     ret = audio_extn_utils_get_codec_version(snd_card_name,
@@ -4163,6 +4179,205 @@
     return ret;
 }
 
+/*
+ * configures afe with bit width and Sample Rate
+ */
+
+int platform_set_capture_codec_backend_cfg(struct audio_device* adev,
+                         snd_device_t snd_device,
+                         unsigned int bit_width, unsigned int sample_rate,
+                         audio_format_t format)
+{
+    int ret = 0;
+    int backend_idx = DEFAULT_CODEC_BACKEND;
+    struct platform_data *my_data = (struct platform_data *)adev->platform;
+
+    ALOGI("%s:txbecf: afe: bitwidth %d, samplerate %d, backend_idx %d device (%s)",
+          __func__, bit_width, sample_rate, backend_idx,
+          platform_get_snd_device_name(snd_device));
+
+    if (bit_width !=
+        my_data->current_tx_backend_cfg[backend_idx].bit_width) {
+
+        struct  mixer_ctl *ctl = NULL;
+        ctl = mixer_get_ctl_by_name(adev->mixer,
+                        my_data->current_tx_backend_cfg[backend_idx].bitwidth_mixer_ctl);
+        if (!ctl) {
+            ALOGE("%s:txbecf: afe: Could not get ctl for mixer command - %s",
+                  __func__,
+                  my_data->current_tx_backend_cfg[backend_idx].bitwidth_mixer_ctl);
+            return -EINVAL;
+        }
+
+        if (bit_width == 24) {
+            if (format == AUDIO_FORMAT_PCM_24_BIT_PACKED)
+                ret = mixer_ctl_set_enum_by_string(ctl, "S24_3LE");
+            else
+                ret = mixer_ctl_set_enum_by_string(ctl, "S24_LE");
+        } else {
+            ret = mixer_ctl_set_enum_by_string(ctl, "S16_LE");
+        }
+
+        if (ret < 0) {
+            ALOGE("%s:txbecf: afe: Could not set ctl for mixer command - %s",
+                  __func__,
+                  my_data->current_tx_backend_cfg[backend_idx].bitwidth_mixer_ctl);
+            return -EINVAL;
+        }
+
+        my_data->current_tx_backend_cfg[backend_idx].bit_width = bit_width;
+        ALOGD("%s:txbecf: afe: %s mixer set to %d bit", __func__,
+              my_data->current_tx_backend_cfg[backend_idx].bitwidth_mixer_ctl, bit_width);
+    }
+
+    /*
+     * Backend sample rate configuration follows:
+     * 16 bit record - 48khz for streams at any valid sample rate
+     * 24 bit record - 48khz for stream sample rate less than 48khz
+     * 24 bit record - 96khz for sample rate range of 48khz to 96khz
+     * 24 bit record - 192khz for sample rate range of 96khz to 192 khz
+     * Upper limit is inclusive in the sample rate range.
+     */
+    // TODO: This has to be more dynamic based on policy file
+
+    if (sample_rate != my_data->current_tx_backend_cfg[(int)backend_idx].sample_rate) {
+            /*
+             * sample rate update is needed only for hifi audio enabled platforms
+             */
+            char *rate_str = NULL;
+            struct  mixer_ctl *ctl = NULL;
+
+            switch (sample_rate) {
+            case 8000:
+            case 11025:
+            case 16000:
+            case 22050:
+            case 32000:
+            case 44100:
+            case 48000:
+                rate_str = "KHZ_48";
+                break;
+            case 64000:
+            case 88200:
+            case 96000:
+                rate_str = "KHZ_96";
+                break;
+            case 176400:
+            case 192000:
+                rate_str = "KHZ_192";
+                break;
+            default:
+                rate_str = "KHZ_48";
+                break;
+            }
+
+            ctl = mixer_get_ctl_by_name(adev->mixer,
+                my_data->current_tx_backend_cfg[backend_idx].samplerate_mixer_ctl);
+
+            if (ctl < 0) {
+                ALOGE("%s:txbecf: afe: Could not get ctl to set the Sample Rate for mixer command - %s",
+                      __func__,
+                      my_data->current_tx_backend_cfg[backend_idx].samplerate_mixer_ctl);
+                return -EINVAL;
+            }
+
+            ALOGD("%s:txbecf: afe: %s set to %s", __func__,
+                  my_data->current_tx_backend_cfg[backend_idx].samplerate_mixer_ctl,
+                  rate_str);
+            ret = mixer_ctl_set_enum_by_string(ctl, rate_str);
+            if (ret < 0) {
+                ALOGE("%s:txbecf: afe: Could not set ctl for mixer command - %s",
+                      __func__,
+                      my_data->current_tx_backend_cfg[backend_idx].samplerate_mixer_ctl);
+                return -EINVAL;
+            }
+
+            my_data->current_tx_backend_cfg[backend_idx].sample_rate = sample_rate;
+    }
+
+    return ret;
+}
+
+/*
+ * goes through all the current usecases and picks the highest
+ * bitwidth & samplerate
+ */
+bool platform_check_capture_codec_backend_cfg(struct audio_device* adev,
+                                   unsigned int* new_bit_width,
+                                   unsigned int* new_sample_rate)
+{
+    bool backend_change = false;
+    unsigned int bit_width;
+    unsigned int sample_rate;
+    int backend_idx = DEFAULT_CODEC_BACKEND;
+    struct platform_data *my_data = (struct platform_data *)adev->platform;
+
+    bit_width = *new_bit_width;
+    sample_rate = *new_sample_rate;
+
+    ALOGI("%s:txbecf: afe: 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 i.e. 16b/48K, only applicable to
+    // default backend
+    // force routing is not required here, caller will do it anyway
+    if ((voice_is_in_call(adev) || adev->mode == AUDIO_MODE_IN_COMMUNICATION) ||
+        (!is_external_codec)) {
+        ALOGW("%s:txbecf: afe:Use default bw and sr for voice/voip calls",
+              __func__);
+        bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
+        sample_rate =  CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
+    }
+
+    ALOGI("%s:txbecf: afe: Codec selected backend: %d updated bit width: %d and "
+          "sample rate: %d", __func__, backend_idx, bit_width, sample_rate);
+    // Force routing if the expected bitwdith or samplerate
+    // is not same as current backend comfiguration
+    if ((bit_width != my_data->current_tx_backend_cfg[backend_idx].bit_width) ||
+        (sample_rate != my_data->current_tx_backend_cfg[backend_idx].sample_rate)) {
+        *new_bit_width = bit_width;
+        *new_sample_rate = sample_rate;
+        backend_change = true;
+        ALOGI("%s:txbecf: afe: Codec backend needs to be updated. new bit width: %d "
+              "new sample rate: %d", __func__, *new_bit_width, *new_sample_rate);
+    }
+
+    return backend_change;
+}
+
+bool platform_check_and_set_capture_codec_backend_cfg(struct audio_device* adev,
+    struct audio_usecase *usecase, snd_device_t snd_device)
+{
+    unsigned int new_bit_width;
+    unsigned int new_sample_rate;
+    audio_format_t format = AUDIO_FORMAT_PCM_16_BIT;
+    int backend_idx = DEFAULT_CODEC_BACKEND;
+    int ret = 0;
+
+    if(usecase->type == PCM_CAPTURE) {
+        new_sample_rate = usecase->stream.in->sample_rate;
+        new_bit_width = usecase->stream.in->bit_width;
+        format = usecase->stream.in->format;
+    } else {
+        new_bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
+        new_sample_rate =  CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
+    }
+
+    ALOGI("%s:txbecf: afe: bitwidth %d, samplerate %d"
+          ", backend_idx %d usecase = %d device (%s)", __func__, new_bit_width,
+          new_sample_rate, backend_idx, usecase->id,
+          platform_get_snd_device_name(snd_device));
+    if (platform_check_capture_codec_backend_cfg(adev, &new_bit_width,
+                                       &new_sample_rate)) {
+        ret = platform_set_capture_codec_backend_cfg(adev, snd_device,
+                                       new_bit_width, new_sample_rate, format);
+        if(!ret)
+            return true;
+    }
+
+    return false;
+}
+
 int platform_set_snd_device_backend(snd_device_t device, const char *backend_tag,
                                     const char * hw_interface)
 {
diff --git a/hal/msm8916/platform.h b/hal/msm8916/platform.h
index 23435ea..9380561 100644
--- a/hal/msm8916/platform.h
+++ b/hal/msm8916/platform.h
@@ -189,6 +189,7 @@
 #define MAX_PORT                        6
 #define ALL_CODEC_BACKEND_PORT          0
 #define HEADPHONE_44_1_BACKEND_PORT     5
+#define MAX_CODEC_TX_BACKENDS           1
 enum {
     DEFAULT_CODEC_BACKEND,
     SLIMBUS_0_RX = DEFAULT_CODEC_BACKEND,
@@ -239,10 +240,6 @@
 #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
 
diff --git a/hal/msm8960/platform.c b/hal/msm8960/platform.c
index 43de781..5a41b07 100644
--- a/hal/msm8960/platform.c
+++ b/hal/msm8960/platform.c
@@ -1069,6 +1069,12 @@
     return false;
 }
 
+bool platform_check_and_set_capture_codec_backend_cfg(struct audio_device* adev __unused,
+                                              struct audio_usecase *usecase __unused)
+{
+    return false;
+}
+
 int platform_get_usecase_index(const char * usecase __unused)
 {
     return -ENOSYS;
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index 4b20544..385d20b 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -243,6 +243,7 @@
     bool edid_valid;
     char ec_ref_mixer_path[64];
     codec_backend_cfg_t current_backend_cfg[MAX_CODEC_BACKENDS];
+    codec_backend_cfg_t current_tx_backend_cfg[MAX_CODEC_TX_BACKENDS];
     char codec_version[CODEC_VERSION_MAX_LENGTH];
     int hw_dep_fd;
 };
@@ -1630,6 +1631,11 @@
     my_data->current_backend_cfg[HEADPHONE_44_1_BACKEND].samplerate_mixer_ctl =
         strdup("SLIM_5_RX SampleRate");
 
+    my_data->current_tx_backend_cfg[DEFAULT_CODEC_BACKEND].bitwidth_mixer_ctl =
+        strdup("SLIM_0_TX Format");
+    my_data->current_tx_backend_cfg[DEFAULT_CODEC_BACKEND].samplerate_mixer_ctl =
+        strdup("SLIM_0_TX SampleRate");
+
     ret = audio_extn_utils_get_codec_version(snd_card_name,
                                              my_data->adev->snd_card,
                                              my_data->codec_version);
@@ -4075,6 +4081,202 @@
     return ret;
 }
 
+/*
+ * configures afe with bit width and Sample Rate
+ */
+
+int platform_set_capture_codec_backend_cfg(struct audio_device* adev,
+                         snd_device_t snd_device,
+                         unsigned int bit_width, unsigned int sample_rate,
+                         audio_format_t format)
+{
+    int ret = 0;
+    int backend_idx = DEFAULT_CODEC_BACKEND;
+    struct platform_data *my_data = (struct platform_data *)adev->platform;
+
+    ALOGI("%s:txbecf: afe: bitwidth %d, samplerate %d, backend_idx %d device (%s)",
+          __func__, bit_width, sample_rate, backend_idx,
+          platform_get_snd_device_name(snd_device));
+
+    if (bit_width !=
+        my_data->current_tx_backend_cfg[backend_idx].bit_width) {
+
+        struct  mixer_ctl *ctl = NULL;
+        ctl = mixer_get_ctl_by_name(adev->mixer,
+                        my_data->current_tx_backend_cfg[backend_idx].bitwidth_mixer_ctl);
+        if (!ctl) {
+            ALOGE("%s:txbecf: afe: Could not get ctl for mixer command - %s",
+                  __func__,
+                  my_data->current_tx_backend_cfg[backend_idx].bitwidth_mixer_ctl);
+            return -EINVAL;
+        }
+        if (bit_width == 24) {
+            if (format == AUDIO_FORMAT_PCM_24_BIT_PACKED)
+                ret = mixer_ctl_set_enum_by_string(ctl, "S24_3LE");
+            else
+                ret = mixer_ctl_set_enum_by_string(ctl, "S24_LE");
+        } else {
+            ret = mixer_ctl_set_enum_by_string(ctl, "S16_LE");
+        }
+
+        if (ret < 0) {
+            ALOGE("%s:txbecf: afe: Could not set ctl for mixer command - %s",
+                  __func__,
+                  my_data->current_tx_backend_cfg[backend_idx].bitwidth_mixer_ctl);
+            return -EINVAL;
+        }
+
+        my_data->current_tx_backend_cfg[backend_idx].bit_width = bit_width;
+        ALOGD("%s:txbecf: afe: %s mixer set to %d bit", __func__,
+              my_data->current_tx_backend_cfg[backend_idx].bitwidth_mixer_ctl, bit_width);
+    }
+
+    /*
+     * Backend sample rate configuration follows:
+     * 16 bit record - 48khz for streams at any valid sample rate
+     * 24 bit record - 48khz for stream sample rate less than 48khz
+     * 24 bit record - 96khz for sample rate range of 48khz to 96khz
+     * 24 bit record - 192khz for sample rate range of 96khz to 192 khz
+     * Upper limit is inclusive in the sample rate range.
+     */
+    // TODO: This has to be more dynamic based on policy file
+
+    if (sample_rate != my_data->current_tx_backend_cfg[(int)backend_idx].sample_rate) {
+            /*
+             * sample rate update is needed only for hifi audio enabled platforms
+             */
+            char *rate_str = NULL;
+            struct  mixer_ctl *ctl = NULL;
+
+            switch (sample_rate) {
+            case 8000:
+            case 11025:
+            case 16000:
+            case 22050:
+            case 32000:
+            case 44100:
+            case 48000:
+                rate_str = "KHZ_48";
+                break;
+            case 64000:
+            case 88200:
+            case 96000:
+                rate_str = "KHZ_96";
+                break;
+            case 176400:
+            case 192000:
+                rate_str = "KHZ_192";
+                break;
+            default:
+                rate_str = "KHZ_48";
+                break;
+            }
+
+            ctl = mixer_get_ctl_by_name(adev->mixer,
+                my_data->current_tx_backend_cfg[backend_idx].samplerate_mixer_ctl);
+
+            if (!ctl) {
+                ALOGE("%s:txbecf: afe: Could not get ctl to set the Sample Rate for mixer command - %s",
+                      __func__,
+                      my_data->current_tx_backend_cfg[backend_idx].samplerate_mixer_ctl);
+                return -EINVAL;
+            }
+
+            ALOGD("%s:txbecf: afe: %s set to %s", __func__,
+                  my_data->current_tx_backend_cfg[backend_idx].samplerate_mixer_ctl,
+                  rate_str);
+            ret = mixer_ctl_set_enum_by_string(ctl, rate_str);
+            if (ret < 0) {
+                ALOGE("%s:txbecf: afe: Could not set ctl for mixer command - %s",
+                      __func__,
+                      my_data->current_tx_backend_cfg[backend_idx].samplerate_mixer_ctl);
+                return -EINVAL;
+            }
+
+            my_data->current_tx_backend_cfg[backend_idx].sample_rate = sample_rate;
+    }
+
+    return ret;
+}
+
+/*
+ * goes through all the current usecases and picks the highest
+ * bitwidth & samplerate
+ */
+bool platform_check_capture_codec_backend_cfg(struct audio_device* adev,
+                                   unsigned int* new_bit_width,
+                                   unsigned int* new_sample_rate)
+{
+    bool backend_change = false;
+    unsigned int bit_width;
+    unsigned int sample_rate;
+    int backend_idx = DEFAULT_CODEC_BACKEND;
+    struct platform_data *my_data = (struct platform_data *)adev->platform;
+
+    bit_width = *new_bit_width;
+    sample_rate = *new_sample_rate;
+
+    ALOGI("%s:txbecf: afe: 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 i.e. 16b/48K, only applicable to
+    // default backend
+    // force routing is not required here, caller will do it anyway
+    if (voice_is_in_call(adev) || adev->mode == AUDIO_MODE_IN_COMMUNICATION) {
+        ALOGW("%s:txbecf: afe:Use default bw and sr for voice/voip calls and "
+              "for unprocessed/camera source", __func__);
+        bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
+        sample_rate =  CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
+    }
+
+    ALOGI("%s:txbecf: afe: Codec selected backend: %d updated bit width: %d and "
+          "sample rate: %d", __func__, backend_idx, bit_width, sample_rate);
+    // Force routing if the expected bitwdith or samplerate
+    // is not same as current backend comfiguration
+    if ((bit_width != my_data->current_tx_backend_cfg[backend_idx].bit_width) ||
+        (sample_rate != my_data->current_tx_backend_cfg[backend_idx].sample_rate)) {
+        *new_bit_width = bit_width;
+        *new_sample_rate = sample_rate;
+        backend_change = true;
+        ALOGI("%s:txbecf: afe: Codec backend needs to be updated. new bit width: %d "
+              "new sample rate: %d", __func__, *new_bit_width, *new_sample_rate);
+    }
+
+    return backend_change;
+}
+
+bool platform_check_and_set_capture_codec_backend_cfg(struct audio_device* adev,
+    struct audio_usecase *usecase, snd_device_t snd_device)
+{
+    unsigned int new_bit_width;
+    unsigned int new_sample_rate;
+    audio_format_t format = AUDIO_FORMAT_PCM_16_BIT;
+    int backend_idx = DEFAULT_CODEC_BACKEND;
+    int ret = 0;
+    if(usecase->type == PCM_CAPTURE) {
+        new_sample_rate = usecase->stream.in->sample_rate;
+        new_bit_width = usecase->stream.in->bit_width;
+        format = usecase->stream.in->format;
+    } else {
+        new_bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
+        new_sample_rate =  CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
+    }
+
+    ALOGI("%s:txbecf: afe: bitwidth %d, samplerate %d"
+          ", backend_idx %d usecase = %d device (%s)", __func__, new_bit_width,
+          new_sample_rate, backend_idx, usecase->id,
+          platform_get_snd_device_name(snd_device));
+    if (platform_check_capture_codec_backend_cfg(adev, &new_bit_width,
+                                                 &new_sample_rate)) {
+        ret = platform_set_capture_codec_backend_cfg(adev, snd_device,
+                                       new_bit_width, new_sample_rate, format);
+        if(!ret)
+            return true;
+    }
+
+    return false;
+}
+
 int platform_set_snd_device_backend(snd_device_t device, const char *backend_tag,
                                     const char * hw_interface)
 {
diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h
index caa40d1..7fe7271 100644
--- a/hal/msm8974/platform.h
+++ b/hal/msm8974/platform.h
@@ -179,7 +179,7 @@
 
 #define DEFAULT_OUTPUT_SAMPLING_RATE    48000
 #define OUTPUT_SAMPLING_RATE_44100      44100
-
+#define MAX_CODEC_TX_BACKENDS           1
 enum {
     DEFAULT_CODEC_BACKEND,
     SLIMBUS_0_RX = DEFAULT_CODEC_BACKEND,
diff --git a/hal/platform_api.h b/hal/platform_api.h
index 04ed8f5..df80a0c 100644
--- a/hal/platform_api.h
+++ b/hal/platform_api.h
@@ -114,6 +114,8 @@
 
 bool platform_check_and_set_codec_backend_cfg(struct audio_device* adev,
                    struct audio_usecase *usecase, snd_device_t snd_device);
+bool platform_check_and_set_capture_codec_backend_cfg(struct audio_device* adev,
+                   struct audio_usecase *usecase, snd_device_t snd_device);
 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(struct audio_device *adev, bool enable, audio_devices_t out_device);