hal: Enable direct playback support for AUDIO_FORMAT_PCM_FLOAT

-Add changes to support PCM_FLOAT format using direct track.
-For targets supporting true 32 bit, convert FLOAT pcm data
to 32 bit.
-Targets which dont support true 32 bit, convert FLOAT or
32 bit input to 24 bit Packed in HAL.

Change-Id: I8052c8b878bbd4d70c0453df054953d494773b0a
diff --git a/hal/Android.mk b/hal/Android.mk
index 9888396..0143c2c 100644
--- a/hal/Android.mk
+++ b/hal/Android.mk
@@ -247,11 +247,13 @@
 	libtinycompress \
 	libaudioroute \
 	libdl \
+	libaudioutils \
 	libexpat
 
 LOCAL_C_INCLUDES += \
 	external/tinyalsa/include \
 	external/tinycompress/include \
+	system/media/audio_utils/include \
 	external/expat/lib \
 	$(call include-path-for, audio-route) \
 	$(call include-path-for, audio-effects) \
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index 090e6b0..357f036 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -524,10 +524,17 @@
 #define AUDIO_FORMAT_DTS_LBR 0x1E000000UL
 #endif
 
+#define DIV_ROUND_UP(x, y) (((x) + (y) - 1)/(y))
+#define ALIGN(x, y) ((y) * DIV_ROUND_UP((x), (y)))
+
 int b64decode(char *inp, int ilen, uint8_t* outp);
 int b64encode(uint8_t *inp, int ilen, char* outp);
 int read_line_from_file(const char *path, char *buf, size_t count);
 int audio_extn_utils_get_codec_version(const char *snd_card_name, int card_num, char *codec_version);
+audio_format_t alsa_format_to_hal(uint32_t alsa_format);
+uint32_t hal_format_to_alsa(audio_format_t pcm_format);
+void audio_extn_utils_update_direct_pcm_fragment_size(struct stream_out *out);
+
 #ifndef KPI_OPTIMIZE_ENABLED
 #define audio_extn_perf_lock_init() (0)
 #define audio_extn_perf_lock_acquire(handle, duration, opts, size) (0)
diff --git a/hal/audio_extn/utils.c b/hal/audio_extn/utils.c
index cb646cf..df20120 100644
--- a/hal/audio_extn/utils.c
+++ b/hal/audio_extn/utils.c
@@ -99,6 +99,7 @@
     STRING_TO_ENUM(AUDIO_FORMAT_PCM_16_BIT),
     STRING_TO_ENUM(AUDIO_FORMAT_PCM_24_BIT_PACKED),
     STRING_TO_ENUM(AUDIO_FORMAT_PCM_8_24_BIT),
+    STRING_TO_ENUM(AUDIO_FORMAT_PCM_32_BIT),
     STRING_TO_ENUM(AUDIO_FORMAT_PCM_8_BIT),
     STRING_TO_ENUM(AUDIO_FORMAT_MP3),
     STRING_TO_ENUM(AUDIO_FORMAT_AAC),
@@ -702,6 +703,124 @@
    return rv;
 }
 
