hal: add support for compressed recording

Add support for recording through commpressed driver.
Add qahw interface layer for non standard API implementation.

Change-Id: Id1689f2ccab9bb8b920098e9cda1083b7d3ec4da
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 0a7586c..cfd29e0 100644
--- a/hal/audio_extn/audio_defs.h
+++ b/hal/audio_extn/audio_defs.h
@@ -106,4 +106,9 @@
 /* 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
+
 #endif /* AUDIO_DEFS_H */
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index d7f127a..337acd1 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -593,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)
@@ -699,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..c032480
--- /dev/null
+++ b/hal/audio_extn/compress_in.c
@@ -0,0 +1,312 @@
+/*
+* 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)
+        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) {
+        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/utils.c b/hal/audio_extn/utils.c
index d4ffadd..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
@@ -104,6 +105,7 @@
     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[] = {
@@ -1081,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)
 {
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index ca5d3ad..d275e3d 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;
@@ -1750,6 +1697,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;
 
@@ -1795,6 +1750,7 @@
             goto error_open;
     }
 
+done_open:
     audio_extn_perf_lock_release(&adev->perf_lock_handle);
     ALOGD("%s: exit", __func__);
 
@@ -3400,6 +3356,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);
@@ -3450,6 +3408,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;
@@ -3586,7 +3546,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);
 
@@ -3620,14 +3580,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)) {
@@ -3636,23 +3598,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);
@@ -3686,7 +3644,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)
@@ -4606,7 +4564,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)
 {
@@ -4660,17 +4618,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;
@@ -4684,6 +4631,58 @@
     }
     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;
+        }
+    }
+
+    /* 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);
+    }
+
     if (in->device == AUDIO_DEVICE_IN_TELEPHONY_RX) {
         if (adev->mode != AUDIO_MODE_IN_CALL) {
             ret = -EINVAL;
@@ -4723,48 +4722,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;
@@ -4831,9 +4793,11 @@
         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 (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__);
@@ -4872,6 +4836,7 @@
         platform_deinit(adev->platform);
         if (adev->adm_deinit)
             adev->adm_deinit(adev->adm_data);
+        qahwi_deinit(device);
         free(device);
         adev = NULL;
     }
@@ -5120,6 +5085,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 8402578..38ac547 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"
@@ -117,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,
 
@@ -273,6 +277,8 @@
     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;
 };
@@ -413,6 +419,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..bfeda9b
--- /dev/null
+++ b/hal/audio_hw_extn_api.c
@@ -0,0 +1,187 @@
+/*
+* 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
+
+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..a6de6e9 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)},
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index 3abb904..7bfc5de 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)},