Merge "qahw: test: Add condition check for fwrite" into audio-userspace.lnx.2.2-dev
diff --git a/Makefile.am b/Makefile.am
index 57c0c82..299385d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,2 +1,7 @@
-SUBDIRS = hal qahw_api qahw_api/test
+SUBDIRS = hal
+
+if QAHW_SUPPORT
+SUBDIRS += qahw_api qahw_api/test
+endif
+
 ACLOCAL_AMFLAGS = -I m4
diff --git a/configure.ac b/configure.ac
index c4c43c9..cbc082c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -56,6 +56,8 @@
 
 AM_CONDITIONAL(USE_GLIB, test "x${with_glib}" = "xyes")
 
+AM_CONDITIONAL([QAHW_SUPPORT], [test x$BOARD_SUPPORTS_QAHW = xtrue])
+
 AM_CONDITIONAL([HDMI_EDID],    [test x$AUDIO_FEATURE_ENABLED_HDMI_EDID = xtrue])
 AM_CONDITIONAL([FM_POWER_OPT], [test x$AUDIO_FEATURE_ENABLED_FM_POWER_OPT = xtrue])
 AM_CONDITIONAL([USBAUDIO], [test x$AUDIO_FEATURE_ENABLED_USBAUDIO = xtrue])
@@ -78,6 +80,8 @@
 AM_CONDITIONAL([ALAC_SUPPORT], [test x$AUDIO_FEATURE_ENABLED_EXTN_ALAC_DECODER = xtrue])
 AM_CONDITIONAL([VORBIS_SUPPORT], [test x$AUDIO_FEATURE_ENABLED_EXTN_VORBIS_DECODER = xtrue])
 AM_CONDITIONAL([WMA_SUPPORT], [test x$AUDIO_FEATURE_ENABLED_EXTN_WMA_DECODER = xtrue])
+AM_CONDITIONAL([COMPRESS_INPUT], [test x$AUDIO_FEATURE_ENABLED_COMPRESS_INPUT = xtrue])
+AM_CONDITIONAL([AUDIO_HW_EXTN_API], [test x$BOARD_SUPPORTS_QAHW = xtrue])
 
 AC_CONFIG_FILES([ \
         Makefile \
diff --git a/hal/Android.mk b/hal/Android.mk
index f971b85..570e556 100644
--- a/hal/Android.mk
+++ b/hal/Android.mk
@@ -254,6 +254,16 @@
     LOCAL_SRC_FILES += audio_extn/qaf.c
 endif
 
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_COMPRESS_INPUT)),true)
+    LOCAL_CFLAGS += -DCOMPRESS_INPUT_ENABLED
+    LOCAL_SRC_FILES += audio_extn/compress_in.c
+endif
+
+ifeq ($(strip $(BOARD_SUPPORTS_QAHW)),true)
+    LOCAL_CFLAGS += -DAUDIO_HW_EXTN_API_ENABLED
+    LOCAL_SRC_FILES += audio_hw_extn_api.c
+endif
+
 LOCAL_SHARED_LIBRARIES := \
 	liblog \
 	libcutils \
@@ -262,7 +272,6 @@
 	libaudioroute \
 	libdl \
 	libaudioutils \
-	libhardware \
 	libexpat
 
 LOCAL_C_INCLUDES += \
diff --git a/hal/Makefile.am b/hal/Makefile.am
index c6e3072..6e1b9f4 100644
--- a/hal/Makefile.am
+++ b/hal/Makefile.am
@@ -123,6 +123,16 @@
 AM_CFLAGS += -DCOMPRESS_METADATA_NEEDED
 endif
 
+if COMPRESS_INPUT
+AM_CFLAGS += -DCOMPRESS_INPUT_ENABLED
+c_sources += audio_extn/compress_in.c
+endif
+
+if AUDIO_HW_EXTN_API
+AM_CFLAGS += -DAUDIO_HW_EXTN_API_ENABLED
+c_sources += audio_hw_extn_api.c
+endif
+
 h_sources = audio_extn/audio_defs.h \
             audio_extn/audio_extn.h \
             audio_hw.h \
diff --git a/hal/audio_extn/audio_defs.h b/hal/audio_extn/audio_defs.h
index 1c5da54..ee4f7d4 100644
--- a/hal/audio_extn/audio_defs.h
+++ b/hal/audio_extn/audio_defs.h
@@ -103,4 +103,38 @@
 
 #define AUDIO_PARAMETER_IS_HW_DECODER_SESSION_ALLOWED  "is_hw_dec_session_allowed"
 
+/* Set or Query stream profile type */
+#define AUDIO_PARAMETER_STREAM_PROFILE "audio_stream_profile"
+
+/* audio inout flag for timestamp mode.
+ * check other input flags defined in audio.h for conflicts
+ */
+#define AUDIO_INPUT_FLAG_TIMESTAMP 0x80000000
+
+/* MAX SECTORS for sourcetracking feature */
+#define MAX_SECTORS 8
+
+struct qahw_source_tracking_param {
+    uint8_t   vad[MAX_SECTORS];
+    uint16_t  doa_speech;
+    uint16_t  doa_noise[3];
+    uint8_t   polar_activity[360];
+};
+
+struct qahw_sound_focus_param {
+    uint16_t  start_angle[MAX_SECTORS];
+    uint8_t   enable[MAX_SECTORS];
+    uint16_t  gain_step;
+};
+
+typedef union {
+    struct qahw_source_tracking_param st_params;
+    struct qahw_sound_focus_param sf_params;
+} qahw_param_payload;
+
+typedef enum {
+    QAHW_PARAM_SOURCE_TRACK,
+    QAHW_PARAM_SOUND_FOCUS
+} qahw_param_id;
+
 #endif /* AUDIO_DEFS_H */
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index 07714f6..337acd1 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -501,14 +501,17 @@
 void audio_extn_pm_unvote(void);
 #endif
 
-void audio_extn_utils_update_streams_output_cfg_list(void *platform,
+void audio_extn_utils_update_streams_cfg_lists(void *platform,
                                   struct mixer *mixer,
-                                  struct listnode *streams_output_cfg_list);
-void audio_extn_utils_dump_streams_output_cfg_list(
-                                  struct listnode *streams_output_cfg_list);
-void audio_extn_utils_release_streams_output_cfg_list(
-                                  struct listnode *streams_output_cfg_list);
-void audio_extn_utils_update_stream_app_type_cfg(void *platform,
+                                  struct listnode *streams_output_cfg_list,
+                                  struct listnode *streams_input_cfg_list);
+void audio_extn_utils_dump_streams_cfg_lists(
+                                  struct listnode *streams_output_cfg_list,
+                                  struct listnode *streams_input_cfg_list);
+void audio_extn_utils_release_streams_cfg_lists(
+                                  struct listnode *streams_output_cfg_list,
+                                  struct listnode *streams_input_cfg_list);
+void audio_extn_utils_update_stream_output_app_type_cfg(void *platform,
                                   struct listnode *streams_output_cfg_list,
                                   audio_devices_t devices,
                                   audio_output_flags_t flags,
@@ -516,11 +519,24 @@
                                   uint32_t sample_rate,
                                   uint32_t bit_width,
                                   audio_channel_mask_t channel_mask,
+                                  char *profile,
+                                  struct stream_app_type_cfg *app_type_cfg);
+void audio_extn_utils_update_stream_input_app_type_cfg(void *platform,
+                                  struct listnode *streams_input_cfg_list,
+                                  audio_devices_t devices,
+                                  audio_input_flags_t flags,
+                                  audio_format_t format,
+                                  uint32_t sample_rate,
+                                  uint32_t bit_width,
+                                  char *profile,
                                   struct stream_app_type_cfg *app_type_cfg);
 int audio_extn_utils_send_app_type_cfg(struct audio_device *adev,
                                        struct audio_usecase *usecase);
 void audio_extn_utils_send_audio_calibration(struct audio_device *adev,
                                              struct audio_usecase *usecase);
+void audio_extn_utils_update_stream_app_type_cfg_for_usecase(
+                                  struct audio_device *adev,
+                                  struct audio_usecase *usecase);
 #ifdef DS2_DOLBY_DAP_ENABLED
 #define LIB_DS2_DAP_HAL "vendor/lib/libhwdaphal.so"
 #define SET_HW_INFO_FUNC "dap_hal_set_hw_info"
@@ -577,6 +593,8 @@
 uint32_t hal_format_to_pcm(audio_format_t hal_format);
 
 void audio_extn_utils_update_direct_pcm_fragment_size(struct stream_out *out);
+size_t audio_extn_utils_convert_format_24_8_to_8_24(void *buf, size_t bytes);
+int get_snd_codec_id(audio_format_t format);
 
 #ifndef KPI_OPTIMIZE_ENABLED
 #define audio_extn_perf_lock_init() (0)
@@ -683,4 +701,25 @@
 int audio_extn_snd_mon_unregister_listener(void *stream);
 #endif
 
+#ifdef COMPRESS_INPUT_ENABLED
+bool audio_extn_cin_applicable_stream(struct stream_in *in);
+bool audio_extn_cin_attached_usecase(audio_usecase_t uc_id);
+size_t audio_extn_cin_get_buffer_size(struct stream_in *in);
+int audio_extn_cin_start_input_stream(struct stream_in *in);
+void audio_extn_cin_stop_input_stream(struct stream_in *in);
+void audio_extn_cin_close_input_stream(struct stream_in *in);
+int audio_extn_cin_read(struct stream_in *in, void *buffer,
+                        size_t bytes, size_t *bytes_read);
+int audio_extn_cin_configure_input_stream(struct stream_in *in);
+#else
+#define audio_extn_cin_applicable_stream(in) (false)
+#define audio_extn_cin_attached_usecase(uc_id) (false)
+#define audio_extn_cin_get_buffer_size(in) (0)
+#define audio_extn_cin_start_input_stream(in) (0)
+#define audio_extn_cin_stop_input_stream(in) (0)
+#define audio_extn_cin_close_input_stream(in) (0)
+#define audio_extn_cin_read(in, buffer, bytes, bytes_read) (0)
+#define audio_extn_cin_configure_input_stream(in) (0)
+#endif
+
 #endif /* AUDIO_EXTN_H */
diff --git a/hal/audio_extn/compress_in.c b/hal/audio_extn/compress_in.c
new file mode 100644
index 0000000..403ee8b
--- /dev/null
+++ b/hal/audio_extn/compress_in.c
@@ -0,0 +1,314 @@
+/*
+* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are
+* met:
+*     * Redistributions of source code must retain the above copyright
+*       notice, this list of conditions and the following disclaimer.
+*     * Redistributions in binary form must reproduce the above
+*       copyright notice, this list of conditions and the following
+*       disclaimer in the documentation and/or other materials provided
+*       with the distribution.
+*     * Neither the name of The Linux Foundation nor the names of its
+*       contributors may be used to endorse or promote products derived
+*       from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+* ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#define LOG_TAG "audio_hw_cin"
+/*#define LOG_NDEBUG 0*/
+#define LOG_NDDEBUG 0
+
+#ifdef COMPRESS_INPUT_ENABLED
+#include <cutils/log.h>
+#include <cutils/properties.h>
+#include <cutils/str_parms.h>
+#include <cutils/log.h>
+
+#include "audio_hw.h"
+#include "platform.h"
+#include "platform_api.h"
+
+#include <hardware/audio.h>
+#include <errno.h>
+#include <time.h>
+#include <stdlib.h>
+#include <dlfcn.h>
+
+#include "audio_extn.h"
+#include "audio_defs.h"
+#include "sound/compress_params.h"
+
+/* default timestamp metadata definition if not defined in kernel*/
+#ifndef COMPRESSED_TIMESTAMP_FLAG
+#define COMPRESSED_TIMESTAMP_FLAG 0
+struct snd_codec_metadata {
+uint64_t timestamp;
+};
+#define compress_config_set_timstamp_flag(config) (-ENOSYS)
+#else
+#define compress_config_set_timstamp_flag(config) \
+            (config)->codec->flags |= COMPRESSED_TIMESTAMP_FLAG
+#endif
+
+#define COMPRESS_RECORD_NUM_FRAGMENTS 8
+
+struct cin_private_data {
+    struct compr_config compr_config;
+    struct compress *compr;
+};
+
+typedef struct cin_private_data cin_private_data_t;
+
+static unsigned int cin_usecases_state;
+
+static const audio_usecase_t cin_usecases[] = {
+    USECASE_AUDIO_RECORD_COMPRESS2,
+    USECASE_AUDIO_RECORD_COMPRESS3,
+    USECASE_AUDIO_RECORD_COMPRESS4
+};
+
+static pthread_mutex_t cin_lock = PTHREAD_MUTEX_INITIALIZER;
+
+bool audio_extn_cin_applicable_stream(struct stream_in *in)
+{
+    if ((in->flags & AUDIO_INPUT_FLAG_TIMESTAMP) ||
+        in->usecase == USECASE_AUDIO_RECORD_COMPRESS2)
+        return true;
+
+    return false;
+}
+
+/* all audio_extn_cin_xxx calls must be made on an input
+ * only after validating that input against audio_extn_cin_attached_usecase
+ * except below calls
+ * 1. audio_extn_cin_applicable_stream(in)
+ * 2. audio_extn_cin_configure_input_stream(in)
+ */
+
+bool audio_extn_cin_attached_usecase(audio_usecase_t uc_id)
+{
+    unsigned int i;
+
+    for (i = 0; i < sizeof(cin_usecases)/
+                    sizeof(cin_usecases[0]); i++) {
+        if (uc_id == cin_usecases[i] &&
+            (cin_usecases_state & (0x1 << i)))
+            return true;
+    }
+    return false;
+}
+
+static audio_usecase_t get_cin_usecase(void)
+{
+    audio_usecase_t ret_uc = USECASE_INVALID;
+    unsigned int i, num_usecase = sizeof(cin_usecases) / sizeof(cin_usecases[0]);
+    char value[PROPERTY_VALUE_MAX] = {0};
+
+    property_get("audio.record.multiple.enabled", value, NULL);
+    if (!(atoi(value) || !strncmp("true", value, 4)))
+        num_usecase = 1; /* If prop is not set, limit the num of record usecases to 1 */
+
+    ALOGV("%s: num_usecase: %d", __func__, num_usecase);
+    pthread_mutex_lock(&cin_lock);
+    for (i = 0; i < num_usecase; i++) {
+        if (!(cin_usecases_state & (0x1 << i))) {
+            cin_usecases_state |= 0x1 << i;
+            ret_uc = cin_usecases[i];
+            break;
+        }
+    }
+    pthread_mutex_unlock(&cin_lock);
+    ALOGV("%s: picked usecase: %d", __func__, ret_uc);
+    return ret_uc;
+}
+
+static void free_cin_usecase(audio_usecase_t uc_id)
+{
+    unsigned int i;
+
+    ALOGV("%s: free usecase %d", __func__, uc_id);
+    pthread_mutex_lock(&cin_lock);
+    for (i = 0; i < sizeof(cin_usecases) /
+                    sizeof(cin_usecases[0]); i++) {
+        if (uc_id == cin_usecases[i])
+            cin_usecases_state &= ~(0x1 << i);
+            break;
+    }
+    pthread_mutex_unlock(&cin_lock);
+}
+
+size_t audio_extn_cin_get_buffer_size(struct stream_in *in)
+{
+    size_t sz = 0;
+    cin_private_data_t *cin_data = (cin_private_data_t *) in->cin_extn;
+
+    sz = cin_data->compr_config.fragment_size;
+    if (in->flags & AUDIO_INPUT_FLAG_TIMESTAMP)
+        sz -= sizeof(struct snd_codec_metadata);
+
+    ALOGV("%s: in %p, flags 0x%x, cin_data %p, size %zd",
+                  __func__, in, in->flags, cin_data, sz);
+    return sz;
+}
+
+int audio_extn_cin_start_input_stream(struct stream_in *in)
+{
+    int ret = -EINVAL;
+    struct audio_device *adev = in->dev;
+    cin_private_data_t *cin_data = (cin_private_data_t *) in->cin_extn;
+
+    ALOGV("%s: in %p, cin_data %p", __func__, in, cin_data);
+    cin_data->compr = compress_open(adev->snd_card, in->pcm_device_id,
+                                    COMPRESS_OUT, &cin_data->compr_config);
+    if (cin_data->compr == NULL || !is_compress_ready(cin_data->compr)) {
+        ALOGE("%s: %s", __func__,
+              cin_data->compr ? compress_get_error(cin_data->compr) : "null");
+        if (cin_data->compr) {
+            compress_close(cin_data->compr);
+            cin_data->compr = NULL;
+        }
+        ret = -EIO;
+    } else {
+        ret = 0;
+    }
+    return ret;
+}
+
+void audio_extn_cin_stop_input_stream(struct stream_in *in)
+{
+    cin_private_data_t *cin_data = (cin_private_data_t *) in->cin_extn;
+
+    ALOGV("%s: in %p, cin_data %p", __func__, in, cin_data);
+    if (cin_data->compr) {
+        compress_close(cin_data->compr);
+        cin_data->compr = NULL;
+    }
+}
+
+void audio_extn_cin_close_input_stream(struct stream_in *in)
+{
+    cin_private_data_t *cin_data = (cin_private_data_t *) in->cin_extn;
+
+    ALOGV("%s: in %p, cin_data %p", __func__, in, cin_data);
+    if (cin_data) {
+        free(cin_data->compr_config.codec);
+        free(cin_data);
+    }
+    free_cin_usecase(in->usecase);
+}
+
+int audio_extn_cin_read(struct stream_in *in, void *buffer,
+                        size_t bytes, size_t *bytes_read)
+{
+    int ret = -EINVAL;
+    size_t read_size = bytes;
+    size_t mdata_size = (sizeof(struct snd_codec_metadata));
+    cin_private_data_t *cin_data = (cin_private_data_t *) in->cin_extn;
+
+    if (cin_data->compr) {
+        /* start stream if not already done */
+        if (!is_compress_running(cin_data->compr))
+            compress_start(cin_data->compr);
+
+        if (!(in->flags & AUDIO_INPUT_FLAG_TIMESTAMP))
+            mdata_size = 0;
+
+        if (buffer && read_size) {
+            read_size = compress_read(cin_data->compr, buffer, read_size);
+            if (read_size == bytes) {
+                /* set ret to 0 if compress_read succeeded*/
+                ret = 0;
+                *bytes_read = bytes;
+                /* data from DSP comes in 24_8 format, convert it to 8_24 */
+                if (in->format == AUDIO_FORMAT_PCM_8_24_BIT) {
+                    if (audio_extn_utils_convert_format_24_8_to_8_24(
+                                          (char *)buffer + mdata_size, bytes) != bytes)
+                        ret = -EIO;
+                }
+            } else {
+                ret = errno;
+                ALOGE("%s: failed error = %d, read = %zd, err_str %s", __func__,
+                           ret, read_size, compress_get_error(cin_data->compr));
+            }
+        }
+    }
+    ALOGV("%s: in %p, flags 0x%x, buf %p, bytes %zd, read_size %zd, ret %d",
+                        __func__, in, in->flags, buffer, bytes, read_size, ret);
+    return ret;
+}
+
+int audio_extn_cin_configure_input_stream(struct stream_in *in)
+{
+    struct audio_device *adev = in->dev;
+    struct audio_config config = {.format = 0};
+    int ret = 0, buffer_size = 0, meta_size = sizeof(struct snd_codec_metadata);
+    cin_private_data_t *cin_data = NULL;
+
+    if (!COMPRESSED_TIMESTAMP_FLAG &&
+        (in->flags & AUDIO_INPUT_FLAG_TIMESTAMP)) {
+        ALOGE("%s: timestamp mode not supported!", __func__);
+        return -EINVAL;
+    }
+
+    cin_data = (cin_private_data_t *) calloc(1, sizeof(cin_private_data_t));
+    in->cin_extn = (void *)cin_data;
+    if (!cin_data) {
+        ALOGE("%s, allocation for private data failed!", __func__);
+        return -ENOMEM;
+    }
+
+    cin_data->compr_config.codec = (struct snd_codec *)
+                              calloc(1, sizeof(struct snd_codec));
+    if (!cin_data->compr_config.codec) {
+        ALOGE("%s, allocation for codec data failed!", __func__);
+        ret = -ENOMEM;
+        goto err_config;
+    }
+
+    in->usecase = get_cin_usecase();
+    if (in->usecase == USECASE_INVALID) {
+        ALOGE("%s, Max allowed compress record usecase reached!", __func__);
+        ret = -EEXIST;
+        goto err_config;
+    }
+
+    config.sample_rate = in->sample_rate;
+    config.channel_mask = in->channel_mask;
+    config.format = in->format;
+    in->config.channels = audio_channel_count_from_in_mask(in->channel_mask);
+    buffer_size = adev->device.get_input_buffer_size(&adev->device, &config);
+
+    cin_data->compr_config.fragment_size = buffer_size;
+    cin_data->compr_config.codec->id = get_snd_codec_id(in->format);
+    cin_data->compr_config.fragments = COMPRESS_RECORD_NUM_FRAGMENTS;
+    cin_data->compr_config.codec->sample_rate = in->sample_rate;
+    cin_data->compr_config.codec->ch_in = in->config.channels;
+    cin_data->compr_config.codec->ch_out = in->config.channels;
+    cin_data->compr_config.codec->format = hal_format_to_alsa(in->format);
+    if (in->flags & AUDIO_INPUT_FLAG_TIMESTAMP) {
+        compress_config_set_timstamp_flag(&cin_data->compr_config);
+        cin_data->compr_config.fragment_size += meta_size;
+    }
+    ALOGD("%s: format %d flags 0x%x SR %d CM 0x%x buf_size %d in %p",
+          __func__, in->format, in->flags, in->sample_rate, in->channel_mask,
+          cin_data->compr_config.fragment_size, in);
+    return ret;
+
+err_config:
+    audio_extn_cin_close_input_stream(in);
+    return ret;
+}
+#endif /* COMPRESS_INPUT_ENABLED end */
diff --git a/hal/audio_extn/source_track.c b/hal/audio_extn/source_track.c
index 0a0b970..d34ed6b 100644
--- a/hal/audio_extn/source_track.c
+++ b/hal/audio_extn/source_track.c
@@ -502,6 +502,36 @@
     }
 }
 