+/*Translates ALSA formats to AOSP PCM formats*/
+audio_format_t alsa_format_to_hal(uint32_t alsa_format)
+{
+    audio_format_t format;
+
+    switch(alsa_format) {
+    case SNDRV_PCM_FORMAT_S16_LE:
+        format = AUDIO_FORMAT_PCM_16_BIT;
+        break;
+    case SNDRV_PCM_FORMAT_S24_3LE:
+        format = AUDIO_FORMAT_PCM_24_BIT_PACKED;
+        break;
+    case SNDRV_PCM_FORMAT_S24_LE:
+        format = AUDIO_FORMAT_PCM_8_24_BIT;
+        break;
+    case SNDRV_PCM_FORMAT_S32_LE:
+        format = AUDIO_FORMAT_PCM_32_BIT;
+        break;
+    default:
+        ALOGW("Incorrect ALSA format");
+        format = AUDIO_FORMAT_INVALID;
+    }
+    return format;
+}
+
+/*Translates hal format (AOSP) to alsa formats*/
+uint32_t hal_format_to_alsa(audio_format_t hal_format)
+{
+    uint32_t alsa_format;
+
+    switch (hal_format) {
+    case AUDIO_FORMAT_PCM_32_BIT: {
+        if (platform_supports_true_32bit())
+            alsa_format = SNDRV_PCM_FORMAT_S32_LE;
+        else
+            alsa_format = SNDRV_PCM_FORMAT_S24_3LE;
+        }
+        break;
+    case AUDIO_FORMAT_PCM_8_BIT:
+        alsa_format = SNDRV_PCM_FORMAT_S8;
+        break;
+    case AUDIO_FORMAT_PCM_24_BIT_PACKED:
+        alsa_format = SNDRV_PCM_FORMAT_S24_3LE;
+        break;
+    case AUDIO_FORMAT_PCM_8_24_BIT: {
+        if (platform_supports_true_32bit())
+            alsa_format = SNDRV_PCM_FORMAT_S32_LE;
+        else
+            alsa_format = SNDRV_PCM_FORMAT_S24_3LE;
+        }
+        break;
+    case AUDIO_FORMAT_PCM_FLOAT:
+        alsa_format = SNDRV_PCM_FORMAT_S24_3LE;
+        break;
+    default:
+    case AUDIO_FORMAT_PCM_16_BIT:
+        alsa_format = SNDRV_PCM_FORMAT_S16_LE;
+        break;
+    }
+    return alsa_format;
+}
+
+uint32_t get_alsa_fragment_size(uint32_t bytes_per_sample,
+                                  uint32_t sample_rate,
+                                  uint32_t noOfChannels)
+{
+    uint32_t fragment_size = 0;
+    uint32_t pcm_offload_time = PCM_OFFLOAD_BUFFER_DURATION;
+
+    fragment_size = (pcm_offload_time
+                     * sample_rate
+                     * bytes_per_sample
+                     * noOfChannels)/1000;
+    if (fragment_size < MIN_PCM_OFFLOAD_FRAGMENT_SIZE)
+        fragment_size = MIN_PCM_OFFLOAD_FRAGMENT_SIZE;
+    else if (fragment_size > MAX_PCM_OFFLOAD_FRAGMENT_SIZE)
+        fragment_size = MAX_PCM_OFFLOAD_FRAGMENT_SIZE;
+    /*To have same PCM samples for all channels, the buffer size requires to
+     *be multiple of (number of channels * bytes per sample)
+     *For writes to succeed, the buffer must be written at address which is multiple of 32
+     */
+    fragment_size = ALIGN(fragment_size, (bytes_per_sample * noOfChannels * 32));
+
+    ALOGI("PCM offload Fragment size to %d bytes", fragment_size);
+    return fragment_size;
+}
+
+/* Calculates the fragment size required to configure compress session.
+ * Based on the alsa format selected, decide if conversion is needed in
+
+ * HAL ( e.g. convert AUDIO_FORMAT_PCM_FLOAT input format to
+ * AUDIO_FORMAT_PCM_24_BIT_PACKED before writing to the compress driver.
+ */
+void audio_extn_utils_update_direct_pcm_fragment_size(struct stream_out *out)
+{
+    audio_format_t dst_format = out->compr_pcm_config.hal_op_format;
+    audio_format_t src_format = out->compr_pcm_config.hal_ip_format;
+    uint32_t hal_op_bytes_per_sample = audio_bytes_per_sample(dst_format);
+    uint32_t hal_ip_bytes_per_sample = audio_bytes_per_sample(src_format);
+
+    out->compr_config.fragment_size =
+             get_alsa_fragment_size(hal_op_bytes_per_sample,
+                                      out->sample_rate,
+                                      popcount(out->channel_mask));
+
+    if ((src_format != dst_format) &&
+         hal_op_bytes_per_sample != hal_ip_bytes_per_sample) {
+
+        out->compr_pcm_config.hal_fragment_size =
+                  ((out->compr_config.fragment_size * hal_ip_bytes_per_sample) /
+                   hal_op_bytes_per_sample);
+        ALOGI("enable conversion hal_input_fragment_size is %d src_format %x dst_format %x",
+               out->compr_pcm_config.hal_fragment_size, src_format, dst_format);
+    } else {
+        out->compr_pcm_config.hal_fragment_size = out->compr_config.fragment_size;
+    }
+}
+
 void audio_extn_utils_send_audio_calibration(struct audio_device *adev,
                                              struct audio_usecase *usecase)
 {
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index d6e81b2..7978adf 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -64,6 +64,7 @@
 #include <system/thread_defs.h>
 #include <audio_effects/effect_aec.h>
 #include <audio_effects/effect_ns.h>
+#include <audio_utils/format.h>
 #include "audio_hw.h"
 #include "platform_api.h"
 #include <platform.h>
@@ -164,6 +165,18 @@
     .avail_min = AFE_PROXY_RECORD_PERIOD_SIZE,
 };
 