+int audio_extn_get_soundfocus_data(const struct audio_device *adev,
+                                   struct sound_focus_param *payload)
+{
+    int ret = 0;
+    int bitmask =0;
+    struct sound_focus_param *sound_focus_data = payload;
+
+    bitmask = BITMASK_AUDIO_PARAMETER_KEYS_SOUND_FOCUS;
+
+    ret = get_soundfocus_sourcetracking_data(adev, bitmask,
+                    sound_focus_data, NULL);
+
+    return ret ;
+}
+
+int audio_extn_get_sourcetrack_data(const struct audio_device *adev,
+                              struct source_tracking_param *payload)
+{
+    int ret = 0;
+    int bitmask = 0;
+    struct source_tracking_param *source_tracking_data = payload;
+
+    bitmask = BITMASK_AUDIO_PARAMETER_KEYS_SOURCE_TRACKING;
+
+    ret = get_soundfocus_sourcetracking_data(adev, bitmask,
+                    NULL, source_tracking_data);
+
+    return ret ;
+}
+
 void audio_extn_source_track_get_parameters(const struct audio_device *adev,
                                             struct str_parms *query,
                                             struct str_parms *reply)
diff --git a/hal/audio_extn/utils.c b/hal/audio_extn/utils.c
index 90b39b5..b14b1e7 100644
--- a/hal/audio_extn/utils.c
+++ b/hal/audio_extn/utils.c
@@ -34,6 +34,7 @@
 #include "platform_api.h"
 #include "audio_extn.h"
 #include "voice.h"
+#include "sound/compress_params.h"
 
 #ifdef AUDIO_EXTERNAL_HDMI_ENABLED
 #ifdef HDMI_PASSTHROUGH_ENABLED
@@ -43,14 +44,18 @@
 
 #ifdef LINUX_ENABLED
 #define AUDIO_OUTPUT_POLICY_VENDOR_CONFIG_FILE "/etc/audio_output_policy.conf"
+#define AUDIO_IO_POLICY_VENDOR_CONFIG_FILE "/etc/audio_io_policy.conf"
 #else
 #define AUDIO_OUTPUT_POLICY_VENDOR_CONFIG_FILE "/vendor/etc/audio_output_policy.conf"
+#define AUDIO_IO_POLICY_VENDOR_CONFIG_FILE "/vendor/etc/audio_io_policy.conf"
 #endif
 
 #define OUTPUTS_TAG "outputs"
+#define INPUTS_TAG "inputs"
 
 #define DYNAMIC_VALUE_TAG "dynamic"
 #define FLAGS_TAG "flags"
+#define PROFILES_TAG "profile"
 #define FORMATS_TAG "formats"
 #define SAMPLING_RATES_TAG "sampling_rates"
 #define BIT_WIDTH_TAG "bit_width"
@@ -95,6 +100,12 @@
     STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_INCALL_MUSIC),
 #endif
     STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_COMPRESS_PASSTHROUGH),
+    STRING_TO_ENUM(AUDIO_INPUT_FLAG_NONE),
+    STRING_TO_ENUM(AUDIO_INPUT_FLAG_FAST),
+    STRING_TO_ENUM(AUDIO_INPUT_FLAG_HW_HOTWORD),
+    STRING_TO_ENUM(AUDIO_INPUT_FLAG_RAW),
+    STRING_TO_ENUM(AUDIO_INPUT_FLAG_SYNC),
+    STRING_TO_ENUM(AUDIO_INPUT_FLAG_TIMESTAMP),
 };
 
 const struct string_to_enum s_format_name_to_enum_table[] = {
@@ -161,9 +172,10 @@
     return 0;
 }
 
-static audio_output_flags_t parse_flag_names(char *name)
+static audio_io_flags_t parse_flag_names(char *name)
 {
     uint32_t flag = 0;
+    audio_io_flags_t io_flags;
     char *last_r;
     char *flag_name = strtok_r(name, "|", &last_r);
     while (flag_name != NULL) {
@@ -176,10 +188,12 @@
     }
 
     ALOGV("parse_flag_names: flag - %d", flag);
-    return (audio_output_flags_t)flag;
+    io_flags.in_flags = (audio_input_flags_t)flag;
+    io_flags.out_flags = (audio_output_flags_t)flag;
+    return io_flags;
 }
 
-static void parse_format_names(char *name, struct streams_output_cfg *so_info)
+static void parse_format_names(char *name, struct streams_io_cfg *s_info)
 {
     struct stream_format *sf_info = NULL;
     char *last_r;
@@ -188,7 +202,7 @@
     if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG) == 0)
         return;
 
-    list_init(&so_info->format_list);
+    list_init(&s_info->format_list);
     while (str != NULL) {
         audio_format_t format = (audio_format_t)string_to_enum(s_format_name_to_enum_table,
                                               ARRAY_SIZE(s_format_name_to_enum_table), str);
@@ -199,13 +213,13 @@
                 break; /* return whatever was parsed */
 
             sf_info->format = format;
-            list_add_tail(&so_info->format_list, &sf_info->list);
+            list_add_tail(&s_info->format_list, &sf_info->list);
         }
         str = strtok_r(NULL, "|", &last_r);
     }
 }
 
-static void parse_sample_rate_names(char *name, struct streams_output_cfg *so_info)
+static void parse_sample_rate_names(char *name, struct streams_io_cfg *s_info)
 {
     struct stream_sample_rate *ss_info = NULL;
     uint32_t sample_rate = 48000;
@@ -215,7 +229,7 @@
     if (str != NULL && 0 == strcmp(str, DYNAMIC_VALUE_TAG))
         return;
 
-    list_init(&so_info->sample_rate_list);
+    list_init(&s_info->sample_rate_list);
     while (str != NULL) {
         sample_rate = (uint32_t)strtol(str, (char **)NULL, 10);
         ALOGV("%s: sample_rate - %d", __func__, sample_rate);
@@ -226,7 +240,7 @@
                 return;
             }
             ss_info->sample_rate = sample_rate;
-            list_add_tail(&so_info->sample_rate_list, &ss_info->list);
+            list_add_tail(&s_info->sample_rate_list, &ss_info->list);
         }
         str = strtok_r(NULL, "|", &last_r);
     }
@@ -258,65 +272,82 @@
     return app_type;
 }
 
-static void update_streams_output_cfg_list(cnode *root, void *platform,
-                                           struct listnode *streams_output_cfg_list)
+static void update_streams_cfg_list(cnode *root, void *platform,
+                                    struct listnode *streams_cfg_list)
 {
     cnode *node = root->first_child;
-    struct streams_output_cfg *so_info;
+    struct streams_io_cfg *s_info;
 
     ALOGV("%s", __func__);
-    so_info = (struct streams_output_cfg *)calloc(1, sizeof(struct streams_output_cfg));
+    s_info = (struct streams_io_cfg *)calloc(1, sizeof(struct streams_io_cfg));
 
-    if (!so_info) {
-        ALOGE("failed to allocate mem for so_info list element");
+    if (!s_info) {
+        ALOGE("failed to allocate mem for s_info list element");
         return;
     }
 
     while (node) {
         if (strcmp(node->name, FLAGS_TAG) == 0) {
-            so_info->flags = parse_flag_names((char *)node->value);
+            s_info->flags = parse_flag_names((char *)node->value);
+        } else if (strcmp(node->name, PROFILES_TAG) == 0) {
+            strlcpy(s_info->profile, (char *)node->value, sizeof(s_info->profile));
         } else if (strcmp(node->name, FORMATS_TAG) == 0) {
-            parse_format_names((char *)node->value, so_info);
+            parse_format_names((char *)node->value, s_info);
         } else if (strcmp(node->name, SAMPLING_RATES_TAG) == 0) {
-            so_info->app_type_cfg.sample_rate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
-            parse_sample_rate_names((char *)node->value, so_info);
+            s_info->app_type_cfg.sample_rate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
+            parse_sample_rate_names((char *)node->value, s_info);
         } else if (strcmp(node->name, BIT_WIDTH_TAG) == 0) {
-            so_info->app_type_cfg.bit_width = parse_bit_width_names((char *)node->value);
+            s_info->app_type_cfg.bit_width = parse_bit_width_names((char *)node->value);
         } else if (strcmp(node->name, APP_TYPE_TAG) == 0) {
-            so_info->app_type_cfg.app_type = parse_app_type_names(platform, (char *)node->value);
+            s_info->app_type_cfg.app_type = parse_app_type_names(platform, (char *)node->value);
         }
         node = node->next;
     }
-    list_add_tail(streams_output_cfg_list, &so_info->list);
+    list_add_tail(streams_cfg_list, &s_info->list);
 }
 
-static void load_output(cnode *root, void *platform,
-                        struct listnode *streams_output_cfg_list)
+static void load_cfg_list(cnode *root, void *platform,
+                          struct listnode *streams_output_cfg_list,
+                          struct listnode *streams_input_cfg_list)
 {
-    cnode *node = config_find(root, OUTPUTS_TAG);
-    if (node == NULL) {
-        ALOGE("%s: could not load output, node is NULL", __func__);
-        return;
+    cnode *node = NULL;
+
+    node = config_find(root, OUTPUTS_TAG);
+    if (node != NULL) {
+        node = node->first_child;
+        while (node) {
+            ALOGV("%s: loading output %s", __func__, node->name);
+            update_streams_cfg_list(node, platform, streams_output_cfg_list);
+            node = node->next;
+        }
+    } else {
+        ALOGI("%s: could not load output, node is NULL", __func__);
     }
 
-    node = node->first_child;
-    while (node) {
-        ALOGV("%s: loading output %s", __func__, node->name);
-        update_streams_output_cfg_list(node, platform, streams_output_cfg_list);
-        node = node->next;
+    node = config_find(root, INPUTS_TAG);
+    if (node != NULL) {
+        node = node->first_child;
+        while (node) {
+            ALOGV("%s: loading input %s", __func__, node->name);
+            update_streams_cfg_list(node, platform, streams_input_cfg_list);
+            node = node->next;
+        }
+    } else {
+        ALOGI("%s: could not load input, node is NULL", __func__);
     }
 }
 
 static void send_app_type_cfg(void *platform, struct mixer *mixer,
-                              struct listnode *streams_output_cfg_list)
+                              struct listnode *streams_output_cfg_list,
+                              struct listnode *streams_input_cfg_list)
 {
-    int app_type_cfg[MAX_LENGTH_MIXER_CONTROL_IN_INT] = {-1};
+    size_t app_type_cfg[MAX_LENGTH_MIXER_CONTROL_IN_INT] = {0};
     int length = 0, i, num_app_types = 0;
     struct listnode *node;
     bool update;
     struct mixer_ctl *ctl = NULL;
     const char *mixer_ctl_name = "App Type Config";
-    struct streams_output_cfg *so_info;
+    struct streams_io_cfg *s_info = NULL;
 
     if (!mixer) {
         ALOGE("%s: mixer is null",__func__);
@@ -327,32 +358,63 @@
         ALOGE("%s: Could not get ctl for mixer cmd - %s",__func__, mixer_ctl_name);
         return;
     }
-    if (streams_output_cfg_list == NULL) {
-        app_type_cfg[length++] = 1;
-        app_type_cfg[length++] = platform_get_default_app_type(platform);
+    app_type_cfg[length++] = num_app_types;
+
+    if (list_empty(streams_output_cfg_list)) {
+        app_type_cfg[length++] = platform_get_default_app_type_v2(platform, PCM_PLAYBACK);
         app_type_cfg[length++] = 48000;
         app_type_cfg[length++] = 16;
-        mixer_ctl_set_array(ctl, app_type_cfg, length);
-        return;
+        num_app_types += 1;
+    }
+    if (list_empty(streams_input_cfg_list)) {
+        app_type_cfg[length++] = platform_get_default_app_type_v2(platform, PCM_CAPTURE);
+        app_type_cfg[length++] = 48000;
+        app_type_cfg[length++] = 16;
+        num_app_types += 1;
     }
 
-    app_type_cfg[length++] = num_app_types;
     list_for_each(node, streams_output_cfg_list) {
-        so_info = node_to_item(node, struct streams_output_cfg, list);
+        s_info = node_to_item(node, struct streams_io_cfg, list);
         update = true;
         for (i=0; i<length; i=i+3) {
-            if (app_type_cfg[i+1] == -1)
+            if (app_type_cfg[i+1] == 0)
                 break;
-            else if (app_type_cfg[i+1] == so_info->app_type_cfg.app_type) {
+            else if (app_type_cfg[i+1] == (size_t)s_info->app_type_cfg.app_type) {
+                if (app_type_cfg[i+2] < s_info->app_type_cfg.sample_rate)
+                    app_type_cfg[i+2] = s_info->app_type_cfg.sample_rate;
+                if (app_type_cfg[i+3] < s_info->app_type_cfg.bit_width)
+                    app_type_cfg[i+3] = s_info->app_type_cfg.bit_width;
                 update = false;
                 break;
             }
         }
         if (update && ((length + 3) <= MAX_LENGTH_MIXER_CONTROL_IN_INT)) {
-            num_app_types += 1 ;
-            app_type_cfg[length++] = so_info->app_type_cfg.app_type;
-            app_type_cfg[length++] = so_info->app_type_cfg.sample_rate;
-            app_type_cfg[length++] = so_info->app_type_cfg.bit_width;
+            num_app_types += 1;
+            app_type_cfg[length++] = s_info->app_type_cfg.app_type;
+            app_type_cfg[length++] = s_info->app_type_cfg.sample_rate;
+            app_type_cfg[length++] = s_info->app_type_cfg.bit_width;
+        }
+    }
+    list_for_each(node, streams_input_cfg_list) {
+        s_info = node_to_item(node, struct streams_io_cfg, list);
+        update = true;
+        for (i=0; i<length; i=i+3) {
+            if (app_type_cfg[i+1] == 0)
+                break;
+            else if (app_type_cfg[i+1] == (size_t)s_info->app_type_cfg.app_type) {
+                if (app_type_cfg[i+2] < s_info->app_type_cfg.sample_rate)
+                    app_type_cfg[i+2] = s_info->app_type_cfg.sample_rate;
+                if (app_type_cfg[i+3] < s_info->app_type_cfg.bit_width)
+                    app_type_cfg[i+3] = s_info->app_type_cfg.bit_width;
+                update = false;
+                break;
+            }
+        }
+        if (update && ((length + 3) <= MAX_LENGTH_MIXER_CONTROL_IN_INT)) {
+            num_app_types += 1;
+            app_type_cfg[length++] = s_info->app_type_cfg.app_type;
+            app_type_cfg[length++] = s_info->app_type_cfg.sample_rate;
+            app_type_cfg[length++] = s_info->app_type_cfg.bit_width;
         }
     }
     ALOGV("%s: num_app_types: %d", __func__, num_app_types);
@@ -362,101 +424,131 @@
     }
 }
 
-void audio_extn_utils_update_streams_output_cfg_list(void *platform,
-                                       struct mixer *mixer,
-                                       struct listnode *streams_output_cfg_list)
+void audio_extn_utils_update_streams_cfg_lists(void *platform,
+                                    struct mixer *mixer,
+                                    struct listnode *streams_output_cfg_list,
+                                    struct listnode *streams_input_cfg_list)
 {
     cnode *root;
-    char *data;
+    char *data = NULL;
 
     ALOGV("%s", __func__);
     list_init(streams_output_cfg_list);
-    data = (char *)load_file(AUDIO_OUTPUT_POLICY_VENDOR_CONFIG_FILE, NULL);
-    if (data == NULL) {
-        send_app_type_cfg(platform, mixer, NULL);
-        ALOGE("%s: could not load output policy config file", __func__);
-        return;
-    }
+    list_init(streams_input_cfg_list);
 
     root = config_node("", "");
     if (root == NULL) {
         ALOGE("cfg_list, NULL config root");
-        free(data);
         return;
     }
 
-    config_load(root, data);
-    load_output(root, platform, streams_output_cfg_list);
+    data = (char *)load_file(AUDIO_IO_POLICY_VENDOR_CONFIG_FILE, NULL);
+    if (data == NULL) {
+        ALOGD("%s: failed to open io config file(%s), trying older config file",
+              __func__, AUDIO_IO_POLICY_VENDOR_CONFIG_FILE);
+        data = (char *)load_file(AUDIO_OUTPUT_POLICY_VENDOR_CONFIG_FILE, NULL);
+        if (data == NULL) {
+            send_app_type_cfg(platform, mixer,
+                              streams_output_cfg_list,
+                              streams_input_cfg_list);
+            ALOGE("%s: could not load io policy config!", __func__);
+            return;
+        }
+    }
 
-    send_app_type_cfg(platform, mixer, streams_output_cfg_list);
+    config_load(root, data);
+    load_cfg_list(root, platform, streams_output_cfg_list,
+                                  streams_input_cfg_list);
+
+    send_app_type_cfg(platform, mixer, streams_output_cfg_list,
+                                       streams_input_cfg_list);
 
     config_free(root);
     free(data);
 }
 
-void audio_extn_utils_dump_streams_output_cfg_list(
-                                       struct listnode *streams_output_cfg_list)
+static void audio_extn_utils_dump_streams_cfg_list(
+                                    struct listnode *streams_cfg_list)
 {
     struct listnode *node_i, *node_j;
-    struct streams_output_cfg *so_info;
+    struct streams_io_cfg *s_info;
     struct stream_format *sf_info;
     struct stream_sample_rate *ss_info;
-    ALOGV("%s", __func__);
-    list_for_each(node_i, streams_output_cfg_list) {
-        so_info = node_to_item(node_i, struct streams_output_cfg, list);
-        ALOGV("%s: flags-%d, output_sample_rate-%d, output_bit_width-%d, app_type-%d",
-               __func__, so_info->flags, so_info->app_type_cfg.sample_rate,
-               so_info->app_type_cfg.bit_width, so_info->app_type_cfg.app_type);
-        list_for_each(node_j, &so_info->format_list) {
+
+    list_for_each(node_i, streams_cfg_list) {
+        s_info = node_to_item(node_i, struct streams_io_cfg, list);
+        ALOGV("%s: flags-%d, sample_rate-%d, bit_width-%d, app_type-%d",
+               __func__, s_info->flags.out_flags, s_info->app_type_cfg.sample_rate,
+               s_info->app_type_cfg.bit_width, s_info->app_type_cfg.app_type);
+        list_for_each(node_j, &s_info->format_list) {
             sf_info = node_to_item(node_j, struct stream_format, list);
             ALOGV("format-%x", sf_info->format);
         }
-        list_for_each(node_j, &so_info->sample_rate_list) {
+        list_for_each(node_j, &s_info->sample_rate_list) {
             ss_info = node_to_item(node_j, struct stream_sample_rate, list);
             ALOGV("sample rate-%d", ss_info->sample_rate);
         }
     }
 }
 
-void audio_extn_utils_release_streams_output_cfg_list(
-                                       struct listnode *streams_output_cfg_list)
+void audio_extn_utils_dump_streams_cfg_lists(
+                                    struct listnode *streams_output_cfg_list,
+                                    struct listnode *streams_input_cfg_list)
+{
+    ALOGV("%s", __func__);
+    audio_extn_utils_dump_streams_cfg_list(streams_output_cfg_list);
+    audio_extn_utils_dump_streams_cfg_list(streams_input_cfg_list);
+}
+
+static void audio_extn_utils_release_streams_cfg_list(
+                                    struct listnode *streams_cfg_list)
 {
     struct listnode *node_i, *node_j;
-    struct streams_output_cfg *so_info;
+    struct streams_io_cfg *s_info;
 
     ALOGV("%s", __func__);
-    while (!list_empty(streams_output_cfg_list)) {
-        node_i = list_head(streams_output_cfg_list);
-        so_info = node_to_item(node_i, struct streams_output_cfg, list);
-        while (!list_empty(&so_info->format_list)) {
-            node_j = list_head(&so_info->format_list);
+
+    while (!list_empty(streams_cfg_list)) {
+        node_i = list_head(streams_cfg_list);
+        s_info = node_to_item(node_i, struct streams_io_cfg, list);
+        while (!list_empty(&s_info->format_list)) {
+            node_j = list_head(&s_info->format_list);
             list_remove(node_j);
             free(node_to_item(node_j, struct stream_format, list));
         }
-        while (!list_empty(&so_info->sample_rate_list)) {
-            node_j = list_head(&so_info->sample_rate_list);
+        while (!list_empty(&s_info->sample_rate_list)) {
+            node_j = list_head(&s_info->sample_rate_list);
             list_remove(node_j);
             free(node_to_item(node_j, struct stream_sample_rate, list));
         }
         list_remove(node_i);
-        free(node_to_item(node_i, struct streams_output_cfg, list));
+        free(node_to_item(node_i, struct streams_io_cfg, list));
     }
 }
 
-static bool set_output_cfg(struct streams_output_cfg *so_info,
-                           struct stream_app_type_cfg *app_type_cfg,
-                           uint32_t sample_rate, uint32_t bit_width)
+void audio_extn_utils_release_streams_cfg_lists(
+                                    struct listnode *streams_output_cfg_list,
+                                    struct listnode *streams_input_cfg_list)
+{
+    ALOGV("%s", __func__);
+    audio_extn_utils_release_streams_cfg_list(streams_output_cfg_list);
+    audio_extn_utils_release_streams_cfg_list(streams_input_cfg_list);
+}
+
+static bool set_app_type_cfg(struct streams_io_cfg *s_info,
+                    struct stream_app_type_cfg *app_type_cfg,
+                    uint32_t sample_rate, uint32_t bit_width)
  {
     struct listnode *node_i;
     struct stream_sample_rate *ss_info;
-    list_for_each(node_i, &so_info->sample_rate_list) {
+    list_for_each(node_i, &s_info->sample_rate_list) {
         ss_info = node_to_item(node_i, struct stream_sample_rate, list);
         if ((sample_rate <= ss_info->sample_rate) &&
-            (bit_width == so_info->app_type_cfg.bit_width)) {
+            (bit_width == s_info->app_type_cfg.bit_width)) {
 
-            app_type_cfg->app_type = so_info->app_type_cfg.app_type;
+            app_type_cfg->app_type = s_info->app_type_cfg.app_type;
             app_type_cfg->sample_rate = ss_info->sample_rate;
-            app_type_cfg->bit_width = so_info->app_type_cfg.bit_width;
+            app_type_cfg->bit_width = s_info->app_type_cfg.bit_width;
             ALOGV("%s app_type_cfg->app_type %d, app_type_cfg->sample_rate %d, app_type_cfg->bit_width %d",
                    __func__, app_type_cfg->app_type, app_type_cfg->sample_rate, app_type_cfg->bit_width);
             return true;
@@ -469,13 +561,13 @@
      */
     sample_rate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
 
-    list_for_each(node_i, &so_info->sample_rate_list) {
+    list_for_each(node_i, &s_info->sample_rate_list) {
         ss_info = node_to_item(node_i, struct stream_sample_rate, list);
         if ((sample_rate <= ss_info->sample_rate) &&
-            (bit_width == so_info->app_type_cfg.bit_width)) {
-            app_type_cfg->app_type = so_info->app_type_cfg.app_type;
+            (bit_width == s_info->app_type_cfg.bit_width)) {
+            app_type_cfg->app_type = s_info->app_type_cfg.app_type;
             app_type_cfg->sample_rate = sample_rate;
-            app_type_cfg->bit_width = so_info->app_type_cfg.bit_width;
+            app_type_cfg->bit_width = s_info->app_type_cfg.bit_width;
             ALOGV("%s Assuming sample rate. app_type_cfg->app_type %d, app_type_cfg->sample_rate %d, app_type_cfg->bit_width %d",
                    __func__, app_type_cfg->app_type, app_type_cfg->sample_rate, app_type_cfg->bit_width);
             return true;
@@ -484,7 +576,45 @@
     return false;
 }
 
-void audio_extn_utils_update_stream_app_type_cfg(void *platform,
+void audio_extn_utils_update_stream_input_app_type_cfg(void *platform,
+                                  struct listnode *streams_input_cfg_list,
+                                  audio_devices_t devices __unused,
+                                  audio_input_flags_t flags,
+                                  audio_format_t format,
+                                  uint32_t sample_rate,
+                                  uint32_t bit_width,
+                                  char* profile,
+                                  struct stream_app_type_cfg *app_type_cfg)
+{
+    struct listnode *node_i, *node_j;
+    struct streams_io_cfg *s_info;
+    struct stream_format *sf_info;
+
+    ALOGV("%s: flags: 0x%x, format: 0x%x sample_rate %d, profile %s",
+           __func__, flags, format, sample_rate, profile);
+
+    list_for_each(node_i, streams_input_cfg_list) {
+        s_info = node_to_item(node_i, struct streams_io_cfg, list);
+        /* Along with flags do profile matching if set at either end.*/
+        if (s_info->flags.in_flags == flags &&
+            ((profile[0] == '\0' && s_info->profile[0] == '\0') ||
+             strncmp(s_info->profile, profile, sizeof(s_info->profile)) == 0)) {
+            list_for_each(node_j, &s_info->format_list) {
+                sf_info = node_to_item(node_j, struct stream_format, list);
+                if (sf_info->format == format) {
+                    if (set_app_type_cfg(s_info, app_type_cfg, sample_rate, bit_width))
+                        return;
+                }
+            }
+        }
+    }
+    ALOGW("%s: App type could not be selected. Falling back to default", __func__);
+    app_type_cfg->app_type = platform_get_default_app_type_v2(platform, PCM_CAPTURE);
+    app_type_cfg->sample_rate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
+    app_type_cfg->bit_width = 16;
+}
+
+void audio_extn_utils_update_stream_output_app_type_cfg(void *platform,
                                   struct listnode *streams_output_cfg_list,
                                   audio_devices_t devices,
                                   audio_output_flags_t flags,
@@ -492,10 +622,11 @@
                                   uint32_t sample_rate,
                                   uint32_t bit_width,
                                   audio_channel_mask_t channel_mask,
+                                  char *profile,
                                   struct stream_app_type_cfg *app_type_cfg)
 {
     struct listnode *node_i, *node_j;
-    struct streams_output_cfg *so_info;
+    struct streams_io_cfg *s_info;
     struct stream_format *sf_info;
     char value[PROPERTY_VALUE_MAX] = {0};
 
@@ -540,29 +671,32 @@
               __func__, sample_rate, bit_width);
     }
 
-    ALOGV("%s: flags: %x, format: %x sample_rate %d",
-           __func__, flags, format, sample_rate);
+    ALOGV("%s: flags: %x, format: %x sample_rate %d, profile %s",
+           __func__, flags, format, sample_rate, profile);
     list_for_each(node_i, streams_output_cfg_list) {
-        so_info = node_to_item(node_i, struct streams_output_cfg, list);
-        if (so_info->flags == flags) {
-            list_for_each(node_j, &so_info->format_list) {
+        s_info = node_to_item(node_i, struct streams_io_cfg, list);
+        /* Along with flags do profile matching if set at either end.*/
+        if (s_info->flags.out_flags == flags &&
+            ((profile[0] == '\0' && s_info->profile[0] == '\0') ||
+             strncmp(s_info->profile, profile, sizeof(s_info->profile)) == 0)) {
+            list_for_each(node_j, &s_info->format_list) {
                 sf_info = node_to_item(node_j, struct stream_format, list);
                 if (sf_info->format == format) {
-                    if (set_output_cfg(so_info, app_type_cfg, sample_rate, bit_width))
+                    if (set_app_type_cfg(s_info, app_type_cfg, sample_rate, bit_width))
                         return;
                 }
             }
         }
     }
     list_for_each(node_i, streams_output_cfg_list) {
-        so_info = node_to_item(node_i, struct streams_output_cfg, list);
-        if (so_info->flags == AUDIO_OUTPUT_FLAG_PRIMARY) {
+        s_info = node_to_item(node_i, struct streams_io_cfg, list);
+        if (s_info->flags.out_flags == AUDIO_OUTPUT_FLAG_PRIMARY) {
             ALOGV("Compatible output profile not found.");
-            app_type_cfg->app_type = so_info->app_type_cfg.app_type;
-            app_type_cfg->sample_rate = so_info->app_type_cfg.sample_rate;
-            app_type_cfg->bit_width = so_info->app_type_cfg.bit_width;
+            app_type_cfg->app_type = s_info->app_type_cfg.app_type;
+            app_type_cfg->sample_rate = s_info->app_type_cfg.sample_rate;
+            app_type_cfg->bit_width = s_info->app_type_cfg.bit_width;
             ALOGV("%s Default to primary output: App type: %d sample_rate %d",
-                  __func__, so_info->app_type_cfg.app_type, app_type_cfg->sample_rate);
+                  __func__, s_info->app_type_cfg.app_type, app_type_cfg->sample_rate);
             return;
         }
     }
@@ -586,20 +720,59 @@
     return native_usecase;
 }
 
+void audio_extn_utils_update_stream_app_type_cfg_for_usecase(
+                                    struct audio_device *adev,
+                                    struct audio_usecase *usecase)
+{
+    ALOGV("%s", __func__);
+
+    switch(usecase->type) {
+    case PCM_PLAYBACK:
+        audio_extn_utils_update_stream_output_app_type_cfg(adev->platform,
+                                                &adev->streams_output_cfg_list,
+                                                usecase->stream.out->devices,
+                                                usecase->stream.out->flags,
+                                                usecase->stream.out->format,
+                                                usecase->stream.out->sample_rate,
+                                                usecase->stream.out->bit_width,
+                                                usecase->stream.out->channel_mask,
+                                                usecase->stream.out->profile,
+                                                &usecase->stream.out->app_type_cfg);
+        ALOGV("%s Selected apptype: %d", __func__, usecase->stream.out->app_type_cfg.app_type);
+        break;
+    case PCM_CAPTURE:
+        audio_extn_utils_update_stream_input_app_type_cfg(adev->platform,
+                                                &adev->streams_input_cfg_list,
+                                                usecase->stream.in->device,
+                                                usecase->stream.in->flags,
+                                                usecase->stream.in->format,
+                                                usecase->stream.in->sample_rate,
+                                                usecase->stream.in->bit_width,
+                                                usecase->stream.in->profile,
+                                                &usecase->stream.in->app_type_cfg);
+        ALOGV("%s Selected apptype: %d", __func__, usecase->stream.in->app_type_cfg.app_type);
+        break;
+    default:
+        ALOGE("%s: app type cfg not supported for usecase type (%d)",
+            __func__, usecase->type);
+    }
+}
+
 int audio_extn_utils_send_app_type_cfg(struct audio_device *adev,
                                        struct audio_usecase *usecase)
 {
     char mixer_ctl_name[MAX_LENGTH_MIXER_CONTROL_IN_INT];
-    int app_type_cfg[MAX_LENGTH_MIXER_CONTROL_IN_INT], len = 0, rc;
+    size_t app_type_cfg[MAX_LENGTH_MIXER_CONTROL_IN_INT] = {0};
+    int len = 0, rc;
     struct mixer_ctl *ctl;
-    int pcm_device_id = 0, acdb_dev_id, snd_device = usecase->out_snd_device;
+    int pcm_device_id, acdb_dev_id = 0, snd_device = usecase->out_snd_device;
     int32_t sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
     char value[PROPERTY_VALUE_MAX] = {0};
 
     ALOGV("%s", __func__);
 
     if (usecase->type != PCM_PLAYBACK && usecase->type != PCM_CAPTURE) {
-        ALOGE("%s: not a playback or capture path, no need to cfg app type", __func__);
+        ALOGE("%s: not a playback/capture path, no need to cfg app type", __func__);
         rc = 0;
         goto exit_send_app_type_cfg;
     }
@@ -608,20 +781,28 @@
         (usecase->id != USECASE_AUDIO_PLAYBACK_MULTI_CH) &&
         (!is_offload_usecase(usecase->id)) &&
         (usecase->type != PCM_CAPTURE)) {
-        ALOGV("%s: a rx/tx path where app type cfg is not required %d", __func__, usecase->id);
+        ALOGV("%s: a rx/tx/loopback path where app type cfg is not required %d", __func__, usecase->id);
         rc = 0;
         goto exit_send_app_type_cfg;
     }
     if (usecase->type == PCM_PLAYBACK) {
         snd_device = usecase->out_snd_device;
         pcm_device_id = platform_get_pcm_device_id(usecase->id, PCM_PLAYBACK);
+        snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
+            "Audio Stream %d App Type Cfg", pcm_device_id);
+        acdb_dev_id = platform_get_snd_device_acdb_id(usecase->out_snd_device);
     } else if (usecase->type == PCM_CAPTURE) {
         snd_device = usecase->in_snd_device;
         pcm_device_id = platform_get_pcm_device_id(usecase->id, PCM_CAPTURE);
+        snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
+            "Audio Stream Capture %d App Type Cfg", pcm_device_id);
+        acdb_dev_id = platform_get_snd_device_acdb_id(usecase->in_snd_device);
     }
-
-    snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
-             "Audio Stream %d App Type Cfg", pcm_device_id);
+    if (acdb_dev_id <= 0) {
+        ALOGE("%s: Couldn't get the acdb dev id", __func__);
+        rc = -EINVAL;
+        goto exit_send_app_type_cfg;
+    }
 
     ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
     if (!ctl) {
@@ -632,40 +813,25 @@
     }
     snd_device = (snd_device == SND_DEVICE_OUT_SPEAKER) ?
                  platform_get_spkr_prot_snd_device(snd_device) : snd_device;
-    acdb_dev_id = platform_get_snd_device_acdb_id(snd_device);
-    if (acdb_dev_id < 0) {
-        ALOGE("%s: Couldn't get the acdb dev id", __func__);
-        rc = -EINVAL;
-        goto exit_send_app_type_cfg;
-    }
-    if ((usecase->type == PCM_PLAYBACK) && (usecase->stream.out == NULL)) {
-         sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
-         app_type_cfg[len++] = platform_get_default_app_type(adev->platform);
-         app_type_cfg[len++] = acdb_dev_id;
-         app_type_cfg[len++] = sample_rate;
-         ALOGI("%s:%d PLAYBACK app_type %d, acdb_dev_id %d, sample_rate %d",
-               __func__, __LINE__,
-               platform_get_default_app_type(adev->platform),
-               acdb_dev_id, sample_rate);
-    } else if (usecase->type == PCM_PLAYBACK) {
 
-         if (usecase->stream.out->devices & AUDIO_DEVICE_OUT_SPEAKER) {
-             usecase->stream.out->app_type_cfg.sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
-         } else if ((usecase->stream.out->app_type_cfg.sample_rate == OUTPUT_SAMPLING_RATE_44100 &&
-                      !(audio_is_this_native_usecase(usecase))) ||
-                      (usecase->stream.out->sample_rate < OUTPUT_SAMPLING_RATE_44100)) {
-                    usecase->stream.out->app_type_cfg.sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
-         }
+    if ((usecase->type == PCM_PLAYBACK) && (usecase->stream.out != NULL)) {
+        if (usecase->stream.out->devices & AUDIO_DEVICE_OUT_SPEAKER) {
+            usecase->stream.out->app_type_cfg.sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
+        } else if ((usecase->stream.out->app_type_cfg.sample_rate == OUTPUT_SAMPLING_RATE_44100 &&
+                     !(audio_is_this_native_usecase(usecase))) ||
+                     (usecase->stream.out->sample_rate < OUTPUT_SAMPLING_RATE_44100)) {
+                   usecase->stream.out->app_type_cfg.sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
+        }
 
-         sample_rate = usecase->stream.out->app_type_cfg.sample_rate;
+        sample_rate = usecase->stream.out->app_type_cfg.sample_rate;
 
-         property_get("audio.playback.mch.downsample",value,"");
-         if (!strncmp("true", value, sizeof("true"))) {
-             if ((popcount(usecase->stream.out->channel_mask) > 2) &&
-                    (usecase->stream.out->app_type_cfg.sample_rate > CODEC_BACKEND_DEFAULT_SAMPLE_RATE) &&
-                    !(usecase->stream.out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_PASSTHROUGH))
-                sample_rate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
-         }
+        property_get("audio.playback.mch.downsample",value,"");
+        if (!strncmp("true", value, sizeof("true"))) {
+            if ((popcount(usecase->stream.out->channel_mask) > 2) &&
+                   (usecase->stream.out->app_type_cfg.sample_rate > CODEC_BACKEND_DEFAULT_SAMPLE_RATE) &&
+                   !(usecase->stream.out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_PASSTHROUGH))
+               sample_rate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
+        }
 
         if ((24 == usecase->stream.out->bit_width) &&
             (usecase->stream.out->devices & AUDIO_DEVICE_OUT_SPEAKER)) {
@@ -698,23 +864,28 @@
         } else {
             app_type_cfg[len++] = sample_rate;
         }
-        ALOGI("%s PLAYBACK app_type %d, acdb_dev_id %d, sample_rate %d",
-              __func__, usecase->stream.out->app_type_cfg.app_type, acdb_dev_id, sample_rate);
-    } else if (usecase->type == PCM_CAPTURE) {
-         app_type_cfg[len++] = platform_get_default_app_type_v2(adev->platform, usecase->type);
-         app_type_cfg[len++] = acdb_dev_id;
-         app_type_cfg[len++] = sample_rate;
-         ALOGI("%s CAPTURE app_type %d, acdb_dev_id %d, sample_rate %d",
-           __func__, platform_get_default_app_type_v2(adev->platform, usecase->type),
-           acdb_dev_id, sample_rate);
+
+         ALOGI("%s PLAYBACK app_type %d, acdb_dev_id %d, sample_rate %d",
+             __func__, usecase->stream.out->app_type_cfg.app_type, acdb_dev_id, sample_rate);
+
+    } else if ((usecase->type == PCM_CAPTURE) && (usecase->stream.in != NULL)) {
+        app_type_cfg[len++] = usecase->stream.in->app_type_cfg.app_type;
+        app_type_cfg[len++] = acdb_dev_id;
+        app_type_cfg[len++] = usecase->stream.in->app_type_cfg.sample_rate;
+        ALOGI("%s CAPTURE app_type %d, acdb_dev_id %d, sample_rate %d",
+           __func__, usecase->stream.in->app_type_cfg.app_type, acdb_dev_id,
+           usecase->stream.in->app_type_cfg.sample_rate);
+    } else {
+        app_type_cfg[len++] = platform_get_default_app_type_v2(adev->platform, usecase->type);
+        app_type_cfg[len++] = acdb_dev_id;
+        app_type_cfg[len++] = sample_rate;
+        ALOGI("%s default app_type %d, acdb_dev_id %d, sample_rate %d",
+              __func__, platform_get_default_app_type_v2(adev->platform, usecase->type),
+              acdb_dev_id, sample_rate);
     }
 
     mixer_ctl_set_array(ctl, app_type_cfg, len);
     rc = 0;
-    ALOGI("%s:becf: adm: app_type %d, acdb_dev_id %d, sample_rate %d",
-          __func__,
-          platform_get_default_app_type_v2(adev->platform, usecase->type),
-          acdb_dev_id, sample_rate);
 exit_send_app_type_cfg:
     return rc;
 }
@@ -912,6 +1083,66 @@
     }
 }
 
+/* converts pcm format 24_8 to 8_24 inplace */
+size_t audio_extn_utils_convert_format_24_8_to_8_24(void *buf, size_t bytes)
+{
+    size_t i = 0;
+    int *int_buf_stream = buf;
+
+    if ((bytes % 4) != 0) {
+        ALOGE("%s: wrong inout buffer! ... is not 32 bit aligned ", __func__);
+        return -EINVAL;
+    }
+
+    for (; i < (bytes / 4); i++)
+        int_buf_stream[i] >>= 8;
+
+    return bytes;
+}
+
+int get_snd_codec_id(audio_format_t format)
+{
+    int id = 0;
+
+    switch (format & AUDIO_FORMAT_MAIN_MASK) {
+    case AUDIO_FORMAT_MP3:
+        id = SND_AUDIOCODEC_MP3;
+        break;
+    case AUDIO_FORMAT_AAC:
+        id = SND_AUDIOCODEC_AAC;
+        break;
+    case AUDIO_FORMAT_AAC_ADTS:
+        id = SND_AUDIOCODEC_AAC;
+        break;
+    case AUDIO_FORMAT_PCM_OFFLOAD:
+    case AUDIO_FORMAT_PCM:
+        id = SND_AUDIOCODEC_PCM;
+        break;
+    case AUDIO_FORMAT_FLAC:
+        id = SND_AUDIOCODEC_FLAC;
+        break;
+    case AUDIO_FORMAT_ALAC:
+        id = SND_AUDIOCODEC_ALAC;
+        break;
+    case AUDIO_FORMAT_APE:
+        id = SND_AUDIOCODEC_APE;
+        break;
+    case AUDIO_FORMAT_VORBIS:
+        id = SND_AUDIOCODEC_VORBIS;
+        break;
+    case AUDIO_FORMAT_WMA:
+        id = SND_AUDIOCODEC_WMA;
+        break;
+    case AUDIO_FORMAT_WMA_PRO:
+        id = SND_AUDIOCODEC_WMA_PRO;
+        break;
+    default:
+        ALOGE("%s: Unsupported audio format :%x", __func__, format);
+    }
+
+    return id;
+}
+
 void audio_extn_utils_send_audio_calibration(struct audio_device *adev,
                                              struct audio_usecase *usecase)
 {
@@ -925,12 +1156,15 @@
         platform_send_audio_calibration(adev->platform, usecase,
                                         out->app_type_cfg.app_type,
                                         usecase->stream.out->app_type_cfg.sample_rate);
-    }
-    if ((type == PCM_HFP_CALL) || (type == PCM_CAPTURE)) {
+    } else if (type == PCM_CAPTURE) {
+        platform_send_audio_calibration(adev->platform, usecase,
+                         usecase->stream.in->app_type_cfg.app_type,
+                         usecase->stream.in->app_type_cfg.sample_rate);
+    } else {
         /* when app type is default. the sample rate is not used to send cal */
         platform_send_audio_calibration(adev->platform, usecase,
-                 platform_get_default_app_type_v2(adev->platform, usecase->type),
-                 48000);
+                         platform_get_default_app_type_v2(adev->platform, usecase->type),
+                         48000);
     }
 }
 
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index bd393f2..fb668d5 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -227,6 +227,9 @@
 
     [USECASE_AUDIO_RECORD] = "audio-record",
     [USECASE_AUDIO_RECORD_COMPRESS] = "audio-record-compress",
+    [USECASE_AUDIO_RECORD_COMPRESS2] = "audio-record-compress2",
+    [USECASE_AUDIO_RECORD_COMPRESS3] = "audio-record-compress3",
+    [USECASE_AUDIO_RECORD_COMPRESS4] = "audio-record-compress4",
     [USECASE_AUDIO_RECORD_LOW_LATENCY] = "low-latency-record",
     [USECASE_AUDIO_RECORD_FM_VIRTUAL] = "fm-virtual-record",
     [USECASE_AUDIO_PLAYBACK_FM] = "play-fm",
@@ -505,62 +508,6 @@
            (uc_id == USECASE_AUDIO_PLAYBACK_AFE_PROXY);
 }
 
-static int get_snd_codec_id(audio_format_t format)
-{
-    int id = 0;
-
-    switch (format & AUDIO_FORMAT_MAIN_MASK) {
-    case AUDIO_FORMAT_MP3:
-        id = SND_AUDIOCODEC_MP3;
-        break;
-    case AUDIO_FORMAT_AAC:
-        id = SND_AUDIOCODEC_AAC;
-        break;
-    case AUDIO_FORMAT_AAC_ADTS:
-        id = SND_AUDIOCODEC_AAC;
-        break;
-    case AUDIO_FORMAT_PCM:
-        id = SND_AUDIOCODEC_PCM;
-        break;
-    case AUDIO_FORMAT_FLAC:
-        id = SND_AUDIOCODEC_FLAC;
-        break;
-    case AUDIO_FORMAT_ALAC:
-        id = SND_AUDIOCODEC_ALAC;
-        break;
-    case AUDIO_FORMAT_APE:
-        id = SND_AUDIOCODEC_APE;
-        break;
-    case AUDIO_FORMAT_DSD:
-        id = SND_AUDIOCODEC_DSD;
-        break;
-    case AUDIO_FORMAT_VORBIS:
-        id = SND_AUDIOCODEC_VORBIS;
-        break;
-    case AUDIO_FORMAT_WMA:
-        id = SND_AUDIOCODEC_WMA;
-        break;
-    case AUDIO_FORMAT_WMA_PRO:
-        id = SND_AUDIOCODEC_WMA_PRO;
-        break;
-    case AUDIO_FORMAT_AC3:
-        id = SND_AUDIOCODEC_AC3;
-        break;
-    case AUDIO_FORMAT_E_AC3:
-    case AUDIO_FORMAT_E_AC3_JOC:
-        id = SND_AUDIOCODEC_EAC3;
-        break;
-    case AUDIO_FORMAT_DTS:
-    case AUDIO_FORMAT_DTS_HD:
-        id = SND_AUDIOCODEC_DTS;
-        break;
-    default:
-        ALOGE("%s: Unsupported audio format :%x", __func__, format);
-    }
-
-    return id;
-}
-
 int get_snd_card_state(struct audio_device *adev)
 {
     int snd_scard_state;
@@ -1142,10 +1089,19 @@
     struct audio_usecase *usecase;
     bool switch_device[AUDIO_USECASE_MAX];
     int i, num_uc_to_switch = 0;
+    int backend_check_cond = AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND;
 
     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);
+
+    /*
+     * Make sure out devices is checked against out codec backend device and
+     * also in devices against in codec backend. Checking out device against in
+     * codec backend or vice versa causes issues.
+     */
+    if (uc_info->type == PCM_CAPTURE)
+        backend_check_cond = AUDIO_DEVICE_IN_ALL_CODEC_BACKEND;
     /*
      * This function is to make sure that all the active capture usecases
      * are always routed to the same input sound device.
@@ -1161,10 +1117,13 @@
 
     list_for_each(node, &adev->usecase_list) {
         usecase = node_to_item(node, struct audio_usecase, list);
+        /*
+         * TODO: Enhance below condition to handle BT sco/USB multi recording
+         */
         if (usecase->type != PCM_PLAYBACK &&
                 usecase != uc_info &&
                 (usecase->in_snd_device != snd_device || force_routing) &&
-                ((uc_info->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) &&
+                ((uc_info->devices & backend_check_cond) &&
                  (((usecase->devices & ~AUDIO_DEVICE_BIT_IN) & AUDIO_DEVICE_IN_ALL_CODEC_BACKEND) ||
                   (usecase->type == VOICE_CALL) || (usecase->type == VOIP_CALL))) &&
                 (usecase->id != USECASE_AUDIO_SPKR_CALIB_TX)) {
@@ -1616,25 +1575,15 @@
     usecase->in_snd_device = in_snd_device;
     usecase->out_snd_device = out_snd_device;
 
+    audio_extn_utils_update_stream_app_type_cfg_for_usecase(adev,
+                                                            usecase);
     if (usecase->type == PCM_PLAYBACK) {
-        audio_extn_utils_update_stream_app_type_cfg(adev->platform,
-                                                &adev->streams_output_cfg_list,
-                                                usecase->stream.out->devices,
-                                                usecase->stream.out->flags,
-                                                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);
-
         /* Notify device change info to effect clients registered */
         audio_extn_gef_notify_device_config(
                 usecase->stream.out->devices,
                 usecase->stream.out->channel_mask,
                 platform_get_snd_device_acdb_id(usecase->out_snd_device));
     }
-
     enable_audio_route(adev, usecase);
 
     if (usecase->type == VOICE_CALL || usecase->type == VOIP_CALL) {
@@ -1760,6 +1709,14 @@
     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);
 
+   if (audio_extn_cin_attached_usecase(in->usecase)) {
+       ret = audio_extn_cin_start_input_stream(in);
+       if (ret)
+           goto error_open;
+       else
+           goto done_open;
+   }
+
     unsigned int flags = PCM_IN;
     unsigned int pcm_open_retry_count = 0;
 
@@ -1805,6 +1762,7 @@
             goto error_open;
     }
 
+done_open:
     audio_extn_perf_lock_release(&adev->perf_lock_handle);
     ALOGD("%s: exit", __func__);
 
@@ -2681,6 +2639,20 @@
         pthread_mutex_unlock(&out->lock);
     }
 
+    err = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_PROFILE, value, sizeof(value));
+    if (err >= 0) {
+        strlcpy(out->profile, value, sizeof(out->profile));
+        ALOGV("updating stream profile with value '%s'", out->profile);
+        lock_output_stream(out);
+        audio_extn_utils_update_stream_output_app_type_cfg(adev->platform,
+                                                          &adev->streams_output_cfg_list,
+                                                          out->devices, out->flags, out->format,
+                                                          out->sample_rate, out->bit_width,
+                                                          out->channel_mask, out->profile,
+                                                          &out->app_type_cfg);
+        pthread_mutex_unlock(&out->lock);
+    }
+
     str_parms_destroy(parms);
 error:
     ALOGV("%s: exit: code(%d)", __func__, ret);
@@ -3396,6 +3368,8 @@
         return voice_extn_compress_voip_in_get_buffer_size(in);
     else if(audio_extn_compr_cap_usecase_supported(in->usecase))
         return audio_extn_compr_cap_get_buffer_size(in->config.format);
+    else if(audio_extn_cin_attached_usecase(in->usecase))
+        return audio_extn_cin_get_buffer_size(in);
 
     return in->config.period_size * in->af_period_multiplier *
         audio_stream_in_frame_size((const struct audio_stream_in *)stream);
@@ -3446,6 +3420,8 @@
             voice_extn_compress_voip_close_input_stream(stream);
             ALOGD("VOIP input entered standby");
         } else {
+            if (audio_extn_cin_attached_usecase(in->usecase))
+                audio_extn_cin_stop_input_stream(in);
             if (in->pcm) {
                 pcm_close(in->pcm);
                 in->pcm = NULL;
@@ -3518,6 +3494,17 @@
         }
     }
 
+    err = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_PROFILE, value, sizeof(value));
+    if (err >= 0) {
+        strlcpy(in->profile, value, sizeof(in->profile));
+        ALOGV("updating stream profile with value '%s'", in->profile);
+        audio_extn_utils_update_stream_input_app_type_cfg(adev->platform,
+                                                          &adev->streams_input_cfg_list,
+                                                          in->device, in->flags, in->format,
+                                                          in->sample_rate, in->bit_width,
+                                                          in->profile, &in->app_type_cfg);
+    }
+
     pthread_mutex_unlock(&adev->lock);
     pthread_mutex_unlock(&in->lock);
 
@@ -3571,7 +3558,7 @@
     struct audio_device *adev = in->dev;
     int ret = -1;
     int snd_scard_state = get_snd_card_state(adev);
-    int *int_buf_stream = NULL;
+    size_t bytes_read = 0;
 
     lock_input_stream(in);
 
@@ -3605,14 +3592,16 @@
     // what's the duration requested by the client?
     long ns = 0;
 
-    if (in->config.rate)
+    if (in->pcm && in->config.rate)
         ns = pcm_bytes_to_frames(in->pcm, bytes)*1000000000LL/
                                              in->config.rate;
 
     request_in_focus(in, ns);
     bool use_mmap = is_mmap_usecase(in->usecase) || in->realtime;
 
-    if (in->pcm) {
+    if (audio_extn_cin_attached_usecase(in->usecase)) {
+        ret = audio_extn_cin_read(in, buffer, bytes, &bytes_read);
+    } else if (in->pcm) {
         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)) {
@@ -3621,23 +3610,19 @@
             ret = pcm_mmap_read(in->pcm, buffer, bytes);
         } else {
             ret = pcm_read(in->pcm, buffer, bytes);
-            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;
-                    size_t itt = 0;
-                    for (itt = 0; itt < bytes/4 ; itt++) {
-                        int_buf_stream[itt] >>= 8;
-                    }
-                } else {
-                    ALOGE("%s: !!! something wrong !!! ... data not 32 bit aligned ", __func__);
+            /* data from DSP comes in 24_8 format, convert it to 8_24 */
+            if (!ret && bytes > 0 && (in->format == AUDIO_FORMAT_PCM_8_24_BIT)) {
+                if (audio_extn_utils_convert_format_24_8_to_8_24(buffer, bytes)
+                    != bytes) {
                     ret = -EINVAL;
                     goto exit;
                 }
-            } if (ret < 0) {
+            } else if (ret < 0) {
                 ret = -errno;
             }
         }
+        /* bytes read is always set to bytes for non compress usecases */
+        bytes_read = bytes;
     }
 
     release_in_focus(in);
@@ -3671,7 +3656,7 @@
         usleep((uint64_t)bytes * 1000000 / audio_stream_in_frame_size(stream) /
                                    in_get_sample_rate(&in->stream.common));
     }
-    return bytes;
+    return bytes_read;
 }
 
 static uint32_t in_get_input_frames_lost(struct audio_stream_in *stream __unused)
@@ -4137,10 +4122,10 @@
     /* TODO remove this hardcoding and check why width is zero*/
     if (out->bit_width == 0)
         out->bit_width = 16;
-    audio_extn_utils_update_stream_app_type_cfg(adev->platform,
+    audio_extn_utils_update_stream_output_app_type_cfg(adev->platform,
                                                 &adev->streams_output_cfg_list,
                                                 devices, flags, format, out->sample_rate,
-                                                out->bit_width, out->channel_mask,
+                                                out->bit_width, out->channel_mask, out->profile,
                                                 &out->app_type_cfg);
     if ((out->usecase == USECASE_AUDIO_PLAYBACK_PRIMARY) ||
         (flags & AUDIO_OUTPUT_FLAG_PRIMARY)) {
@@ -4591,7 +4576,7 @@
                                   audio_devices_t devices,
                                   struct audio_config *config,
                                   struct audio_stream_in **stream_in,
-                                  audio_input_flags_t flags __unused,
+                                  audio_input_flags_t flags,
                                   const char *address __unused,
                                   audio_source_t source)
 {
@@ -4645,17 +4630,6 @@
     in->capture_handle = handle;
     in->flags = flags;
 
-    /* Update config params with the requested sample rate and channels */
-    in->usecase = USECASE_AUDIO_RECORD;
-    if (config->sample_rate == LOW_LATENCY_CAPTURE_SAMPLE_RATE &&
-            (flags & AUDIO_INPUT_FLAG_FAST) != 0) {
-        is_low_latency = true;
-#if LOW_LATENCY_CAPTURE_USE_CASE
-        in->usecase = USECASE_AUDIO_RECORD_LOW_LATENCY;
-#endif
-        in->realtime = may_use_noirq_mode(adev, in->usecase, in->flags);
-    }
-
     in->format = config->format;
     if (in->realtime) {
         in->config = pcm_config_audio_capture_rt;
@@ -4669,6 +4643,75 @@
     }
     in->bit_width = 16;
 
+    /* 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->usecase = USECASE_AUDIO_RECORD;
+    if (config->sample_rate == LOW_LATENCY_CAPTURE_SAMPLE_RATE &&
+            (flags & AUDIO_INPUT_FLAG_FAST) != 0) {
+        is_low_latency = true;
+#if LOW_LATENCY_CAPTURE_USE_CASE
+        in->usecase = USECASE_AUDIO_RECORD_LOW_LATENCY;
+#endif
+        in->realtime = may_use_noirq_mode(adev, in->usecase, in->flags);
+    }
+
+    pthread_mutex_lock(&adev->lock);
+    if (in->usecase == USECASE_AUDIO_RECORD) {
+        if (!(adev->pcm_record_uc_state) &&
+            ((flags & AUDIO_INPUT_FLAG_TIMESTAMP) == 0)) {
+            ALOGV("%s: pcm record usecase", __func__);
+            adev->pcm_record_uc_state = 1;
+        } else {
+            /*
+             * Assign default compress record use case, actual use case
+             * assignment will happen later.
+             */
+             in->usecase = USECASE_AUDIO_RECORD_COMPRESS2;
+             ALOGV("%s: compress record usecase", __func__);
+        }
+    }
+    pthread_mutex_unlock(&adev->lock);
+
+    /* Update config params with the requested sample rate and channels */
     if (in->device == AUDIO_DEVICE_IN_TELEPHONY_RX) {
         if (adev->mode != AUDIO_MODE_IN_CALL) {
             ret = -EINVAL;
@@ -4708,48 +4751,11 @@
             audio_extn_compr_cap_format_supported(config->format) &&
             (in->dev->mode != AUDIO_MODE_IN_COMMUNICATION)) {
         audio_extn_compr_cap_init(in);
+    } else if (audio_extn_cin_applicable_stream(in)) {
+        ret = audio_extn_cin_configure_input_stream(in);
+        if (ret)
+            goto err_open;
     } 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->config.channels = channel_count;
         if (!in->realtime) {
             in->format = config->format;
@@ -4771,6 +4777,11 @@
         }
     }
 
+    audio_extn_utils_update_stream_input_app_type_cfg(adev->platform,
+                                                &adev->streams_input_cfg_list,
+                                                devices, flags, in->format, in->sample_rate,
+                                                in->bit_width, in->profile, &in->app_type_cfg);
+
     /* This stream could be for sound trigger lab,
        get sound trigger pcm if present */
     audio_extn_sound_trigger_check_and_get_session(in);
@@ -4811,10 +4822,19 @@
         audio_extn_ssr_deinit();
     }
 
-    if(audio_extn_compr_cap_enabled() &&
+    if (audio_extn_compr_cap_enabled() &&
             audio_extn_compr_cap_format_supported(in->config.format))
         audio_extn_compr_cap_deinit();
 
+    if (in->usecase == USECASE_AUDIO_RECORD) {
+        pthread_mutex_lock(&adev->lock);
+        adev->pcm_record_uc_state = 0;
+        pthread_mutex_unlock(&adev->lock);
+    }
+
+    if (audio_extn_cin_attached_usecase(in->usecase))
+        audio_extn_cin_close_input_stream(in);
+
     if (in->is_st_session) {
         ALOGV("%s: sound trigger pcm stop lab", __func__);
         audio_extn_sound_trigger_stop_lab(in);
@@ -4841,15 +4861,18 @@
     if ((--audio_device_ref_count) == 0) {
         audio_extn_sound_trigger_deinit(adev);
         audio_extn_listen_deinit(adev);
+        audio_extn_utils_release_streams_cfg_lists(
+                      &adev->streams_output_cfg_list,
+                      &adev->streams_input_cfg_list);
         if (audio_extn_qaf_is_enabled())
             audio_extn_qaf_deinit();
-        audio_extn_utils_release_streams_output_cfg_list(&adev->streams_output_cfg_list);
         audio_route_free(adev->audio_route);
         audio_extn_gef_deinit();
         free(adev->snd_dev_ref_cnt);
         platform_deinit(adev->platform);
         if (adev->adm_deinit)
             adev->adm_deinit(adev->adm_data);
+        qahwi_deinit(device);
         free(device);
         adev = NULL;
     }
@@ -4940,6 +4963,7 @@
     list_init(&adev->usecase_list);
     adev->cur_wfd_channels = 2;
     adev->offload_usecases_state = 0;
+    adev->pcm_record_uc_state = 0;
     adev->is_channel_status_set = false;
     adev->perf_lock_opts[0] = 0x101;
     adev->perf_lock_opts[1] = 0x20E;
@@ -5058,8 +5082,9 @@
     audio_extn_ds2_enable(adev);
     *device = &adev->device.common;
 
-    audio_extn_utils_update_streams_output_cfg_list(adev->platform, adev->mixer,
-                                                    &adev->streams_output_cfg_list);
+    audio_extn_utils_update_streams_cfg_lists(adev->platform, adev->mixer,
+                                             &adev->streams_output_cfg_list,
+                                             &adev->streams_input_cfg_list);
 
     audio_device_ref_count++;
 
@@ -5097,6 +5122,7 @@
     if (adev->adm_init)
         adev->adm_data = adev->adm_init();
 
+    qahwi_init(*device);
     audio_extn_perf_lock_init();
     ALOGV("%s: exit", __func__);
     return 0;
diff --git a/hal/audio_hw.h b/hal/audio_hw.h
index 83ad54d..f837952 100644
--- a/hal/audio_hw.h
+++ b/hal/audio_hw.h
@@ -47,6 +47,7 @@
 #include <audio_route/audio_route.h>
 #include "audio_defs.h"
 #include "voice.h"
+#include "audio_hw_extn_api.h"
 
 #define VISUALIZER_LIBRARY_PATH "/system/lib/soundfx/libqcomvisualizer.so"
 #define OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH "/system/lib/soundfx/libqcompostprocbundle.so"
@@ -79,6 +80,8 @@
 
 #define MAX_PERF_LOCK_OPTS 20
 
+#define MAX_STREAM_PROFILE_STR_LEN 32
+
 typedef enum card_status_t {
     CARD_STATUS_OFFLINE,
     CARD_STATUS_ONLINE
@@ -115,6 +118,9 @@
     /* Capture usecases */
     USECASE_AUDIO_RECORD,
     USECASE_AUDIO_RECORD_COMPRESS,
+    USECASE_AUDIO_RECORD_COMPRESS2,
+    USECASE_AUDIO_RECORD_COMPRESS3,
+    USECASE_AUDIO_RECORD_COMPRESS4,
     USECASE_AUDIO_RECORD_LOW_LATENCY,
     USECASE_AUDIO_RECORD_FM_VIRTUAL,
 
@@ -206,6 +212,7 @@
     audio_format_t format;
     audio_devices_t devices;
     audio_output_flags_t flags;
+    char profile[MAX_STREAM_PROFILE_STR_LEN];
     audio_usecase_t usecase;
     /* Array of supported channel mask configurations. +1 so that the last entry is always 0 */
     audio_channel_mask_t supported_channel_masks[MAX_SUPPORTED_CHANNEL_MASKS + 1];
@@ -262,12 +269,17 @@
     audio_format_t format;
     audio_io_handle_t capture_handle;
     audio_input_flags_t flags;
+    char profile[MAX_STREAM_PROFILE_STR_LEN];
     bool is_st_session;
     bool is_st_session_active;
     int sample_rate;
     int bit_width;
     bool realtime;
     int af_period_multiplier;
+    struct stream_app_type_cfg app_type_cfg;
+    void *cin_extn;
+    qahwi_stream_in_t qahwi_in;
+
     struct audio_device *dev;
 };
 
@@ -291,6 +303,8 @@
     audio_devices_t devices;
     snd_device_t out_snd_device;
     snd_device_t in_snd_device;
+    struct stream_app_type_cfg out_app_type_cfg;
+    struct stream_app_type_cfg in_app_type_cfg;
     union stream_ptr stream;
 };
 
@@ -309,9 +323,15 @@
     uint32_t sample_rate;
 };
 
-struct streams_output_cfg {
+typedef union {
+    audio_output_flags_t out_flags;
+    audio_input_flags_t in_flags;
+} audio_io_flags_t;
+
+struct streams_io_cfg {
     struct listnode list;
-    audio_output_flags_t flags;
+    audio_io_flags_t flags;
+    char profile[MAX_STREAM_PROFILE_STR_LEN];
     struct listnode format_list;
     struct listnode sample_rate_list;
     struct stream_app_type_cfg app_type_cfg;
@@ -346,6 +366,7 @@
     int *snd_dev_ref_cnt;
     struct listnode usecase_list;
     struct listnode streams_output_cfg_list;
+    struct listnode streams_input_cfg_list;
     struct audio_route *audio_route;
     int acdb_settings;
     bool speaker_lr_swap;
@@ -364,6 +385,7 @@
     bool is_channel_status_set;
     void *platform;
     unsigned int offload_usecases_state;
+    unsigned int pcm_record_uc_state;
     void *visualizer_lib;
     int (*visualizer_start_output)(audio_io_handle_t, int);
     int (*visualizer_stop_output)(audio_io_handle_t, int);
@@ -398,6 +420,7 @@
     int perf_lock_opts_size;
     bool native_playback_enabled;
     bool asrc_mode_enabled;
+    qahwi_device_t qahwi_dev;
 };
 
 int select_devices(struct audio_device *adev,
diff --git a/hal/audio_hw_extn_api.c b/hal/audio_hw_extn_api.c
new file mode 100644
index 0000000..c4a3cdf
--- /dev/null
+++ b/hal/audio_hw_extn_api.c
@@ -0,0 +1,220 @@
+/*
+* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are
+* met:
+*     * Redistributions of source code must retain the above copyright
+*       notice, this list of conditions and the following disclaimer.
+*     * Redistributions in binary form must reproduce the above
+*       copyright notice, this list of conditions and the following
+*       disclaimer in the documentation and/or other materials provided
+*       with the distribution.
+*     * Neither the name of The Linux Foundation nor the names of its
+*       contributors may be used to endorse or promote products derived
+*       from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+* ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#define LOG_TAG "qahwi"
+/*#define LOG_NDEBUG 0*/
+#define LOG_NDDEBUG 0
+
+#include <errno.h>
+#include <cutils/log.h>
+
+#include <hardware/audio.h>
+#include "sound/compress_params.h"
+#include "audio_hw.h"
+#include "audio_extn.h"
+#include "audio_hw_extn_api.h"
+
+/* default timestamp metadata definition if not defined in kernel*/
+#ifndef COMPRESSED_TIMESTAMP_FLAG
+#define COMPRESSED_TIMESTAMP_FLAG 0
+struct snd_codec_metadata {
+uint64_t timestamp;
+};
+#endif
+
+int qahwi_get_param_data(const struct audio_device *adev,
+                         qahw_param_id param_id, qahw_param_payload *payload)
+{
+    int ret = 0;
+
+    if (adev == NULL) {
+        ALOGE("%s::INVALID PARAM\n",__func__);
+        return -EINVAL;
+    }
+
+    if (payload == NULL) {
+        ALOGE("%s::INVALID PAYLOAD VALUE\n",__func__);
+        return -EINVAL;
+    }
+
+    switch (param_id) {
+        case QAHW_PARAM_SOUND_FOCUS:
+              ret = audio_extn_get_soundfocus_data(adev,
+                     (struct qahw_sound_focus_param *)payload);
+              break;
+        case QAHW_PARAM_SOURCE_TRACK:
+              ret = audio_extn_get_sourcetrack_data(adev,
+                     (struct qahw_source_tracking_param*)payload);
+              break;
+       default:
+             ALOGE("%s::INVALID PARAM ID:%d\n",__func__,param_id);
+             ret = -EINVAL;
+             break;
+
+        return ret;
+        }
+}
+
+ssize_t qahwi_in_read_v2(struct audio_stream_in *stream, void* buffer,
+                          size_t bytes, uint64_t *timestamp)
+{
+    struct stream_in *in = (struct stream_in *)stream;
+    struct snd_codec_metadata *mdata = NULL;
+    size_t mdata_size = 0, bytes_read = 0;
+    char *buf = NULL;
+    size_t ret = 0;
+
+    if (!in->qahwi_in.is_inititalized) {
+        ALOGE("%s: invalid state!", __func__);
+        return -EINVAL;
+    }
+    if (COMPRESSED_TIMESTAMP_FLAG &&
+        (in->flags & AUDIO_INPUT_FLAG_TIMESTAMP)) {
+        if (bytes != in->stream.common.get_buffer_size(&stream->common)) {
+            ALOGE("%s: bytes requested must be fragment size in timestamp mode!", __func__);
+            return -EINVAL;
+        }
+        mdata_size = sizeof(struct snd_codec_metadata);
+        buf = (char *) in->qahwi_in.ibuf;
+        ret = in->qahwi_in.base.read(&in->stream, (void *)buf, bytes + mdata_size);
+        if (ret == bytes + mdata_size) {
+           bytes_read = bytes;
+           memcpy(buffer, buf + mdata_size, bytes);
+           if (timestamp) {
+               mdata = (struct snd_codec_metadata *) buf;
+               *timestamp = mdata->timestamp;
+           }
+        } else {
+           ALOGE("%s: error! read returned %zd", __func__, ret);
+        }
+    } else {
+        bytes_read = in->qahwi_in.base.read(stream, buffer, bytes);
+        if (timestamp)
+            *timestamp = (uint64_t ) -1;
+    }
+    ALOGV("%s: flag 0x%x, bytes %zd, read %zd, ret %zd",
+          __func__, in->flags, bytes, bytes_read, ret);
+    return bytes_read;
+}
+
+static void qahwi_close_input_stream(struct audio_hw_device *dev,
+                               struct audio_stream_in *stream_in)
+{
+    struct audio_device *adev = (struct audio_device *) dev;
+    struct stream_in *in = (struct stream_in *)stream_in;
+
+    ALOGV("%s", __func__);
+    if (!adev->qahwi_dev.is_inititalized || !in->qahwi_in.is_inititalized) {
+        ALOGE("%s: invalid state!", __func__);
+        return;
+    }
+    if (in->qahwi_in.ibuf)
+        free(in->qahwi_in.ibuf);
+    adev->qahwi_dev.base.close_input_stream(dev, stream_in);
+}
+
+static int qahwi_open_input_stream(struct audio_hw_device *dev,
+                             audio_io_handle_t handle,
+                             audio_devices_t devices,
+                             struct audio_config *config,
+                             struct audio_stream_in **stream_in,
+                             audio_input_flags_t flags,
+                             const char *address,
+                             audio_source_t source)
+{
+    struct audio_device *adev = (struct audio_device *) dev;
+    struct stream_in *in = NULL;
+    size_t buf_size = 0, mdata_size = 0;
+    int ret = 0;
+
+    ALOGV("%s: dev_init %d, flags 0x%x", __func__,
+              adev->qahwi_dev.is_inititalized, flags);
+    if (!adev->qahwi_dev.is_inititalized) {
+        ALOGE("%s: invalid state!", __func__);
+        return -EINVAL;
+    }
+
+    ret = adev->qahwi_dev.base.open_input_stream(dev, handle, devices, config,
+                                                 stream_in, flags, address, source);
+    if (ret)
+        return ret;
+
+    in = (struct stream_in *)*stream_in;
+    // keep adev fptrs before overriding
+    in->qahwi_in.base = in->stream;
+
+    in->qahwi_in.is_inititalized = true;
+
+    if (COMPRESSED_TIMESTAMP_FLAG &&
+        (flags & AUDIO_INPUT_FLAG_TIMESTAMP)) {
+        // set read to NULL as this is not supported in timestamp mode
+        in->stream.read = NULL;
+
+        mdata_size = sizeof(struct snd_codec_metadata);
+        buf_size = mdata_size +
+                   in->qahwi_in.base.common.get_buffer_size(&in->stream.common);
+
+        in->qahwi_in.ibuf = malloc(buf_size);
+        if (!in->qahwi_in.ibuf) {
+            ALOGE("%s: allocation failed for timestamp metadata!", __func__);
+            qahwi_close_input_stream(dev, &in->stream);
+            *stream_in = NULL;
+            ret = -ENOMEM;
+        }
+        ALOGD("%s: ibuf %p, buff_size %zd",
+              __func__, in->qahwi_in.ibuf, buf_size);
+    }
+    return ret;
+}
+
+void qahwi_init(hw_device_t *device)
+{
+    struct audio_device *adev = (struct audio_device *) device;
+
+    ALOGD("%s", __func__);
+
+    // keep adev fptrs before overriding,
+    // as it might be used internally by overriding implementation
+    adev->qahwi_dev.base = adev->device;
+
+    adev->device.open_input_stream = qahwi_open_input_stream;
+    adev->device.close_input_stream = qahwi_close_input_stream;
+
+    adev->qahwi_dev.is_inititalized = true;
+}
+void qahwi_deinit(hw_device_t *device)
+{
+    struct audio_device *adev = (struct audio_device *) device;
+
+    ALOGV("%s: is_initialized %d", __func__, adev->qahwi_dev.is_inititalized);
+    if (!adev->qahwi_dev.is_inititalized) {
+        ALOGE("%s: invalid state!", __func__);
+    }
+}
+
diff --git a/hal/audio_hw_extn_api.h b/hal/audio_hw_extn_api.h
new file mode 100644
index 0000000..e5fa9ec
--- /dev/null
+++ b/hal/audio_hw_extn_api.h
@@ -0,0 +1,60 @@
+/*
+* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are
+* met:
+*     * Redistributions of source code must retain the above copyright
+*       notice, this list of conditions and the following disclaimer.
+*     * Redistributions in binary form must reproduce the above
+*       copyright notice, this list of conditions and the following
+*       disclaimer in the documentation and/or other materials provided
+*       with the distribution.
+*     * Neither the name of The Linux Foundation nor the names of its
+*       contributors may be used to endorse or promote products derived
+*       from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+* ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef AUDIO_HW_EXTN_API_H
+#define AUDIO_HW_EXTN_API_H
+__BEGIN_DECLS
+#ifdef AUDIO_HW_EXTN_API_ENABLED
+#include <hardware/audio.h>
+typedef struct qahwi_stream_in qahwi_stream_in_t;
+typedef struct qahwi_device qahwi_device_t;
+
+struct qahwi_stream_in {
+    struct audio_stream_in base;
+    bool is_inititalized;
+    void *ibuf;
+};
+
+struct qahwi_device {
+    struct audio_hw_device base;
+    bool is_inititalized;
+};
+
+void qahwi_init(hw_device_t *device);
+void qahwi_deinit(hw_device_t *device);
+#else
+typedef void *qahwi_stream_in_t;
+typedef void *qahwi_device_t;
+
+#define qahwi_init(device) (0)
+#define qahwi_deinit(device) (0)
+#endif  // AUDIO_HW_EXTN_API_ENABLED
+
+__END_DECLS
+#endif  // AUDIO_HW_EXTN_API_H
diff --git a/hal/msm8916/platform.c b/hal/msm8916/platform.c
index 012638c..c2bcbe0 100644
--- a/hal/msm8916/platform.c
+++ b/hal/msm8916/platform.c
@@ -301,6 +301,9 @@
     [USECASE_AUDIO_PLAYBACK_ULL] = {MULTIMEDIA3_PCM_DEVICE, MULTIMEDIA3_PCM_DEVICE},
     [USECASE_AUDIO_RECORD] = {AUDIO_RECORD_PCM_DEVICE, AUDIO_RECORD_PCM_DEVICE},
     [USECASE_AUDIO_RECORD_COMPRESS] = {COMPRESS_CAPTURE_DEVICE, COMPRESS_CAPTURE_DEVICE},
+    [USECASE_AUDIO_RECORD_COMPRESS2] = {-1, -1},
+    [USECASE_AUDIO_RECORD_COMPRESS3] = {-1, -1},
+    [USECASE_AUDIO_RECORD_COMPRESS4] = {-1, -1},
     [USECASE_AUDIO_RECORD_LOW_LATENCY] = {LOWLATENCY_PCM_DEVICE,
                                           LOWLATENCY_PCM_DEVICE},
     [USECASE_AUDIO_RECORD_FM_VIRTUAL] = {MULTIMEDIA2_PCM_DEVICE,
@@ -753,6 +756,10 @@
     {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_OFFLOAD9)},
     {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_ULL)},
     {TO_NAME_INDEX(USECASE_AUDIO_RECORD)},
+    {TO_NAME_INDEX(USECASE_AUDIO_RECORD_COMPRESS)},
+    {TO_NAME_INDEX(USECASE_AUDIO_RECORD_COMPRESS2)},
+    {TO_NAME_INDEX(USECASE_AUDIO_RECORD_COMPRESS3)},
+    {TO_NAME_INDEX(USECASE_AUDIO_RECORD_COMPRESS4)},
     {TO_NAME_INDEX(USECASE_AUDIO_RECORD_LOW_LATENCY)},
     {TO_NAME_INDEX(USECASE_VOICE_CALL)},
     {TO_NAME_INDEX(USECASE_VOICE2_CALL)},
@@ -2600,6 +2607,8 @@
         if (backend_tag_table[snd_device] != NULL) {
                 if (strcmp(backend_tag_table[snd_device], "usb-headset-mic") == 0)
                         port = USB_AUDIO_TX_BACKEND;
+                else if (strstr(backend_tag_table[snd_device], "bt-sco") != NULL)
+                        port = BT_SCO_TX_BACKEND;
         }
     } else {
         ALOGW("%s:napb: Invalid device - %d ", __func__, snd_device);
@@ -3317,6 +3326,10 @@
 {
     struct platform_data *my_data = (struct platform_data *)platform;
     struct audio_device *adev = my_data->adev;
+    /*
+     * TODO: active_input always points to last opened input. Source returned will
+     * be wrong if more than one active inputs are present.
+     */
     audio_source_t  source = (adev->active_input == NULL) ?
                                 AUDIO_SOURCE_DEFAULT : adev->active_input->source;
 
@@ -4370,8 +4383,8 @@
           __func__, bit_width, sample_rate, channels,backend_idx,
           platform_get_snd_device_name(snd_device));
 
-    if (bit_width !=
-        my_data->current_backend_cfg[backend_idx].bit_width) {
+    if ((my_data->current_backend_cfg[backend_idx].bitwidth_mixer_ctl) &&
+        (bit_width != my_data->current_backend_cfg[backend_idx].bit_width)) {
 
         struct  mixer_ctl *ctl = NULL;
         ctl = mixer_get_ctl_by_name(adev->mixer,
@@ -4409,7 +4422,8 @@
      */
     // TODO: This has to be more dynamic based on policy file
 
-    if ((sample_rate != my_data->current_backend_cfg[(int)backend_idx].sample_rate) &&
+    if ((my_data->current_backend_cfg[backend_idx].samplerate_mixer_ctl) &&
+        (sample_rate != my_data->current_backend_cfg[(int)backend_idx].sample_rate) &&
             (my_data->hifi_audio)) {
             /*
              * sample rate update is needed only for hifi audio enabled platforms
diff --git a/hal/msm8916/platform.h b/hal/msm8916/platform.h
index a0ae7d0..24c793e 100644
--- a/hal/msm8916/platform.h
+++ b/hal/msm8916/platform.h
@@ -240,6 +240,7 @@
     SLIMBUS_0_TX,
     DEFAULT_CODEC_TX_BACKEND = SLIMBUS_0_TX,
     USB_AUDIO_TX_BACKEND,
+    BT_SCO_TX_BACKEND,
     MAX_CODEC_BACKENDS
 };
 
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index 3abb904..81741fc 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -286,6 +286,9 @@
 
     [USECASE_AUDIO_RECORD] = {AUDIO_RECORD_PCM_DEVICE, AUDIO_RECORD_PCM_DEVICE},
     [USECASE_AUDIO_RECORD_COMPRESS] = {COMPRESS_CAPTURE_DEVICE, COMPRESS_CAPTURE_DEVICE},
+    [USECASE_AUDIO_RECORD_COMPRESS2] = {-1, -1},
+    [USECASE_AUDIO_RECORD_COMPRESS3] = {-1, -1},
+    [USECASE_AUDIO_RECORD_COMPRESS4] = {-1, -1},
     [USECASE_AUDIO_RECORD_LOW_LATENCY] = {LOWLATENCY_PCM_DEVICE,
                                           LOWLATENCY_PCM_DEVICE},
     [USECASE_AUDIO_RECORD_FM_VIRTUAL] = {MULTIMEDIA2_PCM_DEVICE,
@@ -721,6 +724,10 @@
     {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_OFFLOAD8)},
     {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_OFFLOAD9)},
     {TO_NAME_INDEX(USECASE_AUDIO_RECORD)},
+    {TO_NAME_INDEX(USECASE_AUDIO_RECORD_COMPRESS)},
+    {TO_NAME_INDEX(USECASE_AUDIO_RECORD_COMPRESS2)},
+    {TO_NAME_INDEX(USECASE_AUDIO_RECORD_COMPRESS3)},
+    {TO_NAME_INDEX(USECASE_AUDIO_RECORD_COMPRESS4)},
     {TO_NAME_INDEX(USECASE_AUDIO_RECORD_LOW_LATENCY)},
     {TO_NAME_INDEX(USECASE_VOICE_CALL)},
     {TO_NAME_INDEX(USECASE_VOICE2_CALL)},
@@ -2363,6 +2370,8 @@
         if (backend_tag_table[snd_device] != NULL) {
                 if (strcmp(backend_tag_table[snd_device], "usb-headset-mic") == 0)
                         port = USB_AUDIO_TX_BACKEND;
+                else if (strstr(backend_tag_table[snd_device], "bt-sco") != NULL)
+                        port = BT_SCO_TX_BACKEND;
         }
     } else {
         ALOGW("%s:napb: Invalid device - %d ", __func__, snd_device);
@@ -3018,6 +3027,10 @@
 {
     struct platform_data *my_data = (struct platform_data *)platform;
     struct audio_device *adev = my_data->adev;
+    /*
+     * TODO: active_input always points to last opened input. Source returned will
+     * be wrong if more than one active inputs are present.
+     */
     audio_source_t  source = (adev->active_input == NULL) ?
                                 AUDIO_SOURCE_DEFAULT : adev->active_input->source;
 
@@ -4350,8 +4363,8 @@
           sample_rate, channels, backend_idx,
           platform_get_snd_device_name(snd_device));
 
-    if (bit_width !=
-        my_data->current_backend_cfg[backend_idx].bit_width) {
+    if ((my_data->current_backend_cfg[backend_idx].bitwidth_mixer_ctl) &&
+        (bit_width != my_data->current_backend_cfg[backend_idx].bit_width)) {
 
         struct  mixer_ctl *ctl = NULL;
         ctl = mixer_get_ctl_by_name(adev->mixer,
@@ -4385,8 +4398,8 @@
         ret = 0;
     }
 
-    if (sample_rate !=
-       my_data->current_backend_cfg[backend_idx].sample_rate) {
+    if ((my_data->current_backend_cfg[backend_idx].samplerate_mixer_ctl) &&
+        (sample_rate != my_data->current_backend_cfg[backend_idx].sample_rate)) {
             char *rate_str = NULL;
             struct  mixer_ctl *ctl = NULL;
 
diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h
index 6f55c2c..eb34293 100644
--- a/hal/msm8974/platform.h
+++ b/hal/msm8974/platform.h
@@ -231,6 +231,7 @@
     SLIMBUS_0_TX,
     DEFAULT_CODEC_TX_BACKEND = SLIMBUS_0_TX,
     USB_AUDIO_TX_BACKEND,
+    BT_SCO_TX_BACKEND,
     MAX_CODEC_BACKENDS
 };
 
diff --git a/qahw_api/Android.mk b/qahw_api/Android.mk
index 8c99c5b..98e1a38 100644
--- a/qahw_api/Android.mk
+++ b/qahw_api/Android.mk
@@ -17,7 +17,8 @@
 LOCAL_SHARED_LIBRARIES := \
     liblog \
     libcutils \
-    libhardware
+    libhardware \
+    libdl
 
 LOCAL_COPY_HEADERS_TO   := mm-audio/qahw_api/inc
 LOCAL_COPY_HEADERS      := inc/qahw_api.h
diff --git a/qahw_api/inc/qahw_api.h b/qahw_api/inc/qahw_api.h
index 17f6f5f..1dc52f2 100644
--- a/qahw_api/inc/qahw_api.h
+++ b/qahw_api/inc/qahw_api.h
@@ -395,6 +395,12 @@
  */
 int qahw_set_mode(qahw_module_handle_t *hw_module, audio_mode_t mode);
 
+/* Mute/unmute mic during voice/voip/HFP call */
+int qahw_set_mic_mute(qahw_module_handle_t *hw_module, bool state);
+
+/* Get mute/unmute status of mic during voice call */
+int qahw_get_mic_mute(qahw_module_handle_t *hw_module, bool *state);
+
 /* set/get global audio parameters */
 int qahw_set_parameters(qahw_module_handle_t *hw_module, const char *kv_pairs);
 
@@ -415,6 +421,13 @@
 /*returns current QTI HAL version */
 int qahw_get_version();
 
+/* Api to implement get parameters based on keyword param_id
+ * and store data in payload.
+ */
+int qahw_get_param_data(const qahw_module_handle_t *hw_module,
+                        qahw_param_id param_id,
+                        qahw_param_payload *payload);
+
 __END_DECLS
 
 #endif  // QTI_AUDIO_HAL_API_H
diff --git a/qahw_api/inc/qahw_defs.h b/qahw_api/inc/qahw_defs.h
index 4441435..c3def18 100644
--- a/qahw_api/inc/qahw_defs.h
+++ b/qahw_api/inc/qahw_defs.h
@@ -162,6 +162,14 @@
 
 #define QAHW_OFFLOAD_CODEC_VORBIS_BITSTREAM_FMT "music_offload_vorbis_bitstream_fmt"
 
+/* Set or Query stream profile type */
+#define QAHW_PARAMETER_STREAM_PROFILE "audio_stream_profile"
+
+/* audio inout flag for timestamp mode.
+ * check other input flags defined in audio.h for conflicts
+ */
+#define QAHW_INPUT_FLAG_TIMESTAMP 0x80000000
+
 /* Query fm volume */
 #define QAHW_PARAMETER_KEY_FM_VOLUME "fm_volume"
 
@@ -209,6 +217,32 @@
     uint32_t reserved[64]; /*reserved for future */
 } qahw_in_buffer_t;
 
+#define MAX_SECTORS 8
+
+struct qahw_source_tracking_param {
+    uint8_t   vad[MAX_SECTORS];
+    uint16_t  doa_speech;
+    uint16_t  doa_noise[3];
+    uint8_t   polar_activity[360];
+};
+
+struct qahw_sound_focus_param {
+    uint16_t  start_angle[MAX_SECTORS];
+    uint8_t   enable[MAX_SECTORS];
+    uint16_t  gain_step;
+};
+
+typedef union {
+    struct qahw_source_tracking_param st_params;
+    struct qahw_sound_focus_param sf_params;
+} qahw_param_payload;
+
+typedef enum {
+    QAHW_PARAM_SOURCE_TRACK,
+    QAHW_PARAM_SOUND_FOCUS
+} qahw_param_id;
+
+
 __END_DECLS
 
 #endif  // QTI_AUDIO_HAL_DEFS_H
diff --git a/qahw_api/src/qahw.c b/qahw_api/src/qahw.c
index 06bcee1..4025c56 100644
--- a/qahw_api/src/qahw.c
+++ b/qahw_api/src/qahw.c
@@ -31,6 +31,7 @@
 /*#define LOG_NDEBUG 0*/
 #define LOG_NDDEBUG 0
 
+#include <dlfcn.h>
 #include <utils/Log.h>
 #include <stdlib.h>
 #include <cutils/list.h>
@@ -46,6 +47,9 @@
  */
 #define QAHW_MODULE_API_VERSION_CURRENT QAHW_MODULE_API_VERSION_0_0
 
+typedef uint64_t (*qahwi_in_read_v2_t)(audio_stream_in_t *in, void* buffer,
+                                       size_t bytes, uint64_t *timestamp);
+
 typedef struct {
     audio_hw_device_t *audio_device;
     char module_name[MAX_MODULE_NAME_LENGTH];
@@ -54,6 +58,7 @@
     struct listnode out_list;
     pthread_mutex_t lock;
     uint32_t ref_count;
+    const hw_module_t* module;
 } qahw_module_t;
 
 typedef struct {
@@ -74,6 +79,7 @@
     qahw_module_t *module;
     struct listnode list;
     pthread_mutex_t lock;
+    qahwi_in_read_v2_t qahwi_in_read_v2;
 } qahw_stream_in_t;
 
 typedef enum {
@@ -85,6 +91,10 @@
 static int qahw_list_count;
 static pthread_mutex_t qahw_module_init_lock = PTHREAD_MUTEX_INITIALIZER;
 
+typedef int (*qahwi_get_param_data_t) (const struct audio_device *,
+                              qahw_param_id, qahw_param_payload *);
+qahwi_get_param_data_t qahwi_get_param_data;
+
 /** Start of internal functions */
 /******************************************************************************/
 
@@ -916,8 +926,11 @@
 
     pthread_mutex_lock(&qahw_stream_in->lock);
     in = qahw_stream_in->stream;
-    /*TBD:: call HAL timestamp read API*/
-    if (in->read) {
+    if (qahw_stream_in->qahwi_in_read_v2) {
+        rc = qahw_stream_in->qahwi_in_read_v2(in, in_buf->buffer,
+                                         in_buf->bytes, in_buf->timestamp);
+        in_buf->offset = 0;
+    } else if (in->read) {
         rc = in->read(in, in_buf->buffer, in_buf->bytes);
         in_buf->offset = 0;
     } else {
@@ -1078,6 +1091,64 @@
     return rc;
 }
 
+int qahw_set_mic_mute(qahw_module_handle_t *hw_module, bool state)
+{
+    int rc = -EINVAL;
+    qahw_module_t *qahw_module = (qahw_module_t *)hw_module;
+    qahw_module_t *qahw_module_temp;
+
+    pthread_mutex_lock(&qahw_module_init_lock);
+    qahw_module_temp = get_qahw_module_by_ptr(qahw_module);
+    pthread_mutex_unlock(&qahw_module_init_lock);
+    if (qahw_module_temp == NULL) {
+        ALOGE("%s:: invalid hw module %p", __func__, qahw_module);
+        goto exit;
+    }
+
+    pthread_mutex_lock(&qahw_module->lock);
+    if (qahw_module->audio_device->set_mic_mute) {
+        rc = qahw_module->audio_device->set_mic_mute(qahw_module->audio_device,
+                                                 state);
+    } else {
+        rc = -ENOSYS;
+        ALOGW("%s not supported", __func__);
+    }
+    pthread_mutex_unlock(&qahw_module->lock);
+
+exit:
+    return rc;
+}
+
+int qahw_get_mic_mute(qahw_module_handle_t *hw_module, bool *state)
+{
+    size_t rc = 0;
+    qahw_module_t *qahw_module = (qahw_module_t *)hw_module;
+    qahw_module_t *qahw_module_temp;
+    audio_hw_device_t *audio_device;
+
+    pthread_mutex_lock(&qahw_module_init_lock);
+    qahw_module_temp = get_qahw_module_by_ptr(qahw_module);
+    pthread_mutex_unlock(&qahw_module_init_lock);
+    if (qahw_module_temp == NULL) {
+        ALOGE("%s:: invalid hw module %p", __func__, qahw_module);
+        goto exit;
+    }
+
+    pthread_mutex_lock(&qahw_module->lock);
+    audio_device = qahw_module->audio_device;
+    if (qahw_module->audio_device->get_mic_mute) {
+        rc = audio_device->get_mic_mute(qahw_module->audio_device,
+                                                 &state);
+    } else {
+        rc = -ENOSYS;
+        ALOGW("%s not supported", __func__);
+    }
+    pthread_mutex_unlock(&qahw_module->lock);
+
+exit:
+    return rc;
+}
+
 /* set/get global audio parameters */
 int qahw_set_parameters(qahw_module_handle_t *hw_module, const char *kv_pairs)
 {
@@ -1141,6 +1212,39 @@
     return str_param;
 }
 
+/* Api to implement get parameters  based on keyword param_id
+ * and store data in payload.
+ */
+int qahw_get_param_data(const qahw_module_handle_t *hw_module,
+                        qahw_param_id param_id,
+                        qahw_param_payload *payload)
+{
+    int ret = 0;
+    qahw_module_t *qahw_module = (qahw_module_t *)hw_module;
+    qahw_module_t *qahw_module_temp;
+
+    pthread_mutex_lock(&qahw_module_init_lock);
+    qahw_module_temp = get_qahw_module_by_ptr(qahw_module);
+    pthread_mutex_unlock(&qahw_module_init_lock);
+    if (qahw_module_temp == NULL) {
+        ALOGE("%s:: invalid hw module %p", __func__, qahw_module);
+        goto exit;
+    }
+
+    pthread_mutex_lock(&qahw_module->lock);
+
+    if (qahwi_get_param_data){
+        ret = qahwi_get_param_data (qahw_module->audio_device, param_id, payload);
+    } else {
+         ret = -ENOSYS;
+         ALOGE("%s not supported\n",__func__);
+    }
+    pthread_mutex_unlock(&qahw_module->lock);
+
+exit:
+     return ret;
+}
+
 /* Returns audio input buffer size according to parameters passed or
  * 0 if one of the parameters is not supported.
  * See also get_buffer_size which is for a particular stream.
@@ -1322,6 +1426,20 @@
         list_add_tail(&qahw_module->in_list, &qahw_stream_in->list);
     }
 
+    /* dlsym qahwi_in_read_v2 if timestamp flag is used */
+    if (!rc && (flags & QAHW_INPUT_FLAG_TIMESTAMP)) {
+        const char *error;
+
+        /* clear any existing errors */
+        dlerror();
+        qahw_stream_in->qahwi_in_read_v2 = (qahwi_in_read_v2_t)
+                          dlsym(qahw_module->module->dso, "qahwi_in_read_v2");
+        if ((error = dlerror()) != NULL) {
+            ALOGI("%s: dlsym error %s for qahwi_in_read_v2", __func__, error);
+            qahw_stream_in->qahwi_in_read_v2 = NULL;
+        }
+    }
+
 exit:
     pthread_mutex_unlock(&qahw_module->lock);
     return rc;
@@ -1423,8 +1541,14 @@
         audio_hw_device_close(audio_device);
         goto error_exit;
     }
+    qahw_module->module = module;
     ALOGD("%s::Loaded HAL %s module %p", __func__, ahal_name, qahw_module);
 
+    qahwi_get_param_data = (qahwi_get_param_data_t) dlsym (module->dso,
+                            "qahwi_get_param_data");
+    if (!qahwi_get_param_data)
+         ALOGD("%s::qahwi_get_param_data api is not defined\n",__func__);
+
     if (!qahw_list_count)
         list_init(&qahw_module_list);
     qahw_list_count++;