+#define AUDIO_MAX_PCM_FORMATS 7
+
+const uint32_t format_to_bitwidth_table[AUDIO_MAX_PCM_FORMATS] = {
+    [AUDIO_FORMAT_DEFAULT] = 0,
+    [AUDIO_FORMAT_PCM_16_BIT] = sizeof(uint16_t),
+    [AUDIO_FORMAT_PCM_8_BIT] = sizeof(uint8_t),
+    [AUDIO_FORMAT_PCM_32_BIT] = sizeof(uint32_t),
+    [AUDIO_FORMAT_PCM_8_24_BIT] = sizeof(uint32_t),
+    [AUDIO_FORMAT_PCM_FLOAT] = sizeof(float),
+    [AUDIO_FORMAT_PCM_24_BIT_PACKED] = sizeof(uint8_t) * 3,
+};
+
 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",
@@ -337,6 +350,8 @@
         format == AUDIO_FORMAT_AAC_ADTS_HE_V2 ||
         format == AUDIO_FORMAT_PCM_24_BIT_PACKED ||
         format == AUDIO_FORMAT_PCM_8_24_BIT ||
+        format == AUDIO_FORMAT_PCM_FLOAT ||
+        format == AUDIO_FORMAT_PCM_32_BIT ||
         format == AUDIO_FORMAT_PCM_16_BIT ||
         format == AUDIO_FORMAT_AC3 ||
         format == AUDIO_FORMAT_E_AC3 ||
@@ -2123,6 +2138,8 @@
         return out->compr_config.fragment_size;
     else if(out->usecase == USECASE_COMPRESS_VOIP_CALL)
         return voice_extn_compress_voip_out_get_buffer_size(out);
+    else if (out->flags & AUDIO_OUTPUT_FLAG_DIRECT_PCM)
+        return out->compr_pcm_config.hal_fragment_size;
 
     return out->config.period_size *
                 audio_stream_out_frame_size((const struct audio_stream_out *)stream);
@@ -2592,8 +2609,38 @@
                 out->is_compr_metadata_avail = false;
             }
         }
+        if ((out->flags & AUDIO_OUTPUT_FLAG_DIRECT_PCM) &&
+                      (out->compr_pcm_config.convert_buffer) != NULL) {
 
-        ret = compress_write(out->compr, buffer, bytes);
+            if ((bytes > out->compr_pcm_config.hal_fragment_size)) {
+                ALOGW("Error written bytes %zu > %d (fragment_size)",
+                       bytes, out->compr_pcm_config.hal_fragment_size);
+                pthread_mutex_unlock(&out->lock);
+                return -EINVAL;
+            } else {
+                audio_format_t dst_format = out->compr_pcm_config.hal_op_format;
+                audio_format_t src_format = out->compr_pcm_config.hal_ip_format;
+
+                uint32_t frames = bytes / format_to_bitwidth_table[src_format];
+                uint32_t bytes_to_write = frames * format_to_bitwidth_table[dst_format];
+
+                memcpy_by_audio_format(out->compr_pcm_config.convert_buffer,
+                                       dst_format,
+                                       buffer,
+                                       src_format,
+                                       frames);
+
+                ret = compress_write(out->compr, out->compr_pcm_config.convert_buffer,
+                                     bytes_to_write);
+
+                /*Convert written bytes in audio flinger format*/
+                if (ret > 0)
+                    ret = ((ret * format_to_bitwidth_table[out->format]) /
+                           format_to_bitwidth_table[dst_format]);
+            }
+        } else
+            ret = compress_write(out->compr, buffer, bytes);
+
         if (ret < 0)
             ret = -errno;
         ALOGVV("%s: writing buffer (%zu bytes) to compress device returned %zd", __func__, bytes, ret);
@@ -3316,6 +3363,7 @@
     out->handle = handle;
     out->bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
     out->non_blocking = 0;
+    out->compr_pcm_config.convert_buffer = NULL;
 
     if (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL &&
         (flags & AUDIO_OUTPUT_FLAG_DIRECT)) {
@@ -3459,19 +3507,6 @@
             audio_extn_dolby_set_dmid(adev);
         }
 
-        if ((config->offload_info.format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_PCM) {
-            out->compr_config.fragment_size =
-               platform_get_pcm_offload_buffer_size(&config->offload_info);
-            out->compr_config.fragments = DIRECT_PCM_NUM_FRAGMENTS;
-        } else if (audio_extn_passthru_is_passthrough_stream(out)) {
-            out->compr_config.fragment_size =
-               audio_extn_passthru_get_buffer_size(&config->offload_info);
-            out->compr_config.fragments = COMPRESS_OFFLOAD_NUM_FRAGMENTS;
-        } else {
-            out->compr_config.fragment_size =
-               platform_get_compress_offload_buffer_size(&config->offload_info);
-            out->compr_config.fragments = COMPRESS_OFFLOAD_NUM_FRAGMENTS;
-        }
         out->compr_config.codec->sample_rate =
                     config->offload_info.sample_rate;
         out->compr_config.codec->bit_rate =
@@ -3487,12 +3522,58 @@
              out->compr_config.codec->format = SND_AUDIOSTREAMFORMAT_RAW;
         if ((config->offload_info.format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_AAC_ADTS)
             out->compr_config.codec->format = SND_AUDIOSTREAMFORMAT_MP4ADTS;
-        if (config->offload_info.format == AUDIO_FORMAT_PCM_16_BIT)
-            out->compr_config.codec->format = SNDRV_PCM_FORMAT_S16_LE;
-        if (config->offload_info.format == AUDIO_FORMAT_PCM_24_BIT_PACKED)
-            out->compr_config.codec->format = SNDRV_PCM_FORMAT_S24_3LE;
-        if (config->offload_info.format == AUDIO_FORMAT_PCM_8_24_BIT)
-            out->compr_config.codec->format = SNDRV_PCM_FORMAT_S24_LE;
+
+        if ((config->offload_info.format & AUDIO_FORMAT_MAIN_MASK) ==
+             AUDIO_FORMAT_PCM) {
+
+            /*Based on platform support, configure appropriate alsa format for corresponding
+             *hal input format.
+             */
+            out->compr_config.codec->format = hal_format_to_alsa(
+                                              config->offload_info.format);
+
+            out->compr_pcm_config.hal_op_format = alsa_format_to_hal(
+                                                  out->compr_config.codec->format);
+            out->compr_pcm_config.hal_ip_format = out->format;
+
+            /*for direct PCM playback populate bit_width based on selected alsa format as
+             *hal input format and alsa format might differ based on platform support.
+             */
+            out->bit_width = audio_bytes_per_sample(
+                             out->compr_pcm_config.hal_op_format) << 3;
+
+            out->compr_config.fragments = DIRECT_PCM_NUM_FRAGMENTS;
+
+            /* Check if alsa session is configured with the same format as HAL input format,
+             * if not then derive correct fragment size needed to accomodate the
+             * conversion of HAL input format to alsa format.
+             */
+            audio_extn_utils_update_direct_pcm_fragment_size(out);
+
+            /*if hal input and output fragment size is different this indicates HAL input format is
+             *not same as the alsa format
+             */
+            if (out->compr_pcm_config.hal_fragment_size != out->compr_config.fragment_size) {
+                /*Allocate a buffer to convert input data to the alsa configured format.
+                 *size of convert buffer is equal to the size required to hold one fragment size
+                 *worth of pcm data, this is because flinger does not write more than fragment_size
+                 */
+                out->compr_pcm_config.convert_buffer = calloc(1,out->compr_config.fragment_size);
+                if (out->compr_pcm_config.convert_buffer == NULL){
+                    ALOGE("Allocation failed for convert buffer for size %d", out->compr_config.fragment_size);
+                    ret = -ENOMEM;
+                    goto error_open;
+                }
+            }
+        } else if (audio_extn_passthru_is_passthrough_stream(out)) {
+            out->compr_config.fragment_size =
+                   audio_extn_passthru_get_buffer_size(&config->offload_info);
+            out->compr_config.fragments = COMPRESS_OFFLOAD_NUM_FRAGMENTS;
+        } else {
+            out->compr_config.fragment_size =
+                  platform_get_compress_offload_buffer_size(&config->offload_info);
+            out->compr_config.fragments = COMPRESS_OFFLOAD_NUM_FRAGMENTS;
+        }
 
         if (config->offload_info.format == AUDIO_FORMAT_FLAC)
             out->compr_config.codec->options.flac_dec.sample_size = AUDIO_OUTPUT_BIT_WIDTH;
@@ -3652,6 +3733,8 @@
     return 0;
 
 error_open:
+    if (out->compr_pcm_config.convert_buffer)
+        free(out->compr_pcm_config.convert_buffer);
     free(out);
     *stream_out = NULL;
     ALOGD("%s: exit: ret %d", __func__, ret);
@@ -3678,6 +3761,8 @@
         out_standby(&stream->common);
 
     if (is_offload_usecase(out->usecase)) {
+        if (out->compr_pcm_config.convert_buffer != NULL)
+            free(out->compr_pcm_config.convert_buffer);
         audio_extn_dts_remove_state_notifier_node(out->usecase);
         destroy_offload_callback_thread(out);
         free_offload_usecase(adev, out->usecase);
diff --git a/hal/audio_hw.h b/hal/audio_hw.h
index 6c97840..5bd1216 100644
--- a/hal/audio_hw.h
+++ b/hal/audio_hw.h
@@ -182,6 +182,13 @@
     int app_type;
 };
 
+struct compr_pcm_config {
+    uint32_t hal_fragment_size;
+    audio_format_t hal_ip_format;
+    audio_format_t hal_op_format;
+    void *convert_buffer;
+};
+
 struct stream_out {
     struct audio_stream_out stream;
     pthread_mutex_t lock; /* see note below on mutex acquisition order */
@@ -223,6 +230,7 @@
     bool send_next_track_params;
     bool is_compr_metadata_avail;
     unsigned int bit_width;
+    struct compr_pcm_config compr_pcm_config;
 
     struct audio_device *dev;
 };
diff --git a/hal/msm8916/platform.c b/hal/msm8916/platform.c
index 9070478..c66fd38 100644
--- a/hal/msm8916/platform.c
+++ b/hal/msm8916/platform.c
@@ -75,15 +75,6 @@
 #define MIN_COMPRESS_OFFLOAD_FRAGMENT_SIZE (2 * 1024)
 #define COMPRESS_OFFLOAD_FRAGMENT_SIZE_FOR_AV_STREAMING (2 * 1024)
 #define COMPRESS_OFFLOAD_FRAGMENT_SIZE (32 * 1024)
-/* Used in calculating fragment size for pcm offload */
-#define PCM_OFFLOAD_BUFFER_DURATION 40 /* 40 millisecs */
-
-/* MAX PCM fragment size cannot be increased  further due
- * to flinger's cblk size of 1mb,and it has to be a multiple of
- * 24 - lcm of channels supported by DSP
- */
-#define MAX_PCM_OFFLOAD_FRAGMENT_SIZE (240 * 1024)
-#define MIN_PCM_OFFLOAD_FRAGMENT_SIZE  512
 
 /*
  * Offload buffer size for compress passthrough
@@ -91,8 +82,6 @@
 #define MIN_COMPRESS_PASSTHROUGH_FRAGMENT_SIZE (2 * 1024)
 #define MAX_COMPRESS_PASSTHROUGH_FRAGMENT_SIZE (8 * 1024)
 
-#define DIV_ROUND_UP(x, y) (((x) + (y) - 1)/(y))
-#define ALIGN(x, y) ((y) * DIV_ROUND_UP((x), (y)))
 /*
  * This file will have a maximum of 38 bytes:
  *
@@ -208,6 +197,7 @@
 } codec_backend_cfg_t;
 
 static native_audio_prop na_props = {0, 0, 0};
+static bool supports_true_32_bit = false;
 
 struct platform_data {
     struct audio_device *adev;
@@ -2382,6 +2372,28 @@
     return ret;
 }
 
+static void true_32_bit_set_params(struct str_parms *parms,
+                                 char *value, int len)
+{
+    int ret = 0;
+
+    ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_TRUE_32_BIT,
+                            value,len);
+    if (ret >= 0) {
+        if (value && !strncmp(value, "true", sizeof("src")))
+            supports_true_32_bit = true;
+        else
+            supports_true_32_bit = false;
+        str_parms_del(parms, AUDIO_PARAMETER_KEY_TRUE_32_BIT);
+    }
+
+}
+
+bool platform_supports_true_32bit()
+{
+    return supports_true_32_bit;
+}
+
 int check_hdset_combo_device(snd_device_t snd_device)
 {
     int ret = false;
@@ -3610,6 +3622,7 @@
 
     native_audio_set_params(platform, parms, value, sizeof(value));
     audio_extn_spkr_prot_set_parameters(parms, value, len);
+    true_32_bit_set_params(parms, value, len);
     ALOGV("%s: exit with code(%d)", __func__, ret);
     return ret;
 }
@@ -3984,33 +3997,6 @@
     return fragment_size;
 }
 
-uint32_t platform_get_pcm_offload_buffer_size(audio_offload_info_t* info)
-{
-    uint32_t fragment_size = 0;
-    uint32_t bytes_per_sample;
-    uint32_t pcm_offload_time = PCM_OFFLOAD_BUFFER_DURATION;
-
-    bytes_per_sample = audio_bytes_per_sample(info->format);
-
-    //duration is set to 40 ms worth of stereo data at 48Khz
-    //with 16 bit per sample, modify this when the channel
-    //configuration is different
-    fragment_size = (pcm_offload_time
-                     * info->sample_rate
-                     * bytes_per_sample
-                     * popcount(info->channel_mask))/1000;
-    if(fragment_size < MIN_PCM_OFFLOAD_FRAGMENT_SIZE)
-        fragment_size = MIN_PCM_OFFLOAD_FRAGMENT_SIZE;
-    else if(fragment_size > MAX_PCM_OFFLOAD_FRAGMENT_SIZE)
-        fragment_size = MAX_PCM_OFFLOAD_FRAGMENT_SIZE;
-    // To have same PCM samples for all channels, the buffer size requires to
-    // be multiple of (number of channels * bytes per sample)
-    // For writes to succeed, the buffer must be written at address which is multiple of 32
-    fragment_size = ALIGN(fragment_size, (bytes_per_sample * popcount(info->channel_mask) * 32));
-
-    ALOGI("PCM offload Fragment size to %d bytes", fragment_size);
-    return fragment_size;
-}
 
 /*
  * configures afe with bit width and Sample Rate
diff --git a/hal/msm8916/platform.h b/hal/msm8916/platform.h
index 22a0eb0..9c2be1a 100644
--- a/hal/msm8916/platform.h
+++ b/hal/msm8916/platform.h
@@ -217,6 +217,8 @@
 #define AUDIO_PARAMETER_KEY_NATIVE_AUDIO "audio.nat.codec.enabled"
 #define AUDIO_PARAMETER_KEY_NATIVE_AUDIO_MODE "native_audio_mode"
 
+#define AUDIO_PARAMETER_KEY_TRUE_32_BIT "true_32_bit"
+
 #define ALL_SESSION_VSID                0xFFFFFFFF
 #define DEFAULT_MUTE_RAMP_DURATION_MS   20
 #define DEFAULT_VOLUME_RAMP_DURATION_MS 20
@@ -251,6 +253,17 @@
 #define HDMI_MULTI_DEFAULT_CHANNEL_COUNT 6
 #define HDMI_MULTI_PERIOD_BYTES (HDMI_MULTI_PERIOD_SIZE * HDMI_MULTI_DEFAULT_CHANNEL_COUNT * 2)
 
+
+/* Used in calculating fragment size for pcm offload */
+#define PCM_OFFLOAD_BUFFER_DURATION 40 /* 40 millisecs */
+
+/* MAX PCM fragment size cannot be increased  further due
+ * to flinger's cblk size of 1mb,and it has to be a multiple of
+ * 24 - lcm of channels supported by DSP
+ */
+#define MAX_PCM_OFFLOAD_FRAGMENT_SIZE (240 * 1024)
+#define MIN_PCM_OFFLOAD_FRAGMENT_SIZE  512
+
 #define AUDIO_CAPTURE_PERIOD_DURATION_MSEC 20
 #define AUDIO_CAPTURE_PERIOD_COUNT 2
 
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index cd63143..83e560a 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -65,24 +65,12 @@
 #define COMPRESS_OFFLOAD_FRAGMENT_SIZE_FOR_AV_STREAMING (2 * 1024)
 #define COMPRESS_OFFLOAD_FRAGMENT_SIZE (32 * 1024)
 
-/* Used in calculating fragment size for pcm offload */
-#define PCM_OFFLOAD_BUFFER_DURATION 40 /* 40 millisecs */
-
-/* MAX PCM fragment size cannot be increased  further due
- * to flinger's cblk size of 1mb,and it has to be a multiple of
- * 24 - lcm of channels supported by DSP
- */
-#define MAX_PCM_OFFLOAD_FRAGMENT_SIZE (240 * 1024)
-#define MIN_PCM_OFFLOAD_FRAGMENT_SIZE 512
-
 /*
  * Offload buffer size for compress passthrough
  */
 #define MIN_COMPRESS_PASSTHROUGH_FRAGMENT_SIZE (2 * 1024)
 #define MAX_COMPRESS_PASSTHROUGH_FRAGMENT_SIZE (8 * 1024)
 
-#define DIV_ROUND_UP(x, y) (((x) + (y) - 1)/(y))
-#define ALIGN(x, y) ((y) * DIV_ROUND_UP((x), (y)))
 /*
  * This file will have a maximum of 38 bytes:
  *
@@ -205,6 +193,7 @@
 } codec_backend_cfg_t;
 
 static native_audio_prop na_props = {0, 0, 0};
+static bool supports_true_32_bit = false;
 typedef int (*acdb_send_gain_dep_cal_t)(int, int, int, int, int);
 
 struct platform_data {
@@ -3421,6 +3410,28 @@
         free(dptr);
 }
 
+static void true_32_bit_set_params(struct str_parms *parms,
+                                 char *value, int len)
+{
+    int ret = 0;
+
+    ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_TRUE_32_BIT,
+                            value,len);
+    if (ret >= 0) {
+        if (value && !strncmp(value, "true", sizeof("src")))
+            supports_true_32_bit = true;
+        else
+            supports_true_32_bit = false;
+        str_parms_del(parms, AUDIO_PARAMETER_KEY_TRUE_32_BIT);
+    }
+
+}
+
+bool platform_supports_true_32bit()
+{
+   return supports_true_32_bit;
+}
+
 static void perf_lock_set_params(struct platform_data *platform,
                           struct str_parms *parms,
                           char *value, int len)
@@ -3576,6 +3587,7 @@
     audio_extn_spkr_prot_set_parameters(parms, value, len);
     audio_extn_usb_set_sidetone_gain(parms, value, len);
     perf_lock_set_params(platform, parms, value, len);
+    true_32_bit_set_params(parms, value, len);
 done:
     ALOGV("%s: exit with code(%d)", __func__, ret);
     if(kv_pairs != NULL)
@@ -3961,35 +3973,6 @@
     return fragment_size;
 }
 
-uint32_t platform_get_pcm_offload_buffer_size(audio_offload_info_t* info)
-{
-    uint32_t fragment_size = 0;
-    uint32_t bytes_per_sample;
-    uint32_t pcm_offload_time = PCM_OFFLOAD_BUFFER_DURATION;
-
-    bytes_per_sample = audio_bytes_per_sample(info->format);
-
-    //duration is set to 40 ms worth of stereo data at 48Khz
-    //with 16 bit per sample, modify this when the channel
-    //configuration is different
-    fragment_size = (pcm_offload_time
-                     * info->sample_rate
-                     * bytes_per_sample
-                     * popcount(info->channel_mask))/1000;
-    if(fragment_size < MIN_PCM_OFFLOAD_FRAGMENT_SIZE)
-        fragment_size = MIN_PCM_OFFLOAD_FRAGMENT_SIZE;
-    else if(fragment_size > MAX_PCM_OFFLOAD_FRAGMENT_SIZE)
-        fragment_size = MAX_PCM_OFFLOAD_FRAGMENT_SIZE;
-
-    // To have same PCM samples for all channels, the buffer size requires to
-    // be multiple of (number of channels * bytes per sample)
-    // For writes to succeed, the buffer must be written at address which is multiple of 32
-    fragment_size = ALIGN(fragment_size, ((bytes_per_sample) * popcount(info->channel_mask) * 32));
-
-    ALOGI("PCM offload Fragment size to %d bytes", fragment_size);
-    return fragment_size;
-}
-
 /*
  * configures afe with bit width and Sample Rate
  */
diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h
index eb04109..019678a 100644
--- a/hal/msm8974/platform.h
+++ b/hal/msm8974/platform.h
@@ -208,6 +208,8 @@
 #define AUDIO_PARAMETER_KEY_NATIVE_AUDIO "audio.nat.codec.enabled"
 #define AUDIO_PARAMETER_KEY_NATIVE_AUDIO_MODE "native_audio_mode"
 
+#define AUDIO_PARAMETER_KEY_TRUE_32_BIT "true_32_bit"
+
 #define ALL_SESSION_VSID                0xFFFFFFFF
 #define DEFAULT_MUTE_RAMP_DURATION_MS   20
 #define DEFAULT_VOLUME_RAMP_DURATION_MS 20
@@ -237,6 +239,17 @@
 #define HDMI_MULTI_DEFAULT_CHANNEL_COUNT 6
 #define HDMI_MULTI_PERIOD_BYTES (HDMI_MULTI_PERIOD_SIZE * HDMI_MULTI_DEFAULT_CHANNEL_COUNT * 2)
 
+
+/* Used in calculating fragment size for pcm offload */
+#define PCM_OFFLOAD_BUFFER_DURATION 40 /* 40 millisecs */
+
+/* MAX PCM fragment size cannot be increased  further due
+ * to flinger's cblk size of 1mb,and it has to be a multiple of
+ * 24 - lcm of channels supported by DSP
+ */
+#define MAX_PCM_OFFLOAD_FRAGMENT_SIZE (240 * 1024)
+#define MIN_PCM_OFFLOAD_FRAGMENT_SIZE 512
+
 #define AUDIO_CAPTURE_PERIOD_DURATION_MSEC 20
 #define AUDIO_CAPTURE_PERIOD_COUNT 2
 
diff --git a/hal/platform_api.h b/hal/platform_api.h
index fc1c440..0bb73f3 100644
--- a/hal/platform_api.h
+++ b/hal/platform_api.h
@@ -108,7 +108,6 @@
 
 struct audio_offload_info_t;
 uint32_t platform_get_compress_offload_buffer_size(audio_offload_info_t* info);
-uint32_t platform_get_pcm_offload_buffer_size(audio_offload_info_t* info);
 uint32_t platform_get_compress_passthrough_buffer_size(audio_offload_info_t* info);
 
 bool platform_check_and_set_codec_backend_cfg(struct audio_device* adev,
@@ -151,4 +150,5 @@
                           snd_device_t out_snd_device,
                           bool enable,
                           char * str);
+bool platform_supports_true_32bit();
 #endif // AUDIO_PLATFORM_API_H