gta4xl-common: Import libaudioproxy from universal9820 BSP tree

* From https://gitlab.com/Linaro/96boards/e850-96/device/samsung/universal9820/-/tree/2d41352822861e02b1ba5df004a1240a770c9ba7/audio/proxy

Change-Id: I0ef0fb98115b1227260a3cd149ce4a26e0bfe585
diff --git a/audio/Android.mk b/audio/Android.mk
new file mode 100644
index 0000000..fc2a3b2
--- /dev/null
+++ b/audio/Android.mk
@@ -0,0 +1,19 @@
+#
+# Copyright (C) 2023 The LineageOS Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/audio/proxy/Android.mk b/audio/proxy/Android.mk
new file mode 100644
index 0000000..116da29
--- /dev/null
+++ b/audio/proxy/Android.mk
@@ -0,0 +1,71 @@
+# Copyright (C) 2017 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+SOC_BASE_PATH := $(TOP)/hardware/samsung_slsi/exynos
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+	audio_proxy.c \
+	audio_usb_proxy.c
+
+LOCAL_C_INCLUDES += \
+	$(SOC_BASE_PATH)/include/libaudio/audiohal \
+	external/tinyalsa/include \
+	external/tinycompress/include \
+	external/kernel-headers/original/uapi/sound \
+	$(call include-path-for, audio-utils) \
+	$(call include-path-for, audio-route) \
+	$(call include-path-for, alsa-utils) \
+	external/expat/lib
+
+LOCAL_HEADER_LIBRARIES := libhardware_headers
+LOCAL_SHARED_LIBRARIES := liblog libcutils libtinyalsa_sec libtinycompress libaudioutils libaudioroute_sec libalsautils_sec libexpat
+
+# BT A2DP Offload HAL Interface
+ifeq ($(BOARD_USE_BTA2DP_OFFLOAD),true)
+LOCAL_CFLAGS += -DSUPPORT_BTA2DP_OFFLOAD
+LOCAL_SRC_FILES += audio_a2dp_proxy.cpp
+LOCAL_SHARED_LIBRARIES += libbase libhidlbase libhidlmemory libhwbinder libutils android.hidl.allocator@1.0 android.hidl.memory@1.0
+LOCAL_SHARED_LIBRARIES += vendor.samsung_slsi.hardware.ExynosA2DPOffload@1.0
+endif
+
+LOCAL_CFLAGS += -Wno-unused-parameter -Wno-unused-variable -Wno-unused-function
+
+# To use MCD specific definitions
+LOCAL_CFLAGS += -DSUPPORT_MCD_FEATURE
+
+# To use the headers from vndk-ext libs
+LOCAL_CFLAGS += -D__ANDROID_VNDK_SEC__
+
+ifeq ($(BOARD_USE_SOUNDTRIGGER_HAL),true)
+LOCAL_CFLAGS += -DSUPPORT_STHAL_INTERFACE
+LOCAL_CFLAGS += -DTARGET_SOC_NAME=$(TARGET_SOC)
+endif
+
+ifeq ($(BOARD_USE_QUAD_MIC),true)
+LOCAL_CFLAGS += -DSUPPORT_QUAD_MIC
+endif
+
+ifeq ($(BOARD_USE_DIRECT_RCVSPK_PATH),true)
+LOCAL_CFLAGS += -DSUPPORT_DIRECT_RCVSPK_PATH
+endif
+
+LOCAL_MODULE := libaudioproxy
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_PROPRIETARY_MODULE := true
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/audio/proxy/audio_a2dp_proxy.cpp b/audio/proxy/audio_a2dp_proxy.cpp
new file mode 100644
index 0000000..8a896db
--- /dev/null
+++ b/audio/proxy/audio_a2dp_proxy.cpp
@@ -0,0 +1,406 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "audio_hw_a2dp_proxy"
+#define LOG_NDEBUG 0
+
+#include <stdlib.h>
+#include <errno.h>
+#include <dlfcn.h>
+
+#include <system/audio.h>
+#include <log/log.h>
+
+#include <android/hidl/allocator/1.0/IAllocator.h>
+#include <android/hidl/memory/1.0/IMemory.h>
+#include <hidlmemory/mapping.h>
+
+#include "vendor/samsung_slsi/hardware/ExynosA2DPOffload/1.0/IExynosA2DPOffload.h"
+#include "audio_a2dp_proxy.h"
+
+
+/*****************************************************************************/
+/**                                                                         **/
+/** BT A2DP Offload HAL                                                     **/
+/**                                                                         **/
+/*****************************************************************************/
+
+using vendor::samsung_slsi::hardware::ExynosA2DPOffload::V1_0::IExynosA2DPOffload;
+
+using ::android::sp;
+
+using ::android::hidl::base::V1_0::IBase;
+using ::android::hidl::allocator::V1_0::IAllocator;
+using ::android::hidl::memory::V1_0::IMemory;
+
+using ::android::hardware::hidl_memory;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_death_recipient;
+
+
+static android::sp<IExynosA2DPOffload> gA2DPHal_ = nullptr;
+static std::mutex gA2DPHalMutex;
+
+struct A2DPHalDeathRecipient : virtual public hidl_death_recipient {
+    // hidl_death_recipient interface
+    virtual void serviceDied(uint64_t, const android::wp<IBase>&) override {
+        std::lock_guard<std::mutex> lock(gA2DPHalMutex);
+        ALOGE("A2DPHAL just died");
+        gA2DPHal_ = nullptr;
+    }
+};
+
+// Retrieve a copy of client
+static android::sp<IExynosA2DPOffload> getA2DPHal() {
+    std::lock_guard<std::mutex> lock(gA2DPHalMutex);
+    static android::sp<A2DPHalDeathRecipient> gA2DPHalDeathRecipient = nullptr;
+    static bool gA2DPHalExists = true;
+
+    if (gA2DPHalExists && gA2DPHal_ == nullptr) {
+        gA2DPHal_ = IExynosA2DPOffload::getService();
+
+        if (gA2DPHal_ == nullptr) {
+            ALOGE("Unable to get A2DP Offload HAL service");
+            gA2DPHalExists = false;
+        } else {
+            if (gA2DPHalDeathRecipient == nullptr) {
+                gA2DPHalDeathRecipient = new A2DPHalDeathRecipient();
+            }
+            Return<bool> linked = gA2DPHal_->linkToDeath(
+                gA2DPHalDeathRecipient, 0 /* cookie */);
+            if (!linked.isOk()) {
+                ALOGE("Transaction error in linking to A2DP HAL death: %s",
+                      linked.description().c_str());
+                gA2DPHal_ = nullptr;
+            } else if (!linked) {
+                ALOGW("Unable to link to A2DP HAL death notifications");
+                gA2DPHal_ = nullptr;
+            } else {
+                ALOGD("Connect to A2DP HAL and link to death "
+                      "notification successfully");
+            }
+        }
+    }
+    return gA2DPHal_;
+}
+
+
+/*****************************************************************************
+**  Constants & Macros
+******************************************************************************/
+
+/* BT A2DP Host Status */
+typedef enum {
+    AUDIO_A2DP_STATUS_NONE,
+    AUDIO_A2DP_STATUS_INIT,         // Load BT A2DP Host IPC Library & BT A2DP Stream is closed
+    AUDIO_A2DP_STATUS_STANDBY,      // BT A2DP Stream is opened, but not working
+    AUDIO_A2DP_STATUS_STARTED,      // BT A2DP Stream is working
+    AUDIO_A2DP_STATUS_SUSPENDED,    // BT A2DP Stream us suspended
+    AUDIO_A2DP_STATUS_CNT,
+} a2dp_status;
+
+const char * a2dpstatus_table[AUDIO_A2DP_STATUS_CNT] = {
+    [AUDIO_A2DP_STATUS_NONE]      = "A2DP_STATUS_NONE",
+    [AUDIO_A2DP_STATUS_INIT]      = "A2DP_STATUS_INIT",
+    [AUDIO_A2DP_STATUS_STANDBY]   = "A2DP_STATUS_STANDBY",
+    [AUDIO_A2DP_STATUS_STARTED]   = "A2DP_STATUS_STARTED",
+    [AUDIO_A2DP_STATUS_SUSPENDED] = "A2DP_STATUS_SUSPENDED",
+};
+
+struct a2dp_proxy {
+    /* Local variables */
+    a2dp_status cur_status;
+    a2dp_status prev_status;
+};
+
+
+/******************************************************************************/
+/**                                                                          **/
+/** A2DP Proxy is Singleton                                                  **/
+/**                                                                          **/
+/******************************************************************************/
+
+static struct a2dp_proxy *instance = NULL;
+
+static struct a2dp_proxy* getInstance(void)
+{
+    if (instance == NULL) {
+        instance = (struct a2dp_proxy *)calloc(1, sizeof(struct a2dp_proxy));
+        ALOGI("proxy-%s: created A2DP Proxy Instance!", __func__);
+    }
+    return instance;
+}
+
+static void destroyInstance(void)
+{
+    if (instance) {
+        free(instance);
+        instance = NULL;
+        ALOGI("proxy-%s: destroyed A2DP Proxy Instance!", __func__);
+    }
+    return;
+}
+
+
+/******************************************************************************/
+/**                                                                          **/
+/** Bluetooth A2DP Proxy Interfaces                                          **/
+/**                                                                          **/
+/******************************************************************************/
+
+int proxy_a2dp_get_config(uint32_t *type, void *config)
+{
+    struct a2dp_proxy *aproxy = getInstance();
+    hidl_memory codec_info;
+    int ret = -1;
+
+    if (aproxy) {
+        android::sp<IExynosA2DPOffload> a2dpHal = getA2DPHal();
+        if (a2dpHal == nullptr) {
+            return ret;
+        }
+
+        if (aproxy->cur_status == AUDIO_A2DP_STATUS_STARTED) {
+            sp<IAllocator> ashmemAllocator = IAllocator::getService("ashmem");
+            Return<void> allocReturn = ashmemAllocator->allocate(4, [&](bool success, const hidl_memory& m) {
+                if (!success)
+                    ALOGE("proxy-%s: Failed to get AshMem Allocator", __func__);
+                else
+                    codec_info = m;
+            });
+
+            sp<IMemory> memory = ::android::hardware::mapMemory(codec_info);
+            if (memory.get() == nullptr)
+                ALOGE("proxy-%s: Failed to map Shared Memory", __func__);
+            else {
+                ret = a2dpHal->a2dp_get_codec_config(codec_info);
+                if (ret == 0) {
+                    uint32_t* codec_type = static_cast<uint32_t*>(static_cast<void*>(memory->getPointer()));
+                    ALOGI("proxy-%s: Codec Type = %d", __func__, codec_type[0]);
+
+                    // Copy A2DP CODEC Configurations based on CODEC Type
+                    *type = codec_type[0];
+                    if (codec_type[0] == (uint32_t)AUDIO_FORMAT_SBC) {
+                        memcpy(config, (void *)&codec_type[1], sizeof(audio_sbc_encoder_config));
+                    } else if (codec_type[0] == (uint32_t)AUDIO_FORMAT_APTX) {
+                        memcpy(config, (void *)&codec_type[1], sizeof(audio_aptx_encoder_config));
+                    }
+                } else
+                    ALOGE("proxy-%s: A2DP Stream did not get codec config", __func__);
+            }
+        } else
+            ALOGI("proxy-%s: Abnormal A2DP Status(%s)", __func__, a2dpstatus_table[aproxy->cur_status]);
+    }
+
+    return ret;
+}
+
+int proxy_a2dp_start(void)
+{
+    struct a2dp_proxy *aproxy = getInstance();
+    int ret = -1;
+
+    if (aproxy) {
+        android::sp<IExynosA2DPOffload> a2dpHal = getA2DPHal();
+        if (a2dpHal == nullptr) {
+            return ret;
+        }
+
+        if (aproxy->cur_status == AUDIO_A2DP_STATUS_STANDBY) {
+            ret = a2dpHal->a2dp_start_stream();
+            if (ret == 0) {
+                aproxy->prev_status = aproxy->cur_status;
+                aproxy->cur_status = AUDIO_A2DP_STATUS_STARTED;
+                ALOGI("proxy-%s: Transit to %s from %s", __func__,
+                      a2dpstatus_table[aproxy->cur_status], a2dpstatus_table[aproxy->prev_status]);
+            } else
+                ALOGE("proxy-%s: A2DP Stream did not started", __func__);
+        } else
+            ALOGI("proxy-%s: Abnormal A2DP Status(%s)", __func__, a2dpstatus_table[aproxy->cur_status]);
+    }
+
+    return ret;
+}
+
+int proxy_a2dp_stop(void)
+{
+    struct a2dp_proxy *aproxy = getInstance();
+    int ret = -1;
+
+    if (aproxy) {
+        android::sp<IExynosA2DPOffload> a2dpHal = getA2DPHal();
+        if (a2dpHal == nullptr) {
+            return ret;
+        }
+
+        if (aproxy->cur_status == AUDIO_A2DP_STATUS_STARTED) {
+            ret = a2dpHal->a2dp_stop_stream();
+            if (ret == 0) {
+                aproxy->prev_status = aproxy->cur_status;
+                aproxy->cur_status = AUDIO_A2DP_STATUS_STANDBY;
+                ALOGI("proxy-%s: Transit to %s from %s", __func__,
+                      a2dpstatus_table[aproxy->cur_status], a2dpstatus_table[aproxy->prev_status]);
+            } else
+                ALOGE("proxy-%s: A2DP Stream did not stopped", __func__);
+        } else
+            ALOGI("proxy-%s: Ignored as A2DP Status(%s)", __func__, a2dpstatus_table[aproxy->cur_status]);
+    }
+
+    return ret;
+}
+
+int proxy_a2dp_suspend(bool flag)
+{
+    struct a2dp_proxy *aproxy = getInstance();
+    int ret = 0;
+
+    if (aproxy) {
+        android::sp<IExynosA2DPOffload> a2dpHal = getA2DPHal();
+        if (a2dpHal == nullptr) {
+            return -1;
+        }
+
+        if (flag == true) {
+            if (aproxy->cur_status == AUDIO_A2DP_STATUS_STANDBY ||
+                aproxy->cur_status == AUDIO_A2DP_STATUS_STARTED) {
+                ret = a2dpHal->a2dp_suspend_stream();
+                if (ret == 0) {
+                    aproxy->prev_status = aproxy->cur_status;
+                    aproxy->cur_status = AUDIO_A2DP_STATUS_SUSPENDED;
+                    ALOGI("proxy-%s: Transit to %s from %s", __func__,
+                          a2dpstatus_table[aproxy->cur_status], a2dpstatus_table[aproxy->prev_status]);
+                } else
+                    ALOGE("proxy-%s: A2DP Stream did not suspended", __func__);
+            } else {
+                ALOGI("proxy-%s: Ignored as A2DP Status(%s)", __func__, a2dpstatus_table[aproxy->cur_status]);
+                ret = -1;
+            }
+        } else {
+            ret = a2dpHal->a2dp_clear_suspend_flag();
+            if (ret == 0 && aproxy->cur_status == AUDIO_A2DP_STATUS_SUSPENDED) {
+                aproxy->prev_status = aproxy->cur_status;
+                aproxy->cur_status = AUDIO_A2DP_STATUS_STANDBY;
+                ALOGI("proxy-%s: Transit to %s from %s", __func__,
+                      a2dpstatus_table[aproxy->cur_status], a2dpstatus_table[aproxy->prev_status]);
+            } else {
+                ALOGI("proxy-%s: Ignored as A2DP Status(%s)", __func__, a2dpstatus_table[aproxy->cur_status]);
+                ret = 0;
+            }
+        }
+    }
+
+    return ret;
+}
+
+int proxy_a2dp_open(void)
+{
+    struct a2dp_proxy *aproxy = getInstance();
+    int ret = -1;
+
+    if (aproxy) {
+        android::sp<IExynosA2DPOffload> a2dpHal = getA2DPHal();
+        if (a2dpHal == nullptr) {
+            return ret;
+        }
+
+        if (aproxy->cur_status == AUDIO_A2DP_STATUS_INIT) {
+            ret = a2dpHal->a2dp_open_stream();
+            if (ret == 0) {
+                aproxy->prev_status = aproxy->cur_status;
+                aproxy->cur_status = AUDIO_A2DP_STATUS_STANDBY;
+                ALOGI("proxy-%s: Transit to %s from %s", __func__,
+                      a2dpstatus_table[aproxy->cur_status], a2dpstatus_table[aproxy->prev_status]);
+            } else
+                ALOGE("proxy-%s: A2DP Stream did not opened", __func__);
+        } else
+            ALOGE("proxy-%s: Abnormal A2DP Status(%s)", __func__, a2dpstatus_table[aproxy->cur_status]);
+    }
+
+    return ret;
+}
+
+int proxy_a2dp_close(void)
+{
+    struct a2dp_proxy *aproxy = getInstance();
+    int ret = -1;
+
+    if (aproxy) {
+        android::sp<IExynosA2DPOffload> a2dpHal = getA2DPHal();
+        if (a2dpHal == nullptr) {
+            return ret;
+        }
+
+        if (aproxy->cur_status == AUDIO_A2DP_STATUS_STARTED) {
+            ret = a2dpHal->a2dp_stop_stream();
+            if (ret == 0) {
+                aproxy->prev_status = aproxy->cur_status;
+                aproxy->cur_status = AUDIO_A2DP_STATUS_STANDBY;
+                ALOGI("proxy-%s: Transit to %s from %s", __func__,
+                      a2dpstatus_table[aproxy->cur_status], a2dpstatus_table[aproxy->prev_status]);
+            } else
+                ALOGE("proxy-%s: A2DP Stream did not stopped", __func__);
+        }
+
+        ret = a2dpHal->a2dp_close_stream();
+        if (ret == 0) {
+            aproxy->prev_status = aproxy->cur_status;
+            aproxy->cur_status = AUDIO_A2DP_STATUS_INIT;
+            ALOGI("proxy-%s: Transit to %s from %s", __func__,
+                  a2dpstatus_table[aproxy->cur_status], a2dpstatus_table[aproxy->prev_status]);
+        } else
+            ALOGE("proxy-%s: A2DP Stream did not closed", __func__);
+    }
+
+    return ret;
+}
+
+int proxy_a2dp_init(void)
+{
+    struct a2dp_proxy *aproxy = NULL;
+
+    /* Creates the structure for a2dp_proxy */
+    aproxy = getInstance();
+    if (!aproxy) {
+        ALOGE("proxy-%s: Failed to create for a2dp_proxy", __func__);
+        return -1;
+    }
+
+    /* Initializes variables */
+    aproxy->cur_status = AUDIO_A2DP_STATUS_INIT;
+    aproxy->prev_status = AUDIO_A2DP_STATUS_NONE;
+    ALOGI("proxy-%s: Transit to %s from %s", __func__,
+          a2dpstatus_table[aproxy->cur_status], a2dpstatus_table[aproxy->prev_status]);
+
+    return 0;
+}
+
+int proxy_a2dp_deinit(void)
+{
+    struct a2dp_proxy *aproxy = getInstance();
+
+    if (aproxy) {
+        aproxy->cur_status = AUDIO_A2DP_STATUS_NONE;
+        ALOGI("proxy-%s: Transit to %s", __func__, a2dpstatus_table[aproxy->cur_status]);
+
+        destroyInstance();
+        ALOGI("proxy-%s: a2dp_proxy is destroyed", __func__);
+        aproxy = NULL;
+    }
+
+    return 0;
+}
+
diff --git a/audio/proxy/audio_a2dp_proxy.h b/audio/proxy/audio_a2dp_proxy.h
new file mode 100644
index 0000000..c2724b7
--- /dev/null
+++ b/audio/proxy/audio_a2dp_proxy.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AUDIO_A2DP_PROXY_H
+#define AUDIO_A2DP_PROXY_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*****************************************************************************
+**  Constants & Macros
+******************************************************************************/
+
+#if 0
+enum {
+    ENC_CODEC_TYPE_SBC  = 520093696u, // 0x1F000000UL
+    ENC_CODEC_TYPE_APTX = 536870912u, // 0x20000000UL
+};
+#endif
+
+/* Encoder Format & Channel Definition */
+#define ENC_MEDIA_FMT_APTX      0x000131ff
+#define ENC_MEDIA_FMT_APTX_HD   0x00013200
+#define ENC_MEDIA_FMT_SBC       0x00010BF2
+
+#define PCM_CHANNEL_L           1
+#define PCM_CHANNEL_R           2
+#define PCM_CHANNEL_C           3
+
+/* These Configurations from A2DP IPC Library */
+typedef struct {
+    uint32_t subband;       /* 4, 8 */
+    uint32_t blk_len;       /* 4, 8, 12, 16 */
+    uint16_t sampling_rate; /*44.1khz,48khz*/
+    uint8_t  channels;      /*0(Mono),1(Dual_mono),2(Stereo),3(JS)*/
+    uint8_t  alloc;         /*0(Loudness),1(SNR)*/
+    uint8_t  min_bitpool;   /* 2 */
+    uint8_t  max_bitpool;   /*53(44.1khz),51 (48khz) */
+    uint32_t bitrate;       /* 320kbps to 512kbps */
+} audio_sbc_encoder_config;
+
+typedef struct {
+    uint16_t sampling_rate;
+    uint8_t  channels;
+    uint32_t bitrate;
+} audio_aptx_encoder_config;
+
+/* These Configurations for Real A2DP Encoder */
+struct sbc_enc_cfg_t {
+    uint32_t      enc_format;
+    uint32_t      num_subbands;
+    uint32_t      blk_len;
+    uint32_t      channel_mode;
+    uint32_t      alloc_method;
+    uint32_t      bit_rate;
+    uint32_t      sample_rate;
+} __packed;
+
+struct aptx_enc_cfg_t {
+    uint32_t      enc_format;
+    uint32_t      sample_rate;
+    uint32_t      num_channels;
+    uint32_t      reserved;
+    uint32_t      channel_mapping[2];
+    uint32_t      custom_size;
+} __packed;
+
+
+
+/*****************************************************************************
+**  External Functions
+******************************************************************************/
+int proxy_a2dp_get_config(uint32_t *, void *);
+
+int proxy_a2dp_start(void);
+int proxy_a2dp_stop(void);
+int proxy_a2dp_suspend(bool);
+
+int proxy_a2dp_open(void);
+int proxy_a2dp_close(void);
+
+int proxy_a2dp_init(void);
+int proxy_a2dp_deinit(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUDIO_A2DP_PROXY_H */
diff --git a/audio/proxy/audio_abox.h b/audio/proxy/audio_abox.h
new file mode 100644
index 0000000..d79ec3e
--- /dev/null
+++ b/audio/proxy/audio_abox.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __EXYNOS_AUDIOPROXY_ABOX_H__
+#define __EXYNOS_AUDIOPROXY_ABOX_H__
+
+#include <linux/ioctl.h>
+#include <linux/types.h>
+
+/* A-Box HW limitations */
+
+// Supported Sampling Rate
+#define MAX_NUM_PLAYBACK_SR     8
+unsigned int supported_playback_samplingrate[MAX_NUM_PLAYBACK_SR] = {8000, 16000, 32000, 44100, 48000, 96000, 192000, 384000};
+
+/* In spite of A-Box spec, we need to fix 48KHz recording only to support some solution limitation */
+#define MAX_NUM_CAPTURE_SR      1
+unsigned int supported_capture_samplingrate[MAX_NUM_CAPTURE_SR] = {48000};
+
+// Supported Channel Mask
+#define MAX_NUM_PLAYBACK_CM     2
+audio_channel_mask_t supported_playback_channelmask[MAX_NUM_PLAYBACK_CM] = {AUDIO_CHANNEL_OUT_MONO, AUDIO_CHANNEL_OUT_STEREO};
+
+// Supported direct Channel Mask
+#define MAX_NUM_DIRECT_PLAYBACK_CM     3
+audio_channel_mask_t supported_direct_playback_channelmask[MAX_NUM_DIRECT_PLAYBACK_CM] = {AUDIO_CHANNEL_OUT_5POINT1, AUDIO_CHANNEL_OUT_6POINT1, AUDIO_CHANNEL_OUT_7POINT1};
+
+#define MAX_NUM_CAPTURE_CM      2
+audio_channel_mask_t supported_capture_channelmask[MAX_NUM_CAPTURE_CM] = {AUDIO_CHANNEL_IN_STEREO, AUDIO_CHANNEL_IN_FRONT_BACK};
+
+// Supported PCM Format
+#define MAX_NUM_PLAYBACK_PF     3
+audio_format_t supported_playback_pcmformat[MAX_NUM_PLAYBACK_PF] = {AUDIO_FORMAT_PCM_16_BIT, AUDIO_FORMAT_PCM_8_24_BIT, AUDIO_FORMAT_PCM_32_BIT};
+
+#define MAX_NUM_CAPTURE_PF      2
+audio_format_t supported_capture_pcmformat[MAX_NUM_CAPTURE_PF] = {AUDIO_FORMAT_PCM_16_BIT, AUDIO_FORMAT_PCM_8_24_BIT};
+
+// Supported Audio Format
+#define MAX_NUM_PLAYBACK_AF     1
+audio_format_t supported_playback_audioformat[MAX_NUM_PLAYBACK_AF] = {AUDIO_FORMAT_MP3};
+
+/* Calliope Firmware Dump */
+#define CALLIOPE_LOG_BUFFERSIZE     (4 * 1024)
+
+#define CALLIOPE_DBG_PATH  "/sys/kernel/debug/abox/"
+#define CALLIOPE_LOG       "log-00"
+#define SYSFS_PREFIX       "/sys"
+#define ABOX_DEV           "/devices/platform/18c50000.abox/"
+#define ABOX_REGMAP_PATH   "/d/regmap/18c50000.abox/"
+#define ABOX_DEBUG         "0.abox-debug/"
+#define ABOX_SRAM          "calliope_sram"
+#define ABOX_DRAM          "calliope_dram"
+#define ABOX_REG_FILE      "registers"
+#define ABOX_DUMP          "/data/vendor/log/abox/"
+#define ABOX_DUMP_LIMIT (10)
+#define ABOX_GPR           "gpr"
+
+// ION Memory MMAP FD retreiving interface
+struct snd_pcm_mmap_fd {
+    int32_t dir;
+    int32_t fd;
+    int32_t size;
+    int32_t actual_size;
+};
+
+#define SNDRV_PCM_IOCTL_MMAP_DATA_FD    _IOWR('U', 0xd2, struct snd_pcm_mmap_fd)
+
+#endif  // __EXYNOS_AUDIOPROXY_ABOX_H__
diff --git a/audio/proxy/audio_board_info.h b/audio/proxy/audio_board_info.h
new file mode 100644
index 0000000..cf5fc38
--- /dev/null
+++ b/audio/proxy/audio_board_info.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _AUDIO_BOARD_INFO_H_
+#define _AUDIO_BOARD_INFO_H_
+
+ /* Audio Board Device's Information */
+
+#define BOARD_INFO_XML_PATH     "vendor/etc/audio_board_info.xml"
+
+#define AUDIO_STRING_TO_ENUM(X) {#X, X}
+#define ARRAY_SIZE(x)           (sizeof((x))/sizeof((x)[0]) )
+
+typedef enum {
+    INFO_NONE,
+    MICROPHONE_CHARACTERISTIC,
+} set_information;
+
+static set_information set_info;
+
+struct audio_string_to_enum {
+    char *name;
+    int  value;
+};
+
+struct audio_string_to_enum device_in_type[] = {
+    AUDIO_STRING_TO_ENUM(AUDIO_DEVICE_IN_BUILTIN_MIC),
+    AUDIO_STRING_TO_ENUM(AUDIO_DEVICE_IN_BACK_MIC),
+};
+
+struct audio_string_to_enum microphone_location[AUDIO_MICROPHONE_LOCATION_CNT] = {
+    AUDIO_STRING_TO_ENUM(AUDIO_MICROPHONE_LOCATION_UNKNOWN),
+    AUDIO_STRING_TO_ENUM(AUDIO_MICROPHONE_LOCATION_MAINBODY),
+    AUDIO_STRING_TO_ENUM(AUDIO_MICROPHONE_LOCATION_MAINBODY_MOVABLE),
+    AUDIO_STRING_TO_ENUM(AUDIO_MICROPHONE_LOCATION_PERIPHERAL),
+};
+
+struct audio_string_to_enum microphone_directionality[AUDIO_MICROPHONE_DIRECTIONALITY_CNT] = {
+    AUDIO_STRING_TO_ENUM(AUDIO_MICROPHONE_DIRECTIONALITY_UNKNOWN),
+    AUDIO_STRING_TO_ENUM(AUDIO_MICROPHONE_DIRECTIONALITY_OMNI),
+    AUDIO_STRING_TO_ENUM(AUDIO_MICROPHONE_DIRECTIONALITY_BI_DIRECTIONAL),
+    AUDIO_STRING_TO_ENUM(AUDIO_MICROPHONE_DIRECTIONALITY_CARDIOID),
+    AUDIO_STRING_TO_ENUM(AUDIO_MICROPHONE_DIRECTIONALITY_HYPER_CARDIOID),
+    AUDIO_STRING_TO_ENUM(AUDIO_MICROPHONE_DIRECTIONALITY_SUPER_CARDIOID),
+};
+
+#endif  // _AUDIO_BOARD_INFO_H_
diff --git a/audio/proxy/audio_mixer.h b/audio/proxy/audio_mixer.h
new file mode 100644
index 0000000..e248355
--- /dev/null
+++ b/audio/proxy/audio_mixer.h
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __EXYNOS_AUDIOPROXY_MIXER_H__
+#define __EXYNOS_AUDIOPROXY_MIXER_H__
+
+#include <audio_route/audio_route.h>
+
+/* Mixer Card Definition */
+#define MIXER_CARD0     0
+
+
+#define MAX_PATH_NAME_LEN 50
+#define MAX_GAIN_PATH_NAME_LEN 55 //"gain-" + path_name size
+
+/* Mixer Controls for ERAP Handling */
+#define MAX_MIXER_NAME_LEN 50
+
+// Mixer Control for BT A2DP
+#define ABOX_A2DP_OFFLOAD_SET_PARAMS_NAME   "ABOX ERAP info A2DP PARAM"
+#define ABOX_A2DP_OFFLOAD_SET_PARAMS_COUNT  7
+
+/* modified by samsung convgergence */
+// Mixer control for BT A2DP offload Suspend (MCD Specific)
+#define MIXER_CTL_ABOX_A2DP_SUSPEND_PARAMS     "ABOX A2DP SUSPEND PARAM"
+#define MIXER_CTL_ABOX_A2DP_SUSPEND_PARAMS_CNT 1
+
+// Mixer Control for set USB Mode
+#define ABOX_USBMODE_CONTROL_NAME "ABOX ERAP info USB On"
+
+// Mixer Control for set MUTE Control
+#define ABOX_MUTE_CONTROL_NAME "ABOX ERAP info Mute Primary"
+#define ABOX_MUTE_CNT_FOR_PATH_CHANGE 15
+
+// Mixer Control for set A-Box Early WakeUp Control
+#define ABOX_TICKLE_CONTROL_NAME "ABOX Tickle"
+#define ABOX_TICKLE_ON      1
+
+/**
+ ** Sampling Rate, channels & format Modifier Configuration for USB playback
+ **/
+#define ABOX_SAMPLE_RATE_MIXER_NAME     "ABOX SIFS0 Rate"
+#define ABOX_CHANNELS_MIXER_NAME        "ABOX SIFS0 Channel"
+#define ABOX_BIT_WIDTH_MIXER_NAME       "ABOX SIFS0 Width"
+
+typedef enum {
+    USBMODE        = 0,
+    MUTE_CONTROL,
+    TICKLE_CONTROL,
+} erap_trigger;
+
+
+// Mixer Control for set Android Audio Mode
+#define ABOX_AUDIOMODE_CONTROL_NAME "ABOX Audio Mode"
+
+#define SPK_AMPL_POWER_NAME "ABOX Spk AmpL Power"
+
+// Compress Offload Volume
+#define OFFLOAD_VOLUME_CONTROL_NAME "ABOX ComprTx0 Volume"
+#define COMPRESS_PLAYBACK_VOLUME_MAX   8192
+
+// Compress Offload Upscaling
+#define OFFLOAD_UPSCALE_CONTROL_NAME "ABOX ComprTx0 Format"
+
+typedef enum {
+    UPSCALE_NONE        = 0,
+    UPSCALE_48K_16B,
+    UPSCALE_48K_24B,
+    UPSCALE_192K_24B,
+    UPSCALE_384K_24B,
+} upscale_factor;
+
+// Mixer control for UAIF configuration
+#define MIXER_CTL_ABOX_UAIF0_SWITCH      "ABOX UAIF0 Switch"
+#define MIXER_CTL_ABOX_UAIF0_SAMPLERATE  "ABOX UAIF0 Rate"
+#define MIXER_CTL_ABOX_UAIF0_WIDTH       "ABOX UAIF0 Width"
+#define MIXER_CTL_ABOX_UAIF0_CHANNEL     "ABOX UAIF0 Channel"
+#define MIXER_CTL_ABOX_UAIF1_SWITCH      "ABOX UAIF1 Switch"
+#define MIXER_CTL_ABOX_UAIF1_SAMPLERATE  "ABOX UAIF1 Rate"
+#define MIXER_CTL_ABOX_UAIF1_WIDTH       "ABOX UAIF1 Width"
+#define MIXER_CTL_ABOX_UAIF1_CHANNEL     "ABOX UAIF1 Channel"
+#define MIXER_CTL_ABOX_UAIF2_SWITCH      "ABOX UAIF2 Switch"
+#define MIXER_CTL_ABOX_UAIF2_SAMPLERATE  "ABOX UAIF2 Rate"
+#define MIXER_CTL_ABOX_UAIF2_WIDTH       "ABOX UAIF2 Width"
+#define MIXER_CTL_ABOX_UAIF2_CHANNEL     "ABOX UAIF2 Channel"
+#define MIXER_CTL_ABOX_UAIF3_SWITCH      "ABOX UAIF3 Switch"
+#define MIXER_CTL_ABOX_UAIF3_SAMPLERATE  "ABOX UAIF3 Rate"
+#define MIXER_CTL_ABOX_UAIF3_WIDTH       "ABOX UAIF3 Width"
+#define MIXER_CTL_ABOX_UAIF3_CHANNEL     "ABOX UAIF3 Channel"
+
+// Mixer control for SIFS configuration
+#define MIXER_CTL_ABOX_SIFS0_SWITCH      "ABOX SIFS0 OUT Switch"
+#define MIXER_CTL_ABOX_SIFS0_SAMPLERATE  "ABOX SIFS0 Rate"
+#define MIXER_CTL_ABOX_SIFS0_WIDTH       "ABOX SIFS0 Width"
+#define MIXER_CTL_ABOX_SIFS0_CHANNEL     "ABOX SIFS0 Channel"
+
+#define MIXER_ON                         1
+#define MIXER_OFF                        0
+
+// USB Clock Source inforamtion mixer control
+#define MIXER_CTL_ABOX_USB_CLOCKSOURCE   "ABOX PCM ext USB SCDS"
+
+// Capture VirtualPCM DAI input source mixer control
+#define MIXER_CTL_ABOX_CATPURE_VPCMDAI_INSRC    "ABOX VPCMIN_DAI0_A"
+
+// MMAP Playback Volume
+#define MIXER_CTL_ABOX_MMAP_OUT_VOLUME_CONTROL  "ABOX RDMA VOL FACTOR2"
+#define MMAP_PLAYBACK_VOLUME_MAX   0xFFFFFF // Decimal value : 16777215
+
+// Mixer control for BT A2DP offload (MCD Specific)
+#define MIXER_CTL_ABOX_A2DP_DYN_PARAMS     "ABOX A2DP A2DP DYN PARAM"
+#define MIXER_CTL_ABOX_A2DP_DYN_PARAMS_CNT 2
+
+#endif  // __EXYNOS_AUDIOPROXY_MIXER_H__
diff --git a/audio/proxy/audio_pcm.h b/audio/proxy/audio_pcm.h
new file mode 100644
index 0000000..523755c
--- /dev/null
+++ b/audio/proxy/audio_pcm.h
@@ -0,0 +1,870 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __EXYNOS_AUDIOPROXY_PCM_H__
+#define __EXYNOS_AUDIOPROXY_PCM_H__
+
+#include <tinyalsa/asoundlib.h>
+#include <tinycompress/tinycompress.h>
+#include <compress_params.h>
+
+
+/* Actual HW DMA mapped Sound Card & Device Definition */
+#define SOUND_CARD0                     0
+
+// Sound Devices mapped for A-Box RDMA
+#define SOUND_DEVICE_ABOX_RDMA0         0       // A-Box RDMA0
+#define SOUND_DEVICE_ABOX_RDMA1         1       // A-Box RDMA1
+#define SOUND_DEVICE_ABOX_RDMA2         2       // A-Box RDMA2
+#define SOUND_DEVICE_ABOX_RDMA3         3       // A-Box RDMA3
+#define SOUND_DEVICE_ABOX_RDMA4         4       // A-Box RDMA4
+#define SOUND_DEVICE_ABOX_RDMA5         5       // A-Box RDMA5
+#define SOUND_DEVICE_ABOX_RDMA6         6       // A-Box RDMA6
+#define SOUND_DEVICE_ABOX_RDMA7         7       // A-Box RDMA7
+#define SOUND_DEVICE_ABOX_RDMA8         8       // A-Box RDMA8
+#define SOUND_DEVICE_ABOX_RDMA9         9       // A-Box RDMA9
+#define SOUND_DEVICE_ABOX_RDMA10        10      // A-Box RDMA10
+#define SOUND_DEVICE_ABOX_RDMA11        11      // A-Box RDMA11
+
+// Sound Devices mapped for A-Box WDMA
+#define SOUND_DEVICE_ABOX_WDMA0         12      // A-Box WDMA0
+#define SOUND_DEVICE_ABOX_WDMA1         13      // A-Box WDMA1
+#define SOUND_DEVICE_ABOX_WDMA2         14      // A-Box WDMA2
+#define SOUND_DEVICE_ABOX_WDMA3         15      // A-Box WDMA3
+#define SOUND_DEVICE_ABOX_WDMA4         16      // A-Box WDMA4
+#define SOUND_DEVICE_ABOX_WDMA5         17      // A-Box WDMA5
+#define SOUND_DEVICE_ABOX_WDMA6         18      // A-Box WDMA6
+#define SOUND_DEVICE_ABOX_WDMA7         19      // A-Box WDMA7
+
+// Sound Devices mapped for other DMA
+// Devices 20 & 21 are used by VTS driver
+#define SOUND_DEVICE_AUX                22      // Aux Digital Device for DP Audio
+
+/* Vitural PCM DAI Sound Card & Device Definition */
+#define SOUND_CARD1                     1
+
+// Sound Devices using Virtual PCM DAIs with sound-card1
+// Playback devices
+#define SOUND_DEVICE_VIRT_PRIMARY_PLAYBACK       0       // primary playback virtual device
+// Capture devices
+#define SOUND_DEVICE_VIRT_PRIMARY_CAPTURE        20      // primary capture virtual device
+#define SOUND_DEVICE_VIRT_FM_RECORD              21      // WDMA for FM Radio Recording
+
+/* Virtual DMA mapped Sound Card & Device Definition */
+#define SOUND_CARD2                     2
+
+// Device  0 ~ 12 : used for A-Box DMA Dump
+// Device 13 ~ 15 : used for Compress Offload Dump
+// Device 16 ~ 18 : used for OEM Analysis Dump
+// From Device 19
+#define SOUND_DEVICE_CALL_RECORD        24      // WDMA for Call Recording
+#define SOUND_DEVICE_TELEPHONYRX_RECORD 34      // TelephonyRx Recording virtual pcm
+
+#define SOUND_DEVICE_UNDEFINE           99
+
+/* Default values for Media PCM Configuration */
+#define DEFAULT_CAPTURE_CHANNELS                1                   // Mono
+#define DEFAULT_MEDIA_CHANNELS                  2                   // Stereo
+#define DEFAULT_MEDIA_SAMPLING_RATE             48000               // 48KHz
+#define DEFAULT_MEDIA_FORMAT                    PCM_FORMAT_S16_LE   // 16bit PCM
+#define DEFAULT_MEDIA_24_ZEROPAD_FORMAT         PCM_FORMAT_S24_LE   // 24bit PCM
+#define DEFAULT_MEDIA_32_FORMAT                 PCM_FORMAT_S32_LE   // 32bit PCM
+
+// Definition for MMAP Stream
+#define MMAP_PERIOD_SIZE (DEFAULT_MEDIA_SAMPLING_RATE/1000)
+#define MMAP_PERIOD_COUNT_MIN 32
+#define MMAP_PERIOD_COUNT_MAX 512
+#define MMAP_PERIOD_COUNT_DEFAULT (MMAP_PERIOD_COUNT_MAX)
+
+// Channel count definitions
+#define MEDIA_1_CHANNEL                         1
+/* 4Channels is required for SPK AMP/Quad Mic TDM */
+#define MEDIA_4_CHANNELS                        4
+/* 8Channels is required for Direct output stream */
+#define MEDIA_8_CHANNELS                        8
+
+/* Default values for Voice PCM Configuration */
+#define SAMPLING_RATE_NB                8000                // 8KHz(Narrow Band)
+#define SAMPLING_RATE_WB                16000               // 16KHz(Wide Band)
+#define SAMPLING_RATE_SWB               32000               // 32KHz(Wide Band)
+#define SAMPLING_RATE_FB                48000               // 48KHz(Full Band)
+
+#define DEFAULT_VOICE_CHANNELS          2                   // Stereo
+#define DEFAULT_VOICE_SAMPLING_RATE     SAMPLING_RATE_SWB
+#define DEFAULT_VOICE_FORMAT            PCM_FORMAT_S16_LE   // 16bit PCM
+
+/* Default values for CP Voice Recording PCM Configuration */
+#define DEFAULT_VOICE_REC_CHANNELS      2                   // Stereo
+#define DEFAULT_VOICE_REC_SAMPLINGRATE  SAMPLING_RATE_SWB   // 32KHz
+#define DEFAULT_VOICE_REC_PERIODSIZE    2048                // Sync with A-Box Firmware
+#define DEFAULT_VOICE_REC_PERIODCOUNT   2
+#define DEFAULT_VOICE_REC_FORMAT        PCM_FORMAT_S16_LE   // 16bit PCM
+
+/* Default values for FM Recording PCM Configuration */
+#define DEFAULT_FM_REC_CHANNELS         2                   // Stereo
+#define DEFAULT_FM_REC_SAMPLINGRATE     48000               // 48KHz
+#define DEFAULT_FM_REC_PERIODSIZE       480                // Sync with WDMA7 config
+#define DEFAULT_FM_REC_PERIODCOUNT      4
+#define DEFAULT_FM_REC_FORMAT           PCM_FORMAT_S16_LE   // 16bit PCM
+
+#define UHQA_MEDIA_FORMAT               PCM_FORMAT_S24_LE   // 24bit PCM
+#define UHQA_MEDIA_SAMPLING_RATE        192000
+
+#define SUHQA_MEDIA_FORMAT              PCM_FORMAT_S32_LE   // 32bit PCM
+#define SUHQA_MEDIA_SAMPLING_RATE       384000
+
+/* Default values for USB Playback or Capture PCM Configuration */
+#define DEFAULT_MEDIA_BITWIDTH              24   // 24bit PCM
+#define ABOX_UNSUPPORTED_CHANNELS           6
+#define ABOX_SUPPORTED_MAX_CHANNELS         8
+//----------------------------------------------------------------------------------------------//
+// For Playback (Speaker) Path
+
+/* PCM Configurations */
+// PCM Configurations for Primary Playback Stream
+#define PRIMARY_PLAYBACK_CARD           SOUND_CARD0
+#define PRIMARY_PLAYBACK_DEVICE         SOUND_DEVICE_ABOX_RDMA0
+
+#define PRIMARY_PLAYBACK_CHANNELS       DEFAULT_MEDIA_CHANNELS
+#define PRIMARY_PLAYBACK_SAMPLING_RATE  DEFAULT_MEDIA_SAMPLING_RATE
+#define PRIMARY_PLAYBACK_PERIOD_SIZE    960
+#define PRIMARY_PLAYBACK_PERIOD_COUNT   4
+#define PRIMARY_PLAYBACK_FORMAT         DEFAULT_MEDIA_FORMAT
+#define PRIMARY_PLAYBACK_START          PRIMARY_PLAYBACK_PERIOD_SIZE
+#define PRIMARY_PLAYBACK_STOP           UINT_MAX
+
+struct pcm_config pcm_config_primary_playback = {
+    .channels        = PRIMARY_PLAYBACK_CHANNELS,
+    .rate            = PRIMARY_PLAYBACK_SAMPLING_RATE,
+    .period_size     = PRIMARY_PLAYBACK_PERIOD_SIZE,
+    .period_count    = PRIMARY_PLAYBACK_PERIOD_COUNT,
+    .format          = PRIMARY_PLAYBACK_FORMAT,
+    .start_threshold = PRIMARY_PLAYBACK_START,
+    .stop_threshold  = PRIMARY_PLAYBACK_STOP,
+};
+
+// PCM Configurations for Virtual Primary playback Stream
+#define VIRTUAL_PRIMARY_PLAYBACK_CARD           SOUND_CARD1
+#define VIRTUAL_PRIMARY_PLAYBACK_DEVICE         SOUND_DEVICE_VIRT_PRIMARY_PLAYBACK
+
+// PCM Configurations for Fast Playback Stream
+#define FAST_PLAYBACK_CARD              SOUND_CARD0
+#define FAST_PLAYBACK_DEVICE            SOUND_DEVICE_ABOX_RDMA1
+
+#define FAST_PLAYBACK_CHANNELS          DEFAULT_MEDIA_CHANNELS
+#define FAST_PLAYBACK_SAMPLING_RATE     DEFAULT_MEDIA_SAMPLING_RATE
+#define FAST_PLAYBACK_PERIOD_SIZE       192
+#define FAST_PLAYBACK_PERIOD_COUNT      2
+#define FAST_PLAYBACK_FORMAT            DEFAULT_MEDIA_FORMAT
+#define FAST_PLAYBACK_START             (FAST_PLAYBACK_PERIOD_SIZE * FAST_PLAYBACK_PERIOD_COUNT)
+#define FAST_PLAYBACK_STOP              UINT_MAX
+
+struct pcm_config pcm_config_fast_playback = {
+    .channels        = FAST_PLAYBACK_CHANNELS,
+    .rate            = FAST_PLAYBACK_SAMPLING_RATE,
+    .period_size     = FAST_PLAYBACK_PERIOD_SIZE,
+    .period_count    = FAST_PLAYBACK_PERIOD_COUNT,
+    .format          = FAST_PLAYBACK_FORMAT,
+    .start_threshold = FAST_PLAYBACK_START,
+    .stop_threshold  = FAST_PLAYBACK_STOP,
+};
+
+// PCM Configurations for Low Latency Playback Stream
+#define LOW_PLAYBACK_CARD               SOUND_CARD0
+#define LOW_PLAYBACK_DEVICE             SOUND_DEVICE_ABOX_RDMA1
+
+#define LOW_PLAYBACK_CHANNELS           DEFAULT_MEDIA_CHANNELS
+#define LOW_PLAYBACK_SAMPLING_RATE      DEFAULT_MEDIA_SAMPLING_RATE
+#define LOW_PLAYBACK_PERIOD_SIZE        96
+#define LOW_PLAYBACK_PERIOD_COUNT       4
+#define LOW_PLAYBACK_FORMAT             DEFAULT_MEDIA_FORMAT
+#define LOW_PLAYBACK_START              LOW_PLAYBACK_PERIOD_SIZE
+#define LOW_PLAYBACK_STOP               UINT_MAX
+
+struct pcm_config pcm_config_low_playback = {
+    .channels        = LOW_PLAYBACK_CHANNELS,
+    .rate            = LOW_PLAYBACK_SAMPLING_RATE,
+    .period_size     = LOW_PLAYBACK_PERIOD_SIZE,
+    .period_count    = LOW_PLAYBACK_PERIOD_COUNT,
+    .format          = LOW_PLAYBACK_FORMAT,
+    .start_threshold = LOW_PLAYBACK_START,
+    .stop_threshold  = LOW_PLAYBACK_STOP,
+};
+
+// PCM Configurations for MMAP Playback Stream
+#define MMAP_PLAYBACK_CARD               SOUND_CARD0
+#define MMAP_PLAYBACK_DEVICE             SOUND_DEVICE_ABOX_RDMA2
+
+#define MMAP_PLAYBACK_CHANNELS           DEFAULT_MEDIA_CHANNELS
+#define MMAP_PLAYBACK_SAMPLING_RATE      DEFAULT_MEDIA_SAMPLING_RATE
+#define MMAP_PLAYBACK_PERIOD_SIZE        MMAP_PERIOD_SIZE
+#define MMAP_PLAYBACK_PERIOD_COUNT       MMAP_PERIOD_COUNT_DEFAULT
+#define MMAP_PLAYBACK_FORMAT             DEFAULT_MEDIA_FORMAT
+#define MMAP_PLAYBACK_START              (MMAP_PLAYBACK_PERIOD_SIZE * 8)
+#define MMAP_PLAYBACK_STOP               UINT_MAX
+
+struct pcm_config pcm_config_mmap_playback = {
+    .channels        = MMAP_PLAYBACK_CHANNELS,
+    .rate            = MMAP_PLAYBACK_SAMPLING_RATE,
+    .period_size     = MMAP_PLAYBACK_PERIOD_SIZE,
+    .period_count    = MMAP_PLAYBACK_PERIOD_COUNT,
+    .format          = MMAP_PLAYBACK_FORMAT,
+    .start_threshold = MMAP_PLAYBACK_START,
+    .stop_threshold  = MMAP_PLAYBACK_STOP,
+};
+
+// PCM Configurations for DeepBuffer Playback Stream
+#define DEEP_PLAYBACK_CARD              SOUND_CARD0
+#define DEEP_PLAYBACK_DEVICE            SOUND_DEVICE_ABOX_RDMA3
+
+#define DEEP_PLAYBACK_CHANNELS          DEFAULT_MEDIA_CHANNELS
+#define DEEP_PLAYBACK_SAMPLING_RATE     DEFAULT_MEDIA_SAMPLING_RATE
+#define DEEP_PLAYBACK_PERIOD_SIZE       960
+#define DEEP_PLAYBACK_PERIOD_COUNT      4
+#define DEEP_PLAYBACK_FORMAT            DEFAULT_MEDIA_24_ZEROPAD_FORMAT
+#define DEEP_PLAYBACK_START             DEEP_PLAYBACK_PERIOD_SIZE
+#define DEEP_PLAYBACK_STOP              (DEEP_PLAYBACK_PERIOD_SIZE * DEEP_PLAYBACK_PERIOD_COUNT)
+
+struct pcm_config pcm_config_deep_playback = {
+    .channels        = DEEP_PLAYBACK_CHANNELS,
+    .rate            = DEEP_PLAYBACK_SAMPLING_RATE,
+    .period_size     = DEEP_PLAYBACK_PERIOD_SIZE,
+    .period_count    = DEEP_PLAYBACK_PERIOD_COUNT,
+    .format          = DEEP_PLAYBACK_FORMAT,
+    .start_threshold = DEEP_PLAYBACK_START,
+    .stop_threshold  = DEEP_PLAYBACK_STOP,
+};
+
+// PCM Configurations for Deep UHQA Playback Stream
+#define DEEP_PLAYBACK_UHQA_FORMAT            UHQA_MEDIA_FORMAT
+#define DEEP_PLAYBACK_UHQA_SAMPLING_RATE     UHQA_MEDIA_SAMPLING_RATE
+
+#define DEEP_PLAYBACK_SUHQA_FORMAT           SUHQA_MEDIA_FORMAT
+#define DEEP_PLAYBACK_SUHQA_SAMPLING_RATE    SUHQA_MEDIA_SAMPLING_RATE
+
+struct pcm_config pcm_config_deep_playback_wide_res = {
+    .channels        = DEEP_PLAYBACK_CHANNELS,
+    .rate            = DEEP_PLAYBACK_SAMPLING_RATE,
+    .period_size     = DEEP_PLAYBACK_PERIOD_SIZE,
+    .period_count    = DEEP_PLAYBACK_PERIOD_COUNT,
+    .format          = DEEP_PLAYBACK_UHQA_FORMAT,
+};
+
+struct pcm_config pcm_config_deep_playback_uhqa = {
+    .channels        = DEEP_PLAYBACK_CHANNELS,
+    .rate            = DEEP_PLAYBACK_UHQA_SAMPLING_RATE,
+    .period_size     = DEEP_PLAYBACK_PERIOD_SIZE * 4,
+    .period_count    = DEEP_PLAYBACK_PERIOD_COUNT,
+    .format          = DEEP_PLAYBACK_UHQA_FORMAT,
+};
+
+struct pcm_config pcm_config_deep_playback_suhqa = {
+    .channels        = DEEP_PLAYBACK_CHANNELS,
+    .rate            = DEEP_PLAYBACK_SUHQA_SAMPLING_RATE,
+    .period_size     = DEEP_PLAYBACK_PERIOD_SIZE * 8,
+    .period_count    = DEEP_PLAYBACK_PERIOD_COUNT,
+    .format          = DEEP_PLAYBACK_SUHQA_FORMAT,
+};
+
+// PCM Configurations for Voice RX Playback Stream
+#define VRX_PLAYBACK_CARD               SOUND_CARD0
+#define VRX_PLAYBACK_DEVICE             SOUND_DEVICE_ABOX_RDMA4
+
+#define VRX_PLAYBACK_CHANNELS           DEFAULT_VOICE_CHANNELS
+#define VRX_PLAYBACK_SAMPLING_RATE      DEFAULT_VOICE_SAMPLING_RATE
+#define VRX_PLAYBACK_PERIOD_SIZE        480
+#define VRX_PLAYBACK_PERIOD_COUNT       4
+#define VRX_PLAYBACK_FORMAT             DEFAULT_VOICE_FORMAT
+#define VRX_PLAYBACK_START              VRX_PLAYBACK_PERIOD_SIZE
+#define VRX_PLAYBACK_STOP               UINT_MAX
+
+struct pcm_config pcm_config_voicerx_playback = {
+    .channels        = VRX_PLAYBACK_CHANNELS,
+    .rate            = VRX_PLAYBACK_SAMPLING_RATE,
+    .period_size     = VRX_PLAYBACK_PERIOD_SIZE,
+    .period_count    = VRX_PLAYBACK_PERIOD_COUNT,
+    .format          = VRX_PLAYBACK_FORMAT,
+    .start_threshold = VRX_PLAYBACK_START,
+    .stop_threshold  = VRX_PLAYBACK_STOP,
+};
+
+// PCM Configurations for Compress Offload Playback Stream
+#define OFFLOAD_PLAYBACK_CARD           SOUND_CARD0
+#define OFFLOAD_PLAYBACK_DEVICE         SOUND_DEVICE_ABOX_RDMA5
+
+/*
+ * These values are based on HW Decoder: Max Buffer Size = FRAGMENT_SIZE * NUM_FRAGMENTS
+ * 0 means that we will use the predefined value by device driver
+ */
+// Offload Buffer Size is set to Maximum possible buffer size,
+// as offload Pause issue after Drain notification is resolved from kernel side
+#define OFFLOAD_PLAYBACK_BUFFER_SIZE  (1024 * 64)  // fragment_size is fixed 64KBytes = 64 * 1024
+#define OFFLOAD_PLAYBACK_BUFFER_COUNT 5            // fragment is fixed 5
+
+#define OFFLOAD_OFFLOAD_FRAGMENT_SIZE OFFLOAD_PLAYBACK_BUFFER_SIZE
+#define OFFLOAD_OFFLOAD_NUM_FRAGMENTS OFFLOAD_PLAYBACK_BUFFER_COUNT
+
+struct compr_config compr_config_offload_playback = {
+    .fragment_size  = OFFLOAD_OFFLOAD_FRAGMENT_SIZE,
+    .fragments      = OFFLOAD_OFFLOAD_NUM_FRAGMENTS,
+    .codec          = NULL,
+};
+
+// Internal loopback related PCM node configurations
+// PCM Configurations for BT-SCO Playback Stream
+#define BTSCO_PLAYBACK_CARD             SOUND_CARD0
+#define BTSCO_PLAYBACK_DEVICE           SOUND_DEVICE_ABOX_RDMA6
+
+#define BTSCO_PLAYBACK_CHANNELS         DEFAULT_MEDIA_CHANNELS
+#define BTSCO_PLAYBACK_SAMPLING_RATE    DEFAULT_MEDIA_SAMPLING_RATE
+#define BTSCO_PLAYBACK_PERIOD_SIZE      480
+#define BTSCO_PLAYBACK_PERIOD_COUNT     4
+#define BTSCO_PLAYBACK_FORMAT           DEFAULT_MEDIA_32_FORMAT
+#define BTSCO_PLAYBACK_START            BTSCO_PLAYBACK_PERIOD_SIZE
+#define BTSCO_PLAYBACK_STOP             UINT_MAX
+
+struct pcm_config pcm_config_btsco_playback = {
+    .channels        = BTSCO_PLAYBACK_CHANNELS,
+    .rate            = BTSCO_PLAYBACK_SAMPLING_RATE,
+    .period_size     = BTSCO_PLAYBACK_PERIOD_SIZE,
+    .period_count    = BTSCO_PLAYBACK_PERIOD_COUNT,
+    .format          = BTSCO_PLAYBACK_FORMAT,
+    .start_threshold = BTSCO_PLAYBACK_START,
+    .stop_threshold  = BTSCO_PLAYBACK_STOP,
+};
+
+// Internal loopback related PCM node configurations
+// PCM Configurations for BT-A2DP Playback Stream
+#define BTA2DP_PLAYBACK_CARD             SOUND_CARD0
+#define BTA2DP_PLAYBACK_DEVICE           SOUND_DEVICE_ABOX_RDMA6
+
+#define BTA2DP_PLAYBACK_CHANNELS         DEFAULT_MEDIA_CHANNELS
+#define BTA2DP_PLAYBACK_SAMPLING_RATE    DEFAULT_MEDIA_SAMPLING_RATE
+#define BTA2DP_PLAYBACK_PERIOD_SIZE      480
+#define BTA2DP_PLAYBACK_PERIOD_COUNT     4
+#define BTA2DP_PLAYBACK_FORMAT           DEFAULT_MEDIA_FORMAT
+#define BTA2DP_PLAYBACK_START            BTA2DP_PLAYBACK_PERIOD_SIZE
+#define BTA2DP_PLAYBACK_STOP             UINT_MAX
+
+struct pcm_config pcm_config_bta2dp_playback = {
+    .channels        = BTA2DP_PLAYBACK_CHANNELS,
+    .rate            = BTA2DP_PLAYBACK_SAMPLING_RATE,
+    .period_size     = BTA2DP_PLAYBACK_PERIOD_SIZE,
+    .period_count    = BTA2DP_PLAYBACK_PERIOD_COUNT,
+    .format          = BTA2DP_PLAYBACK_FORMAT,
+    .start_threshold = BTA2DP_PLAYBACK_START,
+    .stop_threshold  = BTA2DP_PLAYBACK_STOP,
+};
+
+// PCM Configurations for A2DP Mute Playback Stream
+#define A2DPMUTE_PLAYBACK_CARD          SOUND_CARD0
+#define A2DPMUTE_PLAYBACK_DEVICE        SOUND_DEVICE_ABOX_RDMA11
+
+#define A2DPMUTE_PLAYBACK_CHANNELS      DEFAULT_MEDIA_CHANNELS
+#define A2DPMUTE_PLAYBACK_SAMPLING_RATE DEFAULT_MEDIA_SAMPLING_RATE
+#define A2DPMUTE_PLAYBACK_PERIOD_SIZE   480
+#define A2DPMUTE_PLAYBACK_PERIOD_COUNT  4
+#define A2DPMUTE_PLAYBACK_FORMAT        DEFAULT_MEDIA_FORMAT
+#define A2DPMUTE_PLAYBACK_START         A2DPMUTE_PLAYBACK_PERIOD_SIZE
+#define A2DPMUTE_PLAYBACK_STOP          UINT_MAX
+
+struct pcm_config pcm_config_a2dp_mute_playback = {
+    .channels        = A2DPMUTE_PLAYBACK_CHANNELS,
+    .rate            = A2DPMUTE_PLAYBACK_SAMPLING_RATE,
+    .period_size     = A2DPMUTE_PLAYBACK_PERIOD_SIZE,
+    .period_count    = A2DPMUTE_PLAYBACK_PERIOD_COUNT,
+    .format          = A2DPMUTE_PLAYBACK_FORMAT,
+    .start_threshold = A2DPMUTE_PLAYBACK_START,
+    .stop_threshold  = A2DPMUTE_PLAYBACK_STOP,
+};
+
+// PCM Configurations for SpeakerAMP Playback Stream
+#define SPKAMP_PLAYBACK_CARD            SOUND_CARD0
+#define SPKAMP_PLAYBACK_DEVICE          SOUND_DEVICE_ABOX_RDMA7
+
+#define SPKAMP_PLAYBACK_CHANNELS        MEDIA_4_CHANNELS
+#define SPKAMP_PLAYBACK_SAMPLING_RATE   DEFAULT_MEDIA_SAMPLING_RATE
+#define SPKAMP_PLAYBACK_PERIOD_SIZE     480
+#define SPKAMP_PLAYBACK_PERIOD_COUNT    4
+#define SPKAMP_PLAYBACK_FORMAT          DEFAULT_MEDIA_32_FORMAT
+#define SPKAMP_PLAYBACK_START           SPKAMP_PLAYBACK_PERIOD_SIZE
+#define SPKAMP_PLAYBACK_STOP            UINT_MAX
+
+struct pcm_config pcm_config_spkamp_playback = {
+    .channels        = SPKAMP_PLAYBACK_CHANNELS,
+    .rate            = SPKAMP_PLAYBACK_SAMPLING_RATE,
+    .period_size     = SPKAMP_PLAYBACK_PERIOD_SIZE,
+    .period_count    = SPKAMP_PLAYBACK_PERIOD_COUNT,
+    .format          = SPKAMP_PLAYBACK_FORMAT,
+    .start_threshold = SPKAMP_PLAYBACK_START,
+    .stop_threshold  = SPKAMP_PLAYBACK_STOP,
+};
+
+// PCM Configurations for FM Radio Playback Stream
+#define FMRADIO_PLAYBACK_CARD           SOUND_CARD0
+#define FMRADIO_PLAYBACK_DEVICE         SOUND_DEVICE_ABOX_RDMA8
+
+#define FMRADIO_PLAYBACK_CHANNELS       DEFAULT_MEDIA_CHANNELS
+#define FMRADIO_PLAYBACK_SAMPLING_RATE  DEFAULT_MEDIA_SAMPLING_RATE
+#define FMRADIO_PLAYBACK_PERIOD_SIZE    480
+#define FMRADIO_PLAYBACK_PERIOD_COUNT   4
+#define FMRADIO_PLAYBACK_FORMAT         DEFAULT_MEDIA_FORMAT
+#define FMRADIO_PLAYBACK_START          FMRADIO_PLAYBACK_PERIOD_SIZE
+#define FMRADIO_PLAYBACK_STOP           UINT_MAX
+
+struct pcm_config pcm_config_fmradio_playback = {
+    .channels        = FMRADIO_PLAYBACK_CHANNELS,
+    .rate            = FMRADIO_PLAYBACK_SAMPLING_RATE,
+    .period_size     = FMRADIO_PLAYBACK_PERIOD_SIZE,
+    .period_count    = FMRADIO_PLAYBACK_PERIOD_COUNT,
+    .format          = FMRADIO_PLAYBACK_FORMAT,
+    .start_threshold = FMRADIO_PLAYBACK_START,
+    .stop_threshold  = FMRADIO_PLAYBACK_STOP,
+};
+
+// PCM Configurations for Direct Playback Stream
+#define DIRECT_PLAYBACK_CARD            SOUND_CARD0
+#define DIRECT_PLAYBACK_DEVICE          SOUND_DEVICE_ABOX_RDMA9
+
+#define DIRECT_PLAYBACK_CHANNELS        MEDIA_8_CHANNELS
+#define DIRECT_PLAYBACK_SAMPLING_RATE   DEFAULT_MEDIA_SAMPLING_RATE
+#define DIRECT_PLAYBACK_PERIOD_SIZE     480
+#define DIRECT_PLAYBACK_PERIOD_COUNT    4
+#define DIRECT_PLAYBACK_FORMAT          DEFAULT_MEDIA_24_ZEROPAD_FORMAT
+#define DIRECT_PLAYBACK_START           DIRECT_PLAYBACK_PERIOD_SIZE
+#define DIRECT_PLAYBACK_STOP            (DIRECT_PLAYBACK_PERIOD_SIZE * DIRECT_PLAYBACK_PERIOD_COUNT)
+
+struct pcm_config pcm_config_direct_playback = {
+    .channels        = DIRECT_PLAYBACK_CHANNELS,
+    .rate            = DIRECT_PLAYBACK_SAMPLING_RATE,
+    .period_size     = DIRECT_PLAYBACK_PERIOD_SIZE,
+    .period_count    = DIRECT_PLAYBACK_PERIOD_COUNT,
+    .format          = DIRECT_PLAYBACK_FORMAT,
+};
+
+// PCM Configurations for USB Output Loopback Stream
+#define USBOUT_LOOPBACK_CARD             SOUND_CARD0
+#define USBOUT_LOOPBACK_DEVICE           SOUND_DEVICE_ABOX_WDMA6
+
+#define USBOUT_LOOPBACK_CHANNELS         DEFAULT_MEDIA_CHANNELS
+#define USBOUT_LOOPBACK_SAMPLING_RATE    DEFAULT_MEDIA_SAMPLING_RATE
+#define USBOUT_LOOPBACK_PERIOD_SIZE      480
+#define USBOUT_LOOPBACK_PERIOD_COUNT     2
+#define USBOUT_LOOPBACK_FORMAT           DEFAULT_MEDIA_FORMAT
+#define USBOUT_LOOPBACK_START            USBOUT_LOOPBACK_PERIOD_SIZE
+#define USBOUT_LOOPBACK_STOP             UINT_MAX
+
+struct pcm_config pcm_config_usb_out_loopback = {
+    .channels        = USBOUT_LOOPBACK_CHANNELS,
+    .rate            = USBOUT_LOOPBACK_SAMPLING_RATE,
+    .period_size     = USBOUT_LOOPBACK_PERIOD_SIZE,
+    .period_count    = USBOUT_LOOPBACK_PERIOD_COUNT,
+    .format          = USBOUT_LOOPBACK_FORMAT,
+    .start_threshold = USBOUT_LOOPBACK_START,
+    .stop_threshold  = USBOUT_LOOPBACK_STOP,
+};
+
+// PCM Configurations for USB Input Loopback Stream
+#define USBIN_LOOPBACK_CARD             SOUND_CARD0
+#define USBIN_LOOPBACK_DEVICE           SOUND_DEVICE_ABOX_RDMA10
+
+#define USBIN_LOOPBACK_CHANNELS         DEFAULT_MEDIA_CHANNELS
+#define USBIN_LOOPBACK_SAMPLING_RATE    DEFAULT_MEDIA_SAMPLING_RATE
+#define USBIN_LOOPBACK_PERIOD_SIZE      480
+#define USBIN_LOOPBACK_PERIOD_COUNT     4
+#define USBIN_LOOPBACK_FORMAT           DEFAULT_MEDIA_FORMAT
+#define USBIN_LOOPBACK_START            USBIN_LOOPBACK_PERIOD_SIZE
+#define USBIN_LOOPBACK_STOP             UINT_MAX
+
+struct pcm_config pcm_config_usb_in_loopback = {
+    .channels        = USBIN_LOOPBACK_CHANNELS,
+    .rate            = USBIN_LOOPBACK_SAMPLING_RATE,
+    .period_size     = USBIN_LOOPBACK_PERIOD_SIZE,
+    .period_count    = USBIN_LOOPBACK_PERIOD_COUNT,
+    .format          = USBIN_LOOPBACK_FORMAT,
+    .start_threshold = USBIN_LOOPBACK_START,
+    .stop_threshold  = USBIN_LOOPBACK_STOP,
+};
+
+// AUX doesn't use A-Box pcm node
+// PCM Configurations for AUX Digital(HDMI / DisplayPort) Playback Stream
+#define AUX_PLAYBACK_CARD               SOUND_CARD0
+#define AUX_PLAYBACK_DEVICE             SOUND_DEVICE_AUX
+
+#define AUX_PLAYBACK_CHANNELS           DEFAULT_MEDIA_CHANNELS
+#define AUX_PLAYBACK_SAMPLING_RATE      DEFAULT_MEDIA_SAMPLING_RATE
+#define AUX_PLAYBACK_PERIOD_SIZE        960
+#define AUX_PLAYBACK_PERIOD_COUNT       2
+#define AUX_PLAYBACK_FORMAT             DEFAULT_MEDIA_FORMAT
+#define AUX_PLAYBACK_START              AUX_PLAYBACK_PERIOD_SIZE
+#define AUX_PLAYBACK_STOP               UINT_MAX
+
+struct pcm_config pcm_config_aux_playback = {
+    .channels        = AUX_PLAYBACK_CHANNELS,
+    .rate            = AUX_PLAYBACK_SAMPLING_RATE,
+    .period_size     = AUX_PLAYBACK_PERIOD_SIZE,
+    .period_count    = AUX_PLAYBACK_PERIOD_COUNT,
+    .format          = AUX_PLAYBACK_FORMAT,
+    .start_threshold = AUX_PLAYBACK_START,
+    .stop_threshold  = AUX_PLAYBACK_STOP,
+};
+
+//----------------------------------------------------------------------------------------------//
+// For Capture (MIC) Path
+
+// FIXME: Currently unused configuration
+// PCM Configurations for Mixed Capture Stream
+#define MIXED_CAPTURE_CARD              SOUND_CARD0
+#define MIXED_CAPTURE_DEVICE            SOUND_DEVICE_ABOX_WDMA0
+
+#define MIXED_CAPTURE_CHANNELS          DEFAULT_MEDIA_CHANNELS
+#define MIXED_CAPTURE_SAMPLING_RATE     DEFAULT_MEDIA_SAMPLING_RATE
+#define MIXED_CAPTURE_PERIOD_SIZE       480
+#define MIXED_CAPTURE_PERIOD_COUNT      4
+#define MIXED_CAPTURE_FORMAT            DEFAULT_MEDIA_FORMAT
+#define MIXED_CAPTURE_START             MIXED_CAPTURE_PERIOD_SIZE
+#define MIXED_CAPTURE_STOP              UINT_MAX
+
+struct pcm_config pcm_config_mixed_capture = {
+    .channels        = MIXED_CAPTURE_CHANNELS,
+    .rate            = MIXED_CAPTURE_SAMPLING_RATE,
+    .period_size     = MIXED_CAPTURE_PERIOD_SIZE,
+    .period_count    = MIXED_CAPTURE_PERIOD_COUNT,
+    .format          = MIXED_CAPTURE_FORMAT,
+    .start_threshold = MIXED_CAPTURE_START,
+    .stop_threshold  = MIXED_CAPTURE_STOP,
+};
+
+// PCM Configurations for Primary Capture Stream
+#define PRIMARY_CAPTURE_CARD            SOUND_CARD0
+#define PRIMARY_CAPTURE_DEVICE          SOUND_DEVICE_ABOX_WDMA1
+
+#define PRIMARY_CAPTURE_CHANNELS        DEFAULT_MEDIA_CHANNELS
+#define PRIMARY_CAPTURE_SAMPLING_RATE   DEFAULT_MEDIA_SAMPLING_RATE
+#define PRIMARY_CAPTURE_PERIOD_SIZE     960
+#define PRIMARY_CAPTURE_PERIOD_COUNT    4
+#define PRIMARY_CAPTURE_FORMAT          DEFAULT_MEDIA_FORMAT
+#define PRIMARY_CAPTURE_START           PRIMARY_CAPTURE_PERIOD_SIZE
+#define PRIMARY_CAPTURE_STOP            UINT_MAX
+
+struct pcm_config pcm_config_primary_capture = {
+    .channels        = PRIMARY_CAPTURE_CHANNELS,
+    .rate            = PRIMARY_CAPTURE_SAMPLING_RATE,
+    .period_size     = PRIMARY_CAPTURE_PERIOD_SIZE,
+    .period_count    = PRIMARY_CAPTURE_PERIOD_COUNT,
+    .format          = PRIMARY_CAPTURE_FORMAT,
+    .start_threshold = PRIMARY_CAPTURE_START,
+    .stop_threshold  = PRIMARY_CAPTURE_STOP,
+};
+
+#ifdef SUPPORT_QUAD_MIC
+// PCM Configurations for Primary Quad-Mic 4 channel Capture Stream
+#define PRIMARY_QUAD_CAPTURE_CHANNELS       MEDIA_4_CHANNELS
+#define PRIMARY_QUAD_CAPTURE_SAMPLING_RATE  DEFAULT_MEDIA_SAMPLING_RATE
+#define PRIMARY_QUAD_CAPTURE_PERIOD_SIZE    960
+#define PRIMARY_QUAD_CAPTURE_PERIOD_COUNT   4
+#define PRIMARY_QUAD_CAPTURE_FORMAT         DEFAULT_MEDIA_FORMAT
+#define PRIMARY_QUAD_CAPTURE_START          PRIMARY_QUAD_CAPTURE_PERIOD_SIZE
+#define PRIMARY_QUAD_CAPTURE_STOP           UINT_MAX
+
+struct pcm_config pcm_config_primary_quad_mic_capture = {
+    .channels        = PRIMARY_QUAD_CAPTURE_CHANNELS,
+    .rate            = PRIMARY_QUAD_CAPTURE_SAMPLING_RATE,
+    .period_size     = PRIMARY_QUAD_CAPTURE_PERIOD_SIZE,
+    .period_count    = PRIMARY_QUAD_CAPTURE_PERIOD_COUNT,
+    .format          = PRIMARY_QUAD_CAPTURE_FORMAT,
+    .start_threshold = PRIMARY_QUAD_CAPTURE_START,
+    .stop_threshold  = PRIMARY_QUAD_CAPTURE_STOP,
+};
+#endif
+
+// PCM Configurations for Virtual Primary Capture Stream
+#define VIRTUAL_PRIMARY_CAPTURE_CARD            SOUND_CARD1
+#define VIRTUAL_PRIMARY_CAPTURE_DEVICE          SOUND_DEVICE_VIRT_PRIMARY_CAPTURE
+
+// PCM Configurations for Low Latency Capture Stream
+#define LOW_CAPTURE_CARD                SOUND_CARD0
+#define LOW_CAPTURE_DEVICE              SOUND_DEVICE_ABOX_WDMA1
+
+#define LOW_CAPTURE_CHANNELS            DEFAULT_MEDIA_CHANNELS
+#define LOW_CAPTURE_SAMPLING_RATE       DEFAULT_MEDIA_SAMPLING_RATE
+#define LOW_CAPTURE_PERIOD_SIZE         FAST_PLAYBACK_PERIOD_SIZE
+#define LOW_CAPTURE_PERIOD_COUNT        FAST_PLAYBACK_PERIOD_COUNT
+#define LOW_CAPTURE_FORMAT              DEFAULT_MEDIA_FORMAT
+#define LOW_CAPTURE_START               LOW_CAPTURE_PERIOD_SIZE
+#define LOW_CAPTURE_STOP                UINT_MAX
+
+struct pcm_config pcm_config_low_capture = {
+    .channels        = LOW_CAPTURE_CHANNELS,
+    .rate            = LOW_CAPTURE_SAMPLING_RATE,
+    .period_size     = LOW_CAPTURE_PERIOD_SIZE,
+    .period_count    = LOW_CAPTURE_PERIOD_COUNT,
+    .format          = LOW_CAPTURE_FORMAT,
+    .start_threshold = LOW_CAPTURE_START,
+    .stop_threshold  = LOW_CAPTURE_STOP,
+};
+
+// PCM Configurations for MMAP Capture Stream
+#define MMAP_CAPTURE_CARD               SOUND_CARD0
+#define MMAP_CAPTURE_DEVICE             SOUND_DEVICE_ABOX_WDMA1
+
+#define MMAP_CAPTURE_CHANNELS           DEFAULT_MEDIA_CHANNELS
+#define MMAP_CAPTURE_SAMPLING_RATE      DEFAULT_MEDIA_SAMPLING_RATE
+#define MMAP_CAPTURE_PERIOD_SIZE        MMAP_PERIOD_SIZE
+#define MMAP_CAPTURE_PERIOD_COUNT       MMAP_PERIOD_COUNT_DEFAULT
+#define MMAP_CAPTURE_FORMAT             DEFAULT_MEDIA_FORMAT
+#define MMAP_CAPTURE_START              MMAP_CAPTURE_PERIOD_SIZE
+#define MMAP_CAPTURE_STOP               UINT_MAX
+
+struct pcm_config pcm_config_mmap_capture = {
+    .channels        = MMAP_CAPTURE_CHANNELS,
+    .rate            = MMAP_CAPTURE_SAMPLING_RATE,
+    .period_size     = MMAP_CAPTURE_PERIOD_SIZE,
+    .period_count    = MMAP_CAPTURE_PERIOD_COUNT,
+    .format          = MMAP_CAPTURE_FORMAT,
+    .start_threshold = MMAP_CAPTURE_START,
+    .stop_threshold  = MMAP_CAPTURE_STOP,
+};
+
+// PCM Configurations for Voice TX Capture Stream
+#define VTX_CAPTURE_CARD                SOUND_CARD0
+#define VTX_CAPTURE_DEVICE              SOUND_DEVICE_ABOX_WDMA2
+
+#define VTX_CAPTURE_CHANNELS            DEFAULT_VOICE_CHANNELS
+#define VTX_CAPTURE_SAMPLING_RATE       DEFAULT_VOICE_SAMPLING_RATE
+#define VTX_CAPTURE_PERIOD_SIZE         480
+#define VTX_CAPTURE_PERIOD_COUNT        4
+#define VTX_CAPTURE_FORMAT              DEFAULT_VOICE_FORMAT
+#define VTX_CAPTURE_START               VTX_CAPTURE_PERIOD_SIZE
+#define VTX_CAPTURE_STOP                UINT_MAX
+
+struct pcm_config pcm_config_voicetx_capture = {
+    .channels        = VTX_CAPTURE_CHANNELS,
+    .rate            = VTX_CAPTURE_SAMPLING_RATE,
+    .period_size     = VTX_CAPTURE_PERIOD_SIZE,
+    .period_count    = VTX_CAPTURE_PERIOD_COUNT,
+    .format          = VTX_CAPTURE_FORMAT,
+    .start_threshold = VTX_CAPTURE_START,
+    .stop_threshold  = VTX_CAPTURE_STOP,
+};
+
+#ifdef SUPPORT_QUAD_MIC
+// PCM Configurations for Quad-mic Voice TX Capture Stream
+#define VTX_QUAD_MIC_CAPTURE_CHANNELS           MEDIA_4_CHANNELS
+#define VTX_QUAD_MIC_CAPTURE_SAMPLING_RATE      DEFAULT_VOICE_SAMPLING_RATE
+#define VTX_QUAD_MIC_CAPTURE_PERIOD_SIZE        480
+#define VTX_QUAD_MIC_CAPTURE_PERIOD_COUNT       4
+#define VTX_QUAD_MIC_CAPTURE_FORMAT             DEFAULT_VOICE_FORMAT
+#define VTX_QUAD_MIC_CAPTURE_START              VTX_QUAD_MIC_CAPTURE_PERIOD_SIZE
+#define VTX_QUAD_MIC_CAPTURE_STOP               UINT_MAX
+
+struct pcm_config pcm_config_quad_mic_voicetx_capture = {
+    .channels        = VTX_QUAD_MIC_CAPTURE_CHANNELS,
+    .rate            = VTX_QUAD_MIC_CAPTURE_SAMPLING_RATE,
+    .period_size     = VTX_QUAD_MIC_CAPTURE_PERIOD_SIZE,
+    .period_count    = VTX_QUAD_MIC_CAPTURE_PERIOD_COUNT,
+    .format          = VTX_QUAD_MIC_CAPTURE_FORMAT,
+    .start_threshold = VTX_QUAD_MIC_CAPTURE_START,
+    .stop_threshold  = VTX_QUAD_MIC_CAPTURE_STOP,
+};
+#endif
+
+// PCM Configurations for FM Radio/Voice Call Capture Stream
+#define VC_FMRADIO_CAPTURE_CARD            SOUND_CARD0
+#define VC_FMRADIO_CAPTURE_DEVICE          SOUND_DEVICE_ABOX_WDMA7
+
+#define VC_FMRADIO_CAPTURE_CHANNELS        DEFAULT_MEDIA_CHANNELS
+#define VC_FMRADIO_CAPTURE_SAMPLING_RATE   DEFAULT_MEDIA_SAMPLING_RATE
+#define VC_FMRADIO_CAPTURE_PERIOD_SIZE     480
+#define VC_FMRADIO_CAPTURE_PERIOD_COUNT    4
+#define VC_FMRADIO_CAPTURE_FORMAT          DEFAULT_MEDIA_FORMAT
+#define VC_FMRADIO_CAPTURE_START           VC_FMRADIO_CAPTURE_PERIOD_SIZE
+#define VC_FMRADIO_CAPTURE_STOP            UINT_MAX
+
+struct pcm_config pcm_config_vc_fmradio_capture = {
+    .channels        = VC_FMRADIO_CAPTURE_CHANNELS,
+    .rate            = VC_FMRADIO_CAPTURE_SAMPLING_RATE,
+    .period_size     = VC_FMRADIO_CAPTURE_PERIOD_SIZE,
+    .period_count    = VC_FMRADIO_CAPTURE_PERIOD_COUNT,
+    .format          = VC_FMRADIO_CAPTURE_FORMAT,
+    .start_threshold = VC_FMRADIO_CAPTURE_START,
+    .stop_threshold  = VC_FMRADIO_CAPTURE_STOP,
+};
+
+#ifdef SUPPORT_QUAD_MIC
+// PCM Configuration for Quad-Mic direct Capture Stream
+#define QUAD_MIC_CAPTURE_CHANNELS        MEDIA_4_CHANNELS
+#define QUAD_MIC_CAPTURE_SAMPLING_RATE   DEFAULT_MEDIA_SAMPLING_RATE
+#define QUAD_MIC_CAPTURE_PERIOD_SIZE     480
+#define QUAD_MIC_CAPTURE_PERIOD_COUNT    4
+#define QUAD_MIC_CAPTURE_FORMAT          DEFAULT_MEDIA_FORMAT
+#define QUAD_MIC_CAPTURE_START           QUAD_MIC_CAPTURE_PERIOD_SIZE
+#define QUAD_MIC_CAPTURE_STOP            UINT_MAX
+
+struct pcm_config pcm_config_vc_quad_mic_capture = {
+    .channels        = QUAD_MIC_CAPTURE_CHANNELS,
+    .rate            = QUAD_MIC_CAPTURE_SAMPLING_RATE,
+    .period_size     = QUAD_MIC_CAPTURE_PERIOD_SIZE,
+    .period_count    = QUAD_MIC_CAPTURE_PERIOD_COUNT,
+    .format          = QUAD_MIC_CAPTURE_FORMAT,
+    .start_threshold = QUAD_MIC_CAPTURE_START,
+    .stop_threshold  = QUAD_MIC_CAPTURE_STOP,
+};
+#endif
+
+// PCM Configurations for ERAP In Stream
+#define ERAP_IN_CARD                    SOUND_CARD0
+#define ERAP_IN_DEVICE                  SOUND_DEVICE_ABOX_WDMA3
+
+#define ERAP_IN_CHANNELS                DEFAULT_MEDIA_CHANNELS
+#define ERAP_IN_SAMPLING_RATE           DEFAULT_MEDIA_SAMPLING_RATE
+#define ERAP_IN_PERIOD_SIZE             480
+#define ERAP_IN_PERIOD_COUNT            4
+#define ERAP_IN_FORMAT                  DEFAULT_MEDIA_32_FORMAT
+#define ERAP_IN_START                   ERAP_IN_PERIOD_SIZE
+#define ERAP_IN_STOP                    UINT_MAX
+
+struct pcm_config pcm_config_erap_in = {
+    .channels        = ERAP_IN_CHANNELS,
+    .rate            = ERAP_IN_SAMPLING_RATE,
+    .period_size     = ERAP_IN_PERIOD_SIZE,
+    .period_count    = ERAP_IN_PERIOD_COUNT,
+    .format          = ERAP_IN_FORMAT,
+    .start_threshold = ERAP_IN_START,
+    .stop_threshold  = ERAP_IN_STOP,
+};
+
+// PCM Configurations for Speaker AMP Reference Stream
+#define SPKAMP_REFERENCE_CARD           SOUND_CARD0
+#define SPKAMP_REFERENCE_DEVICE         SOUND_DEVICE_ABOX_WDMA4
+
+#define SPKAMP_REFERENCE_CHANNELS       MEDIA_4_CHANNELS
+#define SPKAMP_REFERENCE_SAMPLING_RATE  DEFAULT_MEDIA_SAMPLING_RATE
+#define SPKAMP_REFERENCE_PERIOD_SIZE    480
+#define SPKAMP_REFERENCE_PERIOD_COUNT   4
+#define SPKAMP_REFERENCE_FORMAT         DEFAULT_MEDIA_32_FORMAT
+#define SPKAMP_REFERENCE_START          SPKAMP_REFERENCE_PERIOD_SIZE
+#define SPKAMP_REFERENCE_STOP           UINT_MAX
+
+struct pcm_config pcm_config_spkamp_reference = {
+    .channels        = SPKAMP_REFERENCE_CHANNELS,
+    .rate            = SPKAMP_REFERENCE_SAMPLING_RATE,
+    .period_size     = SPKAMP_REFERENCE_PERIOD_SIZE,
+    .period_count    = SPKAMP_REFERENCE_PERIOD_COUNT,
+    .format          = SPKAMP_REFERENCE_FORMAT,
+    .start_threshold = SPKAMP_REFERENCE_START,
+    .stop_threshold  = SPKAMP_REFERENCE_STOP,
+};
+
+// PCM Configurations for BT A2DP Output Loopback Stream
+#define BTA2DP_OUT_LOOPBACK_CARD             SOUND_CARD0
+#define BTA2DP_OUT_LOOPBACK_DEVICE           SOUND_DEVICE_ABOX_WDMA5
+
+#define BTA2DP_OUT_LOOPBACK_CHANNELS         DEFAULT_MEDIA_CHANNELS
+#define BTA2DP_OUT_LOOPBACK_SAMPLING_RATE    DEFAULT_MEDIA_SAMPLING_RATE
+#define BTA2DP_OUT_LOOPBACK_PERIOD_SIZE      480
+#define BTA2DP_OUT_LOOPBACK_PERIOD_COUNT     4
+#define BTA2DP_OUT_LOOPBACK_FORMAT           DEFAULT_MEDIA_FORMAT
+#define BTA2DP_OUT_LOOPBACK_START            BTA2DP_OUT_LOOPBACK_PERIOD_SIZE
+#define BTA2DP_OUT_LOOPBACK_STOP             UINT_MAX
+
+struct pcm_config pcm_config_bta2dp_out_loopback = {
+    .channels        = BTA2DP_OUT_LOOPBACK_CHANNELS,
+    .rate            = BTA2DP_OUT_LOOPBACK_SAMPLING_RATE,
+    .period_size     = BTA2DP_OUT_LOOPBACK_PERIOD_SIZE,
+    .period_count    = BTA2DP_OUT_LOOPBACK_PERIOD_COUNT,
+    .format          = BTA2DP_OUT_LOOPBACK_FORMAT,
+    .start_threshold = BTA2DP_OUT_LOOPBACK_START,
+    .stop_threshold  = BTA2DP_OUT_LOOPBACK_STOP,
+};
+
+// PCM Configurations for Voice Call/TelephonyRx Recording Stream
+#define TELERX_RECORD_CARD              SOUND_CARD2
+#define TELERX_RECORD_DEVICE            SOUND_DEVICE_TELEPHONYRX_RECORD
+
+#define CALL_RECORD_CARD                SOUND_CARD2
+#define CALL_RECORD_DEVICE              SOUND_DEVICE_CALL_RECORD
+
+#define CALL_RECORD_CHANNELS            DEFAULT_VOICE_REC_CHANNELS
+#define CALL_RECORD_SAMPLING_RATE       DEFAULT_VOICE_REC_SAMPLINGRATE
+#define CALL_RECORD_PERIOD_SIZE         DEFAULT_VOICE_REC_PERIODSIZE
+#define CALL_RECORD_PERIOD_COUNT        DEFAULT_VOICE_REC_PERIODCOUNT
+#define CALL_RECORD_FORMAT              DEFAULT_VOICE_REC_FORMAT
+#define CALL_RECORD_START               CALL_RECORD_PERIOD_SIZE
+#define CALL_RECORD_STOP                UINT_MAX
+
+struct pcm_config pcm_config_call_record = {
+    .channels        = CALL_RECORD_CHANNELS,
+    .rate            = CALL_RECORD_SAMPLING_RATE,
+    .period_size     = CALL_RECORD_PERIOD_SIZE,
+    .period_count    = CALL_RECORD_PERIOD_COUNT,
+    .format          = CALL_RECORD_FORMAT,
+    .start_threshold = CALL_RECORD_START,
+    .stop_threshold  = CALL_RECORD_STOP,
+};
+
+// PCM Configurations for FM Radio Recording Stream
+#define FM_RECORD_CARD                  SOUND_CARD1
+#define FM_RECORD_DEVICE                SOUND_DEVICE_VIRT_FM_RECORD
+
+#define FM_RECORD_CHANNELS              DEFAULT_FM_REC_CHANNELS
+#define FM_RECORD_SAMPLING_RATE         DEFAULT_FM_REC_SAMPLINGRATE
+#define FM_RECORD_PERIOD_SIZE           DEFAULT_FM_REC_PERIODSIZE
+#define FM_RECORD_PERIOD_COUNT          DEFAULT_FM_REC_PERIODCOUNT
+#define FM_RECORD_FORMAT                DEFAULT_FM_REC_FORMAT
+#define FM_RECORD_START                 FM_RECORD_PERIOD_SIZE
+#define FM_RECORD_STOP                  FM_RECORD_PERIOD_SIZE * FM_RECORD_PERIOD_COUNT
+
+struct pcm_config pcm_config_fm_record = {
+    .channels        = FM_RECORD_CHANNELS,
+    .rate            = FM_RECORD_SAMPLING_RATE,
+    .period_size     = FM_RECORD_PERIOD_SIZE,
+    .period_count    = FM_RECORD_PERIOD_COUNT,
+    .format          = FM_RECORD_FORMAT,
+    .start_threshold = FM_RECORD_START,
+    .stop_threshold  = FM_RECORD_STOP,
+};
+
+
+#ifdef SUPPORT_STHAL_INTERFACE
+// PCM Configurations for hotword capture Stream
+// Note: Should be matching with STHAL pcm configuration
+#define DEFAULT_HOTWORD_CHANNELS                1       // Mono
+#define DEFAULT_HOTWORD_SAMPLING_RATE           16000
+#define HOTWORD_PERIOD_SIZE                     480     // 480 frames, 30ms in case of 16KHz Stream
+#define HOTWORD_PERIOD_COUNT                    128     // Buffer count => Total  122880 Bytes = 480 * 1(Mono) * 2(16bit PCM) * 128(Buffer count)
+
+struct pcm_config pcm_config_hotword_capture = {
+    .channels = DEFAULT_HOTWORD_CHANNELS,
+    .rate = DEFAULT_HOTWORD_SAMPLING_RATE,
+    .period_size = HOTWORD_PERIOD_SIZE,
+    .period_count = HOTWORD_PERIOD_COUNT,
+    .format = PCM_FORMAT_S16_LE,
+};
+#endif
+
+#define MAX_PCM_PATH_LEN 256
+
+// Duration for DP Playback
+#define PREDEFINED_DP_PLAYBACK_DURATION     20  // 20ms
+
+// Duration for MMAP pcm configurations
+#define PREDEFINED_MMAP_CAPTURE_DURATION    1   // 1ms
+
+// Duration for Remote-Mic Playback/Capture loopback node configuration
+#define PREDEFINED_REMOTE_MIC_DURATION      20  // 20ms
+
+#endif  // __EXYNOS_AUDIOPROXY_PCM_H__
diff --git a/audio/proxy/audio_proxy.c b/audio/proxy/audio_proxy.c
new file mode 100644
index 0000000..ddbf6df
--- /dev/null
+++ b/audio/proxy/audio_proxy.c
@@ -0,0 +1,6389 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "audio_hw_proxy"
+#define LOG_NDEBUG 0
+
+//#define VERY_VERY_VERBOSE_LOGGING
+#ifdef VERY_VERY_VERBOSE_LOGGING
+#define ALOGVV ALOGD
+#else
+#define ALOGVV(a...) do { } while(0)
+#endif
+
+//#define SEAMLESS_DUMP
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <dlfcn.h>
+#include <fcntl.h>
+#include <expat.h>
+
+#include <log/log.h>
+#include <cutils/str_parms.h>
+#include <cutils/properties.h>
+
+#include <audio_utils/channels.h>
+#include <audio_utils/primitives.h>
+#include <audio_utils/clock.h>
+#include <tinyalsa/asoundlib.h>
+
+#include "audio_proxy.h"
+#include "audio_proxy_interface.h"
+#include "audio_tables.h"
+#include "audio_definition.h"
+#include "audio_board_info.h"
+
+#include "audio_usb_proxy_interface.h"
+#ifdef SUPPORT_BTA2DP_OFFLOAD
+#include "audio_a2dp_proxy.h"
+#endif
+
+
+/* Vendor Property Definitions */
+#define NUM_EARPIECE_DEFAULT    "1"
+#define NUM_EARPIECE_PROPERTY   "ro.vendor.config.num_earpiece"
+
+#define NUM_SPEAKER_DEFAULT     "1"
+#define NUM_SPEAKER_PROPERTY    "ro.vendor.config.num_speaker"
+
+#define NUM_PROXIMITY_DEFAULT   "1"
+#define NUM_PROXIMITY_PROPERTY  "ro.vendor.config.num_proximity"
+
+#define SPEAKER_AMP_DEFAULT     "1"
+#define SPEAKER_AMP_PROPERTY    "ro.vendor.config.speaker_amp"
+
+#define BLUETOOTH_DEFAULT       "external"
+#define BLUETOOTH_PROPERTY      "ro.vendor.config.bluetooth"
+
+#define FMRADIO_DEFAULT         "external"
+#define FMRADIO_PROPERTY        "ro.vendor.config.fmradio"
+
+#define USBBYPRIMARY_DEFAULT    "no"
+#define USBBYPRIMARY_PROPERTY   "ro.vendor.config.usb_by_primary"
+
+
+/******************************************************************************/
+/**                                                                          **/
+/** Audio Proxy is Singleton                                                 **/
+/**                                                                          **/
+/******************************************************************************/
+
+static struct audio_proxy *instance = NULL;
+
+static struct audio_proxy* getInstance(void)
+{
+    if (instance == NULL) {
+        instance = calloc(1, sizeof(struct audio_proxy));
+        ALOGI("proxy-%s: created Audio Proxy Instance!", __func__);
+    }
+    return instance;
+}
+
+static void destroyInstance(void)
+{
+    if (instance) {
+        free(instance);
+        instance = NULL;
+        ALOGI("proxy-%s: destroyed Audio Proxy Instance!", __func__);
+    }
+    return;
+}
+
+/******************************************************************************/
+/**                                                                          **/
+/** Utility Interfaces                                                       **/
+/**                                                                          **/
+/******************************************************************************/
+int get_supported_device_number(void *proxy, int device_type)
+{
+    struct audio_proxy *aproxy = (struct audio_proxy *)proxy;
+    int ret = 0;
+
+    switch (device_type) {
+        case BUILTIN_EARPIECE:
+            ret = aproxy->num_earpiece;
+            break;
+
+        case BUILTIN_SPEAKER:
+            ret = aproxy->num_speaker;
+            break;
+
+        case BUILTIN_MIC:
+            ret = aproxy->num_mic;
+            break;
+
+        case PROXIMITY_SENSOR:
+            ret = aproxy->num_proximity;
+            break;
+
+        default:
+            break;
+    }
+
+    return ret;
+}
+
+int  get_supported_config(void *proxy, int device_type)
+{
+    struct audio_proxy *aproxy = (struct audio_proxy *)proxy;
+    int ret = DEVICE_CONFIG_NONE;
+
+    switch (device_type) {
+        case DEVICE_BLUETOOTH:
+            if (aproxy->bt_internal)
+                ret = DEVICE_CONFIG_INTERNAL;
+            else if (aproxy->bt_external)
+                ret = DEVICE_CONFIG_EXTERNAL;
+            break;
+
+        case DEVICE_FMRADIO:
+            if (aproxy->fm_internal)
+                ret = DEVICE_CONFIG_INTERNAL;
+            else if (aproxy->fm_external)
+                ret = DEVICE_CONFIG_EXTERNAL;
+            break;
+
+        default:
+            break;
+    }
+
+    return ret;
+}
+
+bool is_needed_config(void *proxy, int config_type)
+{
+    struct audio_proxy *aproxy = (struct audio_proxy *)proxy;
+    bool ret = false;
+
+    switch (config_type) {
+        case NEED_VOICEPCM_REOPEN:
+            if (aproxy->btsco_playback)
+                ret = true;
+            break;
+
+        case SUPPORT_USB_BY_PRIMARY:
+            if (aproxy->usb_by_primary)
+                ret = true;
+            break;
+
+        default:
+            break;
+    }
+
+    return ret;
+}
+
+bool is_active_usage_CPCall(void *proxy)
+{
+    struct audio_proxy *aproxy = (struct audio_proxy *)proxy;
+
+    if (aproxy->active_playback_ausage >= AUSAGE_CPCALL_MIN &&
+        aproxy->active_playback_ausage <= AUSAGE_CPCALL_MAX)
+        return true;
+    else
+        return false;
+}
+
+bool is_usage_CPCall(audio_usage ausage)
+{
+    if (ausage >= AUSAGE_CPCALL_MIN && ausage <= AUSAGE_CPCALL_MAX)
+        return true;
+    else
+        return false;
+}
+
+bool is_active_usage_APCall(void *proxy)
+{
+    struct audio_proxy *aproxy = (struct audio_proxy *)proxy;
+
+    if (aproxy->active_playback_ausage >= AUSAGE_APCALL_MIN &&
+        aproxy->active_playback_ausage <= AUSAGE_APCALL_MAX)
+        return true;
+    else
+        return false;
+}
+
+bool is_usage_APCall(audio_usage ausage)
+{
+    if (ausage >= AUSAGE_APCALL_MIN && ausage <= AUSAGE_APCALL_MAX)
+        return true;
+    else
+        return false;
+}
+
+bool is_usage_Call(audio_usage ausage)
+{
+    if (ausage >= AUSAGE_CPCALL_MIN && ausage <= AUSAGE_CPCALL_MAX)
+        return true;
+    else if (ausage >= AUSAGE_APCALL_MIN && ausage <= AUSAGE_APCALL_MAX)
+        return true;
+    else
+        return false;
+}
+
+bool is_usage_Loopback(audio_usage ausage)
+{
+    // AUSAGE_LOOPBACK == min, AUSAGE_LOOPBACK_CODEC == max
+    if (ausage >= AUSAGE_LOOPBACK && ausage <= AUSAGE_LOOPBACK_CODEC)
+        return true;
+    else
+        return false;
+}
+
+bool is_usb_connected(void)
+{
+    struct audio_proxy *aproxy = getInstance();
+
+    if (proxy_is_usb_playback_device_connected(aproxy->usb_aproxy))
+        return true;
+    else
+        return false;
+}
+
+#ifdef SUPPORT_BTA2DP_OFFLOAD
+bool proxy_is_bt_a2dp_ready(void)
+{
+    struct audio_proxy *aproxy = getInstance();
+
+    // bt offload enabled and not suspend state
+    if (aproxy && aproxy->a2dp_out_enabled) {
+        if (!proxy_a2dp_is_suspended())
+            return true;
+    }
+
+    return false;
+}
+
+static const audio_format_t AUDIO_FORMAT_SEC_BT_A2DP_OFFLOAD = (audio_format_t)0x200000u;
+static inline bool audio_is_bt_offload_format(audio_format_t format){
+     if ((format & AUDIO_FORMAT_SEC_BT_A2DP_OFFLOAD) == AUDIO_FORMAT_SEC_BT_A2DP_OFFLOAD) {
+         return true;
+     }
+     return false;
+
+}
+#endif
+
+void update_usb_clksource_info(bool flag)
+{
+    struct audio_proxy *aproxy = getInstance();
+    struct mixer_ctl *ctrl = NULL;
+    int ret = 0;
+
+    pthread_rwlock_rdlock(&aproxy->mixer_update_lock);
+
+    // set usb device clock info if flag is true and usb connected
+    if (flag) {
+        /* USB Clock Source information Mixer control */
+        ctrl = mixer_get_ctl_by_name(aproxy->mixer, MIXER_CTL_ABOX_USB_CLOCKSOURCE);
+        if (ctrl) {
+            ret = mixer_ctl_get_value(ctrl, 0);
+            if (ret < 0) {
+                ALOGE("proxy-%s: failed to get %s %d", __func__, MIXER_CTL_ABOX_USB_CLOCKSOURCE, ret);
+            } else {
+                aproxy->is_usb_single_clksrc = ret;
+                ALOGI("proxy-%s: get USB Device ClockSource information %d",
+                    __func__, aproxy->is_usb_single_clksrc);
+            }
+        } else {
+            ALOGE("proxy-%s: cannot find %s Mixer Control", __func__, MIXER_CTL_ABOX_USB_CLOCKSOURCE);
+        }
+    } else {
+        // reset usb device clock info when usb disconnected
+        aproxy->is_usb_single_clksrc = false;
+        ALOGI("proxy-%s: reset USB Device ClockSource information %d",
+            __func__, aproxy->is_usb_single_clksrc);
+    }
+
+    pthread_rwlock_unlock(&aproxy->mixer_update_lock);
+
+    return;
+}
+
+bool is_usb_single_clksource()
+{
+    struct audio_proxy *aproxy = getInstance();
+
+    return aproxy->is_usb_single_clksrc;
+}
+
+/******************************************************************************/
+/**                                                                          **/
+/** Local Fuctions for Audio Device Proxy                                    **/
+/**                                                                          **/
+/******************************************************************************/
+
+static audio_format_t get_pcmformat_from_alsaformat(enum pcm_format pcmformat)
+{
+    audio_format_t format = AUDIO_FORMAT_PCM_16_BIT;
+
+    switch (pcmformat) {
+        case PCM_FORMAT_S16_LE:
+            format = AUDIO_FORMAT_PCM_16_BIT;
+            break;
+        case PCM_FORMAT_S32_LE:
+            format = AUDIO_FORMAT_PCM_32_BIT;
+            break;
+        case PCM_FORMAT_S8:
+            format = AUDIO_FORMAT_PCM_8_BIT;
+            break;
+        case PCM_FORMAT_S24_LE:
+        case PCM_FORMAT_S24_3LE:
+            format = AUDIO_FORMAT_PCM_8_24_BIT;
+            break;
+        case PCM_FORMAT_INVALID:
+        case PCM_FORMAT_MAX:
+            format = AUDIO_FORMAT_PCM_16_BIT;
+            break;
+    }
+
+    return format;
+}
+
+static bool is_playback_device_bt(device_type device)
+{
+    if (device == DEVICE_BT_HEADSET || device == DEVICE_SPEAKER_AND_BT_HEADSET
+#ifdef SUPPORT_BTA2DP_OFFLOAD
+        || device == DEVICE_BT_A2DP_HEADPHONE || device == DEVICE_SPEAKER_AND_BT_A2DP_HEADPHONE
+#endif
+    )
+        return true;
+    else
+        return false;
+}
+
+static bool is_playback_device_speaker_dualpath(device_type device)
+{
+    if (device == DEVICE_SPEAKER_AND_HEADSET ||
+        device == DEVICE_SPEAKER_AND_HEADPHONE ||
+        device == DEVICE_SPEAKER_AND_BT_HEADSET ||
+        device == DEVICE_SPEAKER_AND_USB_HEADSET
+#ifdef SUPPORT_BTA2DP_OFFLOAD
+        || device == DEVICE_SPEAKER_AND_BT_A2DP_HEADPHONE
+#endif
+    )
+        return true;
+    else
+        return false;
+}
+
+#ifdef SUPPORT_BTA2DP_OFFLOAD
+static bool is_active_playback_device_bta2dp(struct audio_proxy *aproxy)
+{
+    if (aproxy->active_playback_device == DEVICE_BT_A2DP_HEADPHONE ||
+        aproxy->active_playback_device == DEVICE_SPEAKER_AND_BT_A2DP_HEADPHONE)
+        return true;
+    else
+        return false;
+}
+
+static bool is_playback_device_bta2dp(device_type device)
+{
+    if (device == DEVICE_BT_A2DP_HEADPHONE || device == DEVICE_SPEAKER_AND_BT_A2DP_HEADPHONE)
+        return true;
+    else
+        return false;
+}
+#endif
+
+static bool is_device_speaker(device_type device)
+{
+    if (device < DEVICE_MAIN_MIC) {
+        if ((device == DEVICE_SPEAKER)
+#ifdef SEC_AUDIO_SUPPORT_GAMECHAT_SPK_AEC
+                || (device == DEVICE_SPEAKER_GAMING)
+#endif
+                || (device == DEVICE_SPEAKER_DEX)) {
+            return true;
+        }
+        return false;
+    } else {
+        if ((device == DEVICE_SPEAKER_MIC)
+#ifdef SEC_AUDIO_SUPPORT_GAMECHAT_SPK_AEC
+                || (device == DEVICE_SPEAKER_GAMING_MIC)
+#endif
+                || (device == DEVICE_SPEAKER_DEX_MIC)) {
+            return true;
+        }
+        return false;
+    }
+}
+
+static bool is_usb_mic_device(device_type device)
+{
+    return (device == DEVICE_USB_HEADSET_MIC /*||
+                device == DEVICE_USB_FULL_MIC ||
+                device == DEVICE_USB_HCO_MIC*/);
+}
+
+#ifdef SUPPORT_QUAD_MIC
+static bool is_quad_mic_device(device_type device)
+{
+    struct audio_proxy *aproxy = getInstance();
+    bool flag = false;
+
+    if (device == DEVICE_QUAD_MIC)
+        flag = true;
+    else if (is_usage_CPCall(aproxy->active_capture_ausage) ||
+            is_usage_APCall(aproxy->active_capture_ausage))
+        flag = (device == DEVICE_MAIN_MIC ||
+                device == DEVICE_HANDSET_MIC ||
+                device == DEVICE_HEADPHONE_MIC ||
+                device == DEVICE_SPEAKER_MIC ||
+                device == DEVICE_SPEAKER_DEX_MIC /*||
+                device == DEVICE_SPEAKER_GAMING_MIC*/);
+	return flag;
+}
+#endif
+
+// If there are specific device number in mixer_paths.xml, it get the specific device number from mixer_paths.xml
+static int get_pcm_device_number(void *proxy, void *proxy_stream)
+{
+    struct audio_proxy *aproxy = proxy;
+    struct audio_proxy_stream *apstream = (struct audio_proxy_stream *)proxy_stream;
+    struct audio_route *aroute = aproxy->aroute;
+    int pcm_device_number = -1;
+
+    pthread_rwlock_rdlock(&aproxy->mixer_update_lock);
+    if (apstream) {
+        switch(apstream->stream_type) {
+            case ASTREAM_PLAYBACK_PRIMARY:
+                pcm_device_number = get_dai_link(aroute, PLAYBACK_DEEP_LINK);
+                if (pcm_device_number < 0)
+                    pcm_device_number = PRIMARY_PLAYBACK_DEVICE;
+                break;
+
+            case ASTREAM_PLAYBACK_FAST:
+                pcm_device_number = FAST_PLAYBACK_DEVICE;
+                break;
+
+            case ASTREAM_PLAYBACK_LOW_LATENCY:
+                pcm_device_number = get_dai_link(aroute, PLAYBACK_LOW_LINK);
+                if (pcm_device_number < 0)
+                    pcm_device_number = LOW_PLAYBACK_DEVICE;
+                break;
+
+            case ASTREAM_PLAYBACK_DEEP_BUFFER:
+                pcm_device_number = get_dai_link(aroute, PLAYBACK_DEEP_LINK);
+                if (pcm_device_number < 0)
+                    pcm_device_number = DEEP_PLAYBACK_DEVICE;
+                break;
+
+            case ASTREAM_PLAYBACK_COMPR_OFFLOAD:
+                pcm_device_number = get_dai_link(aroute, PLAYBACK_OFFLOAD_LINK);
+                if (pcm_device_number < 0)
+                    pcm_device_number = OFFLOAD_PLAYBACK_DEVICE;
+                break;
+
+            case ASTREAM_PLAYBACK_MMAP:
+                pcm_device_number = MMAP_PLAYBACK_DEVICE;
+                break;
+
+            case ASTREAM_PLAYBACK_AUX_DIGITAL:
+                pcm_device_number = get_dai_link(aroute, PLAYBACK_AUX_DIGITAL_LINK);
+                if (pcm_device_number < 0)
+                    pcm_device_number = AUX_PLAYBACK_DEVICE;
+                break;
+
+            case ASTREAM_PLAYBACK_DIRECT:
+                pcm_device_number = get_dai_link(aroute, PLAYBACK_DIRECT_LINK);
+                if (pcm_device_number < 0)
+                    pcm_device_number = DIRECT_PLAYBACK_DEVICE;
+                break;
+
+            case ASTREAM_CAPTURE_PRIMARY:
+                pcm_device_number = get_dai_link(aroute, CAPTURE_LINK);
+                if (pcm_device_number < 0)
+                    pcm_device_number = PRIMARY_CAPTURE_DEVICE;
+                break;
+
+            case ASTREAM_CAPTURE_CALL:
+                pcm_device_number = get_dai_link(aroute, CALL_REC_CAPTURE_LINK);
+                if (pcm_device_number < 0)
+                    pcm_device_number = CALL_RECORD_DEVICE;
+                break;
+
+            case ASTREAM_CAPTURE_TELEPHONYRX:
+                pcm_device_number = get_dai_link(aroute, TELEPHONYRX_CAPTURE_LINK);
+                if (pcm_device_number < 0)
+                    pcm_device_number = TELERX_RECORD_DEVICE;
+                break;
+
+            case ASTREAM_CAPTURE_LOW_LATENCY:
+                pcm_device_number = LOW_CAPTURE_DEVICE;
+                break;
+
+            case ASTREAM_CAPTURE_MMAP:
+                pcm_device_number = MMAP_CAPTURE_DEVICE;
+                break;
+
+            case ASTREAM_CAPTURE_FM:
+                pcm_device_number = FM_RECORD_DEVICE;
+                break;
+
+            default:
+                break;
+        }
+    } else {
+    }
+    pthread_rwlock_unlock(&aproxy->mixer_update_lock);
+
+    return pcm_device_number;
+}
+
+/*
+ * Internal Path Control Functions for A-Box
+ */
+static void disable_erap_in(void *proxy)
+{
+    struct audio_proxy *aproxy = proxy;
+    char pcm_path[MAX_PCM_PATH_LEN];
+
+    if (aproxy->support_out_loopback) {
+        snprintf(pcm_path, sizeof(pcm_path), "/dev/snd/pcmC%uD%u%c",
+                 ERAP_IN_CARD, ERAP_IN_DEVICE, 'c');
+
+        /* Disables ERAP In Path */
+        if (aproxy->erap_in) {
+            pcm_stop(aproxy->erap_in);
+            pcm_close(aproxy->erap_in);
+            aproxy->erap_in = NULL;
+
+            ALOGI("proxy-%s: ERAP In PCM Device(%s) is stopped & closed!", __func__, pcm_path);
+        }
+    }
+
+    return ;
+}
+
+static void enable_erap_in(void *proxy, device_type target_device)
+{
+    struct audio_proxy *aproxy = proxy;
+    struct pcm_config pcmconfig = pcm_config_erap_in;
+    char pcm_path[MAX_PCM_PATH_LEN];
+
+    if (aproxy->support_out_loopback) {
+        snprintf(pcm_path, sizeof(pcm_path), "/dev/snd/pcmC%uD%u%c",
+                 ERAP_IN_CARD, ERAP_IN_DEVICE, 'c');
+
+        /* Enables ERAP In Path */
+        if (aproxy->erap_in == NULL) {
+            /* If target device is USB Headset, then loopback path's PCM channels should be
+             * matched with USB device supported channels */
+            if (target_device == DEVICE_SPEAKER_AND_USB_HEADSET) {
+                pcmconfig.channels = proxy_usb_get_playback_channels(aproxy->usb_aproxy);
+                /* check if connected USB headset's highest channel count is 6, then forcelly
+                 * change it to 8 channels as A-Box HW cannot support 6 channel conversion */
+                if (pcmconfig.channels == ABOX_UNSUPPORTED_CHANNELS) {
+                    ALOGI("proxy-%s: supported CH is(%d) Changed to (%d)", __func__, pcmconfig.channels,
+                        ABOX_SUPPORTED_MAX_CHANNELS);
+                    pcmconfig.channels = ABOX_SUPPORTED_MAX_CHANNELS;
+                }
+                ALOGI("proxy-%s: ERAP In USB Device channels updated as CC(%d)",
+                  __func__, pcmconfig.channels);
+            }
+#ifdef SUPPORT_QUAD_MIC
+            else if (target_device == DEVICE_CALL_FWD || target_device == DEVICE_SPECTRO) {
+                pcmconfig.channels = MEDIA_4_CHANNELS;
+                ALOGI("proxy-%s: Call-forwarding/spectro ERAP In channels fixed to (%d)", __func__, pcmconfig.channels);
+            }
+#endif
+            aproxy->erap_in = pcm_open(ERAP_IN_CARD, ERAP_IN_DEVICE,
+                                       PCM_IN | PCM_MONOTONIC, &pcmconfig);
+            if (aproxy->erap_in && !pcm_is_ready(aproxy->erap_in)) {
+                /* pcm_open does always return pcm structure, not NULL */
+                ALOGE("proxy-%s: ERAP In PCM Device(%s) with SR(%u) PF(%d) CC(%d) is not ready as error(%s)",
+                      __func__, pcm_path, pcmconfig.rate, pcmconfig.format, pcmconfig.channels,
+                      pcm_get_error(aproxy->erap_in));
+                goto err_open;
+            }
+            ALOGVV("proxy-%s: ERAP In PCM Device(%s) with SR(%u) PF(%d) CC(%d) is opened",
+                  __func__, pcm_path, pcmconfig.rate, pcmconfig.format, pcmconfig.channels);
+
+            if (pcm_start(aproxy->erap_in) == 0) {
+                ALOGI("proxy-%s: ERAP In PCM Device(%s) with SR(%u) PF(%d) CC(%d) is opened & started",
+                      __func__, pcm_path, pcmconfig.rate, pcmconfig.format, pcmconfig.channels);
+            } else {
+                ALOGE("proxy-%s: ERAP In PCM Device(%s) with SR(%u) PF(%d) CC(%d) cannot be started as error(%s)",
+                      __func__, pcm_path, pcmconfig.rate, pcmconfig.format, pcmconfig.channels,
+                      pcm_get_error(aproxy->erap_in));
+                goto err_open;
+            }
+        }
+    }
+
+    return ;
+
+err_open:
+    disable_erap_in(proxy);
+    return ;
+}
+
+static void disable_voice_tx_direct_in(void *proxy)
+{
+    struct audio_proxy *aproxy = proxy;
+    char pcm_path[MAX_PCM_PATH_LEN];
+
+    if (aproxy->call_tx_direct) {
+        snprintf(pcm_path, sizeof(pcm_path), "/dev/snd/pcmC%uD%u%c",
+                 VC_FMRADIO_CAPTURE_CARD, VC_FMRADIO_CAPTURE_DEVICE, 'c');
+
+        pcm_stop(aproxy->call_tx_direct);
+        pcm_close(aproxy->call_tx_direct);
+        aproxy->call_tx_direct= NULL;
+        ALOGI("proxy-%s: Voice Call TX Direct PCM Device(%s) is stopped & closed!", __func__, pcm_path);
+    }
+
+    return;
+}
+
+static void enable_voice_tx_direct_in(void *proxy, device_type target_device __unused)
+{
+    struct audio_proxy *aproxy = proxy;
+    struct pcm_config pcmconfig;
+    char pcm_path[MAX_PCM_PATH_LEN];
+
+    if (aproxy->call_tx_direct== NULL) {
+#ifdef SUPPORT_QUAD_MIC
+        if (is_quad_mic_device(target_device)) {
+            pcmconfig = pcm_config_vc_quad_mic_capture;
+            ALOGI("proxy-%s: Quad-Mic config for Voice Call TX Direct ", __func__);
+        } else
+#endif
+            pcmconfig = pcm_config_vc_fmradio_capture;
+        snprintf(pcm_path, sizeof(pcm_path), "/dev/snd/pcmC%uD%u%c",
+                 VC_FMRADIO_CAPTURE_CARD, VC_FMRADIO_CAPTURE_DEVICE, 'c');
+
+        aproxy->call_tx_direct = pcm_open(VC_FMRADIO_CAPTURE_CARD,
+                                        VC_FMRADIO_CAPTURE_DEVICE,
+                                        PCM_IN | PCM_MONOTONIC, &pcmconfig);
+        if (aproxy->call_tx_direct && !pcm_is_ready(aproxy->call_tx_direct)) {
+            /* pcm_open does always return pcm structure, not NULL */
+            ALOGE("proxy-%s: Voice Call TX Direct PCM Device(%s) with SR(%u) PF(%d) CC(%d) is not ready as error(%s)",
+                  __func__, pcm_path, pcmconfig.rate, pcmconfig.format, pcmconfig.channels,
+                  pcm_get_error(aproxy->call_tx_direct));
+            goto err_open;
+        }
+        ALOGVV("proxy-%s: Voice Call TX Direct PCM Device(%s) with SR(%u) PF(%d) CC(%d) is opened",
+              __func__, pcm_path, pcmconfig.rate, pcmconfig.format, pcmconfig.channels);
+
+        if (pcm_start(aproxy->call_tx_direct) == 0) {
+            ALOGI("proxy-%s: Voice Call TX Direct PCM Device(%s) with SR(%u) PF(%d) CC(%d) is opened & started",
+                  __func__, pcm_path, pcmconfig.rate, pcmconfig.format, pcmconfig.channels);
+        } else {
+            ALOGE("proxy-%s: Voice Call TX Direct PCM Device(%s) with SR(%u) PF(%d) CC(%d) cannot be started as error(%s)",
+                  __func__, pcm_path, pcmconfig.rate, pcmconfig.format, pcmconfig.channels,
+                  pcm_get_error(aproxy->call_tx_direct));
+            goto err_open;
+        }
+    }
+
+    return;
+err_open:
+    disable_voice_tx_direct_in(proxy);
+}
+
+static void disable_usb_out_loopback(void *proxy)
+{
+    struct audio_proxy *aproxy = proxy;
+    char pcm_path[MAX_PCM_PATH_LEN];
+
+    if (aproxy->support_usb_out_loopback) {
+        snprintf(pcm_path, sizeof(pcm_path), "/dev/snd/pcmC%uD%u%c",
+                 USBOUT_LOOPBACK_CARD, USBOUT_LOOPBACK_DEVICE, 'c');
+
+        /* Disables USB Out Loopback Path */
+        if (aproxy->usb_out_loopback) {
+            pcm_stop(aproxy->usb_out_loopback);
+            pcm_close(aproxy->usb_out_loopback);
+            aproxy->usb_out_loopback = NULL;
+
+            ALOGI("proxy-%s: USBOut Loopback PCM Device(%s) is stopped & closed!", __func__, pcm_path);
+        }
+    }
+
+    return ;
+}
+
+static void enable_usb_out_loopback(void *proxy)
+{
+    struct audio_proxy *aproxy = proxy;
+    struct pcm_config pcmconfig = pcm_config_usb_out_loopback;
+    char pcm_path[MAX_PCM_PATH_LEN];
+
+    if (aproxy->support_usb_out_loopback) {
+        snprintf(pcm_path, sizeof(pcm_path), "/dev/snd/pcmC%uD%u%c",
+                 USBOUT_LOOPBACK_CARD, USBOUT_LOOPBACK_DEVICE, 'c');
+
+        /* Enables USB Out Loopback path */
+        if (aproxy->usb_out_loopback == NULL) {
+            // Updates PCM Configuration same as USB PCM Configuration
+            pcmconfig.rate = proxy_usb_get_playback_samplerate(aproxy->usb_aproxy);
+            pcmconfig.channels = proxy_usb_get_playback_channels(aproxy->usb_aproxy);
+            /* A-Box limitation all DMA buffer size should be multiple of 16
+               therefore Period Size(Frame Count) is rounded of to nearest 4 multiple */
+            pcmconfig.period_size = ((pcmconfig.rate * PREDEFINED_USB_PLAYBACK_DURATION) / 1000) & ~0x3;
+            pcmconfig.format = proxy_usb_get_playback_format(aproxy->usb_aproxy);
+
+            /* check if connected USB headset's channel count is 6, then forcelly
+              * change it to 8 channels as A-Box HW cannot support 6 channel conversion */
+            if (pcmconfig.channels == ABOX_UNSUPPORTED_CHANNELS) {
+                ALOGI("proxy-%s: supported CH is(%d) Changed to (%d)", __func__, pcmconfig.channels,
+                    ABOX_SUPPORTED_MAX_CHANNELS);
+                pcmconfig.channels = ABOX_SUPPORTED_MAX_CHANNELS;
+            }
+
+            /* PCM_FORMAT_S24_3LE (24bit packed) format is not supported by A-Box hardware
+             * therefore forcefully change the format to PCM_FORMAT_S24_LE */
+            if (pcmconfig.format == PCM_FORMAT_S24_3LE) {
+                ALOGI("proxy-%s: USB Format is forcefully changed 24bit packed -> 24bit padded", __func__);
+                pcmconfig.format = PCM_FORMAT_S24_LE;
+            }
+
+            aproxy->usb_out_loopback = pcm_open(USBOUT_LOOPBACK_CARD, USBOUT_LOOPBACK_DEVICE,
+                                               PCM_IN | PCM_MONOTONIC, &pcmconfig);
+            if (aproxy->usb_out_loopback && !pcm_is_ready(aproxy->usb_out_loopback)) {
+                /* pcm_open does always return pcm structure, not NULL */
+                ALOGE("proxy-%s: USBOut Loopback PCM Device(%s) with SR(%u) PF(%d) CC(%d) is not ready as error(%s)",
+                      __func__, pcm_path, pcmconfig.rate, pcmconfig.format, pcmconfig.channels,
+                      pcm_get_error(aproxy->usb_out_loopback));
+                goto err_open;
+            }
+            ALOGI("proxy-%s: USBOut Loopback PCM Device(%s) with SR(%u) PF(%d) CC(%d) PdSz(%d) PdCnt(%d) is opened",
+                  __func__, pcm_path, pcmconfig.rate, pcmconfig.format, pcmconfig.channels,
+                  pcmconfig.period_size, pcmconfig.period_count);
+
+            if (pcm_start(aproxy->usb_out_loopback) == 0) {
+                ALOGI("proxy-%s: USBOut Loopback PCM Device(%s) with SR(%u) PF(%d) CC(%d) is opened & started",
+                      __func__, pcm_path, pcmconfig.rate, pcmconfig.format, pcmconfig.channels);
+            } else {
+                ALOGE("proxy-%s: USBOut Loopback PCM Device(%s) with SR(%u) PF(%d) CC(%d) cannot be started as error(%s)",
+                      __func__, pcm_path, pcmconfig.rate, pcmconfig.format, pcmconfig.channels,
+                      pcm_get_error(aproxy->usb_out_loopback));
+                goto err_open;
+            }
+        }
+    }
+
+    return ;
+
+err_open:
+    disable_usb_out_loopback(proxy);
+    return ;
+}
+
+
+static void disable_usb_in_loopback(void *proxy)
+{
+    struct audio_proxy *aproxy = proxy;
+    char pcm_path[MAX_PCM_PATH_LEN];
+
+    if (aproxy->support_usb_in_loopback) {
+        snprintf(pcm_path, sizeof(pcm_path), "/dev/snd/pcmC%uD%u%c",
+                 USBIN_LOOPBACK_CARD, USBIN_LOOPBACK_DEVICE, 'p');
+
+        /* Disables USB In Loopback Path */
+        if (aproxy->usb_in_loopback) {
+            pcm_stop(aproxy->usb_in_loopback);
+            pcm_close(aproxy->usb_in_loopback);
+            aproxy->usb_in_loopback = NULL;
+
+            ALOGI("proxy-%s: USBIn Loopback PCM Device(%s) is stopped & closed!", __func__, pcm_path);
+        }
+    }
+
+    return ;
+}
+
+static void enable_usb_in_loopback(void *proxy)
+{
+    struct audio_proxy *aproxy = proxy;
+    struct pcm_config pcmconfig = pcm_config_usb_in_loopback;
+    char pcm_path[MAX_PCM_PATH_LEN];
+
+    if (aproxy->support_usb_in_loopback) {
+        snprintf(pcm_path, sizeof(pcm_path), "/dev/snd/pcmC%uD%u%c",
+                 USBIN_LOOPBACK_CARD, USBIN_LOOPBACK_DEVICE, 'p');
+
+        /* Enables USB In Loopback path */
+        if (aproxy->usb_in_loopback == NULL) {
+            // Updates PCM Configuration same as USB PCM Configuration
+            pcmconfig.rate = proxy_usb_get_capture_samplerate(aproxy->usb_aproxy);
+            pcmconfig.channels = proxy_usb_get_capture_channels(aproxy->usb_aproxy);
+            /* A-Box limitation all DMA buffer size should be multiple of 16
+               therefore Period Size(Frame Count) is rounded of to nearest 4 multiple */
+            pcmconfig.period_size = ((pcmconfig.rate * PREDEFINED_USB_PLAYBACK_DURATION) / 1000) & ~0x3;
+            pcmconfig.format = proxy_usb_get_capture_format(aproxy->usb_aproxy);
+
+            /* check if connected USB headset's channel count is 6, then forcelly
+              * change it to 8 channels as A-Box HW cannot support 6 channel conversion */
+            if (pcmconfig.channels == ABOX_UNSUPPORTED_CHANNELS) {
+                ALOGI("proxy-%s: supported CH is(%d) Changed to (%d)", __func__, pcmconfig.channels,
+                    ABOX_SUPPORTED_MAX_CHANNELS);
+                pcmconfig.channels = ABOX_SUPPORTED_MAX_CHANNELS;
+            }
+
+            /* PCM_FORMAT_S24_3LE (24bit packed) format is not supported by A-Box hardware
+             * therefore forcefully change the format to PCM_FORMAT_S24_LE */
+            if (pcmconfig.format == PCM_FORMAT_S24_3LE) {
+                ALOGI("proxy-%s: USB Format is forcefully changed from 24bit packed -> 24bit padded", __func__);
+                pcmconfig.format = PCM_FORMAT_S24_LE;
+            }
+
+            aproxy->usb_in_loopback = pcm_open(USBIN_LOOPBACK_CARD, USBIN_LOOPBACK_DEVICE,
+                                               PCM_OUT | PCM_MONOTONIC, &pcmconfig);
+            if (aproxy->usb_in_loopback && !pcm_is_ready(aproxy->usb_in_loopback)) {
+                /* pcm_open does always return pcm structure, not NULL */
+                ALOGE("proxy-%s: USBIn Loopback PCM Device(%s) with SR(%u) PF(%d) CC(%d) is not ready as error(%s)",
+                      __func__, pcm_path, pcmconfig.rate, pcmconfig.format, pcmconfig.channels,
+                      pcm_get_error(aproxy->usb_in_loopback));
+                goto err_open;
+            }
+            ALOGI("proxy-%s: USBIn Loopback PCM Device(%s) with SR(%u)PF(%d) CC(%d) PdSz(%d) PdCnt(%d) is opened",
+                  __func__, pcm_path, pcmconfig.rate, pcmconfig.format, pcmconfig.channels,
+                  pcmconfig.period_size, pcmconfig.period_count);
+
+            if (pcm_start(aproxy->usb_in_loopback) == 0) {
+                ALOGI("proxy-%s: USBIn Loopback PCM Device(%s) with SR(%u) PF(%d) CC(%d) is opened & started",
+                      __func__, pcm_path, pcmconfig.rate, pcmconfig.format, pcmconfig.channels);
+            } else {
+                ALOGE("proxy-%s: USBIn Loopback PCM Device(%s) with SR(%u) PF(%d) CC(%d) cannot be started as error(%s)",
+                      __func__, pcm_path, pcmconfig.rate, pcmconfig.format, pcmconfig.channels,
+                      pcm_get_error(aproxy->usb_in_loopback));
+                goto err_open;
+            }
+        }
+    }
+
+    return ;
+
+err_open:
+    disable_usb_in_loopback(proxy);
+    return ;
+}
+
+static void disable_spkamp_reference(void *proxy)
+{
+    struct audio_proxy *aproxy = proxy;
+    char pcm_path[MAX_PCM_PATH_LEN];
+
+    if (aproxy->support_spkamp) {
+        snprintf(pcm_path, sizeof(pcm_path), "/dev/snd/pcmC%uD%u%c",
+                 SPKAMP_REFERENCE_CARD, SPKAMP_REFERENCE_DEVICE, 'c');
+
+        /* Disables Speaker AMP Reference Path */
+        if (aproxy->spkamp_reference) {
+            pcm_stop(aproxy->spkamp_reference);
+            pcm_close(aproxy->spkamp_reference);
+            aproxy->spkamp_reference = NULL;
+
+            ALOGI("proxy-%s: SPKAMP Reference PCM Device(%s) is stopped & closed!", __func__, pcm_path);
+        }
+    }
+
+    return ;
+}
+
+static void enable_spkamp_reference(void *proxy)
+{
+    struct audio_proxy *aproxy = proxy;
+    struct pcm_config pcmconfig = pcm_config_spkamp_reference;
+    char pcm_path[MAX_PCM_PATH_LEN];
+
+    if (aproxy->support_spkamp) {
+        snprintf(pcm_path, sizeof(pcm_path), "/dev/snd/pcmC%uD%u%c",
+                 SPKAMP_REFERENCE_CARD, SPKAMP_REFERENCE_DEVICE, 'c');
+
+        /* Enables Speaker AMP Reference Path */
+        if (aproxy->spkamp_reference == NULL) {
+            aproxy->spkamp_reference = pcm_open(SPKAMP_REFERENCE_CARD, SPKAMP_REFERENCE_DEVICE,
+                                                PCM_IN | PCM_MONOTONIC, &pcmconfig);
+            if (aproxy->spkamp_reference && !pcm_is_ready(aproxy->spkamp_reference)) {
+                /* pcm_open does always return pcm structure, not NULL */
+                ALOGE("proxy-%s: SPKAMP Reference PCM Device(%s) with SR(%u) PF(%d) CC(%d) is not ready as error(%s)",
+                      __func__, pcm_path, pcmconfig.rate, pcmconfig.format, pcmconfig.channels,
+                      pcm_get_error(aproxy->spkamp_reference));
+                goto err_open;
+            }
+            ALOGVV("proxy-%s: SPKAMP Reference PCM Device(%s) with SR(%u) PF(%d) CC(%d) is opened",
+                  __func__, pcm_path, pcmconfig.rate, pcmconfig.format, pcmconfig.channels);
+
+            if (pcm_start(aproxy->spkamp_reference) == 0) {
+                ALOGI("proxy-%s: SPKAMP Reference PCM Device(%s) with SR(%u) PF(%d) CC(%d) is opened & started",
+                      __func__, pcm_path, pcmconfig.rate, pcmconfig.format, pcmconfig.channels);
+            } else {
+                ALOGE("proxy-%s: SPKAMP Reference PCM Device(%s) with SR(%u) PF(%d) CC(%d) cannot be started as error(%s)",
+                      __func__, pcm_path, pcmconfig.rate, pcmconfig.format, pcmconfig.channels,
+                      pcm_get_error(aproxy->spkamp_reference));
+                goto err_open;
+            }
+        }
+    }
+
+    return ;
+
+err_open:
+    disable_spkamp_reference(proxy);
+    return ;
+}
+
+static void disable_spkamp_playback(void *proxy)
+{
+    struct audio_proxy *aproxy = proxy;
+    char pcm_path[MAX_PCM_PATH_LEN];
+
+    if (aproxy->support_spkamp) {
+        snprintf(pcm_path, sizeof(pcm_path), "/dev/snd/pcmC%uD%u%c",
+                 SPKAMP_PLAYBACK_CARD, SPKAMP_PLAYBACK_DEVICE, 'p');
+
+        /* Disables Speaker AMP Playback Path */
+        if (aproxy->spkamp_playback) {
+            pcm_stop(aproxy->spkamp_playback);
+            pcm_close(aproxy->spkamp_playback);
+            aproxy->spkamp_playback = NULL;
+
+            ALOGI("proxy-%s: SPKAMP Playback PCM Device(%s) is stopped & closed!", __func__, pcm_path);
+        }
+    }
+
+    return ;
+}
+
+static void enable_spkamp_playback(void *proxy)
+{
+    struct audio_proxy *aproxy = proxy;
+    struct pcm_config pcmconfig = pcm_config_spkamp_playback;
+    char pcm_path[MAX_PCM_PATH_LEN];
+
+    if (aproxy->support_spkamp) {
+        snprintf(pcm_path, sizeof(pcm_path), "/dev/snd/pcmC%uD%u%c",
+                 SPKAMP_PLAYBACK_CARD, SPKAMP_PLAYBACK_DEVICE, 'p');
+
+        /* Enables Speaker AMP Playback path */
+        if (aproxy->spkamp_playback == NULL) {
+            aproxy->spkamp_playback = pcm_open(SPKAMP_PLAYBACK_CARD, SPKAMP_PLAYBACK_DEVICE,
+                                               PCM_OUT | PCM_MONOTONIC, &pcmconfig);
+            if (aproxy->spkamp_playback && !pcm_is_ready(aproxy->spkamp_playback)) {
+                /* pcm_open does always return pcm structure, not NULL */
+                ALOGE("proxy-%s: SPKAMP Playback PCM Device(%s) with SR(%u) PF(%d) CC(%d) is not ready as error(%s)",
+                      __func__, pcm_path, pcmconfig.rate, pcmconfig.format, pcmconfig.channels,
+                      pcm_get_error(aproxy->spkamp_playback));
+                goto err_open;
+            }
+            ALOGVV("proxy-%s: SPKAMP Playback PCM Device(%s) with SR(%u) PF(%d) CC(%d) is opened",
+                  __func__, pcm_path, pcmconfig.rate, pcmconfig.format, pcmconfig.channels);
+
+            if (pcm_start(aproxy->spkamp_playback) == 0) {
+                ALOGI("proxy-%s: SPKAMP Playback PCM Device(%s) with SR(%u) PF(%d) CC(%d) is opened & started",
+                      __func__, pcm_path, pcmconfig.rate, pcmconfig.format, pcmconfig.channels);
+            } else {
+                ALOGE("proxy-%s: SPKAMP Playback PCM Device(%s) with SR(%u) PF(%d) CC(%d) cannot be started as error(%s)",
+                      __func__, pcm_path, pcmconfig.rate, pcmconfig.format, pcmconfig.channels,
+                      pcm_get_error(aproxy->spkamp_playback));
+                goto err_open;
+            }
+        }
+    }
+
+    return ;
+
+err_open:
+    disable_spkamp_playback(proxy);
+    return ;
+}
+
+static void disable_btsco_playback(void *proxy)
+{
+    struct audio_proxy *aproxy = proxy;
+    char pcm_path[MAX_PCM_PATH_LEN];
+
+    if (aproxy->support_btsco) {
+        snprintf(pcm_path, sizeof(pcm_path), "/dev/snd/pcmC%uD%u%c",
+                 BTSCO_PLAYBACK_CARD, BTSCO_PLAYBACK_DEVICE, 'p');
+
+        /* Disables BT-SCO Playback Path */
+        if (aproxy->btsco_playback) {
+            pcm_stop(aproxy->btsco_playback);
+            pcm_close(aproxy->btsco_playback);
+            aproxy->btsco_playback = NULL;
+
+            ALOGI("proxy-%s: BTSCO Playback PCM Device(%s) is stopped & closed!", __func__, pcm_path);
+        }
+    }
+
+    return ;
+}
+
+static void enable_btsco_playback(void *proxy)
+{
+    struct audio_proxy *aproxy = proxy;
+    struct pcm_config pcmconfig = pcm_config_btsco_playback;
+    char pcm_path[MAX_PCM_PATH_LEN];
+
+    if (aproxy->support_btsco) {
+        snprintf(pcm_path, sizeof(pcm_path), "/dev/snd/pcmC%uD%u%c",
+                 BTSCO_PLAYBACK_CARD, BTSCO_PLAYBACK_DEVICE, 'p');
+
+        /* Enables BT-SCO Playback Path */
+        if (aproxy->btsco_playback == NULL) {
+            aproxy->btsco_playback = pcm_open(BTSCO_PLAYBACK_CARD, BTSCO_PLAYBACK_DEVICE,
+                                              PCM_OUT | PCM_MONOTONIC, &pcmconfig);
+            if (aproxy->btsco_playback && !pcm_is_ready(aproxy->btsco_playback)) {
+                /* pcm_open does always return pcm structure, not NULL */
+                ALOGE("proxy-%s: BTSCO Playback PCM Device(%s) with SR(%u) PF(%d) CC(%d) is not ready as error(%s)",
+                      __func__, pcm_path, pcmconfig.rate, pcmconfig.format, pcmconfig.channels,
+                      pcm_get_error(aproxy->btsco_playback));
+                goto err_open;
+            }
+            ALOGVV("proxy-%s: BTSCO Playback PCM Device(%s) with SR(%u) PF(%d) CC(%d) is opened",
+                  __func__, pcm_path, pcmconfig.rate, pcmconfig.format, pcmconfig.channels);
+
+            if (pcm_start(aproxy->btsco_playback) == 0) {
+                ALOGI("proxy-%s: BTSCO Playback PCM Device(%s) with SR(%u) PF(%d) CC(%d) is opened & started",
+                      __func__, pcm_path, pcmconfig.rate, pcmconfig.format, pcmconfig.channels);
+            } else {
+                ALOGE("proxy-%s: BTSCO Playback PCM Device(%s) with SR(%u) PF(%d) CC(%d) cannot be started as error(%s)",
+                      __func__, pcm_path, pcmconfig.rate, pcmconfig.format, pcmconfig.channels,
+                      pcm_get_error(aproxy->btsco_playback));
+                goto err_open;
+            }
+        }
+    }
+
+    return ;
+
+err_open:
+    disable_btsco_playback(proxy);
+    return ;
+}
+
+#ifdef SUPPORT_BTA2DP_OFFLOAD
+static void disable_bta2dp_out_loopback(void *proxy)
+{
+    struct audio_proxy *aproxy = proxy;
+    char pcm_path[MAX_PCM_PATH_LEN];
+
+    if (aproxy->support_bta2dp) {
+        snprintf(pcm_path, sizeof(pcm_path), "/dev/snd/pcmC%uD%u%c",
+                 BTA2DP_OUT_LOOPBACK_CARD, BTA2DP_OUT_LOOPBACK_DEVICE, 'c');
+
+        /* Disables BT-A2DP Out Loopback Path */
+        if (aproxy->bta2dp_out_loopback) {
+            snprintf(pcm_path, sizeof(pcm_path), "/dev/snd/pcmC%uD%u%c",
+                     BTA2DP_OUT_LOOPBACK_CARD, BTA2DP_OUT_LOOPBACK_DEVICE, 'c');
+            pcm_stop(aproxy->bta2dp_out_loopback);
+            pcm_close(aproxy->bta2dp_out_loopback);
+            aproxy->bta2dp_out_loopback = NULL;
+
+            ALOGI("proxy-%s: BT A2DP Out Loopback PCM Device(%s) is stopped & closed!", __func__, pcm_path);
+        }
+    }
+
+    return;
+}
+
+static void enable_bta2dp_out_loopback(void *proxy)
+{
+    struct audio_proxy *aproxy = proxy;
+    struct pcm_config pcmconfig = pcm_config_bta2dp_out_loopback;
+    char pcm_path[MAX_PCM_PATH_LEN];
+
+    if (aproxy->support_bta2dp) {
+        snprintf(pcm_path, sizeof(pcm_path), "/dev/snd/pcmC%uD%u%c",
+                 BTA2DP_OUT_LOOPBACK_CARD, BTA2DP_OUT_LOOPBACK_DEVICE, 'c');
+
+        /* Enables BT-A2DP Out Loopback Path */
+        if (aproxy->bta2dp_out_loopback == NULL) {
+            aproxy->bta2dp_out_loopback = pcm_open(BTA2DP_OUT_LOOPBACK_CARD, BTA2DP_OUT_LOOPBACK_DEVICE,
+                                                 PCM_IN | PCM_MONOTONIC, &pcmconfig);
+            if (aproxy->bta2dp_out_loopback && !pcm_is_ready(aproxy->bta2dp_out_loopback)) {
+                /* pcm_open does always return pcm structure, not NULL */
+                ALOGE("proxy-%s: BT A2DP Out Loopback PCM Device(%s) with SR(%u) PF(%d) CC(%d) is not ready as error(%s)",
+                      __func__, pcm_path, pcmconfig.rate, pcmconfig.format, pcmconfig.channels,
+                      pcm_get_error(aproxy->bta2dp_out_loopback));
+                goto err_open;
+            }
+            ALOGI("proxy-%s: BT A2DP Out Loopback PCM Device(%s) with SR(%u) PF(%d) CC(%d) is opened",
+                  __func__, pcm_path, pcmconfig.rate, pcmconfig.format, pcmconfig.channels);
+
+            if (pcm_start(aproxy->bta2dp_out_loopback) == 0) {
+                ALOGI("proxy-%s: BT A2DP Out Loopback PCM Device(%s) with SR(%u) PF(%d) CC(%d) is started",
+                      __func__, pcm_path, pcmconfig.rate, pcmconfig.format, pcmconfig.channels);
+            } else {
+                ALOGE("proxy-%s: BT A2DP Out Loopback PCM Device(%s) with SR(%u) PF(%d) CC(%d) cannot be started as error(%s)",
+                      __func__, pcm_path, pcmconfig.rate, pcmconfig.format, pcmconfig.channels,
+                      pcm_get_error(aproxy->bta2dp_out_loopback));
+                goto err_open;
+            }
+        }
+    }
+
+    return;
+
+err_open:
+    disable_bta2dp_out_loopback(aproxy);
+}
+
+static void disable_bta2dp_playback(void *proxy)
+{
+    struct audio_proxy *aproxy = proxy;
+    char pcm_path[MAX_PCM_PATH_LEN];
+
+    if (aproxy->support_bta2dp) {
+        snprintf(pcm_path, sizeof(pcm_path), "/dev/snd/pcmC%uD%u%c",
+                 BTA2DP_PLAYBACK_CARD, BTA2DP_PLAYBACK_DEVICE, 'p');
+
+        /* Disables BT-SCO Playback Path */
+        if (aproxy->bta2dp_playback) {
+            pcm_stop(aproxy->bta2dp_playback);
+            pcm_close(aproxy->bta2dp_playback);
+            aproxy->bta2dp_playback = NULL;
+
+            ALOGI("proxy-%s: BTA2DP Playback PCM Device(%s) is stopped & closed!", __func__, pcm_path);
+        }
+    }
+
+    return ;
+}
+
+static void enable_bta2dp_playback(void *proxy)
+{
+    struct audio_proxy *aproxy = proxy;
+    struct pcm_config pcmconfig = pcm_config_bta2dp_playback;
+    char pcm_path[MAX_PCM_PATH_LEN];
+
+    if (aproxy->support_bta2dp) {
+        snprintf(pcm_path, sizeof(pcm_path), "/dev/snd/pcmC%uD%u%c",
+                 BTA2DP_PLAYBACK_CARD, BTA2DP_PLAYBACK_DEVICE, 'p');
+
+        /* Enables BT-SCO Playback Path */
+        if (aproxy->bta2dp_playback == NULL) {
+            aproxy->bta2dp_playback = pcm_open(BTA2DP_PLAYBACK_CARD, BTA2DP_PLAYBACK_DEVICE,
+                                              PCM_OUT | PCM_MONOTONIC, &pcmconfig);
+            if (aproxy->bta2dp_playback && !pcm_is_ready(aproxy->bta2dp_playback)) {
+                /* pcm_open does always return pcm structure, not NULL */
+                ALOGE("proxy-%s: BTA2DP Playback PCM Device(%s) with SR(%u) PF(%d) CC(%d) is not ready as error(%s)",
+                      __func__, pcm_path, pcmconfig.rate, pcmconfig.format, pcmconfig.channels,
+                      pcm_get_error(aproxy->bta2dp_playback));
+                goto err_open;
+            }
+            ALOGI("proxy-%s: BTA2DP Playback PCM Device(%s) with SR(%u) PF(%d) CC(%d) is opened",
+                  __func__, pcm_path, pcmconfig.rate, pcmconfig.format, pcmconfig.channels);
+
+            if (pcm_start(aproxy->bta2dp_playback) == 0) {
+                ALOGI("proxy-%s: BTA2DP Playback PCM Device(%s) with SR(%u) PF(%d) CC(%d) is started",
+                      __func__, pcm_path, pcmconfig.rate, pcmconfig.format, pcmconfig.channels);
+            } else {
+                ALOGE("proxy-%s: BTA2DP Playback PCM Device(%s) with SR(%u) PF(%d) CC(%d) cannot be started as error(%s)",
+                      __func__, pcm_path, pcmconfig.rate, pcmconfig.format, pcmconfig.channels,
+                      pcm_get_error(aproxy->bta2dp_playback));
+                goto err_open;
+            }
+        }
+    }
+
+    return ;
+
+err_open:
+    disable_bta2dp_playback(proxy);
+}
+
+/* modified by samsung convgergence */
+void set_a2dp_suspend_mixer(int a2dp_suspend)
+{
+    struct audio_proxy *aproxy = getInstance();
+    uint32_t value[MIXER_CTL_ABOX_A2DP_SUSPEND_PARAMS_CNT] = {0, };
+
+    ALOGI("proxy-%s: a2dp-suspend[%d]", __func__, a2dp_suspend);
+
+    value[0] = a2dp_suspend;
+
+    proxy_set_mixer_value_array(aproxy, MIXER_CTL_ABOX_A2DP_SUSPEND_PARAMS, value,
+                                MIXER_CTL_ABOX_A2DP_SUSPEND_PARAMS_CNT);
+
+    /* Forcefully disonnect A2DP to RDMA6 connection to fix BTSCO switching */
+    if (is_active_playback_device_bta2dp(aproxy)) {
+        if (a2dp_suspend == MIXER_ON) {
+            proxy_set_mixer_value_string(aproxy, "ABOX SPUS OUT6", "RESERVED");
+            ALOGI("proxy-%s: set ABOX SPUS OUT6 to RESERVED", __func__);
+            proxy_set_mixer_value_string(aproxy, "ABOX SIFS2", "RESERVED");
+            ALOGI("proxy-%s: set ABOX SIFS2 to RESERVED", __func__);
+        } else {
+            proxy_set_mixer_value_string(aproxy, "ABOX SPUS OUT6", "SIFS2");
+            ALOGI("proxy-%s: set ABOX SPUS OUT6 to SIFS2", __func__);
+            proxy_set_mixer_value_string(aproxy, "ABOX SIFS2", "SPUS OUT6");
+            ALOGI("proxy-%s: set ABOX SIFS2 to SPUS OUT6", __func__);
+        }
+    }
+}
+#endif
+
+// Specific Mixer Control Functions for Internal Loopback Handling
+void proxy_set_mixercontrol(struct audio_proxy *aproxy, erap_trigger type, int value)
+{
+    struct mixer_ctl *ctrl = NULL;
+    char mixer_name[MAX_MIXER_NAME_LEN];
+    int ret = 0, val = value;
+
+    pthread_rwlock_rdlock(&aproxy->mixer_update_lock);
+
+    if (type == MUTE_CONTROL) {
+        ctrl = mixer_get_ctl_by_name(aproxy->mixer, ABOX_MUTE_CONTROL_NAME);
+        snprintf(mixer_name, sizeof(mixer_name), ABOX_MUTE_CONTROL_NAME);
+    } else if (type == TICKLE_CONTROL) {
+        ctrl = mixer_get_ctl_by_name(aproxy->mixer, ABOX_TICKLE_CONTROL_NAME);
+        snprintf(mixer_name, sizeof(mixer_name), ABOX_TICKLE_CONTROL_NAME);
+    }
+
+    if (ctrl) {
+        ret = mixer_ctl_set_value(ctrl, 0,val);
+        if (ret != 0)
+            ALOGE("proxy-%s: failed to set Mixer Control(%s)", __func__, mixer_name);
+        else
+            ALOGI("proxy-%s: set Mixer Control(%s) to %d", __func__, mixer_name, val);
+    } else {
+        ALOGE("proxy-%s: cannot find Mixer Control", __func__);
+    }
+
+    pthread_rwlock_unlock(&aproxy->mixer_update_lock);
+
+    return ;
+}
+
+/* Enable usb playback new Modifier */
+static void set_usb_playback_modifier(void *proxy)
+{
+    struct audio_proxy *aproxy = proxy;
+    struct mixer_ctl *ctrl = NULL;
+    int ret, val = 0;
+
+    pthread_rwlock_rdlock(&aproxy->mixer_update_lock);
+
+    /* Mixer out sample rate configuration */
+    ctrl = mixer_get_ctl_by_name(aproxy->mixer, ABOX_SAMPLE_RATE_MIXER_NAME);
+    if (ctrl) {
+        val = proxy_usb_get_playback_samplerate(aproxy->usb_aproxy);
+        ALOGI("proxy-%s: configured SR(%d)", __func__, val);
+        ret = mixer_ctl_set_value(ctrl, 0, val);
+        if (ret != 0)
+            ALOGE("proxy-%s: failed to set %s", __func__, ABOX_SAMPLE_RATE_MIXER_NAME);
+    } else {
+        ALOGE("proxy-%s: cannot find %s Mixer Control", __func__, ABOX_SAMPLE_RATE_MIXER_NAME);
+    }
+
+    /* Mixer out channels configuration */
+    ctrl = mixer_get_ctl_by_name(aproxy->mixer, ABOX_CHANNELS_MIXER_NAME);
+    if (ctrl) {
+        val = proxy_usb_get_playback_channels(aproxy->usb_aproxy);
+        /* check if connected USB headset's highest channel count is 6, then forcelly
+          * change it to 8 channels as A-Box HW cannot support 6 channel conversion */
+        if (val == ABOX_UNSUPPORTED_CHANNELS) {
+            ALOGI("proxy-%s: supported CH is(%d) Changed to (%d)", __func__, val,
+                ABOX_SUPPORTED_MAX_CHANNELS);
+            val = ABOX_SUPPORTED_MAX_CHANNELS;
+        }
+        ALOGI("proxy-%s: configured CH(%d)", __func__, val);
+        ret = mixer_ctl_set_value(ctrl, 0, val);
+        if (ret != 0)
+            ALOGE("proxy-%s: failed to set %s", __func__, ABOX_CHANNELS_MIXER_NAME);
+    } else {
+        ALOGE("proxy-%s: cannot find %s Mixer Control", __func__, ABOX_CHANNELS_MIXER_NAME);
+    }
+
+    /* Mixer out bit width configuration */
+    ctrl = mixer_get_ctl_by_name(aproxy->mixer, ABOX_BIT_WIDTH_MIXER_NAME);
+    if (ctrl) {
+        val = proxy_usb_get_playback_bitwidth(aproxy->usb_aproxy);
+        ALOGI("proxy-%s: configured BW(%d)", __func__, val);
+        ret = mixer_ctl_set_value(ctrl, 0, val);
+        if (ret != 0)
+            ALOGE("proxy-%s: failed to set %s", __func__, ABOX_BIT_WIDTH_MIXER_NAME);
+    } else {
+        ALOGE("proxy-%s: cannot find %s Mixer Control", __func__, ABOX_BIT_WIDTH_MIXER_NAME);
+    }
+
+#ifdef SUPPORT_DIRECT_RCVSPK_PATH
+        /*
+         * SIFS0 switch control is required to reconfigure all running DMA ASRC configurations
+        */
+        proxy_set_mixer_value_int(proxy, MIXER_CTL_ABOX_SIFS0_SWITCH, MIXER_OFF);
+        proxy_set_mixer_value_int(proxy, MIXER_CTL_ABOX_SIFS0_SWITCH, MIXER_ON);
+        ALOGI("proxy-%s: control SIFS0 Off/On", __func__);
+#endif
+
+    pthread_rwlock_unlock(&aproxy->mixer_update_lock);
+
+    return ;
+}
+
+/* Resset Modifier to default values */
+static void reset_playback_modifier(void *proxy)
+{
+    struct audio_proxy *aproxy = proxy;
+    struct mixer_ctl *ctrl = NULL;
+    int ret, val = 0;
+
+    pthread_rwlock_rdlock(&aproxy->mixer_update_lock);
+
+    /* Mixer out sample rate configuration */
+    ctrl = mixer_get_ctl_by_name(aproxy->mixer, ABOX_SAMPLE_RATE_MIXER_NAME);
+    if (ctrl) {
+        val = DEFAULT_MEDIA_SAMPLING_RATE;
+        ALOGI("proxy-%s: configured SR(%d)", __func__, val);
+        ret = mixer_ctl_set_value(ctrl, 0, val);
+        if (ret != 0)
+            ALOGE("proxy-%s: failed to set %s", __func__, ABOX_SAMPLE_RATE_MIXER_NAME);
+    } else {
+        ALOGE("proxy-%s: cannot find %s Mixer Control", __func__, ABOX_SAMPLE_RATE_MIXER_NAME);
+    }
+
+    /* Mixer out channels configuration */
+    ctrl = mixer_get_ctl_by_name(aproxy->mixer, ABOX_CHANNELS_MIXER_NAME);
+    if (ctrl) {
+        val = DEFAULT_MEDIA_CHANNELS;
+        ALOGI("proxy-%s: configured CH(%d)", __func__, val);
+        ret = mixer_ctl_set_value(ctrl, 0, val);
+        if (ret != 0)
+            ALOGE("proxy-%s: failed to set %s", __func__, ABOX_CHANNELS_MIXER_NAME);
+    } else {
+        ALOGE("proxy-%s: cannot find %s Mixer Control", __func__, ABOX_CHANNELS_MIXER_NAME);
+    }
+
+    /* Mixer out bit width configuration */
+    ctrl = mixer_get_ctl_by_name(aproxy->mixer, ABOX_BIT_WIDTH_MIXER_NAME);
+    if (ctrl) {
+        val = DEFAULT_MEDIA_BITWIDTH;
+        ALOGI("proxy-%s: configured BW(%d)", __func__, val);
+        ret = mixer_ctl_set_value(ctrl, 0, val);
+        if (ret != 0)
+            ALOGE("proxy-%s: failed to set %s", __func__, ABOX_BIT_WIDTH_MIXER_NAME);
+    } else {
+        ALOGE("proxy-%s: cannot find %s Mixer Control", __func__, ABOX_BIT_WIDTH_MIXER_NAME);
+    }
+
+#ifdef SUPPORT_DIRECT_RCVSPK_PATH
+    /*
+     * SIFS0 switch control is required to reconfigure all running DMA ASRC configurations
+    */
+    proxy_set_mixer_value_int(proxy, MIXER_CTL_ABOX_SIFS0_SWITCH, MIXER_OFF);
+    proxy_set_mixer_value_int(proxy, MIXER_CTL_ABOX_SIFS0_SWITCH, MIXER_ON);
+    ALOGI("proxy-%s: control SIFS0 Off/On", __func__);
+#endif
+
+    pthread_rwlock_unlock(&aproxy->mixer_update_lock);
+
+    return ;
+}
+
+#ifdef SUPPORT_BTA2DP_OFFLOAD
+/* BT A2DP Audio Specific Functions */
+static void bta2dp_playback_start(struct audio_proxy *aproxy)
+{
+    audio_format_t codec_type = AUDIO_FORMAT_SBC;   // SBC is Max Size Structure, so it is default
+    audio_sbc_encoder_config codec_info;
+    int ret = 0;
+
+    if (aproxy && aproxy->a2dp_out_enabled) {
+        ret = proxy_a2dp_start();
+        if (ret == 0) {
+            ALOGI("proxy-%s: started BT A2DP", __func__);
+
+            ret = proxy_a2dp_get_config((uint32_t *)&codec_type, (void *)&codec_info);
+            if (ret == 0) {
+                if (codec_type == AUDIO_FORMAT_SBC) {
+                    struct sbc_enc_cfg_t config;
+                    audio_sbc_encoder_config *sbc_config = (audio_sbc_encoder_config *)&codec_info;
+                    memset(&config, 0, sizeof(struct sbc_enc_cfg_t));
+
+                    config.enc_format   = ENC_MEDIA_FMT_SBC;
+                    config.num_subbands = (uint32_t)sbc_config->subband;
+                    config.blk_len      = (uint32_t)sbc_config->blk_len;
+                    config.channel_mode = (uint32_t)sbc_config->channels;
+                    config.alloc_method = (uint32_t)sbc_config->alloc;
+                    config.bit_rate     = (uint32_t)sbc_config->bitrate;
+                    config.sample_rate  = (uint32_t)sbc_config->sampling_rate;
+
+                    proxy_set_mixer_value_array(aproxy, ABOX_A2DP_OFFLOAD_SET_PARAMS_NAME,
+                                               &config, ABOX_A2DP_OFFLOAD_SET_PARAMS_COUNT);
+                    ALOGI("proxy-%s: set A2DP SBC Encoder Configurations", __func__);
+
+                    // Default SBC Latency = 150ms
+                    aproxy->a2dp_default_delay = 150;
+                } else if (codec_type == AUDIO_FORMAT_APTX) {
+                    struct aptx_enc_cfg_t config;
+                    audio_aptx_encoder_config *aptx_config = (audio_aptx_encoder_config *)&codec_info;
+                    memset(&config, 0, sizeof(struct aptx_enc_cfg_t));
+
+                    config.enc_format   = ENC_MEDIA_FMT_APTX;
+                    config.sample_rate  = (uint32_t)aptx_config->sampling_rate;
+                    config.num_channels = (uint32_t)aptx_config->channels;
+                    switch (config.num_channels) {
+                        case 1:
+                            config.channel_mapping[0] = PCM_CHANNEL_C;
+                            break;
+                        case 2:
+                        default:
+                            config.channel_mapping[0] = PCM_CHANNEL_L;
+                            config.channel_mapping[1] = PCM_CHANNEL_R;
+                    }
+
+                    proxy_set_mixer_value_array(aproxy, ABOX_A2DP_OFFLOAD_SET_PARAMS_NAME,
+                                               &config, ABOX_A2DP_OFFLOAD_SET_PARAMS_COUNT);
+                    ALOGI("proxy-%s: set A2DP APTX Encoder Configurations", __func__);
+
+                    // Default APTX Latency = 200ms
+                    aproxy->a2dp_default_delay = 200;
+                }
+            } else
+                ALOGE("proxy-%s: failed to get BT A2DP Codec Configurations", __func__);
+        }
+    }
+
+    return ;
+}
+
+static void bta2dp_playback_stop(struct audio_proxy *aproxy)
+{
+    int ret = 0;
+
+    if (aproxy && aproxy->a2dp_out_enabled) {
+        ret = proxy_a2dp_stop();
+        if (ret == 0)
+            ALOGI("proxy-%s: stopped stream for BT A2DP", __func__);
+    }
+
+    return ;
+}
+
+static void disable_a2dp_mute_playback(void *proxy)
+{
+    struct audio_proxy *aproxy = proxy;
+    char pcm_path[MAX_PCM_PATH_LEN];
+
+    if (aproxy->support_bta2dp) {
+        snprintf(pcm_path, sizeof(pcm_path), "/dev/snd/pcmC%uD%u%c",
+                 A2DPMUTE_PLAYBACK_CARD, A2DPMUTE_PLAYBACK_DEVICE, 'p');
+
+        /* Disables a2dp mute playback Path */
+        if (aproxy->a2dp_mute_playback) {
+            pcm_stop(aproxy->a2dp_mute_playback);
+            pcm_close(aproxy->a2dp_mute_playback);
+            aproxy->a2dp_mute_playback = NULL;
+
+            ALOGI("proxy-%s: A2DP Mute playback PCM Device(%s) is stopped & closed!", __func__, pcm_path);
+        }
+    }
+
+    return ;
+}
+
+static void enable_a2dp_mute_playback(void *proxy)
+{
+    struct audio_proxy *aproxy = proxy;
+    struct pcm_config pcmconfig = pcm_config_a2dp_mute_playback;
+    char pcm_path[MAX_PCM_PATH_LEN];
+
+    if (aproxy->support_bta2dp) {
+        snprintf(pcm_path, sizeof(pcm_path), "/dev/snd/pcmC%uD%u%c",
+                 A2DPMUTE_PLAYBACK_CARD, A2DPMUTE_PLAYBACK_DEVICE, 'p');
+
+        /* Enables A2DP Mute playback path */
+        if (aproxy->a2dp_mute_playback == NULL) {
+            aproxy->a2dp_mute_playback = pcm_open(A2DPMUTE_PLAYBACK_CARD, A2DPMUTE_PLAYBACK_DEVICE,
+                                               PCM_OUT | PCM_MONOTONIC, &pcmconfig);
+            if (aproxy->a2dp_mute_playback && !pcm_is_ready(aproxy->a2dp_mute_playback)) {
+                /* pcm_open does always return pcm structure, not NULL */
+                ALOGE("proxy-%s: A2DP Mute playback PCM Device(%s) with SR(%u) PF(%d) CC(%d) is not ready as error(%s)",
+                      __func__, pcm_path, pcmconfig.rate, pcmconfig.format, pcmconfig.channels,
+                      pcm_get_error(aproxy->a2dp_mute_playback));
+                goto err_open;
+            }
+            ALOGI("proxy-%s: A2DP Mute playback PCM Device(%s) with SR(%u)PF(%d) CC(%d) PdSz(%d) PdCnt(%d) is opened",
+                  __func__, pcm_path, pcmconfig.rate, pcmconfig.format, pcmconfig.channels,
+                  pcmconfig.period_size, pcmconfig.period_count);
+
+            if (pcm_start(aproxy->a2dp_mute_playback) == 0) {
+                ALOGI("proxy-%s: A2DP Mute playback PCM Device(%s) with SR(%u) PF(%d) CC(%d) is opened & started",
+                      __func__, pcm_path, pcmconfig.rate, pcmconfig.format, pcmconfig.channels);
+            } else {
+                ALOGE("proxy-%s: A2DP Mute playback PCM Device(%s) with SR(%u) PF(%d) CC(%d) cannot be started as error(%s)",
+                      __func__, pcm_path, pcmconfig.rate, pcmconfig.format, pcmconfig.channels,
+                      pcm_get_error(aproxy->a2dp_mute_playback));
+                goto err_open;
+            }
+        }
+    }
+
+    return ;
+
+err_open:
+    disable_a2dp_mute_playback(proxy);
+    return ;
+}
+#endif
+
+static void enable_internal_path(void *proxy, int ausage, device_type target_device)
+{
+    struct audio_proxy *aproxy = proxy;
+
+    /* skip internal pcm controls for VoiceCall bandwidth change */
+    if (aproxy->skip_internalpath) {
+        ALOGI("proxy-%s: skip enabling internal path", __func__);
+        return;
+    }
+
+    if (target_device == DEVICE_EARPIECE ||
+        target_device == DEVICE_SPEAKER || target_device == DEVICE_SPEAKER2 ||
+        target_device == DEVICE_SPEAKER_DUAL || target_device == DEVICE_SPEAKER_DEX ||
+        target_device == DEVICE_SPEAKER_AND_HEADSET || target_device == DEVICE_SPEAKER_AND_HEADPHONE) {
+#ifdef SUPPORT_DIRECT_RCVSPK_PATH
+            if (is_playback_device_speaker_dualpath(target_device)
+                || ausage == AUSAGE_FM_RADIO || ausage == AUSAGE_USB_FM_RADIO)
+#endif
+            {
+                enable_spkamp_playback(aproxy);
+                enable_erap_in(aproxy, target_device);
+            }
+        enable_spkamp_reference(aproxy);
+#ifdef SUPPORT_BTA2DP_OFFLOAD
+    } else if (target_device == DEVICE_BT_A2DP_HEADPHONE ||
+               target_device == DEVICE_SPEAKER_AND_BT_A2DP_HEADPHONE) {
+        /* Transit BT A2DP Status */
+        pthread_mutex_lock(&aproxy->a2dp_lock);
+        // Case : Audio Path changed from Others to A2DP Device
+        //        BT A2DP need to be started
+        bta2dp_playback_start(aproxy);
+        pthread_mutex_unlock(&aproxy->a2dp_lock);
+
+        if (target_device == DEVICE_SPEAKER_AND_BT_A2DP_HEADPHONE) {
+            enable_erap_in(aproxy, target_device);
+            enable_spkamp_reference(aproxy);
+            enable_spkamp_playback(aproxy);
+        }
+        enable_bta2dp_playback(aproxy);
+        enable_bta2dp_out_loopback(aproxy);
+
+        // Start A2DP Mute playback node
+        enable_a2dp_mute_playback(proxy);
+#endif
+    } else if (target_device == DEVICE_BT_HEADSET || target_device == DEVICE_SPEAKER_AND_BT_HEADSET) {
+        enable_erap_in(aproxy, target_device);
+        if (target_device == DEVICE_SPEAKER_AND_BT_HEADSET) {
+            enable_spkamp_reference(aproxy);
+            enable_spkamp_playback(aproxy);
+        }
+        enable_btsco_playback(aproxy);
+    } else if (target_device == DEVICE_HEADSET || target_device == DEVICE_HEADPHONE ||
+               target_device == DEVICE_CALL_FWD || target_device == DEVICE_SPECTRO ||
+               target_device == DEVICE_HEARING_AID) {
+        /* In cases of CP/AP Calland Loopback, ERAP Path is needed for SE */
+        // In case of Normal Media, ERAP Path is not needed
+        if (is_active_usage_CPCall(aproxy) || is_active_usage_APCall(aproxy) ||
+            is_usage_Loopback(ausage))
+            enable_erap_in(aproxy, target_device);
+    } else if (target_device == DEVICE_USB_HEADSET ||
+               target_device == DEVICE_SPEAKER_AND_USB_HEADSET) {
+        /* Prepare USB device configuration based upon usage */
+        if (aproxy->usb_aproxy) {
+            /* USB output playback constraints
+             * Full configuration for all modes except CP Call mode
+             * CP Call mode: fix configuration to 48KHz 16bit or
+             * supported configuration */
+            if (is_usage_CPCall(ausage) &&
+                !proxy_is_usb_playback_CPCall_prepared(aproxy->usb_aproxy)) {
+                /* prepare for cp call playback with fixed configuration */
+                proxy_usb_playback_prepare(aproxy->usb_aproxy, false);
+            } else if (!is_usage_CPCall(ausage) &&
+                proxy_is_usb_playback_CPCall_prepared(aproxy->usb_aproxy)) {
+                /* prepare for playback with default configuration */
+                proxy_usb_playback_prepare(aproxy->usb_aproxy, true);
+            }
+            proxy_usb_open_out_proxy(aproxy->usb_aproxy);
+        }
+
+        /* set USB playback modifier controls */
+        set_usb_playback_modifier(aproxy);
+
+        if (target_device == DEVICE_SPEAKER_AND_USB_HEADSET) {
+            enable_spkamp_playback(aproxy);
+            enable_spkamp_reference(aproxy);
+        }
+        // In cases of CP/AP Call, Internal Loop & ERAP Path is needed for SE
+        // In case of Normal Media, No Paths are needed
+        if (target_device == DEVICE_SPEAKER_AND_USB_HEADSET ||
+            is_active_usage_CPCall(aproxy) || is_active_usage_APCall(aproxy) ||
+            is_usage_Loopback(ausage)) {
+            enable_erap_in(aproxy, target_device);
+        }
+
+        enable_usb_out_loopback(aproxy);
+    } else if (is_usb_mic_device(target_device)) {
+        // Check whether USB device is single clocksource, and match samplerate
+        // with playback
+        if (aproxy->is_usb_single_clksrc)
+            proxy_usb_capture_prepare(aproxy->usb_aproxy, true);
+
+        if (aproxy->usb_aproxy)
+            proxy_usb_open_in_proxy(aproxy->usb_aproxy);
+        enable_usb_in_loopback(proxy);
+    }
+
+    /* enable direct MIC path pcm for voiceCall scenario */
+    if ((is_usage_CPCall(ausage) || is_usage_Loopback(ausage)) &&
+        target_device >= DEVICE_MAIN_MIC)
+        enable_voice_tx_direct_in(aproxy, target_device);
+
+    /* enable usb_fm_radio loopback pcm node
+     * Assumption: USB Mic will not used in usb-fm-radio scenario
+     */
+    if (ausage == AUSAGE_USB_FM_RADIO && target_device < DEVICE_MAIN_MIC
+        && target_device != DEVICE_USB_HEADSET) {
+        // Check whether USB device is single clocksource, and match samplerate
+        // with playback
+        if (aproxy->is_usb_single_clksrc)
+            proxy_usb_capture_prepare(aproxy->usb_aproxy, true);
+
+        if (aproxy->usb_aproxy)
+            proxy_usb_open_in_proxy(aproxy->usb_aproxy);
+        enable_usb_in_loopback(proxy);
+    }
+    return;
+}
+
+static void disable_internal_path(void *proxy, int ausage, device_type target_device)
+{
+    struct audio_proxy *aproxy = proxy;
+
+    /* skip internal pcm controls for VoiceCall bandwidth change */
+    if (aproxy->skip_internalpath) {
+        ALOGI("proxy-%s: skip disabling internal path", __func__);
+        return;
+    }
+
+    /* disable usb_fm_radio loopback pcm node */
+    if (ausage == AUSAGE_USB_FM_RADIO && target_device < DEVICE_MAIN_MIC
+        && target_device != DEVICE_USB_HEADSET) {
+        disable_usb_in_loopback(proxy);
+        if (aproxy->usb_aproxy)
+            proxy_usb_close_in_proxy(aproxy->usb_aproxy);
+    }
+
+    /* disable direct MIC path pcm for voiceCall scenario */
+    if ((is_usage_CPCall(ausage) || is_usage_Loopback(ausage)) &&
+        target_device >= DEVICE_MAIN_MIC)
+        disable_voice_tx_direct_in(aproxy);
+
+    if (target_device == DEVICE_SPEAKER ||
+        target_device == DEVICE_SPEAKER2 || target_device == DEVICE_SPEAKER_DUAL ||
+        target_device == DEVICE_EARPIECE || target_device == DEVICE_SPEAKER_DEX ||
+        target_device == DEVICE_SPEAKER_AND_HEADSET || target_device == DEVICE_SPEAKER_AND_HEADPHONE) {
+#ifdef SUPPORT_DIRECT_RCVSPK_PATH
+        if (is_playback_device_speaker_dualpath(target_device)
+            || ausage == AUSAGE_FM_RADIO || ausage == AUSAGE_USB_FM_RADIO)
+#endif
+        {
+            disable_erap_in(aproxy);
+            disable_spkamp_playback(aproxy);
+        }
+        disable_spkamp_reference(aproxy);
+#ifdef SUPPORT_BTA2DP_OFFLOAD
+    } else if (target_device == DEVICE_BT_A2DP_HEADPHONE ||
+               target_device == DEVICE_SPEAKER_AND_BT_A2DP_HEADPHONE) {
+        /* Transit BT A2DP Status */
+        pthread_mutex_lock(&aproxy->a2dp_lock);
+        // Case : Audio Path reset for A2DP Device
+        //        BT A2DP need to be stoped
+        bta2dp_playback_stop(aproxy);
+        pthread_mutex_unlock(&aproxy->a2dp_lock);
+
+        // Stop A2DP Mute playback node
+        disable_a2dp_mute_playback(proxy);
+
+        if (target_device == DEVICE_SPEAKER_AND_BT_A2DP_HEADPHONE) {
+            disable_spkamp_playback(aproxy);
+            disable_spkamp_reference(aproxy);
+            disable_erap_in(aproxy);
+        }
+        disable_bta2dp_out_loopback(aproxy);
+        disable_bta2dp_playback(aproxy);
+#endif
+    } else if (target_device == DEVICE_BT_HEADSET || target_device == DEVICE_SPEAKER_AND_BT_HEADSET) {
+        disable_btsco_playback(aproxy);
+        if (target_device == DEVICE_SPEAKER_AND_BT_HEADSET) {
+            disable_spkamp_playback(aproxy);
+            disable_spkamp_reference(aproxy);
+        }
+        disable_erap_in(aproxy);
+
+        /* reset Mixp configuration to default values when path is disabled */
+        reset_playback_modifier(aproxy);
+    } else if (target_device == DEVICE_HEADSET || target_device == DEVICE_HEADPHONE ||
+               target_device == DEVICE_CALL_FWD || target_device == DEVICE_SPECTRO ||
+               target_device == DEVICE_HEARING_AID) {
+        if (is_active_usage_CPCall(aproxy) || is_active_usage_APCall(aproxy) ||
+            is_usage_Loopback(ausage))
+            disable_erap_in(aproxy);
+    } else if (target_device == DEVICE_USB_HEADSET ||
+                target_device == DEVICE_SPEAKER_AND_USB_HEADSET) {
+        if (target_device == DEVICE_SPEAKER_AND_USB_HEADSET ||
+            is_active_usage_CPCall(aproxy) || is_active_usage_APCall(aproxy) ||
+            is_usage_Loopback(ausage)) {
+            disable_erap_in(aproxy);
+        }
+
+        if (target_device == DEVICE_SPEAKER_AND_USB_HEADSET) {
+            disable_spkamp_playback(aproxy);
+            disable_spkamp_reference(aproxy);
+        }
+        disable_usb_out_loopback(aproxy);
+        if (aproxy->usb_aproxy)
+            proxy_usb_close_out_proxy(aproxy->usb_aproxy);
+
+        /* reset Mixp configuration to default values when path is disabled */
+        reset_playback_modifier(aproxy);
+    } else if (is_usb_mic_device(target_device)) {
+        disable_usb_in_loopback(proxy);
+        if (aproxy->usb_aproxy)
+            proxy_usb_close_in_proxy(aproxy->usb_aproxy);
+    }
+
+    return ;
+}
+
+// Voice Call PCM Handler
+static void voice_rx_stop(struct audio_proxy *aproxy)
+{
+    char pcm_path[MAX_PCM_PATH_LEN];
+
+    /* Disables Voice Call RX Playback Stream */
+    if (aproxy->call_rx) {
+        snprintf(pcm_path, sizeof(pcm_path), "/dev/snd/pcmC%uD%u%c",
+                 VRX_PLAYBACK_CARD, VRX_PLAYBACK_DEVICE, 'p');
+
+        pcm_stop(aproxy->call_rx);
+        pcm_close(aproxy->call_rx);
+        aproxy->call_rx = NULL;
+
+        ALOGI("proxy-%s: Voice Call RX PCM Device(%s) is stopped & closed!", __func__, pcm_path);
+    }
+}
+
+static int voice_rx_start(struct audio_proxy *aproxy)
+{
+    struct pcm_config pcmconfig = pcm_config_voicerx_playback;
+    char pcm_path[MAX_PCM_PATH_LEN];
+
+    /* Enables Voice Call RX Playback Stream */
+    if (aproxy->call_rx == NULL) {
+        snprintf(pcm_path, sizeof(pcm_path), "/dev/snd/pcmC%uD%u%c",
+                 VRX_PLAYBACK_CARD, VRX_PLAYBACK_DEVICE, 'p');
+
+        aproxy->call_rx = pcm_open(VRX_PLAYBACK_CARD, VRX_PLAYBACK_DEVICE,
+                                   PCM_OUT | PCM_MONOTONIC, &pcmconfig);
+        if (aproxy->call_rx && !pcm_is_ready(aproxy->call_rx)) {
+            /* pcm_open does always return pcm structure, not NULL */
+            ALOGE("proxy-%s: Voice Call RX PCM Device(%s) with SR(%u) PF(%d) CC(%d) is not ready as error(%s)",
+                  __func__, pcm_path, pcmconfig.rate, pcmconfig.format, pcmconfig.channels,
+                  pcm_get_error(aproxy->call_rx));
+            goto err_open;
+        }
+        ALOGVV("proxy-%s: Voice Call RX PCM Device(%s) with SR(%u) PF(%d) CC(%d) is opened",
+              __func__, pcm_path, pcmconfig.rate, pcmconfig.format, pcmconfig.channels);
+
+        if (pcm_start(aproxy->call_rx) == 0) {
+            ALOGI("proxy-%s: Voice Call RX PCM Device(%s) with SR(%u) PF(%d) CC(%d) is opened & started",
+                  __func__, pcm_path, pcmconfig.rate, pcmconfig.format, pcmconfig.channels);
+        } else {
+            ALOGE("proxy-%s: Voice Call RX PCM Device(%s) with SR(%u) PF(%d) CC(%d) cannot be started as error(%s)",
+                  __func__, pcm_path, pcmconfig.rate, pcmconfig.format, pcmconfig.channels,
+                  pcm_get_error(aproxy->call_rx));
+            goto err_open;
+        }
+    }
+    return 0;
+
+err_open:
+    voice_rx_stop(aproxy);
+    return -1;
+}
+
+static void voice_tx_stop(struct audio_proxy *aproxy)
+{
+    char pcm_path[MAX_PCM_PATH_LEN];
+
+    /* Disables Voice Call TX Capture Stream */
+    if (aproxy->call_tx) {
+        snprintf(pcm_path, sizeof(pcm_path), "/dev/snd/pcmC%uD%u%c",
+                 VTX_CAPTURE_CARD, VTX_CAPTURE_DEVICE, 'c');
+
+        pcm_stop(aproxy->call_tx);
+        pcm_close(aproxy->call_tx);
+        aproxy->call_tx = NULL;
+        ALOGI("proxy-%s: Voice Call TX PCM Device(%s) is stopped & closed!", __func__, pcm_path);
+    }
+}
+
+static int voice_tx_start(struct audio_proxy *aproxy)
+{
+    struct pcm_config pcmconfig;
+    char pcm_path[MAX_PCM_PATH_LEN];
+
+    /* Enables Voice Call TX Capture Stream */
+    if (aproxy->call_tx == NULL) {
+#ifdef SUPPORT_QUAD_MIC
+        if (is_quad_mic_device(aproxy->active_capture_device)) {
+            pcmconfig = pcm_config_quad_mic_voicetx_capture;
+            ALOGI("proxy-%s: Quad-Mic config for Voice Call TX", __func__);
+        } else
+#endif
+            pcmconfig = pcm_config_voicetx_capture;
+        snprintf(pcm_path, sizeof(pcm_path), "/dev/snd/pcmC%uD%u%c",
+                 VTX_CAPTURE_CARD, VTX_CAPTURE_DEVICE, 'c');
+
+        aproxy->call_tx = pcm_open(VTX_CAPTURE_CARD, VTX_CAPTURE_DEVICE,
+                                   PCM_IN | PCM_MONOTONIC, &pcmconfig);
+        if (aproxy->call_tx && !pcm_is_ready(aproxy->call_tx)) {
+            /* pcm_open does always return pcm structure, not NULL */
+            ALOGE("proxy-%s: Voice Call TX PCM Device(%s) with SR(%u) PF(%d) CC(%d) is not ready as error(%s)",
+                  __func__, pcm_path, pcmconfig.rate, pcmconfig.format, pcmconfig.channels,
+                  pcm_get_error(aproxy->call_tx));
+            goto err_open;
+        }
+        ALOGVV("proxy-%s: Voice Call TX PCM Device(%s) with SR(%u) PF(%d) CC(%d) is opened",
+              __func__, pcm_path, pcmconfig.rate, pcmconfig.format, pcmconfig.channels);
+
+        if (pcm_start(aproxy->call_tx) == 0) {
+            ALOGI("proxy-%s: Voice Call TX PCM Device(%s) with SR(%u) PF(%d) CC(%d) is opened & started",
+                  __func__, pcm_path, pcmconfig.rate, pcmconfig.format, pcmconfig.channels);
+        } else {
+            ALOGE("proxy-%s: Voice Call TX PCM Device(%s) with SR(%u) PF(%d) CC(%d) cannot be started as error(%s)",
+                  __func__, pcm_path, pcmconfig.rate, pcmconfig.format, pcmconfig.channels,
+                  pcm_get_error(aproxy->call_tx));
+            goto err_open;
+        }
+    }
+    return 0;
+
+err_open:
+    voice_tx_stop(aproxy);
+    return -1;
+}
+
+// FM Radio PCM Handler
+static void fmradio_playback_stop(struct audio_proxy *aproxy)
+{
+    char pcm_path[MAX_PCM_PATH_LEN];
+
+    /* Disables FM Radio Playback Stream */
+    if (aproxy->fm_playback) {
+        snprintf(pcm_path, sizeof(pcm_path), "/dev/snd/pcmC%uD%u%c",
+                 FMRADIO_PLAYBACK_CARD, FMRADIO_PLAYBACK_DEVICE, 'p');
+
+        pcm_stop(aproxy->fm_playback);
+        pcm_close(aproxy->fm_playback);
+        aproxy->fm_playback = NULL;
+
+        ALOGI("proxy-%s: FM Radio Playback PCM Device(%s) is stopped & closed!", __func__, pcm_path);
+    }
+}
+
+static int fmradio_playback_start(struct audio_proxy *aproxy)
+{
+    struct pcm_config pcmconfig = pcm_config_fmradio_playback;
+    char pcm_path[MAX_PCM_PATH_LEN];
+
+    /* Enables RM Radio Playback Stream */
+    if (aproxy->fm_playback == NULL) {
+        snprintf(pcm_path, sizeof(pcm_path), "/dev/snd/pcmC%uD%u%c",
+                 FMRADIO_PLAYBACK_CARD, FMRADIO_PLAYBACK_DEVICE, 'p');
+
+        aproxy->fm_playback = pcm_open(FMRADIO_PLAYBACK_CARD, FMRADIO_PLAYBACK_DEVICE,
+                                       PCM_OUT | PCM_MONOTONIC, &pcmconfig);
+        if (aproxy->fm_playback && !pcm_is_ready(aproxy->fm_playback)) {
+            /* pcm_open does always return pcm structure, not NULL */
+            ALOGE("proxy-%s: FM Radio Playback PCM Device(%s) with SR(%u) PF(%d) CC(%d) is not ready as error(%s)",
+                  __func__, pcm_path, pcmconfig.rate, pcmconfig.format, pcmconfig.channels,
+                  pcm_get_error(aproxy->fm_playback));
+            goto err_open;
+        }
+        ALOGVV("proxy-%s: FM Radio Playback PCM Device(%s) with SR(%u) PF(%d) CC(%d) is opened",
+              __func__, pcm_path, pcmconfig.rate, pcmconfig.format, pcmconfig.channels);
+
+        if (pcm_start(aproxy->fm_playback) == 0) {
+            ALOGI("proxy-%s: FM Radio Playback PCM Device(%s) with SR(%u) PF(%d) CC(%d) is opened & started",
+                  __func__, pcm_path, pcmconfig.rate, pcmconfig.format, pcmconfig.channels);
+        } else {
+            ALOGE("proxy-%s: FM Radio Playback PCM Device(%s) with SR(%u) PF(%d) CC(%d) cannot be started as error(%s)",
+                  __func__, pcm_path, pcmconfig.rate, pcmconfig.format, pcmconfig.channels,
+                  pcm_get_error(aproxy->fm_playback));
+            goto err_open;
+        }
+    }
+
+    return 0;
+
+err_open:
+    fmradio_playback_stop(aproxy);
+    return -1;
+}
+
+static void fmradio_capture_stop(struct audio_proxy *aproxy)
+{
+    char pcm_path[MAX_PCM_PATH_LEN];
+
+    /* Disables FM Radio Capture Stream */
+    if (aproxy->fm_capture) {
+        snprintf(pcm_path, sizeof(pcm_path), "/dev/snd/pcmC%uD%u%c",
+                 VC_FMRADIO_CAPTURE_CARD, VC_FMRADIO_CAPTURE_DEVICE, 'c');
+
+        pcm_stop(aproxy->fm_capture);
+        pcm_close(aproxy->fm_capture);
+        aproxy->fm_capture = NULL;
+
+        ALOGI("proxy-%s: FM Radio Capture PCM Device(%s) is stopped & closed!", __func__, pcm_path);
+    }
+}
+
+static int fmradio_capture_start(struct audio_proxy *aproxy)
+{
+    struct pcm_config pcmconfig = pcm_config_vc_fmradio_capture;
+    char pcm_path[MAX_PCM_PATH_LEN];
+
+    /* Enables RM Radio Capture Stream */
+    if (aproxy->fm_capture == NULL) {
+        snprintf(pcm_path, sizeof(pcm_path), "/dev/snd/pcmC%uD%u%c",
+                 VC_FMRADIO_CAPTURE_CARD, VC_FMRADIO_CAPTURE_DEVICE, 'c');
+
+        aproxy->fm_capture = pcm_open(VC_FMRADIO_CAPTURE_CARD, VC_FMRADIO_CAPTURE_DEVICE,
+                                                           PCM_IN | PCM_MONOTONIC, &pcmconfig);
+        if (aproxy->fm_capture && !pcm_is_ready(aproxy->fm_capture)) {
+            /* pcm_open does always return pcm structure, not NULL */
+            ALOGE("proxy-%s: FM Radio Capture PCM Device(%s) with SR(%u) PF(%d) CC(%d) is not ready as error(%s)",
+                  __func__, pcm_path, pcmconfig.rate, pcmconfig.format, pcmconfig.channels,
+                  pcm_get_error(aproxy->fm_capture));
+            goto err_open;
+        }
+        ALOGVV("proxy-%s: FM Radio Capture PCM Device(%s) with SR(%u) PF(%d) CC(%d) is opened",
+              __func__, pcm_path, pcmconfig.rate, pcmconfig.format, pcmconfig.channels);
+
+        if (pcm_start(aproxy->fm_capture) == 0) {
+            ALOGI("proxy-%s: FM Radio Capture PCM Device(%s) with SR(%u) PF(%d) CC(%d) is opened & started",
+                  __func__, pcm_path, pcmconfig.rate, pcmconfig.format, pcmconfig.channels);
+        } else {
+            ALOGE("proxy-%s: FM Radio Capture PCM Device(%s) with SR(%u) PF(%d) CC(%d) cannot be started as error(%s)",
+                  __func__, pcm_path, pcmconfig.rate, pcmconfig.format, pcmconfig.channels,
+                  pcm_get_error(aproxy->fm_capture));
+            goto err_open;
+        }
+    }
+
+    return 0;
+
+err_open:
+    fmradio_capture_stop(aproxy);
+    return -1;
+}
+
+static void *mixer_update_loop(void *context)
+{
+    struct audio_proxy *aproxy = (struct audio_proxy *)context;
+    struct snd_ctl_event *event = NULL;
+    struct timespec ts_start, ts_tick;
+
+    ALOGI("proxy-%s: started running Mixer Updater Thread", __func__);
+
+    clock_gettime(CLOCK_MONOTONIC, &ts_start);
+    do {
+        if (aproxy->mixer) {
+            ALOGD("proxy-%s: wait add event", __func__);
+            event = mixer_read_event_sec(aproxy->mixer, MIXER_EVENT_ADD);
+            if (!event) {
+                ALOGE("proxy-%s: returned as error or mixer close", __func__);
+                clock_gettime(CLOCK_MONOTONIC, &ts_tick);
+                if ((ts_tick.tv_sec - ts_start.tv_sec) > MIXER_UPDATE_TIMEOUT) {
+                    ALOGI("proxy-%s: Mixer Update Timeout, it will be destroyed", __func__);
+                    break;
+                }
+                continue;
+            }
+            ALOGD("proxy-%s: returned as add event", __func__);
+        } else
+            continue;
+
+        pthread_rwlock_wrlock(&aproxy->mixer_update_lock);
+
+        mixer_close(aproxy->mixer);
+        aproxy->mixer = mixer_open(MIXER_CARD0);
+        if (!aproxy->mixer)
+            ALOGE("proxy-%s: failed to re-open Mixer", __func__);
+
+        mixer_subscribe_events(aproxy->mixer, 1);
+        audio_route_free(aproxy->aroute);
+        aproxy->aroute = audio_route_init(MIXER_CARD0, aproxy->xml_path);
+        if (!aproxy->aroute)
+            ALOGE("proxy-%s: failed to re-init audio route", __func__);
+
+        ALOGI("proxy-%s: mixer and route are updated", __func__);
+
+        pthread_rwlock_unlock(&aproxy->mixer_update_lock);
+        free(event);
+    } while (aproxy->mixer && aproxy->aroute && audio_route_missing_ctl(aproxy->aroute));
+
+    ALOGI("proxy-%s: all mixer controls are found", __func__);
+
+    if (aproxy->mixer)
+        mixer_subscribe_events(aproxy->mixer, 0);
+
+    ALOGI("proxy-%s: stopped running Mixer Updater Thread", __func__);
+    return NULL;
+}
+
+static void make_path(audio_usage ausage, device_type device, char *path_name)
+{
+    memset(path_name, 0, MAX_PATH_NAME_LEN);
+    strlcpy(path_name, usage_path_table[ausage], MAX_PATH_NAME_LEN);
+    if (strlen(device_table[device]) > 0) {
+        strlcat(path_name, "-", MAX_PATH_NAME_LEN);
+        strlcat(path_name, device_table[device], MAX_PATH_NAME_LEN);
+    }
+
+    return ;
+}
+
+static void make_gain(char *path_name, char *gain_name)
+{
+    memset(gain_name, 0, MAX_GAIN_PATH_NAME_LEN);
+    strlcpy(gain_name, "gain-", MAX_PATH_NAME_LEN);
+    strlcat(gain_name, path_name, MAX_PATH_NAME_LEN);
+
+    return ;
+}
+
+static void add_dual_path(void *proxy, char *path_name)
+{
+    struct audio_proxy *aproxy = proxy;
+
+    if (aproxy->support_dualspk) {
+        char tempStr[MAX_PATH_NAME_LEN] = {0};
+        char* szDump;
+        szDump = strstr(path_name, "speaker");
+
+        // do not add dual- path for loopback
+        if (strstr(path_name, "loopback")) {
+            return ;
+        }
+
+        if (szDump != NULL) {
+            char tempRet[MAX_PATH_NAME_LEN] = {0};
+            strncpy(tempStr, path_name, szDump - path_name);
+            sprintf(tempRet, "%s%s%s", tempStr, "dual-", szDump);
+            strncpy(path_name, tempRet, MAX_PATH_NAME_LEN);
+        }
+    }
+}
+
+/* Enable new Audio Path */
+static void set_route(void *proxy, audio_usage ausage, device_type device)
+{
+    struct audio_proxy *aproxy = proxy;
+    char path_name[MAX_PATH_NAME_LEN];
+    char gain_name[MAX_GAIN_PATH_NAME_LEN];
+
+    if (device == DEVICE_AUX_DIGITAL)
+        return ;
+
+    pthread_rwlock_rdlock(&aproxy->mixer_update_lock);
+
+    make_path(ausage, device, path_name);
+    add_dual_path(aproxy, path_name);
+    audio_route_apply_and_update_path(aproxy->aroute, path_name);
+    ALOGI("proxy-%s: routed to %s", __func__, path_name);
+
+    make_gain(path_name, gain_name);
+    audio_route_apply_and_update_path(aproxy->aroute, gain_name);
+    ALOGI("proxy-%s: set gain as %s", __func__, gain_name);
+
+    pthread_rwlock_unlock(&aproxy->mixer_update_lock);
+
+    return ;
+}
+
+/* reroute Audio Path */
+static void set_reroute(void *proxy, audio_usage old_ausage, device_type old_device,
+                                     audio_usage new_ausage, device_type new_device)
+{
+    struct audio_proxy *aproxy = proxy;
+    char path_name[MAX_PATH_NAME_LEN];
+    char gain_name[MAX_GAIN_PATH_NAME_LEN];
+
+    pthread_rwlock_rdlock(&aproxy->mixer_update_lock);
+
+    // 1. Unset Active Route
+    make_path(old_ausage, old_device, path_name);
+    add_dual_path(aproxy, path_name);
+    /* Updated to reset_and_update to match Q audio-route changes
+     * otherwise noise issue happened in alarm/ringtone scenarios
+     */
+    audio_route_reset_and_update_path(aproxy->aroute, path_name);
+    ALOGI("proxy-%s: unrouted %s", __func__, path_name);
+
+    make_gain(path_name, gain_name);
+    audio_route_reset_and_update_path(aproxy->aroute, gain_name);
+    ALOGI("proxy-%s: reset gain %s", __func__, gain_name);
+
+    // 2. Set New Route
+    if (new_device != DEVICE_AUX_DIGITAL) {
+        make_path(new_ausage, new_device, path_name);
+        add_dual_path(aproxy, path_name);
+        audio_route_apply_and_update_path(aproxy->aroute, path_name);
+        ALOGI("proxy-%s: routed %s", __func__, path_name);
+
+        make_gain(path_name, gain_name);
+        audio_route_apply_and_update_path(aproxy->aroute, gain_name);
+        ALOGI("proxy-%s: set gain as %s", __func__, gain_name);
+    }
+
+    // 3. Update Mixers
+    audio_route_update_mixer(aproxy->aroute);
+
+    pthread_rwlock_unlock(&aproxy->mixer_update_lock);
+
+    return ;
+}
+
+/* Disable Audio Path */
+static void reset_route(void *proxy, audio_usage ausage, device_type device)
+{
+    struct audio_proxy *aproxy = proxy;
+    char path_name[MAX_PATH_NAME_LEN];
+    char gain_name[MAX_GAIN_PATH_NAME_LEN];
+
+    pthread_rwlock_rdlock(&aproxy->mixer_update_lock);
+
+    make_path(ausage, device, path_name);
+    add_dual_path(aproxy, path_name);
+    audio_route_reset_and_update_path(aproxy->aroute, path_name);
+    ALOGI("proxy-%s: unrouted %s", __func__, path_name);
+
+    make_gain(path_name, gain_name);
+    audio_route_reset_and_update_path(aproxy->aroute, gain_name);
+    ALOGI("proxy-%s: reset gain %s", __func__, gain_name);
+
+    pthread_rwlock_unlock(&aproxy->mixer_update_lock);
+
+    return ;
+}
+
+/* Enable new Modifier */
+static void set_modifier(void *proxy, modifier_type modifier)
+{
+    struct audio_proxy *aproxy = proxy;
+
+    pthread_rwlock_rdlock(&aproxy->mixer_update_lock);
+
+    audio_route_apply_and_update_path(aproxy->aroute, modifier_table[modifier]);
+    ALOGI("proxy-%s: enabled to %s", __func__, modifier_table[modifier]);
+
+    pthread_rwlock_unlock(&aproxy->mixer_update_lock);
+
+    return ;
+}
+
+/* Update Modifier */
+static void update_modifier(void *proxy, modifier_type old_modifier, modifier_type new_modifier)
+{
+    struct audio_proxy *aproxy = proxy;
+
+    pthread_rwlock_rdlock(&aproxy->mixer_update_lock);
+
+    // 1. Unset Active Modifier
+    audio_route_reset_path(aproxy->aroute, modifier_table[old_modifier]);
+    ALOGI("proxy-%s: disabled %s", __func__, modifier_table[old_modifier]);
+
+    // 2. Set New Modifier
+    audio_route_apply_path(aproxy->aroute, modifier_table[new_modifier]);
+    ALOGI("proxy-%s: enabled %s", __func__, modifier_table[new_modifier]);
+
+    // 3. Update Mixers
+    audio_route_update_mixer(aproxy->aroute);
+
+    pthread_rwlock_unlock(&aproxy->mixer_update_lock);
+
+    return ;
+}
+
+/* Disable Modifier */
+static void reset_modifier(void *proxy, modifier_type modifier)
+{
+    struct audio_proxy *aproxy = proxy;
+
+    pthread_rwlock_rdlock(&aproxy->mixer_update_lock);
+
+    audio_route_reset_and_update_path(aproxy->aroute, modifier_table[modifier]);
+    ALOGI("proxy-%s: disabled %s", __func__, modifier_table[modifier]);
+
+    pthread_rwlock_unlock(&aproxy->mixer_update_lock);
+
+    return ;
+}
+
+static void do_operations_by_playback_route_set(struct audio_proxy *aproxy,
+                                                audio_usage routed_ausage, device_type routed_device)
+{
+    /* skip internal pcm controls */
+    if (aproxy->skip_internalpath) {
+        ALOGI("proxy-%s: skip internal path pcm controls", __func__);
+        return;
+    }
+
+    /* Open/Close FM Radio PCM node based on Enable/disable */
+    if (routed_ausage != AUSAGE_FM_RADIO && routed_ausage != AUSAGE_USB_FM_RADIO) {
+        fmradio_playback_stop(aproxy);
+        fmradio_capture_stop(aproxy);
+    }
+
+    /* Set Mute during APCall Path Change */
+    if ((aproxy->active_playback_device != routed_device) &&
+        (is_active_usage_APCall(aproxy) || is_usage_APCall(routed_ausage)))
+        proxy_set_mixercontrol(aproxy, MUTE_CONTROL, ABOX_MUTE_CNT_FOR_PATH_CHANGE);
+
+    return ;
+}
+
+static void do_operations_by_playback_route_reset(struct audio_proxy *aproxy __unused)
+{
+    return ;
+}
+
+
+/*
+ * Dump functions
+ */
+static void calliope_cleanup_old(const char *path, const char *prefix)
+{
+    struct dirent **namelist;
+    int n, match = 0;
+
+    ALOGV("proxy-%s", __func__);
+
+    n = scandir(path, &namelist, NULL, alphasort);
+    if (n > 0) {
+        /* interate in reverse order to get old file */
+        while (n--) {
+            if (strstr(namelist[n]->d_name, prefix) == namelist[n]->d_name) {
+                if (++match > ABOX_DUMP_LIMIT) {
+                    char *tgt;
+
+                    if (asprintf(&tgt, "%s/%s", path, namelist[n]->d_name) != -1) {
+                        remove(tgt);
+                        free(tgt);
+                    }
+                }
+            }
+            free(namelist[n]);
+        }
+        free(namelist);
+    }
+
+    return ;
+}
+
+static void __calliope_dump(int fd, const char *in_prefix, const char *in_file, const char *out_prefix, const char *out_suffix)
+{
+    static const int buf_size = 4096;
+    char *buf, in_path[128], out_path[128];
+    int fd_in = -1, fd_out = -1, n;
+    mode_t mask;
+
+    ALOGV("proxy-%s", __func__);
+
+    if (snprintf(in_path, sizeof(in_path) - 1, "%s%s", in_prefix, in_file) < 0) {
+        ALOGE("proxy-%s: in path error: %s", __func__, strerror(errno));
+        return;
+    }
+
+    if (snprintf(out_path, sizeof(out_path) - 1, "%s%s_%s.bin", out_prefix, in_file, out_suffix) < 0) {
+        ALOGE("proxy-%s: out path error: %s", __func__, strerror(errno));
+        return;
+    }
+
+    buf = malloc(buf_size);
+    if (!buf) {
+        ALOGE("proxy-%s: malloc failed: %s", __func__, strerror(errno));
+        return;
+    }
+
+    mask = umask(0);
+    ALOGV("umask = %o", mask);
+
+    fd_in = open(in_path, O_RDONLY | O_NONBLOCK);
+    if (fd_in < 0)
+        ALOGE("proxy-%s: open error: %s, fd_in=%s", __func__, strerror(errno), in_path);
+    fd_out = open(out_path, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
+    if (fd_out < 0)
+        ALOGE("proxy-%s: open error: %s, fd_out=%s", __func__, strerror(errno), out_path);
+    if (fd_in >= 0 && fd_out >= 0) {
+        while((n = read(fd_in, buf, buf_size)) > 0) {
+            if (write(fd_out, buf, n) < 0) {
+                ALOGE("proxy-%s: write error: %s", __func__, strerror(errno));
+            }
+        }
+        n = snprintf(buf, buf_size, " %s_%s.bin <= %s\n", in_file, out_suffix, in_file);
+        write(fd, buf, n);
+        ALOGI("proxy-%s", buf);
+    }
+
+    calliope_cleanup_old(out_prefix, in_file);
+
+    if (fd_in >= 0)
+        close(fd_in);
+    if (fd_out >= 0)
+        close(fd_out);
+
+    mask = umask(mask);
+    free(buf);
+
+    return ;
+}
+
+static void calliope_ramdump(int fd)
+{
+    char str_time[32];
+    time_t t;
+    struct tm *lt;
+
+    ALOGD("%s", __func__);
+
+    t = time(NULL);
+    lt = localtime(&t);
+    if (lt == NULL) {
+        ALOGE("%s: time conversion error: %s", __func__, strerror(errno));
+        return;
+    }
+    if (strftime(str_time, sizeof(str_time), "%Y%m%d_%H%M%S", lt) == 0) {
+        ALOGE("%s: time error: %s", __func__, strerror(errno));
+    }
+
+    write(fd, "\n", strlen("\n"));
+    write(fd, "Calliope snapshot:\n", strlen("Calliope snapshot:\n"));
+    ALOGI("Calliope snapshot:\n");
+    __calliope_dump(fd, SYSFS_PREFIX ABOX_DEV ABOX_DEBUG, ABOX_GPR, ABOX_DUMP, str_time);
+    __calliope_dump(fd, CALLIOPE_DBG_PATH, CALLIOPE_LOG, ABOX_DUMP, str_time);
+    __calliope_dump(fd, SYSFS_PREFIX ABOX_DEV ABOX_DEBUG, ABOX_SRAM, ABOX_DUMP, str_time);
+    __calliope_dump(fd, SYSFS_PREFIX ABOX_DEV ABOX_DEBUG, ABOX_DRAM, ABOX_DUMP, str_time);
+    __calliope_dump(fd, ABOX_REGMAP_PATH, ABOX_REG_FILE, ABOX_DUMP, str_time);
+    write(fd, "Calliope snapshot done\n", strlen("Calliope snapshot done\n"));
+
+    return ;
+}
+
+/******************************************************************************/
+/**                                                                          **/
+/** Local Functions for Audio Stream Proxy                                   **/
+/**                                                                          **/
+/******************************************************************************/
+/* Compress Offload Specific Functions */
+static bool is_supported_compressed_format(audio_format_t format)
+{
+    switch (format & AUDIO_FORMAT_MAIN_MASK) {
+    case AUDIO_FORMAT_MP3:
+    case AUDIO_FORMAT_AAC:
+    case AUDIO_FORMAT_FLAC:
+        return true;
+    default:
+        break;
+    }
+
+    return false;
+}
+
+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_FLAC:
+        id = SND_AUDIOCODEC_FLAC;
+        break;
+    default:
+            ALOGE("offload_out-%s: Unsupported audio format", __func__);
+    }
+
+    return id;
+}
+
+static int check_direct_config_support(struct audio_proxy_stream *apstream)
+{
+    int i;
+    int ret = 0;
+
+    // Check Sampling Rate
+    for (i = 0; i < MAX_NUM_PLAYBACK_SR; i++) {
+        if (apstream->requested_sample_rate == supported_playback_samplingrate[i]) {
+            if (apstream->requested_sample_rate != apstream->pcmconfig.rate) {
+                apstream->pcmconfig.rate = apstream->requested_sample_rate;
+            }
+            apstream->pcmconfig.period_size = (apstream->pcmconfig.rate * PREDEFINED_USB_PLAYBACK_DURATION) / 1000;
+
+            // DMA in A-Box is 128-bit aligned, so period_size has to be multiple of 4 frames
+            apstream->pcmconfig.period_size &= 0xFFFFFFFC;
+            ALOGD("%s-%s: updates samplig rate to %u, period_size to %u", stream_table[apstream->stream_type],
+                __func__, apstream->pcmconfig.rate,
+                apstream->pcmconfig.period_size);
+            break;
+        }
+    }
+
+    if (i == MAX_NUM_PLAYBACK_SR) {
+        ALOGD("%s-%s: unsupported samplerate to %u", stream_table[apstream->stream_type], __func__,
+                                                apstream->requested_sample_rate);
+        ret = -EINVAL;
+        goto err;
+    }
+
+    // Check Channel Mask
+    for (i = 0; i < MAX_NUM_DIRECT_PLAYBACK_CM; i++) {
+        if (apstream->requested_channel_mask == supported_direct_playback_channelmask[i]) {
+            if (audio_channel_count_from_out_mask(apstream->requested_channel_mask)
+                != apstream->pcmconfig.channels) {
+                if (apstream->requested_channel_mask == AUDIO_CHANNEL_OUT_5POINT1) {
+                    ALOGD("%s-%s: channel padding needed from 6 Channels to %u channels",
+                        stream_table[apstream->stream_type], __func__,
+                        apstream->pcmconfig.channels);
+                    /* A-Box HW doesn't 6 channels therefore 2 channel padding is required */
+                    apstream->need_channelpadding = true;
+                } else {
+                    apstream->pcmconfig.channels =
+                        audio_channel_count_from_out_mask(apstream->requested_channel_mask);
+                    ALOGD("%s-%s: channel count updated to %u",
+                        stream_table[apstream->stream_type], __func__,
+                        apstream->pcmconfig.channels);
+                }
+            }
+            ALOGD("%s-%s: requested channel mask %u configured channels %d ",
+                stream_table[apstream->stream_type], __func__,
+                audio_channel_count_from_out_mask(apstream->requested_channel_mask),
+                apstream->pcmconfig.channels);
+            break;
+        }
+    }
+
+    if (i == MAX_NUM_DIRECT_PLAYBACK_CM) {
+        ALOGD("%s-%s: unsupported channel mask %u ", stream_table[apstream->stream_type],
+            __func__, audio_channel_count_from_out_mask(apstream->requested_channel_mask));
+        ret = -EINVAL;
+    }
+
+    // Check PCM Format
+    for (i = 0; i < MAX_NUM_PLAYBACK_PF; i++) {
+        if (apstream->requested_format == supported_playback_pcmformat[i]) {
+            if (pcm_format_from_audio_format(apstream->requested_format) !=
+                apstream->pcmconfig.format) {
+                apstream->pcmconfig.format =
+                    pcm_format_from_audio_format(apstream->requested_format);
+                ALOGD("%s-%s: updates PCM format to %d", stream_table[apstream->stream_type],
+                    __func__, apstream->pcmconfig.format);
+            }
+            break;
+        }
+    }
+
+    if (i == MAX_NUM_PLAYBACK_PF) {
+        ALOGD("%s-%s: unsupported format 0x%x", stream_table[apstream->stream_type],
+            __func__, apstream->requested_format);
+        ret = -EINVAL;
+        goto err;
+    }
+
+err:
+    return ret;
+}
+
+static void save_written_frames(struct audio_proxy_stream *apstream, int bytes)
+{
+    apstream->frames += bytes / (apstream->pcmconfig.channels *
+                audio_bytes_per_sample(audio_format_from_pcm_format(apstream->pcmconfig.format)));
+    ALOGVV("%s-%s: written = %u frames", stream_table[apstream->stream_type], __func__,
+                                         (unsigned int)apstream->frames);
+    return ;
+}
+
+static void skip_pcm_processing(struct audio_proxy_stream *apstream, int bytes)
+{
+    unsigned int frames = 0;
+
+    frames = bytes / (apstream->pcmconfig.channels *
+             audio_bytes_per_sample(audio_format_from_pcm_format(apstream->pcmconfig.format)));
+    usleep(frames * 1000000 / proxy_get_actual_sampling_rate(apstream));
+    return ;
+}
+
+static void update_capture_pcmconfig(struct audio_proxy_stream *apstream)
+{
+#ifdef SUPPORT_QUAD_MIC
+    struct audio_proxy *aproxy = getInstance();
+#endif
+    int i;
+
+    // Check Sampling Rate
+    for (i = 0; i < MAX_NUM_CAPTURE_SR; i++) {
+        if (apstream->requested_sample_rate == supported_capture_samplingrate[i]) {
+            if (apstream->requested_sample_rate != apstream->pcmconfig.rate) {
+                apstream->pcmconfig.rate = apstream->requested_sample_rate;
+                if (apstream->stream_type == ASTREAM_CAPTURE_PRIMARY)
+                    apstream->pcmconfig.period_size = (apstream->pcmconfig.rate * PREDEFINED_MEDIA_CAPTURE_DURATION) / 1000;
+                else if (apstream->stream_type == ASTREAM_CAPTURE_LOW_LATENCY)
+                    apstream->pcmconfig.period_size = (apstream->pcmconfig.rate * PREDEFINED_LOW_CAPTURE_DURATION) / 1000;
+
+                // WDMA in A-Box is 128-bit aligned, so period_size has to be multiple of 4 frames
+                apstream->pcmconfig.period_size &= 0xFFFFFFFC;
+                ALOGD("%s-%s: updates samplig rate to %u, period_size to %u", stream_table[apstream->stream_type],
+                                                           __func__, apstream->pcmconfig.rate,
+                                                           apstream->pcmconfig.period_size);
+            }
+            break;
+        }
+    }
+
+    if (i == MAX_NUM_CAPTURE_SR)
+        ALOGD("%s-%s: needs re-sampling to %u", stream_table[apstream->stream_type], __func__,
+                                                apstream->requested_sample_rate);
+
+    // Check Channel Mask
+    for (i = 0; i < MAX_NUM_CAPTURE_CM; i++) {
+        if (apstream->requested_channel_mask == supported_capture_channelmask[i]) {
+            if (audio_channel_count_from_in_mask(apstream->requested_channel_mask)
+                != apstream->pcmconfig.channels) {
+#ifdef SUPPORT_QUAD_MIC
+                if ((is_active_usage_CPCall(aproxy) || is_active_usage_APCall(aproxy)
+                    || apstream->stream_usage == AUSAGE_CAMCORDER)
+                    && is_quad_mic_device(aproxy->active_capture_device)) {
+                    ALOGD("%s-%s: Skip channel count updating to %u", stream_table[apstream->stream_type],
+                                            __func__, apstream->pcmconfig.channels);
+                } else
+#endif
+                {
+                    apstream->pcmconfig.channels = audio_channel_count_from_in_mask(apstream->requested_channel_mask);
+                    ALOGD("%s-%s: updates channel count to %u", stream_table[apstream->stream_type],
+                                                                __func__, apstream->pcmconfig.channels);
+                }
+            }
+            break;
+        }
+    }
+
+    if (i == MAX_NUM_CAPTURE_CM)
+        ALOGD("%s-%s: needs re-channeling to %u from %u", stream_table[apstream->stream_type], __func__,
+              audio_channel_count_from_in_mask(apstream->requested_channel_mask), apstream->pcmconfig.channels);
+
+    // Check PCM Format
+    for (i = 0; i < MAX_NUM_CAPTURE_PF; i++) {
+        if (apstream->requested_format == supported_capture_pcmformat[i]) {
+            if (pcm_format_from_audio_format(apstream->requested_format) != apstream->pcmconfig.format) {
+                apstream->pcmconfig.format = pcm_format_from_audio_format(apstream->requested_format);
+                ALOGD("%s-%s: updates PCM format to %d", stream_table[apstream->stream_type], __func__,
+                                                         apstream->pcmconfig.format);
+            }
+            break;
+        }
+    }
+
+    if (i == MAX_NUM_CAPTURE_PF)
+        ALOGD("%s-%s: needs re-formating to 0x%x", stream_table[apstream->stream_type], __func__,
+                                                   apstream->requested_format);
+
+    return ;
+}
+
+// For Resampler
+int proxy_get_requested_frame_size(struct audio_proxy_stream *apstream)
+{
+    return audio_channel_count_from_in_mask(apstream->requested_channel_mask) *
+           audio_bytes_per_sample(apstream->requested_format);
+}
+
+static int get_next_buffer(struct resampler_buffer_provider *buffer_provider,
+                           struct resampler_buffer* buffer)
+{
+    struct audio_proxy_stream *apstream;
+
+    if (buffer_provider == NULL || buffer == NULL)
+        return -EINVAL;
+
+    apstream = (struct audio_proxy_stream *)((char *)buffer_provider -
+                                             offsetof(struct audio_proxy_stream, buf_provider));
+
+    if (apstream->pcm) {
+        if (apstream->read_buf_frames == 0) {
+            unsigned int size_in_bytes = pcm_frames_to_bytes(apstream->pcm, apstream->pcmconfig.period_size);
+            if (apstream->actual_read_buf_size < size_in_bytes) {
+                apstream->actual_read_buf_size = size_in_bytes;
+                apstream->actual_read_buf = (int16_t *) realloc(apstream->actual_read_buf, size_in_bytes);
+                if (apstream->actual_read_buf != NULL)
+                    ALOGI("%s-%s: alloc actual read buffer with %u bytes",
+                           stream_table[apstream->stream_type], __func__, size_in_bytes);
+            }
+
+            if (apstream->actual_read_buf != NULL) {
+                apstream->actual_read_status = pcm_read(apstream->pcm, (void*)apstream->actual_read_buf, size_in_bytes);
+                if (apstream->actual_read_status != 0) {
+                    ALOGE("%s-%s: pcm_read error %d(%s)", stream_table[apstream->stream_type],
+                        __func__, apstream->actual_read_status, pcm_get_error(apstream->pcm));
+                    buffer->raw = NULL;
+                    buffer->frame_count = 0;
+                    return apstream->actual_read_status;
+                }
+
+                if (apstream->stream_type == ASTREAM_CAPTURE_CALL ||
+                    apstream->stream_type == ASTREAM_CAPTURE_TELEPHONYRX) {
+                    /*
+                     * [Call Recording Case]
+                     * In case of Call Recording, A-Box sends stereo stream which uplink/downlink voice
+                     * allocated in left/right to AudioHAL.
+                     * AudioHAL has to select and mix uplink/downlink voice from left/right channel as usage.
+                     */
+                    int16_t data_mono;
+                    int16_t *vc_buf = (int16_t *)(apstream->actual_read_buf);
+
+                    // Channel Selection
+                    // output : Stereo with Left/Right contains same selected channel PCM & Device SR
+                    for (unsigned int i = 0; i < apstream->pcmconfig.period_size; i++){
+                        if (apstream->stream_usage == AUSAGE_INCALL_UPLINK)
+                            data_mono = (*(vc_buf + 2*i + 1)); // Tx
+                        else if (apstream->stream_usage == AUSAGE_INCALL_DOWNLINK){
+                            data_mono = (*(vc_buf + 2*i));     // Rx
+                        } else {
+                            data_mono = clamp16(((int32_t)*(vc_buf+2*i) + (int32_t)*(vc_buf+2*i+1))*0.7); // mix Rx/Tx
+                        }
+
+                        *(vc_buf + 2*i)     = data_mono;
+                        *(vc_buf + 2*i + 1) = data_mono;
+                    }
+                }
+
+                /* Convert A-Box's zero padded 24bit format to signed extension */
+                if (apstream->pcmconfig.format == PCM_FORMAT_S24_LE) {
+                    int *rd_buf = (int *)(apstream->actual_read_buf);
+
+                    for (unsigned int i = 0;
+                        i < (apstream->pcmconfig.period_size * apstream->pcmconfig.channels); i++) {
+                        if (*(rd_buf + i) & 0x800000)
+                            *(rd_buf + i) |= 0xFF000000;
+                    }
+                }
+                apstream->read_buf_frames = apstream->pcmconfig.period_size;
+            } else {
+                ALOGE("%s-%s: failed to reallocate actual_read_buf",
+                      stream_table[apstream->stream_type], __func__);
+                buffer->raw = NULL;
+                buffer->frame_count = 0;
+                apstream->actual_read_status = -ENOMEM;
+                return -ENOMEM;
+            }
+        }
+
+        buffer->frame_count = (buffer->frame_count > apstream->read_buf_frames) ?
+                               apstream->read_buf_frames : buffer->frame_count;
+        buffer->i16 = apstream->actual_read_buf + (apstream->pcmconfig.period_size - apstream->read_buf_frames) *
+                                                  apstream->pcmconfig.channels;
+        return apstream->actual_read_status;
+    } else {
+        buffer->raw = NULL;
+        buffer->frame_count = 0;
+        apstream->actual_read_status = -ENODEV;
+        return -ENODEV;
+    }
+}
+
+static void release_buffer(struct resampler_buffer_provider *buffer_provider,
+                           struct resampler_buffer* buffer)
+{
+    struct audio_proxy_stream *apstream;
+
+    if (buffer_provider == NULL || buffer == NULL)
+        return;
+
+    apstream = (struct audio_proxy_stream *)((char *)buffer_provider -
+                                             offsetof(struct audio_proxy_stream, buf_provider));
+
+    apstream->read_buf_frames -= buffer->frame_count;
+}
+
+static int read_frames(struct audio_proxy_stream *apstream, void *buffer, int frames)
+{
+    int frames_wr = 0;
+
+    while (frames_wr < frames) {
+        size_t frames_rd = frames - frames_wr;
+        ALOGVV("%s-%s: frames_rd: %zd, frames_wr: %d",
+           stream_table[apstream->stream_type], __func__, frames_rd, frames_wr);
+
+        if (apstream->resampler != NULL) {
+            apstream->resampler->resample_from_provider(apstream->resampler,
+            (int16_t *)((char *)buffer + pcm_frames_to_bytes(apstream->pcm, frames_wr)), &frames_rd);
+        } else {
+            struct resampler_buffer buf;
+            buf.raw= NULL;
+            buf.frame_count = frames_rd;
+
+            get_next_buffer(&apstream->buf_provider, &buf);
+            if (buf.raw != NULL) {
+                memcpy((char *)buffer + pcm_frames_to_bytes(apstream->pcm, frames_wr),
+                        buf.raw, pcm_frames_to_bytes(apstream->pcm, buf.frame_count));
+                frames_rd = buf.frame_count;
+            }
+            release_buffer(&apstream->buf_provider, &buf);
+        }
+
+        /* apstream->actual_read_status is updated by getNextBuffer() also called by
+         * apstream->resampler->resample_from_provider() */
+        if (apstream->actual_read_status != 0)
+            return apstream->actual_read_status;
+
+        frames_wr += frames_rd;
+    }
+
+    return frames_wr;
+}
+
+static int read_and_process_frames(struct audio_proxy_stream *apstream, void* buffer, int frames_num)
+{
+    int frames_wr = 0;
+    unsigned int bytes_per_sample = (pcm_format_to_bits(apstream->pcmconfig.format) >> 3);
+    void *proc_buf_out = buffer;
+
+    int num_device_channels = proxy_get_actual_channel_count(apstream);
+    int num_req_channels = audio_channel_count_from_in_mask(apstream->requested_channel_mask);
+
+    /* Prepare Channel Conversion Input Buffer */
+    if (apstream->need_channelconversion && (num_device_channels != num_req_channels)) {
+        int src_buffer_size = frames_num * num_device_channels * bytes_per_sample;
+
+        if (apstream->proc_buf_size < src_buffer_size) {
+            apstream->proc_buf_size = src_buffer_size;
+            apstream->proc_buf_out = realloc(apstream->proc_buf_out, src_buffer_size);
+            ALOGI("%s-%s: alloc resampled read buffer with %d bytes",
+                      stream_table[apstream->stream_type], __func__, src_buffer_size);
+        }
+        proc_buf_out = apstream->proc_buf_out;
+    }
+
+    frames_wr = read_frames(apstream, proc_buf_out, frames_num);
+    if ((frames_wr > 0) && (frames_wr > frames_num))
+        ALOGE("%s-%s: read more frames than requested", stream_table[apstream->stream_type], __func__);
+
+    /*
+     * A-Box can support only Stereo channel, not Mono channel.
+     * If platform wants Mono Channel Recording, AudioHAL has to support mono conversion.
+     */
+    if (apstream->actual_read_status == 0) {
+        if (apstream->need_channelconversion && (num_device_channels != num_req_channels)) {
+            size_t ret = adjust_channels(proc_buf_out, num_device_channels,
+                                         buffer, num_req_channels,
+                                         bytes_per_sample, (frames_wr * num_device_channels * bytes_per_sample));
+            if (ret != (frames_wr * num_req_channels * bytes_per_sample))
+                ALOGE("%s-%s: channel convert failed", stream_table[apstream->stream_type], __func__);
+        }
+    } else {
+        ALOGE("%s-%s: Read Fail = %d", stream_table[apstream->stream_type], __func__, frames_wr);
+    }
+
+    return frames_wr;
+}
+
+static void check_conversion(struct audio_proxy_stream *apstream)
+{
+    int request_cc = audio_channel_count_from_in_mask(apstream->requested_channel_mask);
+
+    // Check Mono Conversion is needed or not
+    if ((request_cc == MEDIA_1_CHANNEL && apstream->pcmconfig.channels == DEFAULT_MEDIA_CHANNELS)
+#ifdef SUPPORT_QUAD_MIC
+        || ((request_cc == DEFAULT_MEDIA_CHANNELS || request_cc == MEDIA_1_CHANNEL)
+        && apstream->pcmconfig.channels == MEDIA_4_CHANNELS)
+#endif
+        ) {
+        // enable channel Conversion
+        apstream->need_channelconversion = true;
+        ALOGD("%s-%s: needs re-channeling to %u from %u", stream_table[apstream->stream_type], __func__,
+              request_cc, apstream->pcmconfig.channels);
+    }
+
+    // Check Re-Sampler is needed or not
+    if (apstream->requested_sample_rate &&
+        apstream->requested_sample_rate != apstream->pcmconfig.rate) {
+        // Only support Stereo Resampling
+        if (apstream->resampler) {
+            release_resampler(apstream->resampler);
+            apstream->resampler = NULL;
+        }
+
+        apstream->buf_provider.get_next_buffer = get_next_buffer;
+        apstream->buf_provider.release_buffer = release_buffer;
+        int ret = create_resampler(apstream->pcmconfig.rate, apstream->requested_sample_rate,
+                                   apstream->pcmconfig.channels, RESAMPLER_QUALITY_DEFAULT,
+                                   &apstream->buf_provider, &apstream->resampler);
+        if (ret !=0) {
+            ALOGE("proxy-%s: failed to create resampler", __func__);
+        } else {
+            ALOGV("proxy-%s: resampler created in-samplerate %d out-samplereate %d",
+                  __func__, apstream->pcmconfig.rate, apstream->requested_sample_rate);
+
+            apstream->need_resampling = true;
+            ALOGD("%s-%s: needs re-sampling to %u Hz from %u Hz", stream_table[apstream->stream_type], __func__,
+                  apstream->requested_sample_rate, apstream->pcmconfig.rate);
+
+            apstream->actual_read_buf = NULL;
+            apstream->actual_read_buf_size = 0;
+            apstream->read_buf_frames = 0;
+
+            apstream->resampler->reset(apstream->resampler);
+        }
+    }
+
+    return ;
+}
+
+/*
+ * Modify config->period_count based on min_size_frames
+ */
+static void adjust_mmap_period_count(struct audio_proxy_stream *apstream, struct pcm_config *config,
+                                     int32_t min_size_frames)
+{
+    int periodCountRequested = (min_size_frames + config->period_size - 1)
+                               / config->period_size;
+    int periodCount = MMAP_PERIOD_COUNT_MIN;
+
+    ALOGV("%s-%s: original config.period_size = %d config.period_count = %d",
+          stream_table[apstream->stream_type], __func__, config->period_size, config->period_count);
+
+    while (periodCount < periodCountRequested && (periodCount * 2) < MMAP_PERIOD_COUNT_MAX) {
+        periodCount *= 2;
+    }
+    config->period_count = periodCount;
+
+    ALOGV("%s-%s: requested config.period_count = %d", stream_table[apstream->stream_type], __func__,
+                                                       config->period_count);
+}
+
+int get_mmap_data_fd(void *proxy_stream, audio_usage_type usage_type,
+                                                            int *fd, unsigned int *size)
+{
+    struct audio_proxy_stream *apstream = (struct audio_proxy_stream *)proxy_stream;
+    struct snd_pcm_mmap_fd mmapfd_info;
+    char dev_name[128];
+    int hw_fd = -1;
+    int ret = 0;
+    int hwdev_node = -1;
+
+    memset(&mmapfd_info, 0, sizeof(mmapfd_info));
+    mmapfd_info.dir = usage_type;
+
+    // get MMAP device node number based on usage direction
+    hwdev_node = ((usage_type ==  AUSAGE_PLAYBACK) ? MMAP_PLAYBACK_DEVICE :
+                            MMAP_CAPTURE_DEVICE);
+    snprintf(dev_name, sizeof(dev_name), "/dev/snd/hwC0D%d", hwdev_node);
+    hw_fd = open(dev_name, O_RDONLY);
+    if (hw_fd < 0) {
+        ALOGE("%s: hw %s node open failed", __func__, dev_name);
+        ret = -1;
+        goto err;
+    }
+
+    // get mmap fd for exclusive mode
+    if (ioctl(hw_fd, SNDRV_PCM_IOCTL_MMAP_DATA_FD, &mmapfd_info) < 0) {
+        ALOGE("%s-%s: get MMAP FD IOCTL failed",
+		   stream_table[apstream->stream_type], __func__);
+        ret = -1;
+        goto err;
+    }
+    *fd = mmapfd_info.fd;
+    *size = mmapfd_info.size;
+
+err:
+    if (hw_fd >= 0)
+        close(hw_fd);
+    return ret;
+}
+
+
+/******************************************************************************/
+/**                                                                          **/
+/** Interfaces for Audio Stream Proxy                                        **/
+/**                                                                          **/
+/******************************************************************************/
+
+uint32_t proxy_get_actual_channel_count(void *proxy_stream)
+{
+    struct audio_proxy_stream *apstream = (struct audio_proxy_stream *)proxy_stream;
+    uint32_t actual_channel_count = 0;
+
+    if (apstream) {
+        if (apstream->stream_type == ASTREAM_PLAYBACK_COMPR_OFFLOAD)
+            actual_channel_count = (uint32_t)audio_channel_count_from_out_mask(apstream->comprconfig.codec->ch_in);
+        else
+            actual_channel_count = (uint32_t)apstream->pcmconfig.channels;
+    }
+
+    return actual_channel_count;
+}
+
+uint32_t proxy_get_actual_sampling_rate(void *proxy_stream)
+{
+    struct audio_proxy_stream *apstream = (struct audio_proxy_stream *)proxy_stream;
+    uint32_t actual_sampling_rate = 0;
+
+    if (apstream) {
+        if (apstream->stream_type == ASTREAM_PLAYBACK_COMPR_OFFLOAD)
+            actual_sampling_rate = (uint32_t)apstream->comprconfig.codec->sample_rate;
+        else
+            actual_sampling_rate = (uint32_t)apstream->pcmconfig.rate;
+    }
+
+    return actual_sampling_rate;
+}
+
+uint32_t proxy_get_actual_period_size(void *proxy_stream)
+{
+    struct audio_proxy_stream *apstream = (struct audio_proxy_stream *)proxy_stream;
+    uint32_t actual_period_size = 0;
+
+    if (apstream) {
+        if (apstream->stream_type == ASTREAM_PLAYBACK_COMPR_OFFLOAD)
+            actual_period_size = (uint32_t)apstream->comprconfig.fragment_size;
+        else
+            actual_period_size = (uint32_t)apstream->pcmconfig.period_size;
+    }
+
+    return actual_period_size;
+}
+
+uint32_t proxy_get_actual_period_count(void *proxy_stream)
+{
+    struct audio_proxy_stream *apstream = (struct audio_proxy_stream *)proxy_stream;
+    uint32_t actual_period_count = 0;
+
+    if (apstream) {
+        if (apstream->stream_type == ASTREAM_PLAYBACK_COMPR_OFFLOAD)
+            actual_period_count = (uint32_t)apstream->comprconfig.fragments;
+        else
+            actual_period_count = (uint32_t)apstream->pcmconfig.period_count;
+    }
+
+    return actual_period_count;
+}
+
+int32_t proxy_get_actual_format(void *proxy_stream)
+{
+    struct audio_proxy_stream *apstream = (struct audio_proxy_stream *)proxy_stream;
+    int32_t actual_format = (int32_t)AUDIO_FORMAT_INVALID;
+
+    if (apstream) {
+        if (apstream->stream_type == ASTREAM_PLAYBACK_COMPR_OFFLOAD)
+            actual_format = (int32_t)apstream->comprconfig.codec->format;
+        else
+            actual_format = (int32_t)audio_format_from_pcm_format(apstream->pcmconfig.format);
+    }
+
+    return actual_format;
+}
+
+void  proxy_offload_set_nonblock(void *proxy_stream)
+{
+    struct audio_proxy_stream *apstream = (struct audio_proxy_stream *)proxy_stream;
+
+    if (apstream->stream_type == ASTREAM_PLAYBACK_COMPR_OFFLOAD)
+        apstream->nonblock_flag = 1;
+
+    return ;
+}
+
+int proxy_offload_compress_func(void *proxy_stream, int func_type)
+{
+    struct audio_proxy_stream *apstream = (struct audio_proxy_stream *)proxy_stream;
+    int ret = 0;
+
+    if (apstream->stream_type == ASTREAM_PLAYBACK_COMPR_OFFLOAD) {
+        if (apstream->compress) {
+            switch (func_type) {
+                case COMPRESS_TYPE_WAIT:
+                    ret = compress_wait(apstream->compress, -1);
+                    ALOGVV("%s-%s: returned from waiting", stream_table[apstream->stream_type], __func__);
+                    break;
+
+                case COMPRESS_TYPE_NEXTTRACK:
+                    ret = compress_next_track(apstream->compress);
+                    ALOGI("%s-%s: set next track", stream_table[apstream->stream_type], __func__);
+                    break;
+
+                case COMPRESS_TYPE_PARTIALDRAIN:
+                    ret = compress_partial_drain(apstream->compress);
+                    ALOGI("%s-%s: drained this track partially", stream_table[apstream->stream_type], __func__);
+
+                    /* Resend the metadata for next iteration */
+                    apstream->ready_new_metadata = 1;
+                    break;
+
+                case COMPRESS_TYPE_DRAIN:
+                    ret = compress_drain(apstream->compress);
+                    ALOGI("%s-%s: drained this track", stream_table[apstream->stream_type], __func__);
+                    break;
+
+                default:
+                    ALOGE("%s-%s: unsupported Offload Compress Function(%d)",
+                           stream_table[apstream->stream_type], __func__, func_type);
+            }
+        }
+    }
+
+    return ret;
+}
+
+int proxy_offload_pause(void *proxy_stream)
+{
+    struct audio_proxy_stream *apstream = (struct audio_proxy_stream *)proxy_stream;
+    int ret = 0;
+
+    if (apstream->stream_type == ASTREAM_PLAYBACK_COMPR_OFFLOAD) {
+        if (apstream->compress) {
+            ret = compress_pause(apstream->compress);
+            ALOGV("%s-%s: paused compress offload!", stream_table[apstream->stream_type], __func__);
+        }
+    }
+
+    return ret;
+}
+
+int proxy_offload_resume(void *proxy_stream)
+{
+    struct audio_proxy_stream *apstream = (struct audio_proxy_stream *)proxy_stream;
+    int ret = 0;
+
+    if (apstream->stream_type == ASTREAM_PLAYBACK_COMPR_OFFLOAD) {
+        if (apstream->compress) {
+            ret = compress_resume(apstream->compress);
+            ALOGV("%s-%s: resumed compress offload!", stream_table[apstream->stream_type], __func__);
+        }
+    }
+
+    return ret;
+}
+
+
+void *proxy_create_playback_stream(void *proxy, int type, void *config, char *address __unused)
+{
+    struct audio_proxy *aproxy = proxy;
+    audio_stream_type stream_type = (audio_stream_type)type;
+    struct audio_config *requested_config = (struct audio_config *)config;
+
+    struct audio_proxy_stream *apstream;
+
+    apstream = (struct audio_proxy_stream *)calloc(1, sizeof(struct audio_proxy_stream));
+    if (!apstream) {
+        ALOGE("proxy-%s: failed to allocate memory for Proxy Stream", __func__);
+        return NULL;;
+    }
+
+    /* Stores the requested configurations. */
+    apstream->requested_sample_rate = requested_config->sample_rate;
+    apstream->requested_channel_mask = requested_config->channel_mask;
+    apstream->requested_format = requested_config->format;
+
+    apstream->stream_type = stream_type;
+    apstream->need_update_pcm_config = false;
+
+    /* Sets basic configuration from Stream Type. */
+    switch (apstream->stream_type) {
+        // For VTS
+        case ASTREAM_PLAYBACK_NO_ATTRIBUTE:
+            apstream->sound_card = PRIMARY_PLAYBACK_CARD;
+            apstream->sound_device = PRIMARY_PLAYBACK_DEVICE;
+            apstream->pcmconfig = pcm_config_primary_playback;
+
+            break;
+
+        case ASTREAM_PLAYBACK_PRIMARY:
+            apstream->sound_card = PRIMARY_PLAYBACK_CARD;
+            apstream->sound_device = get_pcm_device_number(aproxy, apstream);
+            apstream->pcmconfig = pcm_config_primary_playback;
+
+            if (aproxy->primary_out == NULL)
+                aproxy->primary_out = apstream;
+            else
+                ALOGE("proxy-%s: Primary Output Proxy Stream is already created!!!", __func__);
+            break;
+
+        case ASTREAM_PLAYBACK_DEEP_BUFFER:
+            apstream->sound_card = DEEP_PLAYBACK_CARD;
+            apstream->sound_device = get_pcm_device_number(aproxy, apstream);
+            apstream->pcmconfig = pcm_config_deep_playback;
+            break;
+
+        case ASTREAM_PLAYBACK_FAST:
+            apstream->sound_card = FAST_PLAYBACK_CARD;
+            apstream->sound_device = get_pcm_device_number(aproxy, apstream);
+            apstream->pcmconfig = pcm_config_fast_playback;
+            break;
+
+        case ASTREAM_PLAYBACK_LOW_LATENCY:
+            apstream->sound_card = LOW_PLAYBACK_CARD;
+            apstream->sound_device = get_pcm_device_number(aproxy, apstream);
+            apstream->pcmconfig = pcm_config_low_playback;
+            break;
+
+        case ASTREAM_PLAYBACK_COMPR_OFFLOAD:
+            apstream->sound_card = OFFLOAD_PLAYBACK_CARD;
+            apstream->sound_device = get_pcm_device_number(aproxy, apstream);
+            apstream->comprconfig = compr_config_offload_playback;
+            /* dummy primary pcmconfig used for best match selection */
+            apstream->pcmconfig = pcm_config_primary_playback;
+
+            if (is_supported_compressed_format(requested_config->offload_info.format)) {
+                apstream->comprconfig.codec = (struct snd_codec *)calloc(1, sizeof(struct snd_codec));
+                if (apstream->comprconfig.codec == NULL) {
+                    ALOGE("proxy-%s: fail to allocate memory for Sound Codec", __func__);
+                    goto err_open;
+                }
+
+                apstream->comprconfig.codec->id = get_snd_codec_id(requested_config->offload_info.format);
+                apstream->comprconfig.codec->ch_in = requested_config->channel_mask;
+                apstream->comprconfig.codec->ch_out = requested_config->channel_mask;
+                apstream->comprconfig.codec->sample_rate = requested_config->sample_rate;
+                apstream->comprconfig.codec->bit_rate = requested_config->offload_info.bit_rate;
+                apstream->comprconfig.codec->format = requested_config->format;
+
+                apstream->ready_new_metadata = 1;
+            } else {
+                ALOGE("proxy-%s: unsupported Compressed Format(%x)", __func__,
+                                                            requested_config->offload_info.format);
+                goto err_open;
+            }
+            break;
+
+        case ASTREAM_PLAYBACK_MMAP:
+            apstream->sound_card = MMAP_PLAYBACK_CARD;
+            apstream->sound_device = get_pcm_device_number(aproxy, apstream);
+            apstream->pcmconfig = pcm_config_mmap_playback;
+
+            break;
+
+        case ASTREAM_PLAYBACK_AUX_DIGITAL:
+            apstream->sound_card = AUX_PLAYBACK_CARD;
+            apstream->sound_device = get_pcm_device_number(aproxy, apstream);
+            apstream->pcmconfig = pcm_config_aux_playback;
+
+            if (apstream->requested_sample_rate != 0) {
+                apstream->pcmconfig.rate = apstream->requested_sample_rate;
+                // It needs Period Size adjustment based with predefined duration
+                // to avoid underrun noise by small buffer at high sampling rate
+                if (apstream->requested_sample_rate > DEFAULT_MEDIA_SAMPLING_RATE) {
+                    apstream->pcmconfig.period_size = (apstream->requested_sample_rate * PREDEFINED_DP_PLAYBACK_DURATION) / 1000;
+                    ALOGI("proxy-%s: changed Period Size(%d) as requested sampling rate(%d)",
+                          __func__, apstream->pcmconfig.period_size, apstream->pcmconfig.rate);
+                }
+            }
+            if (apstream->requested_channel_mask != AUDIO_CHANNEL_NONE) {
+                apstream->pcmconfig.channels = audio_channel_count_from_out_mask(apstream->requested_channel_mask);
+            }
+            if (apstream->requested_format != AUDIO_FORMAT_DEFAULT) {
+                apstream->pcmconfig.format = pcm_format_from_audio_format(apstream->requested_format);
+            }
+
+            break;
+
+        case ASTREAM_PLAYBACK_DIRECT:
+            apstream->sound_card = DIRECT_PLAYBACK_CARD;
+            apstream->sound_device = get_pcm_device_number(aproxy, apstream);
+            apstream->pcmconfig = pcm_config_direct_playback;
+
+            apstream->need_channelpadding = false;
+            apstream->proc_buf_out = NULL;
+            apstream->proc_buf_size = 0;
+
+            /* check whether connected USB device supports requested channels or not */
+            if (!(proxy_is_usb_playback_device_connected(aproxy->usb_aproxy) &&
+                (int)audio_channel_count_from_out_mask(apstream->requested_channel_mask) <=
+                proxy_usb_get_playback_highest_supported_channels(aproxy->usb_aproxy))) {
+                if (proxy_is_usb_playback_device_connected(aproxy->usb_aproxy))
+                    ALOGE("proxy-%s: Direct stream channel mismatch (request channels %u supported channels %u) ",
+                        __func__, audio_channel_count_from_out_mask(apstream->requested_channel_mask),
+                        proxy_usb_get_playback_highest_supported_channels(aproxy->usb_aproxy));
+                else
+                    ALOGE("proxy-%s: Direct stream is not supported for other output devices except USB ", __func__);
+                goto err_open;
+            }
+
+            /* check whether request configurations are supported by Direct
+             * stream or not, and update pcmconfig */
+            if (check_direct_config_support(apstream)) {
+                ALOGE("proxy-%s: Direct stream unsupported configuration ", __func__);
+                goto err_open;
+            }
+            break;
+
+        default:
+            ALOGE("proxy-%s: failed to open Proxy Stream as unknown stream type(%d)", __func__,
+                                                                          apstream->stream_type);
+            goto err_open;
+    }
+
+    apstream->pcm = NULL;
+    apstream->compress = NULL;
+
+    ALOGI("proxy-%s: opened Proxy Stream(%s)", __func__, stream_table[apstream->stream_type]);
+    return (void *)apstream;
+
+err_open:
+    free(apstream);
+    return NULL;
+}
+
+void proxy_destroy_playback_stream(void *proxy_stream)
+{
+    struct audio_proxy *aproxy = getInstance();
+    struct audio_proxy_stream *apstream = (struct audio_proxy_stream *)proxy_stream;
+
+    if (apstream) {
+        if (apstream->stream_type == ASTREAM_PLAYBACK_COMPR_OFFLOAD) {
+            if (apstream->comprconfig.codec != NULL)
+                free(apstream->comprconfig.codec);
+        }
+
+        if (apstream->stream_type == ASTREAM_PLAYBACK_PRIMARY) {
+            if (aproxy->primary_out != NULL)
+                aproxy->primary_out = NULL;
+        }
+
+        if (apstream->proc_buf_out)
+            free(apstream->proc_buf_out);
+
+        free(apstream);
+    }
+
+    return ;
+}
+
+int proxy_close_playback_stream(void *proxy_stream)
+{
+    struct audio_proxy_stream *apstream = (struct audio_proxy_stream *)proxy_stream;
+    int ret = 0;
+
+    /* Close Noamrl PCM Device */
+    if (apstream->stream_type == ASTREAM_PLAYBACK_COMPR_OFFLOAD) {
+        if (apstream->compress) {
+            compress_close(apstream->compress);
+            apstream->compress = NULL;
+        }
+        ALOGI("%s-%s: closed Compress Device", stream_table[apstream->stream_type], __func__);
+    } else {
+        if (apstream->pcm) {
+            ret = pcm_close(apstream->pcm);
+            apstream->pcm = NULL;
+        }
+        if (apstream->dma_pcm) {
+            pcm_close(apstream->dma_pcm);
+            apstream->dma_pcm = NULL;
+        }
+        ALOGI("%s-%s: closed PCM Device", stream_table[apstream->stream_type], __func__);
+    }
+
+    return ret;
+}
+
+int proxy_open_playback_stream(void *proxy_stream, int32_t min_size_frames, void *mmap_info)
+{
+    struct audio_proxy_stream *apstream = (struct audio_proxy_stream *)proxy_stream;
+    struct audio_proxy *aproxy = getInstance();
+    struct audio_mmap_buffer_info *info = (struct audio_mmap_buffer_info *)mmap_info;
+    unsigned int sound_card;
+    unsigned int sound_device;
+    unsigned int flags;
+    int ret = 0;
+    char pcm_path[MAX_PCM_PATH_LEN];
+
+    /* Get PCM/Compress Device */
+    sound_card = apstream->sound_card;
+    sound_device = apstream->sound_device;
+
+    /* Open Normal PCM Device */
+    if (apstream->stream_type == ASTREAM_PLAYBACK_COMPR_OFFLOAD) {
+        if (apstream->compress == NULL) {
+            flags = COMPRESS_IN;
+
+            apstream->compress = compress_open(sound_card, sound_device, flags, &apstream->comprconfig);
+            if (apstream->compress && !is_compress_ready(apstream->compress)) {
+                /* compress_open does always return compress structure, not NULL */
+                ALOGE("%s-%s: Compress Device is not ready with Sampling_Rate(%u) error(%s)!",
+                      stream_table[apstream->stream_type], __func__, apstream->comprconfig.codec->sample_rate,
+                      compress_get_error(apstream->compress));
+                goto err_open;
+            }
+
+            snprintf(pcm_path, sizeof(pcm_path), "/dev/snd/comprC%uD%u", sound_card, sound_device);
+            ALOGI("%s-%s: The opened Compress Device is %s with Sampling_Rate(%u) PCM_Format(%d) Fragment_Size(%u)",
+                  stream_table[apstream->stream_type], __func__, pcm_path,
+                  apstream->comprconfig.codec->sample_rate, apstream->comprconfig.codec->format,
+                  apstream->comprconfig.fragment_size);
+
+            apstream->pcm = NULL;
+        }
+    } else {
+        if (apstream->pcm == NULL) {
+            struct pcm_config *ppcmconfig = &apstream->pcmconfig;
+
+            if (apstream->stream_type == ASTREAM_PLAYBACK_MMAP) {
+                flags = PCM_OUT | PCM_MMAP | PCM_NOIRQ | PCM_MONOTONIC;
+
+                adjust_mmap_period_count(apstream, ppcmconfig, min_size_frames);
+            } else
+                flags = PCM_OUT | PCM_MONOTONIC;
+
+            apstream->dma_pcm = pcm_open(sound_card, sound_device, flags, ppcmconfig);
+            if (apstream->dma_pcm && !pcm_is_ready(apstream->dma_pcm)) {
+                /* pcm_open does always return pcm structure, not NULL */
+                ALOGE("%s-%s: PCM Device is not ready with Sampling_Rate(%u) error(%s)!",
+                      stream_table[apstream->stream_type], __func__, ppcmconfig->rate,
+                      pcm_get_error(apstream->dma_pcm));
+                goto err_open;
+            }
+
+            snprintf(pcm_path, sizeof(pcm_path), "/dev/snd/pcmC%uD%u%c", sound_card, sound_device ,'p');
+            ALOGI("%s-%s: The opened PCM Device is %s with Sampling_Rate(%u) PCM_Format(%d)  PCM_start-threshold(%d) PCM_stop-threshold(%d)",
+                  stream_table[apstream->stream_type], __func__, pcm_path,
+                  ppcmconfig->rate, ppcmconfig->format,
+                  ppcmconfig->start_threshold, ppcmconfig->stop_threshold);
+
+            /* virtual pcm handling for Primary & Deep streams */
+            if (apstream->stream_type == ASTREAM_PLAYBACK_PRIMARY) {
+                /* DMA PCM should be started */
+                if (pcm_start(apstream->dma_pcm) == 0) {
+                    ALOGI("proxy-%s: PCM Device(%s) with SR(%u) PF(%d) CC(%d) is started",
+                          __func__, pcm_path, ppcmconfig->rate, ppcmconfig->format, ppcmconfig->channels);
+                } else {
+                    ALOGE("proxy-%s: PCM Device(%s) with SR(%u) PF(%d) CC(%d) cannot be started as error(%s)",
+                          __func__, pcm_path, ppcmconfig->rate, ppcmconfig->format, ppcmconfig->channels,
+                          pcm_get_error(apstream->dma_pcm));
+                    goto err_open;
+                }
+
+                /* open virtual primary pcm node */
+                apstream->pcm = pcm_open(VIRTUAL_PRIMARY_PLAYBACK_CARD, VIRTUAL_PRIMARY_PLAYBACK_DEVICE,
+                                            flags, &apstream->pcmconfig);
+                if (apstream->pcm && !pcm_is_ready(apstream->pcm)) {
+                    /* pcm_open does always return pcm structure, not NULL */
+                    ALOGE("%s-%s: Virtual PCM Device is not ready with Sampling_Rate(%u) error(%s)!",
+                          stream_table[apstream->stream_type], __func__, apstream->pcmconfig.rate,
+                          pcm_get_error(apstream->pcm));
+                    goto err_open;
+                }
+
+                snprintf(pcm_path, sizeof(pcm_path), "/dev/snd/pcmC%uD%u%c", VIRTUAL_PRIMARY_PLAYBACK_CARD, VIRTUAL_PRIMARY_PLAYBACK_DEVICE,'p');
+                ALOGI("%s-%s: The opened Virtual PCM Device is %s with Sampling_Rate(%u) PCM_Format(%d)  PCM_start-threshold(%d) PCM_stop-threshold(%d)",
+                      stream_table[apstream->stream_type], __func__, pcm_path,
+                      apstream->pcmconfig.rate, apstream->pcmconfig.format,
+                      apstream->pcmconfig.start_threshold, apstream->pcmconfig.stop_threshold);
+
+            } else {
+                apstream->pcm = apstream->dma_pcm;
+                apstream->dma_pcm = NULL;
+            }
+
+            apstream->compress = NULL;
+
+            if (apstream->stream_type == ASTREAM_PLAYBACK_MMAP) {
+                unsigned int offset1 = 0;
+                unsigned int frames1 = 0;
+                unsigned int buf_size = 0;
+                unsigned int mmap_size = 0;
+
+                ret = pcm_mmap_begin(apstream->pcm, &info->shared_memory_address, &offset1, &frames1);
+                if (ret == 0)  {
+                    ALOGI("%s-%s: PCM Device begin MMAP", stream_table[apstream->stream_type], __func__);
+
+                    info->buffer_size_frames = pcm_get_buffer_size(apstream->pcm);
+                    buf_size = pcm_frames_to_bytes(apstream->pcm, info->buffer_size_frames);
+                    info->burst_size_frames = apstream->pcmconfig.period_size;
+                    // get mmap buffer fd
+                    ret = get_mmap_data_fd(proxy_stream, AUSAGE_PLAYBACK,
+                                                            &info->shared_memory_fd, &mmap_size);
+                    if (ret < 0) {
+                        // Fall back to poll_fd mode, shared mode
+                        info->shared_memory_fd = pcm_get_poll_fd(apstream->pcm);
+                        ALOGI("%s-%s: PCM Device MMAP Exclusive mode not support",
+                            stream_table[apstream->stream_type], __func__);
+                    } else {
+                        if (mmap_size < buf_size) {
+                            ALOGE("%s-%s: PCM Device MMAP buffer size not matching",
+                                  stream_table[apstream->stream_type], __func__);
+                            goto err_open;
+                        }
+                        // FIXME: indicate exclusive mode support by returning a negative buffer size
+                        info->buffer_size_frames *= -1;
+                    }
+
+                    memset(info->shared_memory_address, 0,
+                           pcm_frames_to_bytes(apstream->pcm, info->buffer_size_frames));
+
+                    ret = pcm_mmap_commit(apstream->pcm, 0, MMAP_PERIOD_SIZE);
+                    if (ret < 0) {
+                        ALOGE("%s-%s: PCM Device cannot commit MMAP with error(%s)",
+                              stream_table[apstream->stream_type], __func__, pcm_get_error(apstream->pcm));
+                        goto err_open;
+                    } else {
+                        ALOGI("%s-%s: PCM Device commit MMAP", stream_table[apstream->stream_type], __func__);
+                        ret = 0;
+                    }
+                } else {
+                    ALOGE("%s-%s: PCM Device cannot begin MMAP with error(%s)",
+                          stream_table[apstream->stream_type], __func__, pcm_get_error(apstream->pcm));
+                    goto err_open;
+                }
+            }
+        } else
+            ALOGW("%s-%s: PCM Device is already opened!", stream_table[apstream->stream_type], __func__);
+    }
+
+    if(aproxy->support_dualspk) {
+        if (aproxy->active_playback_device == DEVICE_EARPIECE)
+            proxy_set_mixer_value_int(aproxy, SPK_AMPL_POWER_NAME, true);
+        else
+            proxy_set_mixer_value_int(aproxy, SPK_AMPL_POWER_NAME, aproxy->spk_ampL_powerOn);
+    }
+
+    apstream->need_update_pcm_config = false;
+
+    return ret;
+
+err_open:
+    proxy_close_playback_stream(proxy_stream);
+    return -ENODEV;
+}
+
+int proxy_start_playback_stream(void *proxy_stream)
+{
+    struct audio_proxy_stream *apstream = (struct audio_proxy_stream *)proxy_stream;
+    int ret = 0;
+
+    if (apstream->stream_type == ASTREAM_PLAYBACK_COMPR_OFFLOAD) {
+        if (apstream->compress) {
+            if (apstream->nonblock_flag) {
+                compress_nonblock(apstream->compress, apstream->nonblock_flag);
+                ALOGV("%s-%s: set Nonblock mode!", stream_table[apstream->stream_type], __func__);
+            } else {
+                compress_nonblock(apstream->compress, 0);
+                ALOGV("%s-%s: set Block mode!", stream_table[apstream->stream_type], __func__);
+            }
+
+            ret = compress_start(apstream->compress);
+            if (ret == 0)
+                ALOGI("%s-%s: started Compress Device", stream_table[apstream->stream_type], __func__);
+            else
+                ALOGE("%s-%s: cannot start Compress Offload(%s)", stream_table[apstream->stream_type],
+                                               __func__, compress_get_error(apstream->compress));
+        } else
+            ret = -ENOSYS;
+    } else if (apstream->stream_type == ASTREAM_PLAYBACK_MMAP) {
+        if (apstream->pcm) {
+            ret = pcm_start(apstream->pcm);
+            if (ret == 0)
+                ALOGI("%s-%s: started MMAP Device", stream_table[apstream->stream_type], __func__);
+            else
+                ALOGE("%s-%s: cannot start MMAP device with error(%s)", stream_table[apstream->stream_type],
+                                               __func__, pcm_get_error(apstream->pcm));
+        } else
+            ret = -ENOSYS;
+    }
+
+    return ret;
+}
+
+int proxy_write_playback_buffer(void *proxy_stream, void* buffer, int bytes)
+{
+    struct audio_proxy_stream *apstream = (struct audio_proxy_stream *)proxy_stream;
+    int ret = 0, wrote = 0;
+
+    /* Skip other sounds except AUX Digital Stream when AUX_DIGITAL is connected */
+    if (apstream->stream_type != ASTREAM_PLAYBACK_AUX_DIGITAL &&
+        getInstance()->active_playback_device == DEVICE_AUX_DIGITAL) {
+        skip_pcm_processing(apstream, wrote);
+        wrote = bytes;
+        save_written_frames(apstream, wrote);
+        return wrote;
+     }
+
+    if (apstream->stream_type == ASTREAM_PLAYBACK_COMPR_OFFLOAD) {
+        if (apstream->compress) {
+            if (apstream->ready_new_metadata) {
+                compress_set_gapless_metadata(apstream->compress, &apstream->offload_metadata);
+                ALOGI("%s-%s: sent gapless metadata(delay = %u, padding = %u) to Compress Device",
+                       stream_table[apstream->stream_type], __func__,
+                       apstream->offload_metadata.encoder_delay, apstream->offload_metadata.encoder_padding);
+                apstream->ready_new_metadata = 0;
+        }
+
+            wrote = compress_write(apstream->compress, buffer, bytes);
+            ALOGVV("%s-%s: wrote Request(%u bytes) to Compress Device, and Accepted (%u bytes)",
+                    stream_table[apstream->stream_type], __func__, (unsigned int)bytes, wrote);
+        }
+    } else {
+        if (apstream->pcm) {
+            void *proc_buf_out = buffer;
+            int dst_buffer_size = bytes;
+
+            /* Direct stream volume control & channel expanding if needed */
+            if (apstream->stream_type == ASTREAM_PLAYBACK_DIRECT && apstream->need_channelpadding) {
+                unsigned int bytes_per_src_sample = audio_bytes_per_sample(apstream->requested_format);
+                unsigned int bytes_per_dst_sample = (pcm_format_to_bits(apstream->pcmconfig.format) >> 3);
+                int num_device_channels = proxy_get_actual_channel_count(apstream);
+                int num_req_channels = audio_channel_count_from_out_mask(apstream->requested_channel_mask);
+
+                int frames_num = bytes / (num_req_channels *
+                    audio_bytes_per_sample(apstream->requested_format));
+
+                /* Prepare Channel Conversion output Buffer */
+                dst_buffer_size = frames_num * num_device_channels * bytes_per_dst_sample;
+
+                if (apstream->proc_buf_size < dst_buffer_size) {
+                    apstream->proc_buf_size = dst_buffer_size;
+                    apstream->proc_buf_out = realloc(apstream->proc_buf_out, dst_buffer_size);
+                    ALOGI("%s-%s: alloc expand channel buffer with %d bytes req_channels %d device_channels %d",
+                              stream_table[apstream->stream_type], __func__, dst_buffer_size, num_req_channels, num_device_channels);
+                    ALOGI("%s-%s: Channel adjust src-channels %d to %d, bytes per sample src-bytes %d to %d ",
+                              stream_table[apstream->stream_type], __func__, num_req_channels,
+                              num_device_channels, bytes_per_src_sample, bytes_per_dst_sample);
+                }
+
+                /* Assigned allocated buffer as output buffer for channel expanding */
+                proc_buf_out = apstream->proc_buf_out;
+
+                /* Adjust channels by adding zeros to audio frame end, for Direct output stream */
+                ret = adjust_channels(buffer, num_req_channels,
+                            proc_buf_out, num_device_channels,
+                            bytes_per_src_sample, bytes);
+                if (ret != dst_buffer_size)
+                    ALOGE("%s-%s: channel convert failed", stream_table[apstream->stream_type], __func__);
+
+            }
+
+            ret = pcm_write(apstream->pcm, (void *)proc_buf_out, (unsigned int)dst_buffer_size);
+            if (ret == 0) {
+                ALOGVV("%s-%s: writed %u bytes to PCM Device", stream_table[apstream->stream_type],
+                                                               __func__, (unsigned int)bytes);
+            } else {
+                ALOGE("%s-%s: failed to write to PCM Device with %s",
+                      stream_table[apstream->stream_type], __func__, pcm_get_error(apstream->pcm));
+                skip_pcm_processing(apstream, wrote);
+            }
+            wrote = bytes;
+            save_written_frames(apstream, wrote);
+        }
+    }
+
+    return wrote;
+}
+
+int proxy_stop_playback_stream(void *proxy_stream)
+{
+    struct audio_proxy_stream *apstream = (struct audio_proxy_stream *)proxy_stream;
+    int ret = 0;
+
+    if (apstream->stream_type == ASTREAM_PLAYBACK_COMPR_OFFLOAD) {
+        if (apstream->compress) {
+            ret = compress_stop(apstream->compress);
+            if (ret == 0)
+                ALOGI("%s-%s: stopped Compress Device", stream_table[apstream->stream_type], __func__);
+            else
+                ALOGE("%s-%s: cannot stop Compress Offload(%s)", stream_table[apstream->stream_type],
+                       __func__, compress_get_error(apstream->compress));
+
+            apstream->ready_new_metadata = 1;
+        }
+    } else if (apstream->stream_type == ASTREAM_PLAYBACK_MMAP) {
+        if (apstream->pcm) {
+            ret = pcm_stop(apstream->pcm);
+            if (ret == 0)
+                ALOGI("%s-%s: stop MMAP Device", stream_table[apstream->stream_type], __func__);
+            else
+                ALOGE("%s-%s: cannot stop MMAP device with error(%s)", stream_table[apstream->stream_type],
+                                               __func__, pcm_get_error(apstream->pcm));
+        }
+    }
+
+    return ret;
+}
+
+int proxy_reconfig_playback_stream(void *proxy_stream, int type, void *config)
+{
+    struct audio_proxy_stream *apstream = (struct audio_proxy_stream *)proxy_stream;
+    audio_stream_type new_type = (audio_stream_type)type;
+    struct audio_config *new_config = (struct audio_config *)config;
+
+    if (apstream) {
+        apstream->stream_type = new_type;
+        apstream->requested_sample_rate = new_config->sample_rate;
+        apstream->requested_channel_mask = new_config->channel_mask;
+        apstream->requested_format = new_config->format;
+
+        return 0;
+    } else
+        return -1;
+}
+
+#ifdef SUPPORT_BTA2DP_OFFLOAD
+// dummy update of playback buffer for calculating presentation position
+int proxy_update_playback_buffer(void *proxy_stream, void *buffer, int bytes)
+{
+    struct audio_proxy *aproxy = getInstance();
+    struct audio_proxy_stream *apstream = (struct audio_proxy_stream *)proxy_stream;
+
+    // if bt offload on & suspend state or compr case, skip to use temp add routine
+    if ((aproxy->a2dp_out_enabled)
+            || (apstream->stream_type == ASTREAM_PLAYBACK_COMPR_OFFLOAD)) {
+        return 0;
+    }
+
+    skip_pcm_processing(apstream, 0);
+    save_written_frames(apstream, bytes);
+
+    ALOGE("%s-%s: failed to write and just update written buffer byte (%d), apstream->frames (%u)",
+          stream_table[apstream->stream_type], __func__, bytes, (unsigned int)apstream->frames);
+
+    return bytes;
+}
+
+// dummy calculation of presentation position
+int proxy_get_presen_position_temp(void *proxy_stream, uint64_t *frames, struct timespec *timestamp)
+{
+    struct audio_proxy *aproxy = getInstance();
+    struct audio_proxy_stream *apstream = (struct audio_proxy_stream *)proxy_stream;
+    int ret = -ENODATA;
+
+    if (aproxy->a2dp_out_enabled) {
+         // if bt offload on & suspend state, then get original position from hw
+         ret = proxy_get_presen_position(proxy_stream, frames, timestamp);
+    } else {
+        // use bt offload disbaled state only
+        *frames = apstream->frames;
+        clock_gettime(CLOCK_MONOTONIC, timestamp);
+        ret = 0;
+    }
+    return ret;
+}
+#endif
+
+int proxy_get_render_position(void *proxy_stream, uint32_t *frames)
+{
+    struct audio_proxy *aproxy = getInstance();
+    struct audio_proxy_stream *apstream = (struct audio_proxy_stream *)proxy_stream;
+    uint32_t presented_frames = 0;
+
+    unsigned long hw_frames;
+    unsigned int sample_rate = 0;
+    int ret = -ENODATA;
+
+    if (frames != NULL) {
+        *frames = 0;
+
+        if (apstream->stream_type == ASTREAM_PLAYBACK_COMPR_OFFLOAD) {
+            if (apstream->compress) {
+                ret = compress_get_tstamp(apstream->compress, &hw_frames, &sample_rate);
+                if (ret == 0) {
+                    ALOGVV("%s-%s: rendered frames %u with sample_rate %u",
+                           stream_table[apstream->stream_type], __func__, *frames, sample_rate);
+
+                    presented_frames = (uint32_t)hw_frames;
+#ifdef SUPPORT_BTA2DP_OFFLOAD
+                    if (aproxy->a2dp_out_enabled && is_active_playback_device_bta2dp(aproxy)) {
+                        uint32_t a2dp_delay = 0;
+                        if (aproxy->a2dp_delay > aproxy->a2dp_default_delay)
+                            a2dp_delay = aproxy->a2dp_delay;
+                        else
+                            a2dp_delay = aproxy->a2dp_default_delay;
+                        uint32_t latency_frames = (a2dp_delay *
+                                                   proxy_get_actual_sampling_rate(apstream)) / 1000;
+
+                        if (presented_frames > latency_frames)
+                            *frames = presented_frames - latency_frames;
+                        else
+                            ret = -ENODATA;
+                    } else
+#endif
+                        *frames = presented_frames;
+                } else
+                    ret = -ENODATA;
+            }
+        }
+    } else {
+        ALOGE("%s-%s: Invalid Parameter with Null pointer parameter",
+              stream_table[apstream->stream_type], __func__);
+        ret =  -EINVAL;
+    }
+
+    return ret;
+}
+
+int proxy_get_presen_position(void *proxy_stream, uint64_t *frames, struct timespec *timestamp)
+{
+    struct audio_proxy *aproxy = getInstance();
+    struct audio_proxy_stream *apstream = (struct audio_proxy_stream *)proxy_stream;
+    uint64_t presented_frames = 0;
+
+    unsigned long hw_frames;
+    unsigned int sample_rate = 0;
+    unsigned int avail = 0;
+    int ret = -ENODATA;
+
+    if (frames != NULL && timestamp != NULL) {
+        *frames = 0;
+
+        if (apstream->stream_type == ASTREAM_PLAYBACK_COMPR_OFFLOAD) {
+            if (apstream->compress) {
+                ret = compress_get_tstamp(apstream->compress, &hw_frames, &sample_rate);
+                if (ret == 0) {
+                    ALOGVV("%s-%s: presented frames %lu with sample_rate %u",
+                       stream_table[apstream->stream_type], __func__, hw_frames, sample_rate);
+
+                    presented_frames = (uint64_t)hw_frames;
+#ifdef SUPPORT_BTA2DP_OFFLOAD
+                    if (aproxy->a2dp_out_enabled && is_active_playback_device_bta2dp(aproxy)) {
+                        uint32_t a2dp_delay = 0;
+                        if (aproxy->a2dp_delay > aproxy->a2dp_default_delay)
+                            a2dp_delay = aproxy->a2dp_delay;
+                        else
+                            a2dp_delay = aproxy->a2dp_default_delay;
+                        uint32_t latency_frames = (a2dp_delay *
+                                                   proxy_get_actual_sampling_rate(apstream)) / 1000;
+
+                        if (presented_frames > latency_frames)
+                            *frames = presented_frames - latency_frames;
+                        else
+                            ret = -ENODATA;
+                    } else
+#endif
+                        *frames = presented_frames;
+
+                    clock_gettime(CLOCK_MONOTONIC, timestamp);
+                } else
+                    ret = -ENODATA;
+            }
+        } else {
+            if (apstream->pcm) {
+                ret = pcm_get_htimestamp(apstream->pcm, &avail, timestamp);
+                if (ret == 0) {
+                    // Total Frame Count in kernel Buffer
+                    uint64_t kernel_buffer_size = (uint64_t)apstream->pcmconfig.period_size *
+                                                  (uint64_t)apstream->pcmconfig.period_count;
+
+                    // Real frames which played out to device
+                    int64_t signed_frames = apstream->frames - kernel_buffer_size + avail;
+                    if (signed_frames >= 0) {
+                        presented_frames = (uint64_t)signed_frames;
+#ifdef SUPPORT_BTA2DP_OFFLOAD
+                        if (aproxy->a2dp_out_enabled && is_active_playback_device_bta2dp(aproxy)) {
+                            uint32_t a2dp_delay = 0;
+                            if (aproxy->a2dp_delay > aproxy->a2dp_default_delay)
+                                a2dp_delay = aproxy->a2dp_delay;
+                            else
+                                a2dp_delay = aproxy->a2dp_default_delay;
+                            uint32_t latency_frames = (a2dp_delay *
+                                                  proxy_get_actual_sampling_rate(apstream)) / 1000;
+
+                            if (presented_frames > latency_frames)
+                                *frames = presented_frames - latency_frames;
+                            else
+                                ret = -ENODATA;
+                        } else
+#endif
+                            *frames = presented_frames;
+                    } else {
+                        ret = -ENODATA;
+                    }
+                } else {
+                    ret = -ENODATA;
+                }
+            }
+        }
+    } else {
+        ALOGE("%s-%s: Invalid Parameter with Null pointer parameter",
+              stream_table[apstream->stream_type], __func__);
+        ret =  -EINVAL;
+    }
+
+    return ret;
+}
+
+int proxy_getparam_playback_stream(void *proxy_stream, void *query_params, void *reply_params)
+{
+    struct audio_proxy_stream *apstream = (struct audio_proxy_stream *)proxy_stream;
+    struct audio_proxy *aproxy = getInstance();
+    struct str_parms *query = (struct str_parms *)query_params;
+    struct str_parms *reply = (struct str_parms *)reply_params;
+
+    if (apstream->stream_type == ASTREAM_PLAYBACK_NO_ATTRIBUTE &&
+        proxy_is_usb_playback_device_connected(aproxy->usb_aproxy)) {
+        // get USB playback param information
+        proxy_usb_getparam_playback_stream(aproxy->usb_aproxy, query, reply);
+    } else {
+        /*
+         * Supported Audio Configuration can be different as Target Project.
+         * AudioHAL engineers have to modify these codes based on Target Project.
+         */
+        // supported audio formats
+        if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_FORMATS)) {
+            char formats_list[256];
+
+            memset(formats_list, 0, 256);
+            strncpy(formats_list, stream_format_table[apstream->stream_type],
+                           strlen(stream_format_table[apstream->stream_type]));
+            str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_SUP_FORMATS, formats_list);
+        }
+
+        // supported audio channel masks
+        if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_CHANNELS)) {
+            char channels_list[256];
+
+            memset(channels_list, 0, 256);
+            strncpy(channels_list, stream_channel_table[apstream->stream_type],
+                            strlen(stream_channel_table[apstream->stream_type]));
+            str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_SUP_CHANNELS, channels_list);
+        }
+
+        // supported audio samspling rates
+        if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES)) {
+            char rates_list[256];
+
+            memset(rates_list, 0, 256);
+            strncpy(rates_list, stream_rate_table[apstream->stream_type],
+                         strlen(stream_rate_table[apstream->stream_type]));
+            str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES, rates_list);
+        }
+    }
+
+    return 0;
+}
+
+int proxy_setparam_playback_stream(void *proxy_stream, void *parameters)
+{
+    struct audio_proxy_stream *apstream = (struct audio_proxy_stream *)proxy_stream;
+    struct str_parms *parms = (struct str_parms *)parameters;
+
+    char value[32];
+    int ret = 0;
+
+    if (apstream->stream_type == ASTREAM_PLAYBACK_COMPR_OFFLOAD) {
+        struct compr_gapless_mdata tmp_mdata;
+        bool need_to_set_metadata = false;
+
+        tmp_mdata.encoder_delay = 0;
+        tmp_mdata.encoder_padding = 0;
+
+        ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_DELAY_SAMPLES, value, sizeof(value));
+        if (ret >= 0) {
+            tmp_mdata.encoder_delay = atoi(value);
+            ALOGI("%s-%s: Codec Delay Samples(%u)", stream_table[apstream->stream_type], __func__,
+                                                    tmp_mdata.encoder_delay);
+            need_to_set_metadata = true;
+        }
+
+        ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_PADDING_SAMPLES, value, sizeof(value));
+        if (ret >= 0) {
+            tmp_mdata.encoder_padding = atoi(value);
+            ALOGI("%s-%s: Codec Padding Samples(%u)", stream_table[apstream->stream_type], __func__,
+                                                      tmp_mdata.encoder_padding);
+            need_to_set_metadata = true;
+        }
+
+        if (need_to_set_metadata) {
+            apstream->offload_metadata = tmp_mdata;
+            apstream->ready_new_metadata = 1;
+        }
+    }
+
+    return ret;
+}
+
+uint32_t proxy_get_playback_latency(void *proxy_stream)
+{
+    struct audio_proxy_stream *apstream = (struct audio_proxy_stream *)proxy_stream;
+    uint32_t latency;
+
+    // Total Latency = ALSA Buffer latency + HW Latency
+    if (apstream->stream_type == ASTREAM_PLAYBACK_COMPR_OFFLOAD) {
+        /*
+         * Offload HW latency
+         * - A-Box firmware triggers offload play once two buffers of 20msec each are decoded - 20msec
+         * - Post processing of decoded data - 10 msec
+         * - 20msec extra is provided considering scheduling delays
+         * therefore total offload HW latency will 50msec
+         */
+        latency = 50;
+    } else {
+        latency = (apstream->pcmconfig.period_count * apstream->pcmconfig.period_size * 1000) / (apstream->pcmconfig.rate);
+        latency += 0;   // Need to check HW Latency
+    }
+
+    return latency;
+}
+
+// select best pcmconfig among requested two configs
+bool proxy_select_best_playback_pcmconfig(
+    void *proxy,
+    void *cur_proxy_stream,
+    int compr_upscaler)
+{
+    struct audio_proxy *aproxy = proxy;
+    struct audio_proxy_stream *cur_apstream = (struct audio_proxy_stream *)cur_proxy_stream;
+
+    /* need to update compress stream's dummy pcmconfig based upon upscaler value
+     * before selecting best pcmconfig
+     * compress offload-upscaler values are defined as shown
+     * 0: 48KHz, 16bit
+     * 1: 192KHz, 24bit
+     * 2: 48KHz, 24bit
+     */
+    if (cur_apstream->stream_type == ASTREAM_PLAYBACK_COMPR_OFFLOAD) {
+        if (compr_upscaler == 2)
+            cur_apstream->pcmconfig = pcm_config_deep_playback;
+        else if (compr_upscaler == 1)
+            cur_apstream->pcmconfig = pcm_config_deep_playback_uhqa;
+        else
+            cur_apstream->pcmconfig = pcm_config_primary_playback;
+
+        ALOGI("%s-%s: upscaler: %d pcmconfig rate[%d] format[%d]",
+            stream_table[cur_apstream->stream_type], __func__, compr_upscaler,
+            cur_apstream->pcmconfig.rate, cur_apstream->pcmconfig.format);
+    }
+
+    return proxy_usb_out_pick_best_pcmconfig(aproxy->usb_aproxy, cur_apstream->pcmconfig);
+}
+
+/* selecting best playback pcm config to configure USB device */
+void proxy_set_best_playback_pcmconfig(void *proxy, void *proxy_stream)
+{
+    struct audio_proxy *aproxy = proxy;
+    struct audio_proxy_stream *apstream = (struct audio_proxy_stream *)proxy_stream;
+    bool reprepare_needed = false;
+
+    if (!aproxy->usb_aproxy) {
+        ALOGI("%s-%s: USB audio offload is not initialized",
+            stream_table[apstream->stream_type], __func__);
+        return;
+    }
+
+    /* update & check whether USB device re-configuraiton is required for best config */
+    reprepare_needed = proxy_usb_out_reconfig_needed(aproxy->usb_aproxy);
+
+    if ((aproxy->active_playback_device == DEVICE_USB_HEADSET
+        || aproxy->active_playback_device == DEVICE_SPEAKER_AND_USB_HEADSET)
+        && !aproxy->is_usb_single_clksrc && !is_usage_CPCall(aproxy->active_playback_ausage)
+        && reprepare_needed) {
+        /* steps for re-configuring USB device configuration
+         * - Close WDMA6 & usb out pcm,
+         * - prepare usb for new config,
+         * - modify sifs0 setting to new selected PCM config
+         * - open wdma6 & usb out pcm
+         */
+        /* close loopback and USB pcm nodes */
+        disable_usb_out_loopback(aproxy);
+        proxy_usb_close_out_proxy(aproxy->usb_aproxy);
+
+        /* Prepare USB device for new configuraiton */
+        proxy_usb_playback_prepare(aproxy->usb_aproxy, true);
+        set_usb_playback_modifier(aproxy);
+
+        /* re-open loopback and USB pcm nodes */
+        proxy_usb_open_out_proxy(aproxy->usb_aproxy);
+        enable_usb_out_loopback(aproxy);
+        ALOGI("%s-%s: USB Device re-configured",
+            stream_table[apstream->stream_type], __func__);
+    }
+
+    return;
+}
+
+/* reset playback pcm config for USB device default */
+void proxy_reset_playback_pcmconfig(void *proxy)
+{
+    struct audio_proxy *aproxy = proxy;
+
+    /* reset USB playback config to default values */
+    proxy_usb_out_reset_config(aproxy->usb_aproxy);
+
+    return;
+}
+
+void proxy_dump_playback_stream(void *proxy_stream, int fd)
+{
+    struct audio_proxy_stream *apstream = (struct audio_proxy_stream *)proxy_stream;
+
+    const size_t len = 256;
+    char buffer[len];
+
+    if (apstream->pcm != NULL) {
+        snprintf(buffer, len, "\toutput pcm config sample rate: %d\n",apstream->pcmconfig.rate);
+        write(fd,buffer,strlen(buffer));
+        snprintf(buffer, len, "\toutput pcm config period size : %d\n",apstream->pcmconfig.period_size);
+        write(fd,buffer,strlen(buffer));
+        snprintf(buffer, len, "\toutput pcm config format: %d\n",apstream->pcmconfig.format);
+        write(fd,buffer,strlen(buffer));
+    }
+
+    if (apstream->compress != NULL) {
+        if (apstream->comprconfig.codec != NULL) {
+            snprintf(buffer, len, "\toutput offload codec id: %d\n",apstream->comprconfig.codec->id);
+            write(fd,buffer,strlen(buffer));
+            snprintf(buffer, len, "\toutput offload codec input channel: %d\n",apstream->comprconfig.codec->ch_in);
+            write(fd,buffer,strlen(buffer));
+            snprintf(buffer, len, "\toutput offload codec output channel: %d\n",apstream->comprconfig.codec->ch_out);
+            write(fd,buffer,strlen(buffer));
+            snprintf(buffer, len, "\toutput offload sample rate: %d\n",apstream->comprconfig.codec->sample_rate);
+            write(fd,buffer,strlen(buffer));
+            snprintf(buffer, len, "\toutput offload bit rate : %d\n",apstream->comprconfig.codec->bit_rate);
+            write(fd,buffer,strlen(buffer));
+            snprintf(buffer, len, "\toutput offload config format: %d\n",apstream->comprconfig.codec->format);
+            write(fd,buffer,strlen(buffer));
+        }
+
+        snprintf(buffer, len, "\tOffload Fragment Size: %d\n",apstream->comprconfig.fragment_size);
+        write(fd,buffer,strlen(buffer));
+        snprintf(buffer, len, "\tOffload Fragments: %d\n",apstream->comprconfig.fragments);
+        write(fd,buffer,strlen(buffer));
+    }
+
+    return ;
+}
+
+
+void *proxy_create_capture_stream(void *proxy, int type, int usage, void *config, char *address __unused)
+{
+    struct audio_proxy *aproxy = proxy;
+    audio_stream_type stream_type = (audio_stream_type)type;
+    audio_usage       stream_usage = (audio_usage)usage;
+    struct audio_config *requested_config = (struct audio_config *)config;
+
+    struct audio_proxy_stream *apstream;
+
+    apstream = (struct audio_proxy_stream *)calloc(1, sizeof(struct audio_proxy_stream));
+    if (!apstream) {
+        ALOGE("proxy-%s: failed to allocate memory for Proxy Stream", __func__);
+        return NULL;;
+    }
+
+    /* Stores the requested configurationss */
+    apstream->requested_sample_rate = requested_config->sample_rate;
+    apstream->requested_channel_mask = requested_config->channel_mask;
+    apstream->requested_format = requested_config->format;
+
+    apstream->stream_type = stream_type;
+    apstream->stream_usage = stream_usage;
+
+    // Initialize Post-Processing
+    apstream->need_channelconversion = false;
+    apstream->need_resampling = false;
+
+    apstream->actual_read_buf = NULL;
+    apstream->actual_read_buf_size = 0;
+
+    apstream->proc_buf_out = NULL;
+    apstream->proc_buf_size = 0;
+
+    apstream->resampler = NULL;
+
+    apstream->need_update_pcm_config = false;
+    apstream->skip_ch_convert = false;
+
+    /* Sets basic configuration from Stream Type. */
+    switch (apstream->stream_type) {
+        // For VTS
+        case ASTREAM_CAPTURE_NO_ATTRIBUTE:
+            apstream->sound_card = PRIMARY_CAPTURE_CARD;
+            apstream->sound_device = PRIMARY_CAPTURE_DEVICE;
+            apstream->pcmconfig = pcm_config_primary_capture;
+
+            break;
+
+        case ASTREAM_CAPTURE_PRIMARY:
+            apstream->sound_card = PRIMARY_CAPTURE_CARD;
+            apstream->sound_device = get_pcm_device_number(aproxy, apstream);
+#ifdef SUPPORT_QUAD_MIC
+            if (((is_active_usage_CPCall(aproxy) && aproxy->active_capture_ausage != AUSAGE_CALL_FORWARDING_PRIMARY
+                && aproxy->active_capture_ausage != AUSAGE_SPECTRO)
+                || is_active_usage_APCall(aproxy)
+                || apstream->stream_usage == AUSAGE_CAMCORDER)
+                && is_quad_mic_device(aproxy->active_capture_device)) {
+                apstream->pcmconfig = pcm_config_primary_quad_mic_capture;
+                ALOGE("proxy-%s: Primary reconfig as Quad-Mic", __func__);
+            } else
+#endif
+                apstream->pcmconfig = pcm_config_primary_capture;
+
+            update_capture_pcmconfig(apstream);
+            check_conversion(apstream);
+            break;
+
+        case ASTREAM_CAPTURE_CALL:
+            apstream->sound_card = CALL_RECORD_CARD;
+            apstream->sound_device = get_pcm_device_number(aproxy, apstream);
+            apstream->pcmconfig = pcm_config_call_record;
+
+            check_conversion(apstream);
+            break;
+
+        case ASTREAM_CAPTURE_TELEPHONYRX:
+            apstream->sound_card = TELERX_RECORD_CARD;
+            apstream->sound_device = get_pcm_device_number(aproxy, apstream);
+            apstream->pcmconfig = pcm_config_call_record;
+
+            check_conversion(apstream);
+            break;
+
+        case ASTREAM_CAPTURE_LOW_LATENCY:
+            apstream->sound_card = LOW_CAPTURE_CARD;
+            apstream->sound_device = get_pcm_device_number(aproxy, apstream);
+            apstream->pcmconfig = pcm_config_low_capture;
+
+            update_capture_pcmconfig(apstream);
+            check_conversion(apstream);
+            break;
+
+        case ASTREAM_CAPTURE_MMAP:
+            apstream->sound_card = MMAP_CAPTURE_CARD;
+            apstream->sound_device = get_pcm_device_number(aproxy, apstream);
+            apstream->pcmconfig = pcm_config_mmap_capture;
+
+            /* update HW PCM configuration with requested config, as MMAP usage cann't
+                use software conversions for sample rate and channels, format is fixed to
+                16bit */
+            if (apstream->requested_sample_rate != apstream->pcmconfig.rate) {
+                apstream->pcmconfig.rate = apstream->requested_sample_rate;
+                // Adjust period_size according to sample rate
+                apstream->pcmconfig.period_size = (apstream->pcmconfig.rate * PREDEFINED_MMAP_CAPTURE_DURATION) / 1000;
+
+                // WDMA in A-Box is 128-bit aligned, so period_size has to be multiple of 4 frames
+                apstream->pcmconfig.period_size &= 0xFFFFFFFC;
+                ALOGD("%s-%s: updates samplig rate to %u, period_size to %u",
+                    stream_table[apstream->stream_type], __func__,
+                    apstream->pcmconfig.rate, apstream->pcmconfig.period_size);
+            }
+
+            if (audio_channel_count_from_in_mask(apstream->requested_channel_mask)
+                != apstream->pcmconfig.channels) {
+                apstream->pcmconfig.channels = audio_channel_count_from_in_mask(apstream->requested_channel_mask);
+                ALOGD("%s-%s: updates channel count to %u", stream_table[apstream->stream_type],
+                                                            __func__, apstream->pcmconfig.channels);
+            }
+            break;
+
+        case ASTREAM_CAPTURE_FM:
+            apstream->sound_card = FM_RECORD_CARD;
+            apstream->sound_device = get_pcm_device_number(aproxy, apstream);
+            apstream->pcmconfig = pcm_config_fm_record;
+
+            check_conversion(apstream);
+            break;
+
+#ifdef SUPPORT_STHAL_INTERFACE
+        case ASTREAM_CAPTURE_HOTWORD:
+            apstream->pcmconfig = pcm_config_hotword_capture;
+            break;
+#endif
+
+        default:
+            ALOGE("proxy-%s: failed to open Proxy Stream as unknown stream type(%d)", __func__,
+                                                                          apstream->stream_type);
+            goto err_open;
+    }
+
+    apstream->pcm = NULL;
+    apstream->compress = NULL;
+
+    ALOGI("proxy-%s: opened Proxy Stream(%s)", __func__, stream_table[apstream->stream_type]);
+    return (void *)apstream;
+
+err_open:
+    free(apstream);
+    return NULL;
+}
+
+void proxy_destroy_capture_stream(void *proxy_stream)
+{
+    struct audio_proxy_stream *apstream = (struct audio_proxy_stream *)proxy_stream;
+
+    if (apstream) {
+        if (apstream->resampler) {
+            ALOGV("%s-%s: released resampler", stream_table[apstream->stream_type], __func__);
+            release_resampler(apstream->resampler);
+        }
+
+        if (apstream->actual_read_buf)
+            free(apstream->actual_read_buf);
+
+        if (apstream->proc_buf_out)
+            free(apstream->proc_buf_out);
+
+        free(apstream);
+    }
+
+    return ;
+}
+
+int proxy_close_capture_stream(void *proxy_stream)
+{
+    struct audio_proxy_stream *apstream = (struct audio_proxy_stream *)proxy_stream;
+    struct audio_proxy *aproxy = getInstance();
+    int ret = 0;
+
+#ifdef SUPPORT_STHAL_INTERFACE
+    /* Handle HOTWORD soure separately */
+    if (apstream->stream_type == ASTREAM_CAPTURE_HOTWORD) {
+        if (aproxy->sound_trigger_close_for_streaming) {
+            if (apstream->soundtrigger_handle > 0) {
+                if (apstream->stream_usage == AUSAGE_HOTWORD_SEAMLESS) {
+                    aproxy->sound_trigger_close_for_streaming(apstream->soundtrigger_handle);
+                } else {
+                    aproxy->sound_trigger_close_recording(apstream->soundtrigger_handle);
+                }
+            }
+
+            apstream->soundtrigger_handle = 0;
+#ifdef SEAMLESS_DUMP
+            if (apstream->fp)
+                fclose(apstream->fp);
+#endif
+            ALOGI("VTS PCM Node closed");
+        } else {
+            ALOGE("%s-%s: SoundTrigger HAL Close function Not available!",
+                                    stream_table[apstream->stream_type], __func__);
+            ret = -EIO;
+        }
+
+        return ret;
+    }
+#endif
+
+    /* Close Normal PCM Device */
+    if (apstream->pcm) {
+        ret = pcm_close(apstream->pcm);
+        apstream->pcm = NULL;
+    }
+    if (apstream->dma_pcm) {
+        pcm_close(apstream->dma_pcm);
+        apstream->dma_pcm = NULL;
+    }
+    ALOGI("%s-%s: closed PCM Device", stream_table[apstream->stream_type], __func__);
+
+    return ret;
+}
+
+int proxy_open_capture_stream(void *proxy_stream, int32_t min_size_frames, void *mmap_info)
+{
+    struct audio_proxy_stream *apstream = (struct audio_proxy_stream *)proxy_stream;
+    struct audio_proxy *aproxy = getInstance();
+    struct audio_mmap_buffer_info *info = (struct audio_mmap_buffer_info *)mmap_info;
+    unsigned int sound_card;
+    unsigned int sound_device;
+    unsigned int flags;
+    int ret = 0;
+    char pcm_path[MAX_PCM_PATH_LEN];
+
+#ifdef SUPPORT_STHAL_INTERFACE
+    /* Handle HOTWORD soure separately */
+    if (apstream->stream_type == ASTREAM_CAPTURE_HOTWORD) {
+        if (aproxy->sound_trigger_open_for_streaming) {
+            if (apstream->stream_usage == AUSAGE_HOTWORD_SEAMLESS) {
+                apstream->soundtrigger_handle = aproxy->sound_trigger_open_for_streaming();
+            } else {
+                apstream->soundtrigger_handle = aproxy->sound_trigger_open_recording();
+            }
+            if (apstream->soundtrigger_handle <= 0) {
+                ALOGE("%s: Failed to open VTS PCM Node for streaming", __func__);
+                ret = -EIO;
+                goto err_open;
+            }
+#ifdef SEAMLESS_DUMP
+            apstream->fp = fopen("/data/seamdump.raw", "wr+");
+            if (!apstream->fp)
+                ALOGI("failed to open /data/seamdump.raw");
+#endif
+            ALOGI("Opened VTS PCM Node successfully");
+        } else {
+            ALOGE("%s-%s: SoundTrigger HAL Open function Not available!",
+                        stream_table[apstream->stream_type], __func__);
+            ret = -EIO;
+        }
+
+        apstream->need_update_pcm_config = false;
+
+        return ret;
+    }
+#endif
+
+    if (is_active_usage_APCall(aproxy) && apstream->pcmconfig.rate != 48000) {
+        apstream->sound_card = PRIMARY_CAPTURE_CARD;
+        apstream->sound_device = get_pcm_device_number(aproxy, apstream);
+        apstream->pcmconfig = pcm_config_primary_capture;
+
+        check_conversion(apstream);
+    }
+
+    /* Get PCM Device */
+    sound_card = apstream->sound_card;
+    sound_device = apstream->sound_device;
+
+    /* Open Normal PCM Device */
+    if (apstream->pcm == NULL) {
+        if (apstream->stream_type == ASTREAM_CAPTURE_MMAP) {
+            flags = PCM_IN | PCM_MMAP | PCM_NOIRQ | PCM_MONOTONIC;
+
+            adjust_mmap_period_count(apstream, &apstream->pcmconfig, min_size_frames);
+        } else
+            flags = PCM_IN | PCM_MONOTONIC;
+
+        /* open WDMA pcm first to trigger DMA */
+        apstream->dma_pcm = pcm_open(sound_card, sound_device, flags, &apstream->pcmconfig);
+        if (apstream->dma_pcm && !pcm_is_ready(apstream->dma_pcm)) {
+            /* pcm_open does always return pcm structure, not NULL */
+            ALOGE("%s-%s: PCM Device is not ready with Sampling_Rate(%u) error(%s)!",
+                  stream_table[apstream->stream_type], __func__, apstream->pcmconfig.rate,
+                  pcm_get_error(apstream->dma_pcm));
+            goto err_open;
+        }
+
+        snprintf(pcm_path, sizeof(pcm_path), "/dev/snd/pcmC%uD%u%c", sound_card, sound_device, 'c');
+
+        ALOGI("%s-%s: The opened PCM Device is %s with Sampling_Rate(%u) PCM_Format(%d) Channel(%d)",
+              stream_table[apstream->stream_type], __func__, pcm_path,
+              apstream->pcmconfig.rate, apstream->pcmconfig.format, apstream->pcmconfig.channels);
+
+        /* Virtual dai PCM is required only for normal capture */
+        if (apstream->stream_type != ASTREAM_CAPTURE_LOW_LATENCY &&
+            apstream->stream_type != ASTREAM_CAPTURE_CALL &&
+            apstream->stream_type != ASTREAM_CAPTURE_FM &&
+            apstream->stream_type != ASTREAM_CAPTURE_MMAP &&
+            apstream->stream_type != ASTREAM_CAPTURE_TELEPHONYRX) {
+            /* WDMA pcm should be started before opening virtual pcm */
+            if (pcm_start(apstream->dma_pcm) == 0) {
+                ALOGI("proxy-%s: PCM Device(%s) with SR(%u) PF(%d) CC(%d) is started",
+                      __func__, pcm_path, apstream->pcmconfig.rate, apstream->pcmconfig.format, apstream->pcmconfig.channels);
+            } else {
+                ALOGE("proxy-%s: PCM Device(%s) with SR(%u) PF(%d) CC(%d) cannot be started as error(%s)",
+                      __func__, pcm_path, apstream->pcmconfig.rate, apstream->pcmconfig.format, apstream->pcmconfig.channels,
+                      pcm_get_error(apstream->dma_pcm));
+                goto err_open;
+            }
+
+            apstream->pcm = pcm_open(VIRTUAL_PRIMARY_CAPTURE_CARD, VIRTUAL_PRIMARY_CAPTURE_DEVICE, flags, &apstream->pcmconfig);
+            if (apstream->pcm && !pcm_is_ready(apstream->pcm)) {
+                /* pcm_open does always return pcm structure, not NULL */
+                ALOGE("%s-%s: Virtual PCM Device is not ready with Sampling_Rate(%u) error(%s)!",
+                      stream_table[apstream->stream_type], __func__, apstream->pcmconfig.rate,
+                      pcm_get_error(apstream->pcm));
+                goto err_open;
+            }
+
+            snprintf(pcm_path, sizeof(pcm_path), "/dev/snd/pcmC%uD%u%c", VIRTUAL_PRIMARY_CAPTURE_CARD, VIRTUAL_PRIMARY_CAPTURE_DEVICE, 'c');
+            ALOGI("%s-%s: The opened Virtual PCM Device is %s with Sampling_Rate(%u) PCM_Format(%d) Channel(%d)",
+                  stream_table[apstream->stream_type], __func__, pcm_path,
+                  apstream->pcmconfig.rate, apstream->pcmconfig.format, apstream->pcmconfig.channels);
+        } else {
+            apstream->pcm = apstream->dma_pcm;
+            apstream->dma_pcm = NULL;
+        }
+
+        apstream->compress = NULL;
+
+        if (apstream->stream_type == ASTREAM_CAPTURE_MMAP) {
+            unsigned int offset1 = 0;
+            unsigned int frames1 = 0;
+            unsigned int buf_size = 0;
+            unsigned int mmap_size = 0;
+
+            ret = pcm_mmap_begin(apstream->pcm, &info->shared_memory_address, &offset1, &frames1);
+            if (ret == 0)  {
+                ALOGI("%s-%s: PCM Device begin MMAP", stream_table[apstream->stream_type], __func__);
+
+                info->buffer_size_frames = pcm_get_buffer_size(apstream->pcm);
+                buf_size = pcm_frames_to_bytes(apstream->pcm, info->buffer_size_frames);
+                info->burst_size_frames = apstream->pcmconfig.period_size;
+                // get mmap buffer fd
+                ret = get_mmap_data_fd(proxy_stream, AUSAGE_CAPTURE,
+                                                        &info->shared_memory_fd, &mmap_size);
+                if (ret < 0) {
+                    // Fall back to poll_fd mode, shared mode
+                    info->shared_memory_fd = pcm_get_poll_fd(apstream->pcm);
+                    ALOGI("%s-%s: PCM Device MMAP Exclusive mode not support",
+                        stream_table[apstream->stream_type], __func__);
+                } else {
+                    if (mmap_size < buf_size) {
+                        ALOGE("%s-%s: PCM Device MMAP buffer size not matching",
+                              stream_table[apstream->stream_type], __func__);
+                        goto err_open;
+                    }
+                    // FIXME: indicate exclusive mode support by returning a negative buffer size
+                    info->buffer_size_frames *= -1;
+                }
+
+                memset(info->shared_memory_address, 0,
+                       pcm_frames_to_bytes(apstream->pcm, info->buffer_size_frames));
+
+                ret = pcm_mmap_commit(apstream->pcm, 0, MMAP_PERIOD_SIZE);
+                if (ret < 0) {
+                    ALOGE("%s-%s: PCM Device cannot commit MMAP with error(%s)",
+                          stream_table[apstream->stream_type], __func__, pcm_get_error(apstream->pcm));
+                    goto err_open;
+                } else {
+                    ALOGI("%s-%s: PCM Device commit MMAP", stream_table[apstream->stream_type], __func__);
+                    ret = 0;
+                }
+            } else {
+                ALOGE("%s-%s: PCM Device cannot begin MMAP with error(%s)",
+                      stream_table[apstream->stream_type], __func__, pcm_get_error(apstream->pcm));
+                goto err_open;
+            }
+        }
+
+        /* HACK for MMAP/Low-latency capture path routing, normal recording uses virtualPCM DAI
+        * firmware component but MMAP/Low-latency case for reducing latency we have to capture
+        * data directly from WDMA, therefore VirtualPCM DAI is disabled after routing */
+        if (apstream->stream_type == ASTREAM_CAPTURE_MMAP ||
+            apstream->stream_type == ASTREAM_CAPTURE_LOW_LATENCY) {
+            proxy_set_mixer_value_string(aproxy, MIXER_CTL_ABOX_CATPURE_VPCMDAI_INSRC, "None");
+            ALOGI("%s-%s: MMAP VPCMIN_DAI0 component disconnect forcefully",
+                        stream_table[apstream->stream_type], __func__);
+        }
+    } else
+        ALOGW("%s-%s: PCM Device is already opened!", stream_table[apstream->stream_type], __func__);
+
+    apstream->need_update_pcm_config = false;
+
+    return ret;
+
+err_open:
+    proxy_close_capture_stream(proxy_stream);
+    return -ENODEV;
+}
+
+int proxy_start_capture_stream(void *proxy_stream)
+{
+    struct audio_proxy_stream *apstream = (struct audio_proxy_stream *)proxy_stream;
+    int ret = 0;
+
+#ifdef SUPPORT_STHAL_INTERFACE
+    /* Handle HOTWORD soure separately */
+    if (apstream->stream_type == ASTREAM_CAPTURE_HOTWORD)
+        return ret;
+#endif
+
+    // In case of PCM Playback, pcm_start call is not needed as auto-start
+    if (apstream->pcm) {
+        ret = pcm_start(apstream->pcm);
+        if (ret == 0)
+            ALOGI("%s-%s: started PCM Device", stream_table[apstream->stream_type], __func__);
+        else
+            ALOGE("%s-%s: cannot start PCM(%s)", stream_table[apstream->stream_type], __func__,
+                                                 pcm_get_error(apstream->pcm));
+    }
+
+    return ret;
+}
+
+int proxy_read_capture_buffer(void *proxy_stream, void *buffer, int bytes)
+{
+    struct audio_proxy_stream *apstream = (struct audio_proxy_stream *)proxy_stream;
+    int frames_request = bytes / proxy_get_requested_frame_size(apstream);
+    int frames_actual = -1;
+
+    if (apstream->skip_ch_convert) {
+        frames_request = bytes / (proxy_get_actual_channel_count(apstream) *
+                            audio_bytes_per_sample(apstream->requested_format));
+    }
+
+#ifdef SUPPORT_STHAL_INTERFACE
+    int ret = 0, read = 0;
+    struct audio_proxy *aproxy = getInstance();
+    if (apstream->stream_type == ASTREAM_CAPTURE_HOTWORD) {
+        if (aproxy->sound_trigger_read_samples) {
+            if (apstream->soundtrigger_handle > 0) {
+                if (apstream->stream_usage == AUSAGE_HOTWORD_SEAMLESS) {
+                    ret = aproxy->sound_trigger_read_samples(apstream->soundtrigger_handle,
+                                                                        buffer, bytes);
+                } else {
+                    ret = aproxy->sound_trigger_read_recording_samples(buffer, bytes);
+                }
+
+                if (!ret) {
+                    read = bytes;
+#ifdef SEAMLESS_DUMP
+                    if (apstream->fp ) {
+                        fwrite((void*)buffer, bytes, 1, apstream->fp);
+                        ALOGE("Model binary /data/seamdump.raw write completed");
+                    } else
+                        ALOGE("Error opening /sdcard/seamdump.raw");
+#endif
+                }
+            }
+        } else {
+            ALOGE("%s-%s: SoundTrigger HAL Read function Not available!",
+                        stream_table[apstream->stream_type], __func__);
+        }
+
+        return read;
+    } else
+#endif
+    {
+        frames_actual = read_and_process_frames(apstream, buffer, frames_request);
+        ALOGVV("%s-%s: requested read frames = %d vs. actual processed read frames = %d",
+               stream_table[apstream->stream_type], __func__, frames_request, frames_actual);
+    }
+
+    if (frames_actual < 0) {
+        return frames_actual;
+    } else {
+        /* Saves read frames to calcurate timestamp */
+        apstream->frames += frames_actual;
+        ALOGVV("%s-%s: cumulative read = %u frames", stream_table[apstream->stream_type], __func__,
+                                          (unsigned int)apstream->frames);
+        return bytes;
+    }
+}
+
+int proxy_stop_capture_stream(void *proxy_stream)
+{
+    struct audio_proxy_stream *apstream = (struct audio_proxy_stream *)proxy_stream;
+    int ret = 0;
+
+#ifdef SUPPORT_STHAL_INTERFACE
+    /* Handle HOTWORD soure separately */
+    if (apstream->stream_type == ASTREAM_CAPTURE_HOTWORD)
+        return ret;
+#endif
+
+    if (apstream->pcm) {
+        ret = pcm_stop(apstream->pcm);
+        if (ret == 0)
+            ALOGI("%s-%s: stopped PCM Device", stream_table[apstream->stream_type], __func__);
+        else
+            ALOGE("%s-%s: cannot stop PCM(%s)", stream_table[apstream->stream_type], __func__,
+                                                pcm_get_error(apstream->pcm));
+    }
+
+    return ret;
+}
+
+int proxy_reconfig_capture_stream(void *proxy_stream, int type, void *config)
+{
+    struct audio_proxy_stream *apstream = (struct audio_proxy_stream *)proxy_stream;
+    audio_stream_type new_type = (audio_stream_type)type;
+    struct audio_config *new_config = (struct audio_config *)config;
+
+    if (apstream) {
+        apstream->stream_type = new_type;
+        apstream->requested_sample_rate = new_config->sample_rate;
+        apstream->requested_channel_mask = new_config->channel_mask;
+        apstream->requested_format = new_config->format;
+
+        // If some stream types need to be reset, it has to reconfigure conversions
+
+        return 0;
+    } else
+        return -1;
+}
+
+int proxy_reconfig_capture_usage(void *proxy_stream, int type, int usage)
+{
+    struct audio_proxy_stream *apstream = (struct audio_proxy_stream *)proxy_stream;
+
+    if (apstream == NULL)
+        return -1;
+
+    struct audio_proxy *aproxy = getInstance();
+    audio_stream_type stream_type = (audio_stream_type)type;
+    audio_usage       stream_usage = (audio_usage)usage;
+
+    if (stream_usage != AUSAGE_NONE)
+        apstream->stream_usage = stream_usage;
+
+     switch (stream_type) {
+        case ASTREAM_CAPTURE_PRIMARY:
+            apstream->stream_type = stream_type;
+            apstream->sound_card = PRIMARY_CAPTURE_CARD;
+            apstream->sound_device = get_pcm_device_number(aproxy, apstream);
+
+#ifdef SUPPORT_QUAD_MIC
+            if (((is_active_usage_CPCall(aproxy) && aproxy->active_capture_ausage != AUSAGE_CALL_FORWARDING_PRIMARY
+                && aproxy->active_capture_ausage != AUSAGE_SPECTRO)
+                || is_active_usage_APCall(aproxy)
+                || apstream->stream_usage == AUSAGE_CAMCORDER)
+                && is_quad_mic_device(aproxy->active_capture_device)) {
+                apstream->pcmconfig = pcm_config_primary_quad_mic_capture;
+                ALOGE("proxy-%s: Primary reconfig as Quad-Mic", __func__);
+            } else
+#endif
+                apstream->pcmconfig = pcm_config_primary_capture;
+
+            update_capture_pcmconfig(apstream);
+
+            /*
+            ** Reset previous configurations and release resampler if running
+            ** for reconfiguration purpose
+            */
+            apstream->need_channelconversion = false;
+            if (apstream->resampler) {
+                ALOGI("%s-%s: released resampler", stream_table[apstream->stream_type], __func__);
+                release_resampler(apstream->resampler);
+                apstream->resampler = NULL;
+            }
+
+            check_conversion(apstream);
+            break;
+
+        case ASTREAM_CAPTURE_CALL:
+            apstream->stream_type = stream_type;
+            apstream->sound_card = CALL_RECORD_CARD;
+            apstream->sound_device = get_pcm_device_number(aproxy, apstream);
+            apstream->pcmconfig = pcm_config_call_record;
+
+            check_conversion(apstream);
+            break;
+        default:
+            ALOGE("proxy-%s: failed to reconfig Proxy Stream as unknown stream type(%d)", __func__, stream_type);
+            return -1;
+    }
+
+    ALOGI("proxy-%s: reconfig Proxy Stream(%s)", __func__, stream_table[apstream->stream_type]);
+
+    return 0;
+}
+
+int proxy_get_capture_pos(void *proxy_stream, int64_t *frames, int64_t *time)
+{
+    struct audio_proxy_stream *apstream = (struct audio_proxy_stream *)proxy_stream;
+    unsigned int avail = 0;
+    struct timespec timestamp;
+    int ret = -ENOSYS;;
+
+    if (frames != NULL && time != NULL) {
+        *frames = 0;
+        *time = 0;
+
+        if (apstream->pcm) {
+            ret = pcm_get_htimestamp(apstream->pcm, &avail, &timestamp);
+            if (ret == 0) {
+                // Real frames which captured in from device
+                *frames = apstream->frames + avail;
+                // Nano Seconds Unit Time
+                *time = timestamp.tv_sec * 1000000000LL + timestamp.tv_nsec;
+                ret = 0;
+            }
+        }
+    } else {
+        ALOGE("%s-%s: Invalid Parameter with Null pointer parameter",
+              stream_table[apstream->stream_type], __func__);
+        ret =  -EINVAL;
+    }
+
+    return ret;
+}
+
+int proxy_get_active_microphones(void *proxy_stream, void *array, int *count)
+{
+    struct audio_proxy *aproxy = getInstance();
+    struct audio_proxy_stream *apstream = (struct audio_proxy_stream *)proxy_stream;
+    struct audio_microphone_characteristic_t *mic_array = array;
+    size_t *mic_count = (size_t *)count;
+    size_t actual_mic_count = 0;
+    int ret = 0;
+
+    if (apstream) {
+        if (apstream->stream_type == ASTREAM_CAPTURE_NO_ATTRIBUTE ||
+            apstream->stream_type == ASTREAM_CAPTURE_PRIMARY ||
+            apstream->stream_type == ASTREAM_CAPTURE_LOW_LATENCY ||
+            apstream->stream_type == ASTREAM_CAPTURE_MMAP) {
+            device_type active_device = aproxy->active_capture_device;
+            if (active_device == DEVICE_NONE) {
+                ALOGE("%s-%s: There are no active MIC", stream_table[apstream->stream_type], __func__);
+                ret = -ENOSYS;
+            }
+
+            if (*mic_count == 0) {
+                if (active_device == DEVICE_STEREO_MIC)
+                    actual_mic_count = 2;
+                else
+                    actual_mic_count = 1;
+                ALOGI("proxy-%s: requested number of microphone, return %zu", __func__, *mic_count);
+            } else {
+                if (active_device == DEVICE_STEREO_MIC) {
+                    for (int i = 0; i < 2; i++) {
+                        mic_array[i] = aproxy->mic_info[i];
+                        ALOGD("%s-%s: %dth MIC = %s", stream_table[apstream->stream_type], __func__,
+                                                      i+1, mic_array[i].device_id);
+                        actual_mic_count++;
+                    }
+                } else if (active_device == DEVICE_MAIN_MIC) {
+                        mic_array[0] = aproxy->mic_info[0];
+                        ALOGD("%s-%s: Active MIC = %s", stream_table[apstream->stream_type], __func__,
+                                                        mic_array[0].device_id);
+                        actual_mic_count = 1;
+                } else if (active_device == DEVICE_SUB_MIC) {
+                        mic_array[0] = aproxy->mic_info[1];
+                        ALOGD("%s-%s: Active MIC = %s", stream_table[apstream->stream_type], __func__,
+                                                        mic_array[0].device_id);
+                        actual_mic_count = 1;
+                } else {
+                    ALOGE("%s-%s: Abnormal active device(%s)", stream_table[apstream->stream_type],
+                                                               __func__, device_table[active_device]);
+                    ret = -ENOSYS;
+                }
+            }
+        } else {
+            ALOGE("%s-%s: This stream doesn't have active MIC", stream_table[apstream->stream_type],
+                                                                __func__);
+            ret = -ENOSYS;
+        }
+    } else {
+        ALOGE("proxy-%s: apstream is NULL", __func__);
+        ret = -ENOSYS;
+    }
+
+    *mic_count = actual_mic_count;
+
+    return ret;
+}
+
+int proxy_getparam_capture_stream(void *proxy_stream, void *query_params, void *reply_params)
+{
+    struct audio_proxy_stream *apstream = (struct audio_proxy_stream *)proxy_stream;
+    struct audio_proxy *aproxy = getInstance();
+    struct str_parms *query = (struct str_parms *)query_params;
+    struct str_parms *reply = (struct str_parms *)reply_params;
+
+    if (proxy_is_usb_capture_device_connected(aproxy->usb_aproxy)) {
+        // get USB capture param information
+        proxy_usb_getparam_capture_stream(getInstance()->usb_aproxy, query, reply);
+    } else {
+        /*
+         * Supported Audio Configuration can be different as Target Project.
+         * AudioHAL engineers have to modify these codes based on Target Project.
+         */
+        // supported audio formats
+        if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_FORMATS)) {
+            char formats_list[256];
+
+            memset(formats_list, 0, 256);
+            strncpy(formats_list, stream_format_table[apstream->stream_type],
+                           strlen(stream_format_table[apstream->stream_type]));
+            str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_SUP_FORMATS, formats_list);
+        }
+
+        // supported audio channel masks
+        if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_CHANNELS)) {
+            char channels_list[256];
+
+            memset(channels_list, 0, 256);
+            strncpy(channels_list, stream_channel_table[apstream->stream_type],
+                            strlen(stream_channel_table[apstream->stream_type]));
+            str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_SUP_CHANNELS, channels_list);
+        }
+
+        // supported audio samspling rates
+        if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES)) {
+            char rates_list[256];
+
+            memset(rates_list, 0, 256);
+            strncpy(rates_list, stream_rate_table[apstream->stream_type],
+                         strlen(stream_rate_table[apstream->stream_type]));
+            str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES, rates_list);
+        }
+    }
+
+    return 0;
+}
+
+int proxy_setparam_capture_stream(void *proxy_stream, void *parameters)
+{
+    struct audio_proxy_stream *apstream = (struct audio_proxy_stream *)proxy_stream;
+    struct audio_proxy *aproxy = getInstance();
+    int ret = 0;
+
+    if (proxy_is_usb_capture_device_connected(aproxy->usb_aproxy)) {
+        /* Set USB parameters */
+        ret = proxy_usb_setparam_capture_stream(aproxy->usb_aproxy, parameters);
+    }
+
+    return ret;
+}
+
+void proxy_dump_capture_stream(void *proxy_stream, int fd)
+{
+    struct audio_proxy_stream *apstream = (struct audio_proxy_stream *)proxy_stream;
+
+    const size_t len = 256;
+    char buffer[len];
+
+    if (apstream->pcm != NULL) {
+        snprintf(buffer, len, "\tinput pcm config sample rate: %d\n",apstream->pcmconfig.rate);
+        write(fd,buffer,strlen(buffer));
+        snprintf(buffer, len, "\tinput pcm config period size : %d\n",apstream->pcmconfig.period_size);
+        write(fd,buffer,strlen(buffer));
+        snprintf(buffer, len, "\tinput pcm config format: %d\n",apstream->pcmconfig.format);
+        write(fd,buffer,strlen(buffer));
+    }
+
+    return ;
+}
+
+void proxy_update_capture_usage(void *proxy_stream, int usage)
+{
+    struct audio_proxy_stream *apstream = (struct audio_proxy_stream *)proxy_stream;
+    audio_usage    stream_usage = (audio_usage)usage;
+
+    if(apstream) {
+        apstream->stream_usage = stream_usage;
+        ALOGD("proxy-%s: apstream->stream_usage = %d", __func__, apstream->stream_usage);
+    } else {
+        ALOGD("proxy-%s: apstream is NULL", __func__);
+    }
+    return ;
+}
+
+int proxy_get_mmap_position(void *proxy_stream, void *pos)
+{
+    struct audio_proxy_stream *apstream = (struct audio_proxy_stream *)proxy_stream;
+    struct audio_mmap_position *position = (struct audio_mmap_position *)pos;
+    int ret = -ENOSYS;
+
+    if ((apstream->stream_type == ASTREAM_PLAYBACK_MMAP || apstream->stream_type == ASTREAM_CAPTURE_MMAP)&&
+         apstream->pcm) {
+        struct timespec ts = { 0, 0 };
+
+        ret = pcm_mmap_get_hw_ptr(apstream->pcm, (unsigned int *)&position->position_frames, &ts);
+        if (ret < 0) {
+            ALOGE("proxy-%s: get_hw_ptr error %s ", __func__, pcm_get_error(apstream->pcm));
+        } else if (ret == 0) {
+             position->time_nanoseconds = audio_utils_ns_from_timespec(&ts);
+        }
+    }
+
+    return ret;
+}
+
+
+/******************************************************************************/
+/**                                                                          **/
+/** Interfaces for Audio Device Proxy                                        **/
+/**                                                                          **/
+/******************************************************************************/
+
+/*
+ *  Route Control Functions
+ */
+bool proxy_init_route(void *proxy, char *path)
+{
+    struct audio_proxy *aproxy = proxy;
+    struct audio_route *ar = NULL;
+    bool ret = false;
+
+    if (aproxy) {
+        aproxy->mixer = mixer_open(MIXER_CARD0);
+        proxy_set_mixercontrol(aproxy, TICKLE_CONTROL, ABOX_TICKLE_ON);
+        if (aproxy->mixer) {
+            // In order to get add event, subscription has to be here!
+            mixer_subscribe_events(aproxy->mixer, 1);
+
+            ar = audio_route_init(MIXER_CARD0, path);
+            if (!ar) {
+                ALOGE("proxy-%s: failed to init audio route", __func__);
+                mixer_subscribe_events(aproxy->mixer, 0);
+                mixer_close(aproxy->mixer);
+                aproxy->mixer = NULL;
+            } else {
+                aproxy->aroute = ar;
+                aproxy->xml_path = strdup(path);    // Save Mixer Paths XML File path
+
+                aproxy->active_playback_ausage   = AUSAGE_NONE;
+                aproxy->active_playback_device   = DEVICE_NONE;
+                aproxy->active_playback_modifier = MODIFIER_NONE;
+
+                aproxy->active_capture_ausage   = AUSAGE_NONE;
+                aproxy->active_capture_device   = DEVICE_NONE;
+                aproxy->active_capture_modifier = MODIFIER_NONE;
+
+                ALOGI("proxy-%s: opened Mixer & initialized audio route", __func__);
+                ret = true;
+
+                /* Create Mixer Control Update Thread */
+                pthread_rwlock_init(&aproxy->mixer_update_lock, NULL);
+
+                if (audio_route_missing_ctl(ar)) {
+                    pthread_create(&aproxy->mixer_update_thread, NULL, mixer_update_loop, aproxy);
+                    ALOGI("proxy-%s: missing control found, update thread is created", __func__);
+                } else
+                    mixer_subscribe_events(aproxy->mixer, 0);
+            }
+        } else
+            ALOGE("proxy-%s: failed to open Mixer", __func__);
+    }
+
+    return ret;
+}
+
+void proxy_deinit_route(void *proxy)
+{
+    struct audio_proxy *aproxy = proxy;
+
+    if (aproxy) {
+        pthread_rwlock_wrlock(&aproxy->mixer_update_lock);
+
+        if (aproxy->aroute) {
+            audio_route_free(aproxy->aroute);
+            aproxy->aroute = NULL;
+        }
+        if (aproxy->mixer) {
+            mixer_close(aproxy->mixer);
+            aproxy->mixer = NULL;
+        }
+
+        pthread_rwlock_unlock(&aproxy->mixer_update_lock);
+        pthread_rwlock_destroy(&aproxy->mixer_update_lock);
+        free(aproxy->xml_path);
+    }
+    ALOGI("proxy-%s: closed Mixer & deinitialized audio route", __func__);
+
+    return ;
+}
+
+bool proxy_update_route(void *proxy, int ausage, int device)
+{
+    struct audio_proxy *aproxy = proxy;
+    audio_usage routed_ausage = (audio_usage)ausage;
+    device_type routed_device = (device_type)device;
+
+    // Temp
+    if (aproxy != NULL) {
+        routed_ausage = AUSAGE_NONE;
+        routed_device = DEVICE_NONE;
+    }
+
+    return true;
+}
+
+bool proxy_set_route(void *proxy, int ausage, int device, int modifier, bool set)
+{
+    struct audio_proxy *aproxy = proxy;
+    char path_name[MAX_PATH_NAME_LEN];
+
+    audio_usage   routed_ausage = (audio_usage)ausage;
+    device_type   routed_device = (device_type)device;
+    audio_usage   active_ausage = AUSAGE_NONE;
+    device_type   active_device = DEVICE_NONE;
+
+    modifier_type routed_modifier = (modifier_type)modifier;
+
+    if (set) {
+        /* check whether path routing is for AP/CP call bandwidth or speaker/DEX Device Change */
+        if (routed_device < DEVICE_MAIN_MIC) {
+            active_ausage = aproxy->active_playback_ausage;
+            active_device = aproxy->active_playback_device;
+        } else {
+            active_ausage = aproxy->active_capture_ausage;
+            active_device = aproxy->active_capture_device;
+        }
+
+        if (is_usage_Call(active_ausage) &&
+                is_usage_Call(routed_ausage)) {
+            /* check whether internal path nodes close/re-open should be skipped,
+             * for following scenarios
+             * - cp call bandwidth change
+             * - Dex speaker device state change during ap/cp call
+            */
+            if (((active_ausage != routed_ausage) && (active_device == routed_device) &&
+                (is_usage_CPCall(active_ausage) && is_usage_CPCall(routed_ausage))) ||
+                ((active_ausage == routed_ausage) && (active_device != routed_device) &&
+                is_device_speaker(routed_device) && is_device_speaker(active_device))) {
+                ALOGI("proxy-%s: skip output path loopback PCMs re-open",
+                    __func__);
+                ALOGI("proxy-%s: active-device(%s) requested-device(%s)", __func__,
+                    device_table[active_device],
+                    device_table[routed_device]);
+                aproxy->skip_internalpath = true;
+            }
+        }
+
+        if (routed_device < DEVICE_MAIN_MIC) {
+            /* Do Specific Operation based on Audio Path */
+            do_operations_by_playback_route_set(aproxy, routed_ausage, routed_device);
+
+            if (aproxy->active_playback_ausage != AUSAGE_NONE &&
+                aproxy->active_playback_device != DEVICE_NONE) {
+                disable_internal_path(aproxy, aproxy->active_playback_ausage,
+                                        aproxy->active_playback_device);
+                set_reroute(aproxy, aproxy->active_playback_ausage, aproxy->active_playback_device,
+                                    routed_ausage, routed_device);
+            } else
+                set_route(aproxy, routed_ausage, routed_device);
+
+            aproxy->active_playback_ausage = routed_ausage;
+            aproxy->active_playback_device = routed_device;
+
+            // Audio Path Modifier for Playback Path
+            if (routed_modifier < MODIFIER_BT_SCO_TX_NB) {
+                if (aproxy->active_playback_modifier == MODIFIER_NONE)
+                    set_modifier(aproxy, routed_modifier);
+                else
+                    update_modifier(aproxy, aproxy->active_playback_modifier, routed_modifier);
+            } else if (routed_modifier == MODIFIER_NONE && aproxy->active_playback_modifier != MODIFIER_NONE)
+                reset_modifier(aproxy, aproxy->active_playback_modifier);
+
+            if (routed_device == DEVICE_USB_HEADSET ||
+                routed_device == DEVICE_SPEAKER_AND_USB_HEADSET) {
+                /* set USB gain controls if required */
+                make_path(routed_ausage, routed_device, path_name);
+                proxy_usb_set_gain(aproxy->usb_aproxy, path_name);
+            }
+
+            aproxy->active_playback_modifier = routed_modifier;
+
+            // Set Loopback for Playback Path
+            enable_internal_path(aproxy, routed_ausage, routed_device);
+
+            if (ausage == AUSAGE_FM_RADIO || ausage == AUSAGE_USB_FM_RADIO) {
+                /* Open/Close FM Radio PCM node based on Enable/disable */
+                proxy_start_fm_radio(aproxy);
+            }
+        } else {
+            // Audio Path Routing for Capture Path
+            if (aproxy->active_capture_ausage != AUSAGE_NONE &&
+                aproxy->active_capture_device != DEVICE_NONE) {
+                disable_internal_path(aproxy, aproxy->active_capture_ausage,
+                                        aproxy->active_capture_device);
+                set_reroute(aproxy, aproxy->active_capture_ausage, aproxy->active_capture_device,
+                                    routed_ausage, routed_device);
+            } else {
+                // In case of capture routing setup, it needs A-Box early-wakeup
+                proxy_set_mixercontrol(aproxy, TICKLE_CONTROL, ABOX_TICKLE_ON);
+
+                set_route(aproxy, routed_ausage, routed_device);
+            }
+
+            aproxy->active_capture_ausage = routed_ausage;
+            aproxy->active_capture_device = routed_device;
+
+            // Audio Path Modifier for Capture Path
+            if (routed_modifier >= MODIFIER_BT_SCO_TX_NB && routed_modifier < MODIFIER_NONE) {
+                if (aproxy->active_capture_modifier == MODIFIER_NONE)
+                    set_modifier(aproxy, routed_modifier);
+                else
+                    update_modifier(aproxy, aproxy->active_capture_modifier, routed_modifier);
+            } else if (routed_modifier == MODIFIER_NONE && aproxy->active_capture_modifier != MODIFIER_NONE)
+                reset_modifier(aproxy, aproxy->active_capture_modifier);
+
+            if (is_usb_mic_device(routed_device)) {
+                /* set USB gain controls if required */
+                make_path(routed_ausage, routed_device, path_name);
+                proxy_usb_set_gain(aproxy->usb_aproxy, path_name);
+            }
+
+            aproxy->active_capture_modifier = routed_modifier;
+
+            // Set Loopback for Capture Path
+            enable_internal_path(aproxy, routed_ausage, routed_device);
+        }
+    } else {
+        /* Do Specific Operation based on Audio Path */
+        if (routed_device < DEVICE_MAIN_MIC)
+            do_operations_by_playback_route_reset(aproxy);
+
+        // Reset Loopback
+        disable_internal_path(aproxy, routed_ausage, routed_device);
+
+        // Audio Path Modifier
+        if (routed_modifier != MODIFIER_NONE) {
+            reset_modifier(aproxy, routed_modifier);
+
+            if (routed_modifier < MODIFIER_BT_SCO_TX_NB)
+                aproxy->active_playback_modifier = MODIFIER_NONE;
+            else
+                aproxy->active_capture_modifier = MODIFIER_NONE;
+        } else {
+            aproxy->active_playback_modifier = MODIFIER_NONE;
+            aproxy->active_capture_modifier = MODIFIER_NONE;
+        }
+
+        if (routed_device == DEVICE_USB_HEADSET ||
+            routed_device == DEVICE_SPEAKER_AND_USB_HEADSET ||
+            is_usb_mic_device(routed_device)) {
+            /* reset USB gain controls */
+            make_path(routed_ausage, routed_device, path_name);
+            proxy_usb_reset_gain(aproxy->usb_aproxy, path_name);
+        }
+
+        // Audio Path Routing
+        reset_route(aproxy, routed_ausage, routed_device);
+
+        if (routed_device < DEVICE_MAIN_MIC) {
+            aproxy->active_playback_ausage = AUSAGE_NONE;
+            aproxy->active_playback_device = DEVICE_NONE;
+        } else {
+            aproxy->active_capture_ausage = AUSAGE_NONE;
+            aproxy->active_capture_device = DEVICE_NONE;
+        }
+    }
+
+    /* reset voicecall bandwidth change flag */
+    aproxy->skip_internalpath = false;
+
+    return true;
+}
+
+
+/*
+ *  Proxy Voice Call Control
+ */
+void  proxy_stop_voice_call(void *proxy)
+{
+    struct audio_proxy *aproxy = (struct audio_proxy *)proxy;
+    voice_rx_stop(aproxy);
+    voice_tx_stop(aproxy);
+
+    return ;
+}
+
+void proxy_start_voice_call(void *proxy)
+{
+    struct audio_proxy *aproxy = (struct audio_proxy *)proxy;
+
+    voice_rx_start(aproxy);
+
+    /*
+    ** Voice TX and FM Radio are sharing same WDMA.
+    ** So, it needs to check and close WDMA when FM Radio is working at Voice Call Start.
+    */
+    if (aproxy->fm_playback != NULL && aproxy->fm_capture != NULL) {
+        fmradio_playback_stop(aproxy);
+        fmradio_capture_stop(aproxy);
+    }
+
+    voice_tx_start(aproxy);
+
+    return ;
+}
+
+/*
+ *  Proxy FM Radio Control
+ */
+void proxy_stop_fm_radio(void *proxy)
+{
+    struct audio_proxy *aproxy = (struct audio_proxy *)proxy;
+
+    fmradio_playback_stop(aproxy);
+    fmradio_capture_stop(aproxy);
+
+    return ;
+}
+
+void proxy_start_fm_radio(void *proxy)
+{
+    struct audio_proxy *aproxy = (struct audio_proxy *)proxy;
+
+    fmradio_playback_start(aproxy);
+    fmradio_capture_start(aproxy);
+
+    return ;
+}
+
+
+// General Mixer Control Functions
+int proxy_get_mixer_value_int(void *proxy, const char *name)
+{
+    struct audio_proxy *aproxy = proxy;
+    struct mixer_ctl *ctrl = NULL;
+    int ret = -1;
+
+    if (name == NULL)
+        return ret;
+
+    pthread_rwlock_rdlock(&aproxy->mixer_update_lock);
+
+    ctrl = mixer_get_ctl_by_name(aproxy->mixer, name);
+    if (ctrl) {
+        ret = mixer_ctl_get_value(ctrl, 0);
+    } else {
+        ALOGE("proxy-%s: cannot find %s Mixer Control", __func__, name);
+    }
+
+    pthread_rwlock_unlock(&aproxy->mixer_update_lock);
+
+    return ret;
+}
+
+int proxy_get_mixer_value_array(void *proxy, const char *name, void *value, int count)
+{
+    struct audio_proxy *aproxy = proxy;
+    struct mixer_ctl *ctrl = NULL;
+    int ret = -1;
+
+    if (name == NULL)
+        return ret;
+
+    pthread_rwlock_rdlock(&aproxy->mixer_update_lock);
+
+    ctrl = mixer_get_ctl_by_name(aproxy->mixer, name);
+    if (ctrl) {
+        ret = mixer_ctl_get_array(ctrl, value, count);
+    } else {
+        ALOGE("proxy-%s: cannot find %s Mixer Control", __func__, name);
+    }
+
+    pthread_rwlock_unlock(&aproxy->mixer_update_lock);
+
+    return ret;
+}
+
+void proxy_set_mixer_value_int(void *proxy, const char *name, int value)
+{
+    struct audio_proxy *aproxy = proxy;
+    struct mixer_ctl *ctrl = NULL;
+    int ret = 0, val = value;
+
+    if (name == NULL)
+        return ;
+
+    pthread_rwlock_rdlock(&aproxy->mixer_update_lock);
+
+    ctrl = mixer_get_ctl_by_name(aproxy->mixer, name);
+    if (ctrl) {
+        ret = mixer_ctl_set_value(ctrl, 0, val);
+        if (ret != 0)
+            ALOGE("proxy-%s: failed to set %s", __func__, name);
+    } else {
+        ALOGE("proxy-%s: cannot find %s Mixer Control", __func__, name);
+    }
+
+    pthread_rwlock_unlock(&aproxy->mixer_update_lock);
+
+    return ;
+}
+
+void proxy_set_mixer_value_string(void *proxy, const char *name, const char *value)
+{
+    struct audio_proxy *aproxy = proxy;
+    struct mixer_ctl *ctrl = NULL;
+    int ret = 0;
+
+    if (name == NULL)
+        return ;
+
+    pthread_rwlock_rdlock(&aproxy->mixer_update_lock);
+
+    ctrl = mixer_get_ctl_by_name(aproxy->mixer, name);
+    if (ctrl) {
+        ret = mixer_ctl_set_enum_by_string(ctrl, value);
+        if (ret != 0)
+            ALOGE("proxy-%s: failed to set %s", __func__, name);
+    } else {
+        ALOGE("proxy-%s: cannot find %s Mixer Control", __func__, name);
+    }
+
+    pthread_rwlock_unlock(&aproxy->mixer_update_lock);
+
+    return ;
+}
+
+void proxy_set_mixer_value_array(void *proxy, const char *name, const void *value, int count)
+{
+    struct audio_proxy *aproxy = proxy;
+    struct mixer_ctl *ctrl = NULL;
+    int ret = 0;
+
+    if (aproxy == NULL)
+        aproxy = getInstance();
+
+    if (name == NULL)
+        return ;
+
+    pthread_rwlock_rdlock(&aproxy->mixer_update_lock);
+
+    ctrl = mixer_get_ctl_by_name(aproxy->mixer, name);
+    if (ctrl) {
+        ret = mixer_ctl_set_array(ctrl, value, count);
+        if (ret != 0)
+            ALOGE("proxy-%s: failed to set %s", __func__, name);
+    } else {
+        ALOGE("proxy-%s: cannot find %s Mixer Control", __func__, name);
+    }
+
+    pthread_rwlock_unlock(&aproxy->mixer_update_lock);
+
+    return ;
+}
+
+void proxy_set_audio_interface(void *proxy, unsigned int interface, unsigned int sample_rate,
+                               unsigned int bit_width, unsigned int channel)
+{
+    struct audio_proxy *aproxy = proxy;
+
+    if (aproxy == NULL)
+        return ;
+
+    if (interface == UAIF0) {
+        proxy_set_mixer_value_int(proxy, MIXER_CTL_ABOX_UAIF0_SWITCH, MIXER_OFF);
+        /* SIFS0 Switch Off/On control is required only when SISF0 connected to UAIF0 */
+        if (aproxy->active_playback_device == DEVICE_HEADPHONE ||
+            aproxy->active_playback_device == DEVICE_HEADSET ||
+            aproxy->active_playback_device == DEVICE_SPEAKER_AND_HEADPHONE ||
+            aproxy->active_playback_device == DEVICE_SPEAKER_AND_HEADSET)
+            proxy_set_mixer_value_int(proxy, MIXER_CTL_ABOX_SIFS0_SWITCH, MIXER_OFF);
+
+        proxy_set_mixer_value_int(proxy, MIXER_CTL_ABOX_UAIF0_SAMPLERATE, sample_rate);
+        proxy_set_mixer_value_int(proxy, MIXER_CTL_ABOX_UAIF0_WIDTH, bit_width);
+        proxy_set_mixer_value_int(proxy, MIXER_CTL_ABOX_UAIF0_CHANNEL, channel);
+
+        /* skip SIFS0 configuration for USB device */
+        if (!(aproxy->active_playback_device == DEVICE_USB_HEADSET ||
+            aproxy->active_playback_device == DEVICE_SPEAKER_AND_USB_HEADSET)) {
+            proxy_set_mixer_value_int(proxy, MIXER_CTL_ABOX_SIFS0_SAMPLERATE, sample_rate);
+            proxy_set_mixer_value_int(proxy, MIXER_CTL_ABOX_SIFS0_WIDTH, bit_width);
+            proxy_set_mixer_value_int(proxy, MIXER_CTL_ABOX_SIFS0_CHANNEL, channel);
+        } else {
+            ALOGI("proxy-%s: skip SIFS0 config for %d", __func__, aproxy->active_playback_device);
+        }
+
+        if (aproxy->active_playback_device == DEVICE_HEADPHONE ||
+            aproxy->active_playback_device == DEVICE_HEADSET ||
+            aproxy->active_playback_device == DEVICE_SPEAKER_AND_HEADPHONE ||
+            aproxy->active_playback_device == DEVICE_SPEAKER_AND_HEADSET)
+            proxy_set_mixer_value_int(proxy, MIXER_CTL_ABOX_SIFS0_SWITCH, MIXER_ON);
+
+        proxy_set_mixer_value_int(proxy, MIXER_CTL_ABOX_UAIF0_SWITCH, MIXER_ON);
+    } else if (interface == UAIF1) {
+        proxy_set_mixer_value_int(proxy, MIXER_CTL_ABOX_UAIF1_SWITCH, MIXER_OFF);
+        proxy_set_mixer_value_int(proxy, MIXER_CTL_ABOX_UAIF1_SAMPLERATE, sample_rate);
+        proxy_set_mixer_value_int(proxy, MIXER_CTL_ABOX_UAIF1_WIDTH, bit_width);
+        proxy_set_mixer_value_int(proxy, MIXER_CTL_ABOX_UAIF1_CHANNEL, channel);
+        proxy_set_mixer_value_int(proxy, MIXER_CTL_ABOX_UAIF1_SWITCH, MIXER_ON);
+    } else if (interface == UAIF2) {
+        proxy_set_mixer_value_int(proxy, MIXER_CTL_ABOX_UAIF2_SWITCH, MIXER_OFF);
+        proxy_set_mixer_value_int(proxy, MIXER_CTL_ABOX_UAIF2_SAMPLERATE, sample_rate);
+        proxy_set_mixer_value_int(proxy, MIXER_CTL_ABOX_UAIF2_WIDTH, bit_width);
+        proxy_set_mixer_value_int(proxy, MIXER_CTL_ABOX_UAIF2_CHANNEL, channel);
+        proxy_set_mixer_value_int(proxy, MIXER_CTL_ABOX_UAIF2_SWITCH, MIXER_ON);
+    } else if (interface == UAIF3) {
+        proxy_set_mixer_value_int(proxy, MIXER_CTL_ABOX_UAIF3_SWITCH, MIXER_OFF);
+        proxy_set_mixer_value_int(proxy, MIXER_CTL_ABOX_UAIF3_SAMPLERATE, sample_rate);
+        proxy_set_mixer_value_int(proxy, MIXER_CTL_ABOX_UAIF3_WIDTH, bit_width);
+        proxy_set_mixer_value_int(proxy, MIXER_CTL_ABOX_UAIF3_CHANNEL, channel);
+        proxy_set_mixer_value_int(proxy, MIXER_CTL_ABOX_UAIF3_SWITCH, MIXER_ON);
+    }
+
+    return ;
+}
+
+// Specific Mixer Control Functions
+void proxy_set_audiomode(void *proxy, int audiomode)
+{
+    struct audio_proxy *aproxy = proxy;
+    struct mixer_ctl *ctrl = NULL;
+    int ret = 0, val = audiomode;
+
+    aproxy->audio_mode = val; // set audio mode
+
+    pthread_rwlock_rdlock(&aproxy->mixer_update_lock);
+
+    /* Set Audio Mode to Kernel */
+    ctrl = mixer_get_ctl_by_name(aproxy->mixer, ABOX_AUDIOMODE_CONTROL_NAME);
+    if (ctrl) {
+        ret = mixer_ctl_set_value(ctrl, 0,val);
+        if (ret != 0)
+            ALOGE("proxy-%s: failed to set Android AudioMode to Kernel", __func__);
+    } else {
+        ALOGE("proxy-%s: cannot find AudioMode Mixer Control", __func__);
+    }
+
+    pthread_rwlock_unlock(&aproxy->mixer_update_lock);
+
+    return ;
+}
+
+void proxy_set_volume(void *proxy, int volume_type, float left, float right)
+{
+    struct audio_proxy *aproxy = proxy;
+    struct mixer_ctl *ctrl = NULL;
+    int ret = -ENAVAIL;
+    int val[2];
+
+    pthread_rwlock_rdlock(&aproxy->mixer_update_lock);
+
+    if (volume_type == VOLUME_TYPE_OFFLOAD) {
+        val[0] = (int)(left * COMPRESS_PLAYBACK_VOLUME_MAX);
+        val[1] = (int)(right * COMPRESS_PLAYBACK_VOLUME_MAX);
+
+        ctrl = mixer_get_ctl_by_name(aproxy->mixer, OFFLOAD_VOLUME_CONTROL_NAME);
+    } else if (volume_type == VOLUME_TYPE_MMAP) {
+        val[0] = (int)(left * MMAP_PLAYBACK_VOLUME_MAX);
+        val[1] = (int)(right * MMAP_PLAYBACK_VOLUME_MAX);
+
+        ctrl = mixer_get_ctl_by_name(aproxy->mixer, MIXER_CTL_ABOX_MMAP_OUT_VOLUME_CONTROL);
+    }
+
+    if (ctrl) {
+        if (volume_type == VOLUME_TYPE_OFFLOAD)
+            ret = mixer_ctl_set_array(ctrl, val, sizeof(val)/sizeof(val[0]));
+        else if (volume_type == VOLUME_TYPE_MMAP)
+            ret = mixer_ctl_set_value(ctrl, 0, val[0]);
+
+        if (ret != 0)
+            ALOGE("proxy-%s: failed to set Volume", __func__);
+        else
+            ALOGV("proxy-%s: set Volume(%f:%f) => (%d:%d)", __func__, left, right, val[0], val[1]);
+    } else {
+        ALOGE("proxy-%s: cannot find Volume Control", __func__);
+    }
+
+    pthread_rwlock_unlock(&aproxy->mixer_update_lock);
+
+    return;
+}
+
+void proxy_clear_apcall_txse(void)
+{
+    struct audio_proxy *aproxy = getInstance();
+    char basic_path_name[MAX_PATH_NAME_LEN];
+    char path_name[MAX_PATH_NAME_LEN];
+    audio_usage ausage = aproxy->active_capture_ausage;
+
+    memset(path_name, 0, MAX_PATH_NAME_LEN);
+
+    if (snprintf(path_name, MAX_PATH_NAME_LEN - 1, "set-%s-txse", usage_path_table[ausage]) < 0) {
+        ALOGE("proxy-%s: path name has error: %s", __func__, strerror(errno));
+        return;
+    }
+
+    pthread_rwlock_rdlock(&aproxy->mixer_update_lock);
+
+    audio_route_reset_and_update_path(aproxy->aroute, path_name);
+    ALOGI("proxy-%s: %s is disabled", __func__, path_name);
+
+    pthread_rwlock_unlock(&aproxy->mixer_update_lock);
+
+    return ;
+}
+
+void proxy_set_apcall_txse(void)
+{
+    struct audio_proxy *aproxy = getInstance();
+    char basic_path_name[MAX_PATH_NAME_LEN];
+    char path_name[MAX_PATH_NAME_LEN];
+    audio_usage ausage = aproxy->active_capture_ausage;
+
+    memset(path_name, 0, MAX_PATH_NAME_LEN);
+
+    if (snprintf(path_name, MAX_PATH_NAME_LEN - 1, "set-%s-txse", usage_path_table[ausage]) < 0) {
+        ALOGE("proxy-%s: path name has error: %s", __func__, strerror(errno));
+        return;
+    }
+
+    pthread_rwlock_rdlock(&aproxy->mixer_update_lock);
+
+    audio_route_apply_and_update_path(aproxy->aroute, path_name);
+    ALOGI("proxy-%s: %s is enabled", __func__, path_name);
+
+    pthread_rwlock_unlock(&aproxy->mixer_update_lock);
+
+    return ;
+}
+
+void proxy_set_upscale(void *proxy, int sampling_rate, int pcm_format)
+{
+    struct audio_proxy *aproxy = proxy;
+    struct mixer_ctl *ctrl = NULL;
+    int ret = 0, val = (int)UPSCALE_NONE;
+
+    pthread_rwlock_rdlock(&aproxy->mixer_update_lock);
+
+    /* Set Compress Offload Upscaling Info to Kernel */
+    ctrl = mixer_get_ctl_by_name(aproxy->mixer, OFFLOAD_UPSCALE_CONTROL_NAME);
+    if (ctrl) {
+        if (sampling_rate == 48000 && (audio_format_t)pcm_format == AUDIO_FORMAT_PCM_SUB_16_BIT)
+            val = (int)UPSCALE_48K_16B;
+        else if ((audio_format_t)pcm_format == AUDIO_FORMAT_PCM_SUB_16_BIT) {
+            if (sampling_rate == 48000)
+                val = (int)UPSCALE_48K_24B;
+            else if (sampling_rate == 192000)
+                val = (int)UPSCALE_192K_24B;
+            else if (sampling_rate == 384000)
+                val = (int)UPSCALE_384K_24B;
+        }
+
+        if (val != (int)UPSCALE_NONE) {
+            ret = mixer_ctl_set_value(ctrl, 0, val);
+            if (ret != 0)
+                ALOGE("proxy-%s: failed to set Offload Upscale Info to Kernel", __func__);
+            else
+                ALOGV("proxy-%s: set Offload Upscale Info as %d", __func__, val);
+        } else
+            ALOGE("proxy-%s: invalid Offload Upscale Info", __func__);
+    } else {
+        ALOGE("proxy-%s: cannot find Offload Upscale Info Mixer Control", __func__);
+    }
+
+    pthread_rwlock_unlock(&aproxy->mixer_update_lock);
+
+    return;
+}
+
+#ifdef SUPPORT_STHAL_INTERFACE
+__attribute__ ((visibility ("default")))
+int notify_sthal_status(int hwdmodel_state)
+{
+    struct audio_proxy *aproxy = getInstance();
+
+    /* update sthal 'ok Google' model recognization status
+        true : means recognization started
+        false : means recognization stopped
+    */
+    aproxy->sthal_state = hwdmodel_state;
+
+    ALOGD("proxy-%s: Ok-Google Model Recognition [%s]", __func__,
+            (hwdmodel_state ? "STARTED" : "STOPPED"));
+
+    return 0;
+}
+
+int proxy_check_sthalstate(void *proxy)
+{
+    struct audio_proxy *aproxy = (struct audio_proxy *)proxy;
+
+    return aproxy->sthal_state;
+}
+#endif
+
+void proxy_call_status(void *proxy, int status)
+{
+    struct audio_proxy *aproxy = (struct audio_proxy *)proxy;
+
+    /* status : TRUE means call starting
+        FALSE means call stopped
+    */
+    if (status)
+        aproxy->call_state = true;
+    else
+        aproxy->call_state = false;
+
+#ifdef SUPPORT_STHAL_INTERFACE
+    /* Send call status notification to STHAL */
+    if (aproxy->sound_trigger_voicecall_status) {
+        aproxy->sound_trigger_voicecall_status(status);
+    }
+
+    ALOGD("proxy-%s: Call notification to STHAL [%s]", __func__,
+             (status ? "STARTING" : "STOPPED"));
+#endif
+
+    return;
+}
+
+int proxy_set_parameters(void *proxy, void *parameters)
+{
+    struct audio_proxy *aproxy = (struct audio_proxy *)proxy;
+    struct str_parms *parms = (struct str_parms *)parameters;
+    char value[256];
+    int val;
+    int ret = 0;     // for parameter handling
+    int status = 0;  // for return value
+
+    ret = str_parms_get_int(parms, AUDIO_PARAMETER_DEVICE_CONNECT, &val);
+    if (ret >= 0) {
+        if ((audio_devices_t)val == AUDIO_DEVICE_IN_WIRED_HEADSET) {
+            ALOGD("proxy-%s: Headset Device connected 0x%x", __func__, val);
+#ifdef SUPPORT_STHAL_INTERFACE
+            if (aproxy->sound_trigger_headset_status) {
+                aproxy->sound_trigger_headset_status(true);
+            }
+#endif
+        } else if ((audio_devices_t)val == AUDIO_DEVICE_OUT_BLUETOOTH_A2DP ||
+                   (audio_devices_t)val == AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES ||
+                   (audio_devices_t)val == AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER) {
+            ALOGI("proxy-%s: connected BT A2DP Out Device", __func__);
+#ifdef SUPPORT_BTA2DP_OFFLOAD
+            if (aproxy->support_bta2dp) {
+                ret = str_parms_get_int(parms, AUDIO_PARAMETER_STREAM_FORMAT, &val);
+                if (ret >= 0) {
+                    if (audio_is_bt_offload_format((audio_format_t)val)) {
+                        pthread_mutex_lock(&aproxy->a2dp_lock);
+                        if (!aproxy->a2dp_out_enabled) {
+                            status = proxy_a2dp_open();
+                            if (status == 0) {
+                                aproxy->a2dp_out_enabled = true;
+                                ALOGI("proxy-%s: set BT A2DP Offload Enabled & Open A2DP", __func__);
+                                if (aproxy->a2dp_suspend) {
+                                    // a2dp suspend off -> bt offlaod on case
+                                    ALOGI("proxy-%s: set A2DP Suspend Flag", __func__);
+                                    proxy_a2dp_suspend(true); // set suspend a2dp open
+                                    /* modified by samsung convgergence */
+                                    set_a2dp_suspend_mixer(MIXER_ON);
+                                } else if (is_active_playback_device_bta2dp(aproxy)) {
+                                    bta2dp_playback_start(aproxy);  // bt path already enabled, then bta2dp_playback_start hear
+                                }
+                            }
+                        }
+                        pthread_mutex_unlock(&aproxy->a2dp_lock);
+                    }
+                }
+            }
+#endif
+        }
+    }
+
+    ret = str_parms_get_int(parms, AUDIO_PARAMETER_DEVICE_DISCONNECT, &val);
+    if (ret >= 0) {
+        if ((audio_devices_t)val == AUDIO_DEVICE_IN_WIRED_HEADSET) {
+            ALOGD("proxy-%s: Headset Device disconnected 0x%x", __func__, val);
+#ifdef SUPPORT_STHAL_INTERFACE
+            if (aproxy->sound_trigger_headset_status) {
+                aproxy->sound_trigger_headset_status(false);
+            }
+#endif
+        } else if ((audio_devices_t)val == AUDIO_DEVICE_OUT_BLUETOOTH_A2DP ||
+                   (audio_devices_t)val == AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES ||
+                   (audio_devices_t)val == AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER) {
+            ALOGI("proxy-%s: disconnected BT A2DP Out Device", __func__);
+#ifdef SUPPORT_BTA2DP_OFFLOAD
+            if (aproxy->support_bta2dp) {
+                pthread_mutex_lock(&aproxy->a2dp_lock);
+                if (aproxy->a2dp_out_enabled) {
+                    status = proxy_a2dp_close();
+                    if (status == 0) {
+                        aproxy->a2dp_out_enabled = false;
+                        aproxy->a2dp_delay = 0;
+                        ALOGI("proxy-%s: set BT A2DP Offload Disabled & Close A2DP", __func__);
+                    }
+                }
+                pthread_mutex_unlock(&aproxy->a2dp_lock);
+            }
+#endif
+        }
+    }
+#ifdef SUPPORT_BTA2DP_OFFLOAD
+    /* BT A2DP Specific */
+    ret = str_parms_get_str(parms, "A2dpSuspended", value, sizeof(value));
+    if (ret >= 0 && aproxy->support_bta2dp) {
+        pthread_mutex_lock(&aproxy->a2dp_lock);
+        bool cur_state = proxy_a2dp_is_suspended();
+        if(strncmp(value, "true", 4) == 0) {
+            if (aproxy->a2dp_out_enabled) {  // send suspend call to hidl, only a2dp_offload ON
+                proxy_a2dp_suspend(true);
+                ALOGI("proxy-%s: set A2DP Suspend Flag", __func__);
+            }
+            /* modified by samsung convgergence */
+            set_a2dp_suspend_mixer(MIXER_ON);
+            aproxy->a2dp_suspend = true;
+        } else {
+            proxy_a2dp_suspend(false);
+            if (is_active_playback_device_bta2dp(aproxy) && cur_state) {
+                bta2dp_playback_start(aproxy);  // start bt a2dp on suspend t -> f state
+            }
+            ALOGI("proxy-%s: cleared A2DP Suspend Flag", __func__);
+            /* modified by samsung convgergence */
+            set_a2dp_suspend_mixer(MIXER_OFF);
+            aproxy->a2dp_suspend = false;
+        }
+        pthread_mutex_unlock(&aproxy->a2dp_lock);
+    }
+
+    ret = str_parms_get_str(parms, "bt_offload_enable", value, sizeof(value));
+    if (ret >= 0 && aproxy->support_bta2dp) {
+        pthread_mutex_lock(&aproxy->a2dp_lock);
+        val = atoi(value);
+        if (val == 1 && aproxy->a2dp_out_enabled == false) {
+            status = proxy_a2dp_open();
+            if (status == 0) {
+                aproxy->a2dp_out_enabled = true;
+                ALOGI("proxy-%s: set BT A2DP Offload Enabled & Open A2DP", __func__);
+                if (aproxy->a2dp_suspend) {
+                    // a2dp suspend off -> bt offlaod on case
+                    ALOGI("proxy-%s: set A2DP Suspend Flag", __func__);
+                    proxy_a2dp_suspend(true); // set suspend a2dp open
+                    /* modified by samsung convgergence */
+                    set_a2dp_suspend_mixer(MIXER_ON);
+                } else if (is_active_playback_device_bta2dp(aproxy)) {
+                    bta2dp_playback_start(aproxy);  // bt path already enabled, then bta2dp_playback_start hear
+                }
+            }
+        } else if (val == 0 && aproxy->a2dp_out_enabled == true) {
+            status = proxy_a2dp_close();
+            if (status == 0) {
+                aproxy->a2dp_out_enabled = false;
+                aproxy->a2dp_delay = 0;
+                ALOGI("proxy-%s: set BT A2DP Offload Disabled & Close A2DP", __func__);
+            }
+        }
+        pthread_mutex_unlock(&aproxy->a2dp_lock);
+    }
+
+    ret = str_parms_get_str(parms, "A2dpDelayReport", value, sizeof(value));
+    if (ret >= 0 && aproxy->support_bta2dp) {
+        pthread_mutex_lock(&aproxy->a2dp_lock);
+        val = atoi(value);
+        /* adjustment value to make presentation position as fast as adjust_latency(ms) */
+        if (val > A2DP_CAL_LATENCY_VAL)
+            val = val - A2DP_CAL_LATENCY_VAL;
+        else
+            val = 0;
+
+        ALOGI("proxy-%s: set BT A2DP Delay as %d ms", __func__, val);
+        aproxy->a2dp_delay = (uint32_t)val;
+        pthread_mutex_unlock(&aproxy->a2dp_lock);
+    }
+
+    ret = str_parms_get_str(parms, AUDIO_PARAMETER_RECONFIG_A2DP, value, sizeof(value));
+    if (ret >= 0 && aproxy->support_bta2dp) {
+        pthread_mutex_lock(&aproxy->a2dp_lock);
+        if (aproxy->a2dp_out_enabled) {
+            if(strncmp(value, "true", 4) == 0 && is_active_playback_device_bta2dp(aproxy)) {
+                bta2dp_playback_stop(aproxy);
+                bta2dp_playback_start(aproxy);
+            }
+        }
+        pthread_mutex_unlock(&aproxy->a2dp_lock);
+    }
+#endif
+    /* Check USB parameters */
+    status = proxy_usb_set_parameters((void *)aproxy->usb_aproxy, parameters);
+
+    return status;
+}
+
+int proxy_get_microphones(void *proxy, void *array, int *count)
+{
+    struct audio_proxy *aproxy = (struct audio_proxy *)proxy;
+    struct audio_microphone_characteristic_t *mic_array = array;
+    size_t *mic_count = (size_t *)count;
+    size_t actual_mic_count = 0;
+    int ret = 0;
+
+    if (aproxy) {
+        if (*mic_count == 0) {
+            *mic_count = (size_t)aproxy->num_mic;
+            ALOGI("proxy-%s: requested number of microphone, return %zu", __func__, *mic_count);
+        } else {
+            for (int i = 0; i < aproxy->num_mic; i++) {
+                mic_array[i] = aproxy->mic_info[i];
+                ALOGD("proxy-%s: %dth MIC = %s", __func__, i+1, mic_array[i].device_id);
+                actual_mic_count++;
+            }
+            *mic_count = actual_mic_count;
+        }
+    } else {
+        ALOGE("proxy-%s: aproxy is NULL", __func__);
+        ret = -ENOSYS;
+    }
+
+    return ret;
+}
+
+void proxy_update_uhqa_playback_stream(void *proxy_stream, int hq_mode)
+{
+    struct audio_proxy_stream *apstream = (struct audio_proxy_stream *)proxy_stream;
+    audio_quality_mode_t high_quality_mode = (audio_quality_mode_t)hq_mode;
+
+    ALOGD("proxy-%s: mode(%d)", __func__, high_quality_mode);
+
+    if (apstream) {
+        if (apstream->stream_type == ASTREAM_PLAYBACK_COMPR_OFFLOAD) {
+            // offload case
+        } else if (apstream->stream_type == ASTREAM_PLAYBACK_AUX_DIGITAL) {
+            // DP/HDMI case
+            if (high_quality_mode == AUDIO_QUALITY_UHQ) {
+                apstream->pcmconfig.format = UHQA_MEDIA_FORMAT;
+            } else {
+                apstream->pcmconfig.format = DEFAULT_MEDIA_FORMAT;
+            }
+            apstream->requested_format = get_pcmformat_from_alsaformat(apstream->pcmconfig.format);
+        } else if (apstream->stream_type == ASTREAM_PLAYBACK_DEEP_BUFFER) {
+            struct pcm_config pcm_config_map[AUDIO_QUALITY_CNT] = {
+                    pcm_config_deep_playback,
+                    pcm_config_deep_playback_uhqa,
+                    pcm_config_deep_playback_wide_res,
+                    pcm_config_deep_playback_suhqa,
+            };
+            apstream->pcmconfig = pcm_config_map[high_quality_mode];
+            apstream->requested_format = get_pcmformat_from_alsaformat(apstream->pcmconfig.format);
+            apstream->requested_sample_rate = apstream->pcmconfig.rate;
+        } else {
+            ALOGVV("proxy-%s: not supported stream",  __func__);
+        }
+    }
+}
+
+void proxy_set_uhqa_stream_config(void *proxy_stream, bool config)
+{
+    struct audio_proxy_stream *apstream = (struct audio_proxy_stream *)proxy_stream;
+
+    if (apstream)
+        apstream->need_update_pcm_config = config;
+}
+
+bool proxy_get_uhqa_stream_config(void *proxy_stream)
+{
+    struct audio_proxy_stream *apstream = (struct audio_proxy_stream *)proxy_stream;
+    bool uhqa_stream_config = false;
+
+    if (apstream)
+        uhqa_stream_config = apstream->need_update_pcm_config;
+
+    return uhqa_stream_config;
+}
+
+void proxy_init_offload_effect_lib(void *proxy)
+{
+    struct audio_proxy *aproxy = proxy;
+
+    if(access(OFFLOAD_EFFECT_LIBRARY_PATH, R_OK) == 0){
+        aproxy->offload_effect_lib = dlopen(OFFLOAD_EFFECT_LIBRARY_PATH, RTLD_NOW);
+        if(aproxy->offload_effect_lib == NULL){
+            ALOGI("proxy-%s: dlopen %s failed", __func__, OFFLOAD_EFFECT_LIBRARY_PATH);
+        } else {
+            aproxy->offload_effect_lib_update =
+                (void (*)(struct mixer *, int))dlsym(aproxy->offload_effect_lib,
+                "effect_update_by_hal");
+            aproxy->offload_effect_lib_update(aproxy->mixer, 0);
+        }
+    } else {
+        ALOGI("proxy-%s: access %s failed", __func__, OFFLOAD_EFFECT_LIBRARY_PATH);
+    }
+    return;
+}
+
+void proxy_update_offload_effect(void *proxy, int type){
+    struct audio_proxy *aproxy = proxy;
+
+    if (type && (aproxy->offload_effect_lib_update != NULL)) {
+        aproxy->offload_effect_lib_update(aproxy->mixer, type);
+    }
+}
+
+void proxy_set_dual_speaker_mode(void *proxy, bool state)
+{
+    struct audio_proxy *aproxy = proxy;
+    aproxy->support_dualspk = state;
+}
+
+void proxy_set_stream_channel(void *proxy_stream, int new_channel, bool skip)
+{
+    struct audio_proxy_stream *apstream = (struct audio_proxy_stream *)proxy_stream;
+
+    if (new_channel > 0) {
+        apstream->pcmconfig.channels = new_channel;
+    }
+    apstream->skip_ch_convert = skip;
+    apstream->need_channelconversion = !skip;
+    ALOGI("%s: new_channel %d, skip_ch_convert %d", __func__, new_channel, apstream->skip_ch_convert);
+}
+
+void proxy_set_spk_ampL_power(void* proxy, bool state)
+{
+    struct audio_proxy *aproxy = proxy;
+    aproxy->spk_ampL_powerOn = state;
+
+    if(aproxy->support_dualspk)
+        proxy_set_mixer_value_int(aproxy, SPK_AMPL_POWER_NAME, aproxy->spk_ampL_powerOn);
+}
+
+bool proxy_get_spk_ampL_power(void* proxy)
+{
+    struct audio_proxy *aproxy = proxy;
+    return aproxy->spk_ampL_powerOn;
+}
+
+void proxy_set_primary_mute(void* proxy, int count)
+{
+    struct audio_proxy *aproxy = proxy;
+    struct mixer_ctl *ctrl = NULL;
+    char mixer_name[MAX_MIXER_NAME_LEN];
+    int ret = 0, val = count;
+
+    pthread_rwlock_rdlock(&aproxy->mixer_update_lock);
+
+    ctrl = mixer_get_ctl_by_name(aproxy->mixer, ABOX_MUTE_CONTROL_NAME);
+    snprintf(mixer_name, sizeof(mixer_name), ABOX_MUTE_CONTROL_NAME);
+
+    if (ctrl) {
+        ret = mixer_ctl_set_value(ctrl, 0,val);
+        if (ret != 0)
+            ALOGE("proxy-%s: failed to set primary mute(%s)", __func__, mixer_name);
+        else
+            ALOGI("proxy-%s: set set primary mute(%s) to %d", __func__, mixer_name, val);
+    } else {
+        ALOGE("proxy-%s: cannot find primary mute", __func__);
+    }
+
+    pthread_rwlock_unlock(&aproxy->mixer_update_lock);
+
+    return ;
+}
+
+
+/*
+ *  Proxy Dump
+ */
+int proxy_fw_dump(int fd)
+{
+    ALOGV("proxy-%s: enter with file descriptor(%d)", __func__, fd);
+
+    calliope_ramdump(fd);
+
+    ALOGV("proxy-%s: exit with file descriptor(%d)", __func__, fd);
+
+    return 0;
+}
+
+
+/*
+ *  Proxy Device Creation/Destruction
+ */
+static void check_configurations(struct audio_proxy *aproxy)
+{
+    char property[PROPERTY_VALUE_MAX];
+
+    /* Audio Device Configurations */
+    // BuiltIn Earpiece
+    memset(property, 0, PROPERTY_VALUE_MAX);
+    property_get(NUM_EARPIECE_PROPERTY, property, NUM_EARPIECE_DEFAULT);
+    aproxy->num_earpiece = atoi(property);
+    ALOGI("proxy-%s: The supported number of BuiltIn Earpiece = %d", __func__, aproxy->num_earpiece);
+
+    // BuiltIn Speaker
+    memset(property, 0, PROPERTY_VALUE_MAX);
+    property_get(NUM_SPEAKER_PROPERTY, property, NUM_SPEAKER_DEFAULT);
+    aproxy->num_speaker = atoi(property);
+    ALOGI("proxy-%s: The supported number of BuiltIn Speaker = %d", __func__, aproxy->num_speaker);
+
+    if (aproxy->num_speaker == 2)
+        ALOGI("proxy-%s: This set supports Dual Speaker", __func__);
+
+    // BuiltIn Mic
+    ALOGI("proxy-%s: The number of supported BuiltIn Mic = %d", __func__, aproxy->num_mic);
+
+    // Proximity Sensor
+    memset(property, 0, PROPERTY_VALUE_MAX);
+    property_get(NUM_PROXIMITY_PROPERTY, property, NUM_PROXIMITY_DEFAULT);
+    aproxy->num_proximity = atoi(property);
+    ALOGI("proxy-%s: The supported number of Proximity Sensor = %d", __func__, aproxy->num_proximity);
+
+    // Speaker AMP
+    memset(property, 0, PROPERTY_VALUE_MAX);
+    property_get(SPEAKER_AMP_PROPERTY, property, SPEAKER_AMP_DEFAULT);
+    aproxy->support_spkamp = (bool)atoi(property);
+    if (aproxy->support_spkamp)
+        ALOGI("proxy-%s: The Speaker AMP is supported", __func__);
+
+    // Bluetooth
+    memset(property, 0, PROPERTY_VALUE_MAX);
+    property_get(BLUETOOTH_PROPERTY, property, BLUETOOTH_DEFAULT);
+    if (strcmp(property, "external") == 0) {
+        aproxy->bt_external = true;
+        ALOGI("proxy-%s: The supported BT is External", __func__);
+    } else if (strcmp(property, "internal") == 0) {
+        aproxy->bt_internal = true;
+        ALOGI("proxy-%s: The supported BT is Internal", __func__);
+    } else
+        ALOGI("proxy-%s: The supported BT is None", __func__);
+
+    // FM Radio
+    memset(property, 0, PROPERTY_VALUE_MAX);
+    property_get(FMRADIO_PROPERTY, property, FMRADIO_DEFAULT);
+    if (strcmp(property, "external") == 0) {
+        aproxy->fm_external = true;
+        ALOGI("proxy-%s: The supported FM Radio is External", __func__);
+    } else if (strcmp(property, "internal") == 0) {
+        aproxy->fm_internal = true;
+        ALOGI("proxy-%s: The supported FM Radio is Internal", __func__);
+    } else
+        ALOGI("proxy-%s: The supported FM Radio is None", __func__);
+
+
+    /* A-Box Configurations */
+    // USB Device
+    memset(property, 0, PROPERTY_VALUE_MAX);
+    property_get(USBBYPRIMARY_PROPERTY, property, USBBYPRIMARY_DEFAULT);
+    if (strcmp(property, "yes") == 0) {
+        aproxy->usb_by_primary = true;
+        ALOGI("proxy-%s: The USB Device is supported by Primary AudioHAL", __func__);
+    } else {
+        aproxy->usb_by_primary = false;
+        ALOGI("proxy-%s: The USB Device is supported by USB AudioHAL", __func__);
+    }
+
+    return ;
+}
+
+static bool find_enum_from_string(struct audio_string_to_enum *table, const char *name,
+                                  int32_t table_cnt, int *value)
+{
+    int i;
+
+    for (i = 0; i < table_cnt; i++) {
+        if (strcmp(table[i].name, name) == 0) {
+            *value = table[i].value;
+            return true;
+        }
+    }
+    return false;
+}
+
+static void set_microphone_info(struct audio_microphone_characteristic_t *microphone, const XML_Char **attr)
+{
+    uint32_t curIdx = 0;
+    uint32_t array_cnt = 0;
+    float f_value[3] = {0, };
+    char *ptr = NULL;
+
+    if (strcmp(attr[curIdx++], "device_id") == 0)
+        strcpy(microphone->device_id, attr[curIdx++]);
+
+    if (strcmp(attr[curIdx++], "id") == 0)
+        microphone->id = atoi(attr[curIdx++]);
+
+    if (strcmp(attr[curIdx++], "device") == 0)
+        find_enum_from_string(device_in_type, attr[curIdx++], ARRAY_SIZE(device_in_type), (int *)&microphone->device);
+
+    if (strcmp(attr[curIdx++], "address") == 0)
+        strcpy(microphone->address, attr[curIdx++]);
+
+    if (strcmp(attr[curIdx++], "location") == 0)
+        find_enum_from_string(microphone_location, attr[curIdx++], AUDIO_MICROPHONE_LOCATION_CNT, (int *)&microphone->location);
+
+    if (strcmp(attr[curIdx++], "group") == 0)
+        microphone->group = atoi(attr[curIdx++]);
+
+    if (strcmp(attr[curIdx++], "index_in_the_group") == 0)
+        microphone->index_in_the_group = atoi(attr[curIdx++]);
+
+    if (strcmp(attr[curIdx++], "sensitivity") == 0)
+        microphone->sensitivity = atof(attr[curIdx++]);
+
+    if (strcmp(attr[curIdx++], "max_spl") == 0)
+        microphone->max_spl = atof(attr[curIdx++]);
+
+    if (strcmp(attr[curIdx++], "min_spl") == 0)
+        microphone->min_spl = atof(attr[curIdx++]);
+
+    if (strcmp(attr[curIdx++], "directionality") == 0)
+        find_enum_from_string(microphone_directionality, attr[curIdx++],
+                              AUDIO_MICROPHONE_LOCATION_CNT, (int *)&microphone->directionality);
+
+    if (strcmp(attr[curIdx++], "num_frequency_responses") == 0) {
+        microphone->num_frequency_responses = atoi(attr[curIdx++]);
+        if (microphone->num_frequency_responses > 0) {
+            if (strcmp(attr[curIdx++], "frequencies") == 0) {
+                ptr = strtok((char *)attr[curIdx++], " ");
+                while(ptr != NULL) {
+                    microphone->frequency_responses[0][array_cnt++] = atof(ptr);
+                    ptr = strtok(NULL, " ");
+                }
+            }
+            array_cnt = 0;
+            if (strcmp(attr[curIdx++], "responses") == 0) {
+                ptr = strtok((char *)attr[curIdx++], " ");
+                while(ptr != NULL) {
+                    microphone->frequency_responses[1][array_cnt++] = atof(ptr);
+                    ptr = strtok(NULL, " ");
+                }
+            }
+        }
+    }
+
+    if (strcmp(attr[curIdx++], "geometric_location") == 0) {
+        ptr = strtok((char *)attr[curIdx++], " ");
+        array_cnt = 0;
+        while (ptr != NULL) {
+            f_value[array_cnt++] = atof(ptr);
+            ptr = strtok(NULL, " ");
+        }
+        microphone->geometric_location.x = f_value[0];
+        microphone->geometric_location.y = f_value[1];
+        microphone->geometric_location.z = f_value[2];
+    }
+
+    if (strcmp(attr[curIdx++], "orientation") == 0) {
+        ptr = strtok((char *)attr[curIdx++], " ");
+        array_cnt = 0;
+        while (ptr != NULL) {
+            f_value[array_cnt++] = atof(ptr);
+            ptr = strtok(NULL, " ");
+        }
+        microphone->orientation.x = f_value[0];
+        microphone->orientation.y = f_value[1];
+        microphone->orientation.z = f_value[2];
+    }
+
+    /* Channel mapping doesn't used for now. */
+    for (array_cnt = 0; array_cnt < AUDIO_CHANNEL_COUNT_MAX; array_cnt++)
+        microphone->channel_mapping[array_cnt] = AUDIO_MICROPHONE_CHANNEL_MAPPING_UNUSED;
+}
+
+static void end_tag(void *data, const XML_Char *tag_name)
+{
+    if (strcmp(tag_name, "microphone_characteristis") == 0)
+        set_info = INFO_NONE;
+}
+
+static void start_tag(void *data, const XML_Char *tag_name, const XML_Char **attr)
+{
+    struct audio_proxy *aproxy = getInstance();
+    const XML_Char *attr_name  = NULL;
+    const XML_Char *attr_value = NULL;
+
+    if (strcmp(tag_name, "microphone_characteristics") == 0) {
+        set_info = MICROPHONE_CHARACTERISTIC;
+    } else if (strcmp(tag_name, "microphone") == 0) {
+        if (set_info != MICROPHONE_CHARACTERISTIC) {
+            ALOGE("proxy-%s: microphone tag should be supported with microphone_characteristics tag", __func__);
+            return ;
+        }
+        set_microphone_info(&aproxy->mic_info[aproxy->num_mic++], attr);
+    }
+}
+
+void proxy_set_board_info(void *proxy)
+{
+    struct audio_proxy *aproxy = (struct audio_proxy *)proxy;
+    XML_Parser parser = 0;
+    FILE *file = NULL;
+    char info_file_name[MAX_MIXER_NAME_LEN] = {0};
+    void *buf = NULL;
+    uint32_t buf_size = 1024;
+    int32_t bytes_read = 0;
+
+    strlcpy(info_file_name, BOARD_INFO_XML_PATH, MAX_MIXER_NAME_LEN);
+
+    file = fopen(info_file_name, "r");
+    if (file == NULL)
+        ALOGE("proxy-%s: open error: %s, file=%s", __func__, strerror(errno), info_file_name);
+    else
+        ALOGI("proxy-%s: Board info file name is %s", __func__, info_file_name);
+
+    parser = XML_ParserCreate(NULL);
+
+    XML_SetElementHandler(parser, start_tag, end_tag);
+
+    while (1) {
+        buf = XML_GetBuffer(parser, buf_size);
+        if (buf == NULL) {
+            ALOGE("proxy-%s fail to get buffer", __func__);
+            break;
+        }
+
+        bytes_read = fread(buf, 1, buf_size, file);
+        if (bytes_read < 0) {
+            ALOGE("proxy-%s fail to read from file", __func__);
+            break;
+        }
+
+        XML_ParseBuffer(parser, bytes_read, bytes_read == 0);
+
+        if (bytes_read == 0)
+            break;
+    }
+
+    XML_ParserFree(parser);
+    fclose(file);
+
+    check_configurations(aproxy);
+}
+
+bool proxy_is_initialized(void)
+{
+    if (instance)
+        return true;
+    else
+        return false;
+}
+
+void * proxy_init(void)
+{
+    struct audio_proxy *aproxy;
+    char sound_trigger_hal_path[100] = {0, };
+
+    /* Creates the structure for audio_proxy. */
+    aproxy = getInstance();
+    if (!aproxy) {
+        ALOGE("proxy-%s: failed to create for audio_proxy", __func__);
+        return NULL;
+    }
+
+    aproxy->primary_out = NULL;
+
+    // In case of Output Loopback Support, initializes Out Loopback Stream
+    aproxy->support_out_loopback = true;
+    aproxy->out_loopback = NULL;
+    aproxy->erap_in = NULL;
+
+    // In case of External Speaker AMP Support, initializes Reference & Playback Stream
+    aproxy->support_spkamp = true;
+    aproxy->spkamp_reference = NULL;
+    aproxy->spkamp_playback = NULL;
+#ifdef SUPPORT_BTA2DP_OFFLOAD
+    // BT A2DP Devices Support by Primary AudioHAL
+    pthread_mutex_init(&aproxy->a2dp_lock, (const pthread_mutexattr_t *) NULL);
+
+    pthread_mutex_lock(&aproxy->a2dp_lock);
+    proxy_a2dp_init();
+    aproxy->support_bta2dp = true;
+    aproxy->a2dp_out_enabled = false;
+    aproxy->a2dp_suspend = false;
+    aproxy->a2dp_delay = 0;
+    aproxy->a2dp_default_delay = 0;
+    aproxy->bta2dp_playback = NULL;
+    aproxy->bta2dp_out_loopback = NULL;
+    pthread_mutex_unlock(&aproxy->a2dp_lock);
+    aproxy->a2dp_mute_playback = NULL;
+#endif
+    // In case of External BT-SCO Support, initializes Playback Stream
+    aproxy->support_btsco = true;
+    aproxy->btsco_playback = NULL;
+
+    // Voice Call PCM Devices
+    aproxy->call_rx = NULL;
+    aproxy->call_tx = NULL;
+    aproxy->call_tx_direct = NULL;
+
+    // FM Radio PCM Devices
+    aproxy->fm_playback = NULL;
+    aproxy->fm_capture  = NULL;
+
+    aproxy->usb_aproxy = proxy_usb_init();
+    if (!aproxy->usb_aproxy) {
+        ALOGE("proxy-%s: failed to create audio_proxy_usb", __func__);
+        destroyInstance();
+        return NULL;
+    }
+
+    // In case of USB Input Loopback Support, initializes Out/In Loopback Streams
+    aproxy->support_usb_out_loopback = true;
+    aproxy->usb_out_loopback = NULL;
+    aproxy->support_usb_in_loopback = true;
+    aproxy->usb_in_loopback = NULL;
+
+    // Call State
+    aproxy->call_state = false;
+    aproxy->skip_internalpath = false;
+
+    /* Audio Mode */
+    aproxy->audio_mode = AUDIO_MODE_NORMAL;
+
+    // STHAL interface initialization
+#ifdef SUPPORT_STHAL_INTERFACE
+    aproxy->sthal_state = 0;
+
+    snprintf(sound_trigger_hal_path, sizeof(sound_trigger_hal_path),
+             SOUND_TRIGGER_HAL_LIBRARY_PATH, XSTR(TARGET_SOC_NAME));
+
+    aproxy->sound_trigger_lib = dlopen(sound_trigger_hal_path, RTLD_NOW);
+    if (aproxy->sound_trigger_lib == NULL) {
+        ALOGE("%s: DLOPEN failed for %s", __func__, sound_trigger_hal_path);
+    } else {
+        ALOGV("%s: DLOPEN successful for %s", __func__, sound_trigger_hal_path);
+        aproxy->sound_trigger_open_for_streaming =
+                    (int (*)(void))dlsym(aproxy->sound_trigger_lib,
+                                                    "sound_trigger_open_for_streaming");
+        aproxy->sound_trigger_read_samples =
+                    (size_t (*)(int, void*, size_t))dlsym(aproxy->sound_trigger_lib,
+                                                    "sound_trigger_read_samples");
+        aproxy->sound_trigger_close_for_streaming =
+                    (int (*)(int))dlsym(aproxy->sound_trigger_lib,
+                                                    "sound_trigger_close_for_streaming");
+        aproxy->sound_trigger_open_recording =
+                    (int (*)(void))dlsym(aproxy->sound_trigger_lib,
+                                                   "sound_trigger_open_recording");
+        aproxy->sound_trigger_read_recording_samples =
+                    (size_t (*)(void*, size_t))dlsym(aproxy->sound_trigger_lib,
+                                                   "sound_trigger_read_recording_samples");
+        aproxy->sound_trigger_close_recording =
+                    (int (*)(int))dlsym(aproxy->sound_trigger_lib,
+                                                   "sound_trigger_close_recording");
+        aproxy->sound_trigger_headset_status =
+                    (int (*)(int))dlsym(aproxy->sound_trigger_lib,
+                                                    "sound_trigger_headset_status");
+        aproxy->sound_trigger_voicecall_status =
+                    (int (*)(int))dlsym(aproxy->sound_trigger_lib,
+                                                    "sound_trigger_voicecall_status");
+        if (!aproxy->sound_trigger_open_for_streaming ||
+            !aproxy->sound_trigger_read_samples ||
+            !aproxy->sound_trigger_close_for_streaming ||
+            !aproxy->sound_trigger_open_recording ||
+            !aproxy->sound_trigger_read_recording_samples ||
+            !aproxy->sound_trigger_close_recording ||
+            !aproxy->sound_trigger_headset_status ||
+            !aproxy->sound_trigger_voicecall_status) {
+
+            ALOGE("%s: Error grabbing functions in %s", __func__, sound_trigger_hal_path);
+            aproxy->sound_trigger_open_for_streaming = 0;
+            aproxy->sound_trigger_read_samples = 0;
+            aproxy->sound_trigger_close_for_streaming = 0;
+            aproxy->sound_trigger_open_recording = 0;
+            aproxy->sound_trigger_read_recording_samples = 0;
+            aproxy->sound_trigger_close_recording = 0;
+            aproxy->sound_trigger_headset_status = 0;
+            aproxy->sound_trigger_voicecall_status = 0;
+        }
+    }
+#endif
+
+    /* offload effect */
+    aproxy->offload_effect_lib = NULL;
+    aproxy->offload_effect_lib_update = NULL;
+    aproxy->spk_ampL_powerOn = false;
+
+    ALOGI("proxy-%s: opened & initialized Audio Proxy", __func__);
+    return (void *)aproxy;
+}
+
+void proxy_deinit(void *proxy)
+{
+    struct audio_proxy *aproxy = (struct audio_proxy *)proxy;
+
+    if (aproxy) {
+#ifdef SUPPORT_BTA2DP_OFFLOAD
+        // BT A2DP Devices Support by Primary AudioHAL
+        if (aproxy->support_bta2dp) {
+            pthread_mutex_lock(&aproxy->a2dp_lock);
+            proxy_a2dp_deinit();
+            pthread_mutex_unlock(&aproxy->a2dp_lock);
+
+            pthread_mutex_destroy(&aproxy->a2dp_lock);
+        }
+#endif
+        // USB Devices Support by Primary AudioHAL
+        proxy_usb_deinit(aproxy->usb_aproxy);
+
+        destroyInstance();
+        ALOGI("proxy-%s: destroyed for audio_proxy", __func__);
+    }
+    return ;
+}
+
diff --git a/audio/proxy/audio_proxy.h b/audio/proxy/audio_proxy.h
new file mode 100644
index 0000000..8c1e25b
--- /dev/null
+++ b/audio/proxy/audio_proxy.h
@@ -0,0 +1,234 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AUDIO_PROXY_H
+#define AUDIO_PROXY_H
+
+#include <system/audio.h>
+#include <hardware/hardware.h>
+#include <hardware/audio.h>
+#include <hardware/audio_alsaops.h>
+
+#include <audio_utils/resampler.h>
+
+#include "alsa_device_profile.h"
+#include "alsa_device_proxy.h"
+#include "alsa_logging.h"
+
+#include "audio_streams.h"
+#include "audio_usages.h"
+#include "audio_devices.h"
+#include "audio_offload.h"
+
+#include "audio_pcm.h"
+#include "audio_mixer.h"
+#include "audio_abox.h"
+#include "audio_streamconfig.h"
+#include "audio_board_info.h"
+
+/* Data Structure for Audio Proxy */
+struct audio_proxy_stream
+{
+    audio_stream_type stream_type;
+    audio_usage       stream_usage;
+
+    // Real configuration for PCM/Compress Device
+    int sound_card;
+    int sound_device;
+
+    /* DMA pcm handle is required for triggering Virtual node use-case */
+    struct pcm *dma_pcm;
+    /* Can be actual DMA handle or virtual pcm depends upon scenario */
+    struct pcm *pcm;
+    struct pcm_config pcmconfig;
+
+    // Offload Specific
+    struct compress *compress;
+    struct compr_config comprconfig;
+
+    int nonblock_flag;
+    int ready_new_metadata;
+    struct compr_gapless_mdata offload_metadata;
+
+    // USB Specific
+    alsa_device_profile *usb_profile;
+    alsa_device_proxy   *usb_proxy;
+
+    // Common
+    unsigned int            requested_sample_rate;
+    audio_channel_mask_t    requested_channel_mask;
+    audio_format_t          requested_format;
+
+    float vol_left, vol_right;
+
+    uint64_t frames; /* total frames written, not cleared when entering standby */
+
+
+    // Channel Conversion & Resample for Recording
+    bool   need_channelconversion;
+    bool   need_resampling;
+
+    int16_t* actual_read_buf;
+    int      actual_read_status;
+    size_t   actual_read_buf_size;
+    size_t   read_buf_frames;
+
+    void *   proc_buf_out;
+    int      proc_buf_size;
+
+    // Resampler
+    struct resampler_itfe *             resampler;
+    struct resampler_buffer_provider    buf_provider;
+
+
+#ifdef SUPPORT_STHAL_INTERFACE
+    int soundtrigger_handle;
+#ifdef SEAMLESS_DUMP
+    FILE *fp;
+#endif
+#endif
+
+    bool   need_update_pcm_config;
+    bool   skip_ch_convert;
+    bool   need_channelpadding;
+};
+
+struct audio_proxy
+{
+    // Audio Path Routing
+    struct mixer *mixer;
+    struct audio_route *aroute;
+    char *xml_path;
+
+    // Mixer Update Thread
+    pthread_rwlock_t mixer_update_lock;
+    pthread_t        mixer_update_thread;
+
+    audio_usage   active_playback_ausage;
+    device_type   active_playback_device;
+    modifier_type active_playback_modifier;
+
+    audio_usage   active_capture_ausage;
+    device_type   active_capture_device;
+    modifier_type active_capture_modifier;
+
+    // Primary Output Stream Proxy
+    struct audio_proxy_stream *primary_out;
+
+    /* Device Configuration */
+    int num_earpiece;
+    int num_speaker;
+    int num_proximity;
+
+    /* BuiltIn MIC Characteristics Map */
+    int num_mic;
+    struct audio_microphone_characteristic_t mic_info[AUDIO_MICROPHONE_MAX_COUNT];
+
+    // PCM Devices for Audio Path(Loopback / ERAP)
+    bool support_out_loopback;
+    struct pcm *out_loopback;
+    struct pcm *erap_in;
+
+    /* Speaker AMP Configuration */
+    bool support_spkamp;
+    struct pcm *spkamp_reference;
+    struct pcm *spkamp_playback;
+
+    /* Bluetooth Configuration */
+    bool bt_internal;
+    bool bt_external;
+
+#ifdef SUPPORT_BTA2DP_OFFLOAD
+    pthread_mutex_t a2dp_lock;
+    bool     support_bta2dp;
+    bool     a2dp_out_enabled;
+    bool     a2dp_suspend;
+    uint32_t a2dp_delay;
+    uint32_t a2dp_default_delay;
+    struct pcm *bta2dp_playback;
+    struct pcm *bta2dp_out_loopback;
+    struct pcm *a2dp_mute_playback;
+#endif
+
+    bool support_btsco;
+    struct pcm *btsco_playback;
+
+    /* FM Radio Configuration */
+    bool fm_internal;
+    bool fm_external;
+
+    struct pcm *fm_playback;     // FM PCM Playback from A-Box
+    struct pcm *fm_capture;      // FM PCM Capture to A-Box
+
+    /* USB Configuration */
+    bool usb_by_primary;
+    bool is_usb_single_clksrc;   // USB device clock source info
+
+    void *usb_aproxy;
+
+    // PCM Devices for USB Audio
+    bool support_usb_out_loopback;
+    struct pcm *usb_out_loopback;
+    bool support_usb_in_loopback;
+    struct pcm *usb_in_loopback;
+
+    /* PCM Devices for Voice Call */
+    struct pcm *call_rx;    // CP to Output Devices
+    struct pcm *call_tx;    // Input Devices to CP
+    struct pcm *call_tx_direct;    // Direct routing for Input Devices
+
+    // Call State
+    bool call_state;
+
+    /* Audio Mode */
+    int audio_mode;
+    bool skip_internalpath;     // flag to skip internal pcm close/re-open
+
+    // Voice WakeUp
+#ifdef SUPPORT_STHAL_INTERFACE
+    /* SoundTrigger library interface */
+    void *sound_trigger_lib;
+    int (*sound_trigger_open_for_streaming)();
+    size_t (*sound_trigger_read_samples)(int, void*, size_t);
+    int (*sound_trigger_close_for_streaming)(int);
+    int (*sound_trigger_open_recording)();
+    size_t (*sound_trigger_read_recording_samples)(void*, size_t);
+    int (*sound_trigger_close_recording)();
+
+    int (*sound_trigger_headset_status)(int);
+    int (*sound_trigger_voicecall_status)(int);
+
+    int sthal_state;
+#endif
+
+    void *offload_effect_lib;
+    void (*offload_effect_lib_update)(struct mixer *, int);
+
+    bool support_dualspk;  //Dual Speaker
+    bool spk_ampL_powerOn; //Dual Speaker
+};
+
+
+#define MIXER_UPDATE_TIMEOUT    5  // 5 seconds
+
+#define STR(s) #s
+#define XSTR(s) STR(s)
+
+#ifdef SUPPORT_STHAL_INTERFACE
+#define SOUND_TRIGGER_HAL_LIBRARY_PATH "sound_trigger.primary.%s.so"
+#endif
+
+#endif /* AUDIO_PROXY_H */
diff --git a/audio/proxy/audio_streamconfig.h b/audio/proxy/audio_streamconfig.h
new file mode 100644
index 0000000..2886632
--- /dev/null
+++ b/audio/proxy/audio_streamconfig.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __EXYNOS_AUDIOPROXY_STREAMCONFIG_H__
+#define __EXYNOS_AUDIOPROXY_STREAMCONFIG_H__
+
+
+/*
+ * This header file defines Supported Configurations for each Audio Streams.
+ * These configurations can be different as projects and boards,
+ * so engineers should modify this file based on audio_policy_configuration.xml.
+ */
+
+// Supported Audio Format Tables
+char * stream_format_table[ASTREAM_CNT] = {
+    [ASTREAM_PLAYBACK_NO_ATTRIBUTE]  = "AUDIO_FORMAT_PCM_16_BIT",
+    [ASTREAM_PLAYBACK_PRIMARY]       = "AUDIO_FORMAT_PCM_16_BIT",
+    [ASTREAM_PLAYBACK_FAST]          = "AUDIO_FORMAT_PCM_16_BIT",
+    [ASTREAM_PLAYBACK_DEEP_BUFFER]   = "AUDIO_FORMAT_PCM_8_24_BIT",
+    [ASTREAM_PLAYBACK_LOW_LATENCY]   = "AUDIO_FORMAT_PCM_16_BIT",
+    [ASTREAM_PLAYBACK_COMPR_OFFLOAD] = "AUDIO_FORMAT_MP3",
+    [ASTREAM_PLAYBACK_MMAP]          = "AUDIO_FORMAT_PCM_16_BIT",
+    [ASTREAM_PLAYBACK_AUX_DIGITAL]   = "AUDIO_FORMAT_PCM_16_BIT",
+    [ASTREAM_PLAYBACK_DIRECT]        = "AUDIO_FORMAT_PCM_16_BIT|AUDIO_FORMAT_PCM_8_24_BIT|AUDIO_FORMAT_PCM_32_BIT",
+
+    [ASTREAM_CAPTURE_NO_ATTRIBUTE]   = "AUDIO_FORMAT_PCM_16_BIT",
+    [ASTREAM_CAPTURE_PRIMARY]        = "AUDIO_FORMAT_PCM_16_BIT",
+    [ASTREAM_CAPTURE_CALL]           = "AUDIO_FORMAT_PCM_16_BIT",
+    [ASTREAM_CAPTURE_LOW_LATENCY]    = "AUDIO_FORMAT_PCM_16_BIT",
+    [ASTREAM_CAPTURE_MMAP]           = "AUDIO_FORMAT_PCM_16_BIT",
+    [ASTREAM_CAPTURE_FM]             = "AUDIO_FORMAT_PCM_16_BIT",
+    [ASTREAM_CAPTURE_TELEPHONYRX]    = "AUDIO_FORMAT_PCM_16_BIT",
+#ifdef SUPPORT_STHAL_INTERFACE
+    [ASTREAM_CAPTURE_HOTWORD]        = "AUDIO_FORMAT_PCM_16_BIT",
+#endif
+
+    [ASTREAM_NONE]                   = "AUDIO_FORMAT_INVALID"
+};
+
+// Supported Audio Channel Mask Tables
+char * stream_channel_table[ASTREAM_CNT] = {
+    [ASTREAM_PLAYBACK_NO_ATTRIBUTE]  = "AUDIO_CHANNEL_OUT_MONO|AUDIO_CHANNEL_OUT_STEREO",
+    [ASTREAM_PLAYBACK_PRIMARY]       = "AUDIO_CHANNEL_OUT_STEREO",
+    [ASTREAM_PLAYBACK_FAST]          = "AUDIO_CHANNEL_OUT_STEREO",
+    [ASTREAM_PLAYBACK_DEEP_BUFFER]   = "AUDIO_CHANNEL_OUT_STEREO",
+    [ASTREAM_PLAYBACK_LOW_LATENCY]   = "AUDIO_CHANNEL_OUT_STEREO",
+    [ASTREAM_PLAYBACK_COMPR_OFFLOAD] = "AUDIO_CHANNEL_OUT_STEREO",
+    [ASTREAM_PLAYBACK_MMAP]          = "AUDIO_CHANNEL_OUT_STEREO",
+    [ASTREAM_PLAYBACK_AUX_DIGITAL]   = "AUDIO_CHANNEL_OUT_STEREO",
+    [ASTREAM_PLAYBACK_DIRECT]       = "AUDIO_CHANNEL_OUT_5POINT1|AUDIO_CHANNEL_OUT_6POINT1|AUDIO_CHANNEL_OUT_7POINT1",
+
+    [ASTREAM_CAPTURE_NO_ATTRIBUTE]   = "AUDIO_CHANNEL_IN_MONO|AUDIO_CHANNEL_IN_STEREO",
+    [ASTREAM_CAPTURE_PRIMARY]        = "AUDIO_CHANNEL_IN_MONO|AUDIO_CHANNEL_IN_STEREO",
+    [ASTREAM_CAPTURE_CALL]           = "AUDIO_CHANNEL_IN_MONO|AUDIO_CHANNEL_IN_STEREO",
+    [ASTREAM_CAPTURE_LOW_LATENCY]    = "AUDIO_CHANNEL_IN_MONO|AUDIO_CHANNEL_IN_STEREO",
+    [ASTREAM_CAPTURE_MMAP]           = "AUDIO_CHANNEL_IN_MONO|AUDIO_CHANNEL_IN_STEREO",
+    [ASTREAM_CAPTURE_FM]             = "AUDIO_CHANNEL_IN_MONO|AUDIO_CHANNEL_IN_STEREO",
+    [ASTREAM_CAPTURE_TELEPHONYRX]    = "AUDIO_CHANNEL_IN_MONO|AUDIO_CHANNEL_IN_STEREO",
+#ifdef SUPPORT_STHAL_INTERFACE
+    [ASTREAM_CAPTURE_HOTWORD]        = "AUDIO_CHANNEL_IN_MONO|AUDIO_CHANNEL_IN_STEREO",
+#endif
+
+    [ASTREAM_NONE]                   = "AUDIO_CHANNEL_INVALID"
+};
+
+// Supported Audio Sampling Rate Tables
+char * stream_rate_table[ASTREAM_CNT] = {
+    [ASTREAM_PLAYBACK_NO_ATTRIBUTE]  = "48000",
+    [ASTREAM_PLAYBACK_PRIMARY]       = "48000",
+    [ASTREAM_PLAYBACK_FAST]          = "48000",
+    [ASTREAM_PLAYBACK_DEEP_BUFFER]   = "48000",
+    [ASTREAM_PLAYBACK_LOW_LATENCY]   = "48000",
+    [ASTREAM_PLAYBACK_COMPR_OFFLOAD] = "48000",
+    [ASTREAM_PLAYBACK_MMAP]          = "48000",
+    [ASTREAM_PLAYBACK_AUX_DIGITAL]   = "48000",
+    [ASTREAM_PLAYBACK_DIRECT]        = "8000|16000|32000|44100|48000|96000|192000|384000",
+
+    [ASTREAM_CAPTURE_NO_ATTRIBUTE]   = "8000|16000|32000|48000",
+    [ASTREAM_CAPTURE_PRIMARY]        = "8000|16000|32000|48000",
+    [ASTREAM_CAPTURE_CALL]           = "8000|16000|32000|48000",
+    [ASTREAM_CAPTURE_LOW_LATENCY]    = "48000",
+    [ASTREAM_CAPTURE_MMAP]           = "48000",
+    [ASTREAM_CAPTURE_FM]             = "8000|16000|32000|48000",
+    [ASTREAM_CAPTURE_TELEPHONYRX]    = "8000|16000|32000|48000",
+#ifdef SUPPORT_STHAL_INTERFACE
+    [ASTREAM_CAPTURE_HOTWORD]        = "8000|16000|32000|48000",
+#endif
+
+    [ASTREAM_NONE]                   = "0"
+};
+
+#endif  // __EXYNOS_AUDIOPROXY_STREAMCONFIG_H__
diff --git a/audio/proxy/audio_usb_proxy.c b/audio/proxy/audio_usb_proxy.c
new file mode 100644
index 0000000..6284948
--- /dev/null
+++ b/audio/proxy/audio_usb_proxy.c
@@ -0,0 +1,1790 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "audio_hw_proxy_usb"
+#define LOG_NDEBUG 0
+
+//#define VERY_VERY_VERBOSE_LOGGING
+#ifdef VERY_VERY_VERBOSE_LOGGING
+#define ALOGVV ALOGD
+#else
+#define ALOGVV(a...) do { } while(0)
+#endif
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <pthread.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <dlfcn.h>
+#include <unistd.h>
+
+#include <log/log.h>
+#include <cutils/str_parms.h>
+
+#include <audio_utils/channels.h>
+#include <audio_utils/primitives.h>
+#include <audio_utils/clock.h>
+#include <tinyalsa/asoundlib.h>
+
+#include <system/audio.h>
+#include <hardware/hardware.h>
+#include <hardware/audio.h>
+
+#include "audio_usb_proxy.h"
+
+#define USB_READ_BUFF_SIZE      2048
+#define CHANNEL_NUMBER_STR      "Channels: "
+#define PLAYBACK_PROFILE_STR    "Playback:"
+#define CAPTURE_PROFILE_STR     "Capture:"
+#define DATA_PACKET_INTERVAL_STR "Data packet interval: "
+#define USB_SIDETONE_GAIN_STR   "usb_sidetone_gain"
+#define ABS_SUB(x, y) (((x) > (y)) ? ((x) - (y)):((y) - (x)))
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+#define _MAX(x, y) (((x) >= (y)) ? (x) : (y))
+#define _MIN(x, y) (((x) <= (y)) ? (x) : (y))
+
+
+/* format in order of increasing preference */
+static const int pcm_format_preference_map[] = {
+    PCM_FORMAT_S8,
+    PCM_FORMAT_S16_LE,
+    PCM_FORMAT_S24_LE,
+    PCM_FORMAT_S24_3LE,
+    PCM_FORMAT_S32_LE
+};
+
+/******************************************************************************/
+/**                                                                          **/
+/** Audio Proxy is Singleton                                                 **/
+/**                                                                          **/
+/******************************************************************************/
+
+static struct audio_proxy_usb *usb_instance = NULL;
+
+static struct audio_proxy_usb* getUSBInstance(void)
+{
+    if (usb_instance == NULL) {
+        usb_instance = calloc(1, sizeof(struct audio_proxy_usb));
+        ALOGI("proxy-%s: created Audio Proxy USB Instance!", __func__);
+    }
+    return usb_instance;
+}
+
+static void destroyUSBInstance(void)
+{
+    if (usb_instance) {
+        free(usb_instance);
+        usb_instance = NULL;
+        ALOGI("proxy-%s: destroyed Audio Proxy USB Instance!", __func__);
+    }
+    return;
+}
+
+/******************************************************************************/
+/**                                                                          **/
+/** USB card profile information util functions                              **/
+/**                                                                          **/
+/******************************************************************************/
+static int usb_extract_rates_from_ratestr(
+    char *rates_str,
+    struct usb_device_info *dev_config,
+    unsigned int *rates_mask)
+{
+    uint32_t i;
+    char *next_sr_string, *temp_ptr;
+    uint32_t rate, min_rate, max_rate, rate_size = 0;
+
+    /* USB device profile Sample rate string can be in two different formats as shown below
+     * Rates: 8000 - 48000 (continuous)
+     * Rates: 8000, 44100, 48000
+     * This function supports both formats for rates parsing
+     */
+    ALOGVV("%s: rates_str %s", __func__, rates_str);
+    next_sr_string = strtok_r(rates_str, "Rates: ", &temp_ptr);
+    if (next_sr_string == NULL) {
+        ALOGE("%s: could not find min rates string", __func__);
+        return -EINVAL;
+    }
+    if (strstr(rates_str, "continuous") != NULL) {
+        min_rate = (uint32_t)atoi(next_sr_string);
+        next_sr_string = strtok_r(NULL, " ,.-", &temp_ptr);
+        if (next_sr_string == NULL) {
+            ALOGE("%s: could not find max rates string", __func__);
+            return -EINVAL;
+        }
+        max_rate = (uint32_t)atoi(next_sr_string);
+
+        for (i = 0; i < MAX_NUM_USB_SR; i++) {
+            if (supported_usb_samplingrates[i] >= min_rate &&
+                supported_usb_samplingrates[i] <= max_rate) {
+                dev_config->rates[rate_size++] = supported_usb_samplingrates[i];
+                ALOGVV("%s: continuous sample rate supported_usb_samplingrates[%d] %d",
+                    __func__, i, supported_usb_samplingrates[i]);
+                *rates_mask |= (1<<i);
+            }
+        }
+    } else {
+        do {
+            rate = (uint32_t)atoi(next_sr_string);
+            for (i = 0; i < MAX_NUM_USB_SR; i++) {
+                if (supported_usb_samplingrates[i] == rate) {
+                    ALOGVV("%s: sr %d, supported_usb_samplingrates[%d] %d",
+                        __func__, rate, i, supported_usb_samplingrates[i]);
+                    dev_config->rates[rate_size++] = supported_usb_samplingrates[i];
+                    *rates_mask |= (1<<i);
+                }
+            }
+            next_sr_string = strtok_r(NULL, " ,.-", &temp_ptr);
+        } while (next_sr_string != NULL);
+    }
+    dev_config->rate_size = rate_size;
+    return 0;
+}
+
+static int usb_get_profile_capability(void *proxy, int direction)
+{
+    struct audio_proxy_usb *aproxy_usb = proxy;
+    int32_t size = 0;
+    int32_t fd =-1;
+    char *start_str = NULL;
+    char *end_str = NULL;
+    char *channel_str_start = NULL;
+    char *format_str_start = NULL;
+    char *rates_str_start = NULL;
+    char *format_str = NULL;
+    char *rate_str = NULL;
+    char *lineend_str = NULL;
+    char *read_buf = NULL;
+    char *interval_start_str = NULL;
+    char path[128];
+    int ret = 0;
+    bool check = false;
+    int retries = 5;
+    struct usb_device_info *usb_devconfig;
+    struct listnode *usb_devlist = NULL;
+    int card = -1;
+    unsigned long interval = 0;
+    unsigned int *formats_mask;
+    unsigned int *rates_mask;
+    unsigned int *channels_mask;
+
+    if (direction == USB_OUT) {
+        usb_devlist = &aproxy_usb->usbplayback_devlist;
+        card = aproxy_usb->usb_out_pcm_card;
+        formats_mask = &aproxy_usb->usb_out_formats_mask;
+        channels_mask = &aproxy_usb->usb_out_channels_mask;
+        rates_mask = &aproxy_usb->usb_out_rates_mask;
+    } else {
+        usb_devlist = &aproxy_usb->usbcapture_devlist;
+        card = aproxy_usb->usb_in_pcm_card;
+        formats_mask = &aproxy_usb->usb_in_formats_mask;
+        channels_mask = &aproxy_usb->usb_in_channels_mask;
+        rates_mask = &aproxy_usb->usb_in_rates_mask;
+    }
+
+    memset(path, 0, sizeof(path));
+    // direction: 0 for playback & 1 for capture
+    ALOGI("%s: for %s", __func__, (direction == USB_OUT) ?
+          PLAYBACK_PROFILE_STR : CAPTURE_PROFILE_STR);
+
+    /* generate device access path with card information */
+    ret = snprintf(path, sizeof(path), "/proc/asound/card%u/stream0",
+             card);
+    if (ret < 0) {
+        ALOGE("%s: failed on snprintf (%d) to path %s\n",
+          __func__, ret, path);
+        goto done;
+    }
+
+    while (retries--) {
+        if (access(path, F_OK) < 0) {
+            ALOGW("stream %s doesn't exist retrying\n", path);
+            sleep(1);
+            continue;
+        }
+    }
+
+    fd = open(path, O_RDONLY);
+    if (fd <0) {
+        ALOGE("%s: error failed to open config file %s error: %d\n",
+              __func__, path, errno);
+        ret = -EINVAL;
+        goto done;
+    }
+
+    read_buf = (char *)calloc(1, USB_READ_BUFF_SIZE + 1);
+
+    if (!read_buf) {
+        ALOGE("Failed to create read_buf");
+        ret = -ENOMEM;
+        goto done;
+    }
+
+    if(read(fd, read_buf, USB_READ_BUFF_SIZE) < 0) {
+        ALOGE("file read error\n");
+        goto done;
+    }
+
+    start_str = strstr(read_buf, ((direction == USB_OUT) ?
+                       PLAYBACK_PROFILE_STR : CAPTURE_PROFILE_STR));
+    if (start_str == NULL) {
+        ALOGE("%s: error %s section not found in usb config file",
+               __func__, ((direction == USB_OUT) ?
+               PLAYBACK_PROFILE_STR : CAPTURE_PROFILE_STR));
+        ret = -EINVAL;
+        goto done;
+    }
+    end_str = strstr(read_buf, ((direction == USB_OUT) ?
+                       CAPTURE_PROFILE_STR : PLAYBACK_PROFILE_STR));
+    if (end_str > start_str)
+        check = true;
+
+    ALOGVV("%s: usb_config = %s, check %d\n", __func__, start_str, check);
+
+    while (start_str != NULL) {
+        start_str = strstr(start_str, "Altset");
+        if ((start_str == NULL) || (check  && (start_str >= end_str))) {
+            ALOGVV("%s: done parsing %s\n", __func__, start_str);
+            break;
+        }
+        ALOGVV("%s: remaining string %s\n", __func__, start_str);
+        start_str += sizeof("Altset");
+        usb_devconfig = calloc(1, sizeof(struct usb_device_info));
+        if (usb_devconfig == NULL) {
+            ALOGE("%s: error unable to allocate memory",
+                  __func__);
+            ret = -ENOMEM;
+            break;
+        }
+        //usb_devconfig->type = type;
+        /* format parsing */
+        format_str_start = strstr(start_str, "Format: ");
+        if (format_str_start == NULL) {
+            ALOGI("%s: Could not find bit_width string", __func__);
+            free(usb_devconfig);
+            continue;
+        }
+        lineend_str = strchr(format_str_start, '\n');
+        if (lineend_str == NULL) {
+            ALOGI("%s:end of line not found", __func__);
+            free(usb_devconfig);
+            continue;
+        }
+        size = lineend_str - format_str_start;
+        if ((format_str = (char *)malloc(size + 1)) == NULL) {
+            ALOGE("%s: unable to allocate memory to hold bit width strings",
+                  __func__);
+            ret = -EINVAL;
+            free(usb_devconfig);
+            break;
+        }
+        memcpy(format_str, format_str_start, size);
+        format_str[size] = '\0';
+        if (strstr(format_str, "S16_LE")) {
+            usb_devconfig->bit_width = 16;
+            usb_devconfig->format = PCM_FORMAT_S16_LE;
+            *formats_mask |= (1 << 3);
+        } else if (strstr(format_str, "S24_LE")) {
+            usb_devconfig->bit_width = 24;
+            usb_devconfig->format = PCM_FORMAT_S24_LE;
+            *formats_mask |= (1 << 2);
+        } else if (strstr(format_str, "S24_3LE")) {
+            usb_devconfig->bit_width = 24;
+            usb_devconfig->format = PCM_FORMAT_S24_3LE;
+            *formats_mask |= (1 << 1);
+        } else if (strstr(format_str, "S32_LE")) {
+            usb_devconfig->bit_width = 32;
+            usb_devconfig->format = PCM_FORMAT_S32_LE;
+            *formats_mask |= (1);
+        }
+
+        if (format_str)
+            free(format_str);
+
+        /* channels parsing */
+        channel_str_start = strstr(start_str, CHANNEL_NUMBER_STR);
+        if (channel_str_start == NULL) {
+            ALOGI("%s: could not find Channels string", __func__);
+            free(usb_devconfig);
+            continue;
+        }
+        usb_devconfig->channels = atoi(channel_str_start + strlen(CHANNEL_NUMBER_STR));
+        *channels_mask |= (1 << usb_devconfig->channels);
+
+        /* Sample rates parsing */
+        rates_str_start = strstr(start_str, "Rates: ");
+        if (rates_str_start == NULL) {
+            ALOGI("%s: cant find rates string", __func__);
+            free(usb_devconfig);
+            continue;
+        }
+        lineend_str = strchr(rates_str_start, '\n');
+        if (lineend_str == NULL) {
+            ALOGI("%s: end of line not found", __func__);
+            free(usb_devconfig);
+            continue;
+        }
+        size = lineend_str - rates_str_start;
+        if ((rate_str = (char *)malloc(size + 1)) == NULL) {
+            ALOGE("%s: unable to allocate memory to hold sample rate strings",
+                  __func__);
+            ret = -EINVAL;
+            free(usb_devconfig);
+            break;
+        }
+        memcpy(rate_str, rates_str_start, size);
+        rate_str[size] = '\0';
+        ret = usb_extract_rates_from_ratestr(rate_str, usb_devconfig, rates_mask);
+        if (rate_str)
+            free(rate_str);
+        if (ret < 0) {
+            ALOGE("%s: error unable to get sample rate values",
+                  __func__);
+            free(usb_devconfig);
+            continue;
+        }
+
+        /* Add to list if every field is valid */
+        list_add_tail(usb_devlist, &usb_devconfig->node);
+    }
+
+done:
+    if (fd >= 0) close(fd);
+    if (read_buf) free(read_buf);
+
+    return ret;
+}
+
+static void usb_remove_device_info(void *proxy, int direction)
+{
+    struct audio_proxy_usb *aproxy_usb = proxy;
+    struct listnode *node, *auxi;
+    struct usb_device_info *devinfo_node;
+    struct listnode *usb_devlist = ((direction == USB_OUT) ? &aproxy_usb->usbplayback_devlist
+                : &aproxy_usb->usbcapture_devlist);
+    int count = 0;
+
+    // Removes this stream from playback list
+    list_for_each_safe(node, auxi, usb_devlist)
+    {
+        devinfo_node = node_to_item(node, struct usb_device_info, node);
+        if (devinfo_node) {
+            ALOGI("%s: USB_Device[%s] %d: Info", __func__, ((direction == USB_OUT) ?
+                "PLAYBACK" : "CAPTURE"), ++count);
+            list_remove(node);
+            free(devinfo_node);
+        }
+    }
+
+    return;
+}
+static void usb_print_device_info(void *proxy, int direction)
+{
+    struct audio_proxy_usb *aproxy_usb = proxy;
+    struct listnode *node;
+    struct usb_device_info *devinfo_node;
+    struct listnode *usb_devlist = ((direction == USB_OUT) ? &aproxy_usb->usbplayback_devlist
+                : &aproxy_usb->usbcapture_devlist);
+    int count = 0;
+
+    list_for_each(node, usb_devlist)
+    {
+        devinfo_node = node_to_item(node, struct usb_device_info, node);
+        if (devinfo_node) {
+            ALOGI("USB_Device[%s] %d: Info", ((direction == USB_OUT) ? "PLAYBACK" :
+                "CAPTURE"), ++count);
+            if (devinfo_node->format == PCM_FORMAT_S24_3LE ||
+                devinfo_node->format == PCM_FORMAT_S24_LE)
+                ALOGI("\t bit-width: %d (%s)", devinfo_node->bit_width,
+                ((devinfo_node->format == PCM_FORMAT_S24_3LE) ? "packed" : "padded"));
+            else
+                ALOGI("\t bit-width: %d", devinfo_node->bit_width);
+            ALOGI("\t channels: %d", devinfo_node->channels);
+            ALOGI("\t rate:");
+            for(unsigned int idx = 0; idx < devinfo_node->rate_size; idx++)
+                ALOGI("\t %d", devinfo_node->rates[idx]);
+        }
+    }
+
+    return;
+}
+
+static int usb_get_best_matching_format(
+    struct listnode *usb_devlist,
+    enum pcm_format stream_format)
+{
+    struct listnode *node;
+    struct usb_device_info *devinfo_node;
+    enum pcm_format selected_format = PCM_FORMAT_INVALID;
+    enum pcm_format cur_format = PCM_FORMAT_INVALID;
+
+    list_for_each(node, usb_devlist)
+    {
+        devinfo_node = node_to_item(node, struct usb_device_info, node);
+        if (devinfo_node) {
+            cur_format = devinfo_node->format;
+            ALOGVV("%s: USB fmt(%d) stream fmt(%d) selected fmt(%d)",
+                __func__, cur_format, stream_format, selected_format);
+            if ((cur_format == stream_format)
+                || (cur_format == PCM_FORMAT_S24_3LE
+                && stream_format == PCM_FORMAT_S24_LE)) {
+                selected_format = cur_format;
+                ALOGI("%s: found matching fmt(%d) stream fmt(%d)",
+                    __func__, selected_format, stream_format);
+                goto exit;
+            } else if (selected_format == PCM_FORMAT_INVALID) {
+                selected_format = cur_format;
+            } else if (IS_HIGHEST_PCMFORMAT(cur_format, selected_format)) {
+                selected_format = cur_format;
+                ALOGI("%s: found better matching fmt(%d) stream fmt(%d)",
+                    __func__, selected_format, stream_format);
+            }
+        }
+    }
+exit:
+    return selected_format;
+}
+
+static unsigned int usb_get_best_matching_channels(
+    struct listnode *usb_devlist,
+    int format,
+    unsigned int stream_channels)
+{
+    struct listnode *node;
+    struct usb_device_info *devinfo_node;
+    enum pcm_format cur_format = PCM_FORMAT_INVALID;
+    unsigned int selected_channels = 0;
+    unsigned cur_channels = 0;
+
+    list_for_each(node, usb_devlist)
+    {
+        devinfo_node = node_to_item(node, struct usb_device_info, node);
+        if (devinfo_node) {
+            cur_format = devinfo_node->format;
+            cur_channels = devinfo_node->channels;
+            ALOGVV("%s: USB fmt(%d)ch(%d) stream fmt(%d)ch(%d) selected ch(%d)",
+                __func__, cur_format, cur_channels, format,
+                stream_channels, selected_channels);
+            if (cur_format != format)
+                continue;
+            if (cur_channels == stream_channels) {
+                selected_channels = cur_channels;
+                ALOGI("%s: found matching ch(%d) stream ch(%d)",
+                    __func__, selected_channels, stream_channels);
+                goto exit;
+            } else if (selected_channels == 0) {
+                selected_channels = cur_channels;
+            } else if (((cur_channels > stream_channels) &&
+                    (ABS_SUB(stream_channels, cur_channels) <
+                    ABS_SUB(stream_channels, selected_channels))) ||
+                    ((cur_channels > selected_channels) &&
+                    (stream_channels > cur_channels))) {
+                selected_channels = cur_channels;
+                ALOGI("%s: found better matching ch(%d) stream ch(%d)",
+                    __func__, selected_channels, stream_channels);
+            }
+        }
+    }
+exit:
+    return selected_channels;
+}
+
+static unsigned int usb_get_best_matching_samplerate(
+    struct listnode *usb_devlist,
+    int format,
+    unsigned int channels,
+    unsigned int stream_rate)
+{
+    struct listnode *node;
+    struct usb_device_info *devinfo_node;
+    enum pcm_format cur_format = PCM_FORMAT_INVALID;
+    unsigned cur_channels = 0;
+    unsigned int selected_rate = 0;
+    unsigned int cur_rate = 0;
+    unsigned int i = 0;
+
+    list_for_each(node, usb_devlist)
+    {
+        devinfo_node = node_to_item(node, struct usb_device_info, node);
+        if (devinfo_node) {
+            cur_format = devinfo_node->format;
+            cur_channels = devinfo_node->channels;
+            ALOGVV("%s: USB fmt(%d)ch(%d) stream fmt(%d)ch(%d)rate(%d) selected rate(%d)",
+                __func__, cur_format, cur_channels, format, channels,
+                stream_rate, selected_rate);
+            if ((cur_format != format)
+                || (cur_channels != channels))
+                continue;
+            for (i = 0; i < devinfo_node->rate_size; i++) {
+                ALOGVV("%s: usb next rate(%d) selected rate(%d)",
+                        __func__, devinfo_node->rates[i], selected_rate);
+                if (devinfo_node->rates[i] == stream_rate) {
+                    selected_rate = devinfo_node->rates[i];
+                    ALOGI("%s: found matching rate(%d) stream rate(%d)",
+                        __func__, selected_rate, stream_rate);
+                    goto exit;
+                } else if (selected_rate == 0) {
+                    selected_rate = devinfo_node->rates[i];
+                    ALOGI("%s: initial updated rate(%d) stream rate(%d)",
+                        __func__, selected_rate, stream_rate);
+                } else if (((devinfo_node->rates[i] > stream_rate) &&
+                            (ABS_SUB(stream_rate, devinfo_node->rates[i]) <
+                            ABS_SUB(stream_rate, selected_rate))) ||
+                            ((devinfo_node->rates[i] > selected_rate) &&
+                            (stream_rate > devinfo_node->rates[i]))) {
+                    selected_rate = devinfo_node->rates[i];
+                    ALOGI("%s: found better matching rate(%d) stream rate(%d)",
+                        __func__, selected_rate, stream_rate);
+                }
+            }
+        }
+    }
+exit:
+    return selected_rate;
+}
+
+static bool usb_get_best_matching_config(
+    struct listnode *usb_devlist,
+    enum pcm_format stream_format,
+    unsigned int stream_channels,
+    unsigned int stream_rate,
+    struct pcm_config *best_pcmconfig)
+{
+    /* get best matching USB config for active pcm config
+     * matching sequence
+     * first select best format,
+     * second select channels using selected format.
+     * third select sample rate using selected format & channels
+     */
+    ALOGI("proxy-%s: stream config SR(%d) CH(%d) FMT(%d)", __func__,
+        stream_rate,
+        stream_channels,
+        stream_format);
+
+    best_pcmconfig->format = usb_get_best_matching_format(usb_devlist,
+                                                    stream_format);
+    best_pcmconfig->channels = usb_get_best_matching_channels(usb_devlist,
+                                                    best_pcmconfig->format,
+                                                    stream_channels);
+    best_pcmconfig->rate = usb_get_best_matching_samplerate(usb_devlist,
+                                                    best_pcmconfig->format,
+                                                    best_pcmconfig->channels,
+                                                    stream_rate);
+
+    ALOGI("proxy-%s: USB best matching config SR(%d) CH(%d) FMT(%d)", __func__,
+            best_pcmconfig->rate,
+            best_pcmconfig->channels,
+            best_pcmconfig->format);
+
+    return true;
+}
+
+static unsigned int usb_get_max_channel(struct listnode *usb_devlist)
+{
+    struct listnode *node;
+    struct usb_device_info *devinfo_node;
+    unsigned int selected_channels = 0;
+    unsigned cur_channels = 0;
+
+    list_for_each(node, usb_devlist)
+    {
+        devinfo_node = node_to_item(node, struct usb_device_info, node);
+        if (devinfo_node) {
+            cur_channels = devinfo_node->channels;
+            if (cur_channels > selected_channels)
+                selected_channels = cur_channels;
+        }
+    }
+
+    ALOGI("%s: max channel count ch(%d)", __func__, selected_channels);
+
+    return selected_channels;
+}
+
+static unsigned int usb_get_min_channel(struct listnode *usb_devlist)
+{
+    struct listnode *node;
+    struct usb_device_info *devinfo_node;
+    unsigned int selected_channels = FCC_8;
+    unsigned cur_channels = 0;
+
+    list_for_each(node, usb_devlist)
+    {
+        devinfo_node = node_to_item(node, struct usb_device_info, node);
+        if (devinfo_node) {
+            cur_channels = devinfo_node->channels;
+            if (cur_channels < selected_channels)
+                selected_channels = cur_channels;
+        }
+    }
+
+    ALOGI("%s: min channel count ch(%d)", __func__, selected_channels);
+
+    return selected_channels;
+}
+
+char * usb_get_format_strs(const unsigned int formats_mask)
+{
+    /* if we assume that format strings are about 24 characters (AUDIO_FORMAT_PCM_16_BIT is 23),
+     * plus ~1 for a delimiter "|" this buffer has room for about 10 format strings which seems
+     *  like way too much, but it's a stack variable so only temporary.
+     */
+    char buffer[256];
+    buffer[0] = '\0';
+    size_t buffSize = ARRAY_SIZE(buffer);
+    size_t curStrLen = 0;
+    int idx = 0;
+    unsigned int mask = formats_mask;
+    unsigned int count = _MIN(MAX_NUM_USB_FORMAT, (unsigned int)__builtin_popcount(mask));
+    size_t numEntries = 0;
+
+    ALOGVV("%s: mask:0x%x count:%d", __func__, mask, count);
+
+    while (count--) {
+        idx = __builtin_ffs(mask) - 1;
+        // account for both the null, and potentially the bar.
+        if (buffSize - curStrLen < strlen(supported_usb_format_strs[idx])
+                                   + (numEntries != 0 ? 2 : 1)) {
+            /* we don't have room for another, so bail at this point rather than
+             * return a malformed rate string
+             */
+            break;
+        }
+
+        if (numEntries++ != 0) {
+            strlcat(buffer, "|", buffSize);
+        }
+        curStrLen = strlcat(buffer, supported_usb_format_strs[idx], buffSize);
+        mask &= ~(1<<idx);
+    }
+    ALOGI("%s: %s", __func__, buffer);
+    return strdup(buffer);
+}
+
+char * usb_get_channel_count_strs(void* proxy_usb, const unsigned int channels_mask, int direction)
+{
+    struct audio_proxy_usb *aproxy_usb = (struct audio_proxy_usb *)proxy_usb;
+    /*
+     * If we assume each channel string is 26 chars ("AUDIO_CHANNEL_INDEX_MASK_8" is 26) + 1 for,
+     * the "|" delimiter, then we allocate room for 16 strings.
+     */
+    char buffer[27 * 16 + 1]; /* caution, may need to be expanded */
+    buffer[0] = '\0';
+    size_t buffSize = ARRAY_SIZE(buffer);
+    size_t curStrLen = 0;
+    unsigned int mask = channels_mask;
+    struct listnode *usb_devlist = ((direction == USB_OUT) ?
+                                    &aproxy_usb->usbplayback_devlist :
+                                    &aproxy_usb->usbcapture_devlist);
+    unsigned int max = usb_get_max_channel(usb_devlist);
+    unsigned int min = usb_get_min_channel(usb_devlist);
+    size_t numEntries = 0;
+    char *const *const chans_strs = ((direction == USB_OUT) ?
+                                            supported_usb_out_channel_strs :
+                                            supported_usb_in_channel_strs);
+    unsigned int idx = ((direction == USB_OUT) ? FCC_2 : 1); // OUT start from Stereo, IN start from Mono
+
+    ALOGI("%s: mask:0x%x max:min channels[%d:%d]", __func__, mask, max, min);
+
+    for (; idx <= MAX_NUM_USB_CHANNELS; idx++) {
+        if (idx >= min && idx <= max) {
+            ALOGVV("%s: idx:0x%x channels:%s", __func__, idx, supported_usb_channel_strs[idx]);
+            // account for both the null, and potentially the bar.
+            if (buffSize - curStrLen < strlen(supported_usb_channel_strs[idx])
+                                       + (numEntries != 0 ? 2 : 1)) {
+                /* we don't have room for another, so bail at this point rather than
+                 * return a malformed rate string
+                 */
+                break;
+            }
+
+            if (idx == 1 || idx == 2) {
+                if (numEntries++ != 0) {
+                    strlcat(buffer, "|", buffSize);
+                }
+                curStrLen = strlcat(buffer, chans_strs[idx], buffSize);
+            }
+
+            if (numEntries++ != 0) {
+                strlcat(buffer, "|", buffSize);
+            }
+            curStrLen = strlcat(buffer, supported_usb_channel_strs[idx], buffSize);
+        }
+    }
+    ALOGI("%s: %s", __func__, buffer);
+    return strdup(buffer);
+}
+
+char * usb_get_sample_rate_strs(const unsigned int rates_mask)
+{
+    /* if we assume that rate strings are about 5 characters (48000 is 5), plus ~1 for a
+     * delimiter "|" this buffer has room for about 22 rate strings which seems like
+     * way too much, but it's a stack variable so only temporary.
+     */
+    char buffer[128];
+    buffer[0] = '\0';
+    size_t buffSize = ARRAY_SIZE(buffer);
+    size_t curStrLen = 0;
+    int idx = 0;
+    unsigned int mask = rates_mask;
+    unsigned int count = _MIN(MAX_NUM_USB_SR, (unsigned int)__builtin_popcount(mask));
+    size_t numEntries = 0;
+
+    ALOGVV("%s: mask:0x%x count:%d", __func__, mask, count);
+
+    while (count--) {
+        idx = __builtin_ffs(mask) - 1;
+        ALOGVV("%s: idx:0x%x rate:%s", __func__, idx, supported_usb_samplingrate_strs[idx]);
+        // account for both the null, and potentially the bar.
+        if (buffSize - curStrLen < strlen(supported_usb_samplingrate_strs[idx])
+                                   + (numEntries != 0 ? 2 : 1)) {
+            /* we don't have room for another, so bail at this point rather than
+             * return a malformed rate string
+             */
+            break;
+        }
+
+        if (numEntries++ != 0) {
+            strlcat(buffer, "|", buffSize);
+        }
+        curStrLen = strlcat(buffer, supported_usb_samplingrate_strs[idx], buffSize);
+        mask &= ~(1<<idx);
+    }
+
+    ALOGI("%s: %s", __func__, buffer);
+    return strdup(buffer);
+}
+
+/******************************************************************************/
+/**                                                                          **/
+/** Local Functions of USB Audio Proxy                                       **/
+/**                                                                          **/
+/******************************************************************************/
+/* Functions should be called with usb_lock mutex */
+
+// This function is to load usb gain mixer paths xml file
+static int usb_audio_gain_load_xml(void *proxy, int usb_card)
+{
+    struct audio_proxy_usb *aproxy_usb = proxy;
+    char gain_mixer_path[MAX_USB_PATH_LEN];
+    int ret = 0;
+
+    memset(gain_mixer_path, 0, MAX_USB_PATH_LEN);
+
+    // read gain xml based on PID values
+    if (aproxy_usb->usb_pid == USB_BUNDLE_WHITE_PID) {
+        strcpy(gain_mixer_path, USB_BUNDLE_WHITE_GAIN_XML_MIXER_PATH);
+        ALOGI("proxy-%s: USB White Bundle GainControl XML [%s] loading",
+            __func__, gain_mixer_path);
+    } else {
+        strcpy(gain_mixer_path, USB_BUNDLE_GRAY_GAIN_XML_MIXER_PATH);
+        ALOGI("proxy-%s: USB Gray Bundle GainControl XML [%s] loading",
+            __func__, gain_mixer_path);
+    }
+
+    //initialize audio_route with gain xml
+    aproxy_usb->usb_ar = audio_route_init(usb_card, gain_mixer_path);
+    if (!aproxy_usb->usb_ar) {
+        ALOGE("proxy-%s: failed to init audio route for USB Gain usb_card: %d",
+            __func__, usb_card);
+        ret = -EINVAL;
+    }
+
+    return ret;
+}
+
+// This function is to load usb gain mixer paths xml file
+static void usb_audio_gain_unload_xml(void *proxy)
+{
+    struct audio_proxy_usb *aproxy_usb = proxy;
+
+    if (aproxy_usb->usb_ar) {
+        audio_route_free(aproxy_usb->usb_ar);
+        aproxy_usb->usb_ar = NULL;
+    }
+
+    return;
+}
+
+/* Check to VID (Vendor ID):PID (Product ID) of USB Device and enable gain-control */
+static void usb_audio_gain_control_enable(void *proxy)
+{
+    struct audio_proxy_usb *aproxy_usb = proxy;
+    char path[MAX_USB_PATH_LEN];
+    char readbuf[USB_READ_SIZE];
+    char *endptr;
+    int usb_card = -1;
+    int fd = -1;
+    int ret = 0;
+
+    if (!aproxy_usb->usb_gaincontrol_needed &&
+        (aproxy_usb->usb_out_connected || aproxy_usb->usb_in_connected)) {
+        //get valid usb card number
+        if (aproxy_usb->usb_out_pcm_card != -1 ||
+            aproxy_usb->usb_in_pcm_card != -1) {
+            usb_card = ((aproxy_usb->usb_out_pcm_card != -1) ?
+                        aproxy_usb->usb_out_pcm_card :
+                        aproxy_usb->usb_in_pcm_card);
+        } else {
+            ALOGE("%s: failed get valid usb card", __func__);
+            goto err;
+        }
+
+        // get VID:PID information from usb device node
+        memset(path, 0, sizeof(path));
+        ret = snprintf(path, sizeof(path), "/proc/asound/card%u/usbid",
+                     usb_card);
+        if (ret < 0) {
+            ALOGE("%s: snprintf failed ret (%d)", __func__, ret);
+            goto err;
+        }
+
+        fd = open(path, O_RDONLY);
+        if (fd < 0) {
+            ALOGE("%s: failed to open usbid file %s error: %d",
+                  __func__, path, errno);
+            goto err;
+        }
+
+        if(read(fd, readbuf, USB_READ_SIZE) < 0) {
+           ALOGE("file read error");
+           goto err;
+       }
+
+        //extract VID and PID from string separated by colon
+        aproxy_usb->usb_vid = (int)strtol(readbuf, &endptr, 16);
+        if (endptr == NULL || *endptr == '\0' || *endptr != ':') {
+            ALOGE("failed to parse USB VID");
+            aproxy_usb->usb_vid = -1;
+            goto err;
+        }
+        aproxy_usb->usb_pid = (int)strtol((endptr+1), &endptr, 16);
+
+        ALOGI("proxy-%s: USB Device VID: 0x%x PID: 0x%x", __func__,
+            aproxy_usb->usb_vid, aproxy_usb->usb_pid);
+        // check VID & PID, for gain-control
+        if (aproxy_usb->usb_vid == USB_BUNDLE_VID &&
+            (aproxy_usb->usb_pid == USB_BUNDLE_WHITE_PID ||
+            aproxy_usb->usb_pid == USB_BUNDLE_GRAY_HEADPHONE_PID ||
+            aproxy_usb->usb_pid == USB_BUNDLE_GRAY_HEADSET_PID)) {
+            if (!usb_audio_gain_load_xml(aproxy_usb, usb_card)) {
+                aproxy_usb->usb_gaincontrol_needed = true;
+                ALOGI("proxy-%s: USB GainControl enabled", __func__);
+            } else {
+                ALOGW("proxy-%s: failed to load USB gain XML", __func__);
+            }
+        } else {
+            ALOGI("proxy-%s: USB GainControl not required", __func__);
+        }
+    } else {
+        if (aproxy_usb->usb_gaincontrol_needed)
+            ALOGI("proxy-%s: USB GainControl already enabled", __func__);
+        else
+            ALOGI("proxy-%s: USB Device not connected", __func__);
+    }
+
+err:
+    if (fd >= 0) close(fd);
+    return;
+}
+
+static void usb_audio_gain_control_disable(void *proxy)
+{
+    struct audio_proxy_usb *aproxy_usb = proxy;
+
+    if (aproxy_usb->usb_gaincontrol_needed &&
+        (!aproxy_usb->usb_out_connected && !aproxy_usb->usb_in_connected)) {
+            usb_audio_gain_unload_xml(aproxy_usb);
+            aproxy_usb->usb_gaincontrol_needed = false;
+            ALOGI("proxy-%s: USB GainControl disabled", __func__);
+    } else if (aproxy_usb->usb_gaincontrol_needed) {
+        ALOGI("proxy-%s: USB Device still in use", __func__);
+    }
+
+    return;
+}
+
+/* Function should be called with usb_lock mutex */
+static void usb_open_out_proxy(struct audio_proxy_usb *aproxy_usb)
+{
+    char pcm_path[MAX_USB_PATH_LEN];
+    unsigned int flags = PCM_OUT | PCM_MONOTONIC;
+    struct pcm_config *ppcmconfig = &aproxy_usb->usb_out_active_pcmconfig;
+    unsigned int size = 0;
+    uint16_t *dummy = NULL;
+
+    if (aproxy_usb && aproxy_usb->usb_out_connected) {
+        if (aproxy_usb->usb_out_status == false) {
+            /* Update period-size using updated config rate */
+            ppcmconfig->period_count = DEFAULT_USB_PERIOD_COUNT;
+            ppcmconfig->period_size = (ppcmconfig->rate * DEFAULT_USB_PLAYBACK_DURATION) / 1000;
+            ppcmconfig->stop_threshold = UINT_MAX;
+            aproxy_usb->usb_out_pcm = pcm_open(aproxy_usb->usb_out_pcm_card,
+                                                aproxy_usb->usb_out_pcm_device,
+                                                flags, ppcmconfig);
+            if (aproxy_usb->usb_out_pcm && !pcm_is_ready(aproxy_usb->usb_out_pcm)) {
+                /* pcm_open does always return pcm structure, not NULL */
+                ALOGE("%s-%s: PCM Device is not ready with Sampling_Rate(%u) error(%s)!",
+                      "usb_out", __func__, ppcmconfig->rate,
+                      pcm_get_error(aproxy_usb->usb_out_pcm));
+                goto err_open;
+            }
+
+            // Dummy write to trigger pcm_prepare
+            size = ppcmconfig->period_size;
+            dummy = (uint16_t *)calloc(1, size);
+            if (dummy && aproxy_usb->usb_out_pcm &&
+                pcm_write(aproxy_usb->usb_out_pcm, (void *)dummy, size) == 0) {
+                snprintf(pcm_path, sizeof(pcm_path), "/dev/snd/pcmC%uD%u%c",
+                         aproxy_usb->usb_out_pcm_card, aproxy_usb->usb_out_pcm_device, 'p');
+
+                ALOGI("%s-%s: The opened USB Out PCM Device is %s with SR(%d), CC(%d), Format(%d)",
+                    "usb-out", __func__, pcm_path,
+                    ppcmconfig->rate,
+                    ppcmconfig->channels,
+                    ppcmconfig->format);
+
+                aproxy_usb->usb_out_status = true;
+            } else {
+                ALOGE("%s-%s: USB Out PCM Device write failed %s",
+                        "usb-out", __func__,
+                        ((aproxy_usb->usb_out_pcm) ? pcm_get_error(aproxy_usb->usb_out_pcm) : "Error"));
+                goto err_open;
+            }
+
+            if (dummy)
+                free(dummy);
+        }
+    }
+
+    return;
+err_open:
+    if (aproxy_usb->usb_out_pcm) {
+        pcm_close(aproxy_usb->usb_out_pcm);
+        aproxy_usb->usb_out_pcm = NULL;
+    }
+    if (dummy)
+        free(dummy);
+
+    return;
+}
+
+/* Function should be called with usb_lock mutex */
+static void usb_close_out_proxy(struct audio_proxy_usb *aproxy_usb)
+{
+    if (aproxy_usb && aproxy_usb->usb_out_connected) {
+        if (aproxy_usb->usb_out_status == true) {
+            if (aproxy_usb->usb_out_pcm) {
+                pcm_close(aproxy_usb->usb_out_pcm);
+                aproxy_usb->usb_out_pcm = NULL;
+            }
+            ALOGI("proxy-%s: closed USB Out PCM Device", __func__);
+
+            aproxy_usb->usb_out_status = false;
+        }
+    }
+
+    return ;
+}
+
+static void usb_open_in_proxy(struct audio_proxy_usb *aproxy_usb)
+{
+    char pcm_path[MAX_USB_PATH_LEN];
+    unsigned int flags = PCM_IN | PCM_MONOTONIC;
+    struct pcm_config *ppcmconfig = &aproxy_usb->usb_in_active_pcmconfig;
+
+    if (aproxy_usb && aproxy_usb->usb_in_connected) {
+        /* Update period-size using updated config rate */
+        ppcmconfig->period_count = DEFAULT_USB_PERIOD_COUNT;
+        ppcmconfig->period_size = (ppcmconfig->rate * DEFAULT_USB_CAPTURE_DURATION) / 1000;
+        aproxy_usb->usb_in_pcm = pcm_open(aproxy_usb->usb_in_pcm_card,
+                                            aproxy_usb->usb_in_pcm_device,
+                                            flags, ppcmconfig);
+        if (aproxy_usb->usb_in_pcm && !pcm_is_ready(aproxy_usb->usb_in_pcm)) {
+            /* pcm_open does always return pcm structure, not NULL */
+            ALOGE("%s-%s: PCM Device is not ready with Sampling_Rate(%u) error(%s)!",
+                  "usb_in", __func__, ppcmconfig->rate,
+                  pcm_get_error(aproxy_usb->usb_in_pcm));
+            goto err_open;
+        }
+
+        snprintf(pcm_path, sizeof(pcm_path), "/dev/snd/pcmC%uD%u%c",
+                 aproxy_usb->usb_in_pcm_card, aproxy_usb->usb_in_pcm_device, 'c');
+
+        ALOGVV("%s-%s: USB In PCM Device opened %s with SR(%d), CC(%d), Format(%d)",
+                "usb-in", __func__, pcm_path,
+                ppcmconfig->rate,
+                ppcmconfig->channels,
+                ppcmconfig->format);
+
+        if (aproxy_usb->usb_in_pcm && pcm_start(aproxy_usb->usb_in_pcm) == 0) {
+            ALOGI("%s-%s: USB In PCM Device opened/started %s with SR(%d), CC(%d), Format(%d)",
+                    "usb-in", __func__, pcm_path,
+                    ppcmconfig->rate,
+                    ppcmconfig->channels,
+                    ppcmconfig->format);
+        } else {
+            ALOGE("%s-%s: PCM Device(%s) with SR(%u) CC(%d) Format(%d) cannot be started as error(%s)",
+                "usb-in", __func__, pcm_path,
+                ppcmconfig->rate,
+                ppcmconfig->channels,
+                ppcmconfig->format,
+                ((aproxy_usb->usb_in_pcm) ? pcm_get_error(aproxy_usb->usb_in_pcm) : "Error"));
+            goto err_open;
+        }
+    }
+
+    return;
+err_open:
+    if (aproxy_usb->usb_in_pcm) {
+        pcm_close(aproxy_usb->usb_in_pcm);
+        aproxy_usb->usb_in_pcm = NULL;
+    }
+
+    return;
+}
+
+static void usb_close_in_proxy(struct audio_proxy_usb *aproxy_usb)
+{
+    if (aproxy_usb && aproxy_usb->usb_in_connected) {
+        if (aproxy_usb->usb_in_pcm) {
+            pcm_close(aproxy_usb->usb_in_pcm);
+            aproxy_usb->usb_in_pcm = NULL;
+        }
+        ALOGI("proxy-%s: closed USB In PCM Device", __func__);
+    }
+
+    return ;
+}
+
+static bool parse_card_device_params(const char *kvpairs, int *card, int *device)
+{
+    struct str_parms * parms = str_parms_create_str(kvpairs);
+    char value[32];
+    int param_val;
+
+    // initialize to "undefined" state.
+    *card = -1;
+    *device = -1;
+
+    param_val = str_parms_get_str(parms, "card", value, sizeof(value));
+    if (param_val >= 0) {
+        *card = atoi(value);
+    }
+
+    param_val = str_parms_get_str(parms, "device", value, sizeof(value));
+    if (param_val >= 0) {
+        *device = atoi(value);
+    }
+
+    str_parms_destroy(parms);
+
+    return *card >= 0 && *device >= 0;
+}
+
+/******************************************************************************/
+/**                                                                          **/
+/** Interface Functions of USB Audio Proxy                                   **/
+/**                                                                          **/
+/******************************************************************************/
+int proxy_is_usb_playback_CPCall_prepared(void *proxy_usb)
+{
+    struct audio_proxy_usb *aproxy_usb = (struct audio_proxy_usb *)proxy_usb;
+    return aproxy_usb->usb_out_cpcall_prepared;
+}
+
+int proxy_is_usb_playback_device_connected(void *proxy_usb)
+{
+    struct audio_proxy_usb *aproxy_usb = (struct audio_proxy_usb *)proxy_usb;
+    return aproxy_usb->usb_out_connected;
+}
+
+int proxy_is_usb_capture_device_connected(void *proxy_usb)
+{
+    struct audio_proxy_usb *aproxy_usb = (struct audio_proxy_usb *)proxy_usb;
+    return aproxy_usb->usb_in_connected;
+}
+
+unsigned int proxy_usb_get_capture_samplerate(void *proxy_usb)
+{
+    struct audio_proxy_usb *aproxy_usb = (struct audio_proxy_usb *)proxy_usb;
+    return aproxy_usb->usb_in_active_pcmconfig.rate;
+}
+
+unsigned int proxy_usb_get_capture_channels(void *proxy_usb)
+{
+    struct audio_proxy_usb *aproxy_usb = (struct audio_proxy_usb *)proxy_usb;
+    return aproxy_usb->usb_in_active_pcmconfig.channels;
+}
+
+int proxy_usb_get_capture_format(void *proxy_usb)
+{
+    struct audio_proxy_usb *aproxy_usb = (struct audio_proxy_usb *)proxy_usb;
+    return aproxy_usb->usb_in_active_pcmconfig.format;
+}
+
+int proxy_usb_get_playback_samplerate(void *proxy_usb)
+{
+    struct audio_proxy_usb *aproxy_usb = (struct audio_proxy_usb *)proxy_usb;
+    return aproxy_usb->usb_out_active_pcmconfig.rate;
+}
+
+int proxy_usb_get_playback_channels(void *proxy_usb)
+{
+    struct audio_proxy_usb *aproxy_usb = (struct audio_proxy_usb *)proxy_usb;
+    return aproxy_usb->usb_out_active_pcmconfig.channels;
+}
+
+int proxy_usb_get_playback_format(void *proxy_usb)
+{
+    struct audio_proxy_usb *aproxy_usb = (struct audio_proxy_usb *)proxy_usb;
+    return aproxy_usb->usb_out_active_pcmconfig.format;
+}
+
+int proxy_usb_get_playback_bitwidth(void *proxy_usb)
+{
+    struct audio_proxy_usb *aproxy_usb = (struct audio_proxy_usb *)proxy_usb;
+    int ret = 0;
+    switch (aproxy_usb->usb_out_active_pcmconfig.format) {
+    case PCM_FORMAT_S16_LE:  /* 16-bit signed */
+        ret = 16;
+        break;
+    case PCM_FORMAT_S32_LE:      /* 32-bit signed */
+        ret = 32;
+        break;
+    case PCM_FORMAT_S24_LE:      /* 24-bits in 4-bytes */
+    case PCM_FORMAT_S24_3LE:     /* 24-bits in 3-bytes */
+        ret = 24;
+        break;
+    case PCM_FORMAT_S8:          /* 8-bit signed */
+    default:
+        ret = 16;
+        break;
+    }
+
+    return ret;
+}
+
+int proxy_usb_get_playback_highest_supported_channels(void *proxy_usb)
+{
+    struct audio_proxy_usb *aproxy_usb = (struct audio_proxy_usb *)proxy_usb;
+    return usb_get_max_channel(&aproxy_usb->usbplayback_devlist);
+}
+
+void proxy_usb_playback_prepare(void *proxy_usb, bool set_default)
+{
+    struct audio_proxy_usb *aproxy_usb = (struct audio_proxy_usb *)proxy_usb;
+    // Configure sample rate based on flag
+    // set_default: 'false' means CPCall configuration 48KHz, 16bit, 2CH or supported
+    // set_default: 'true' means to configure selected best playback pcmconfig or supported
+    if (set_default) {
+        /* Use picked stream PCM config and check USB device supported list
+         * Check whether picked config is supported by connect USB device or not
+         * if supported: use picked config
+         * if Not supported: Use default supported config */
+        usb_get_best_matching_config(&aproxy_usb->usbplayback_devlist,
+            aproxy_usb->active_playback_picked_format,
+            aproxy_usb->active_playback_picked_channels,
+            aproxy_usb->active_playback_picked_rate,
+            &aproxy_usb->usb_out_active_pcmconfig);
+        aproxy_usb->usb_out_cpcall_prepared = false;
+    } else { // CPCall fixed or supported configuration
+        usb_get_best_matching_config(&aproxy_usb->usbplayback_devlist,
+            DEFAULT_USB_MEDIA_FORMAT,
+            DEFAULT_USB_MEDIA_CHANNELS,
+            DEFAULT_USB_MEDIA_SAMPLING_RATE,
+            &aproxy_usb->usb_out_active_pcmconfig);
+        aproxy_usb->usb_out_cpcall_prepared = true;
+    }
+
+    ALOGI("proxy-%s: configured USB Out Proxy SR(%d) CH(%d) FMT(%d)", __func__,
+        aproxy_usb->usb_out_active_pcmconfig.rate,
+        aproxy_usb->usb_out_active_pcmconfig.channels,
+        aproxy_usb->usb_out_active_pcmconfig.format);
+
+    return;
+}
+
+int proxy_usb_getparam_playback_stream(void *proxy_usb, void *query_params, void *reply_params)
+{
+    struct audio_proxy_usb *aproxy_usb = (struct audio_proxy_usb *)proxy_usb;
+    struct str_parms *query = (struct str_parms *)query_params;
+    struct str_parms *reply = (struct str_parms *)reply_params;
+
+    if (aproxy_usb->usb_out_connected) {
+        // supported sample formats
+        if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_FORMATS)) {
+            char * format_list = usb_get_format_strs(aproxy_usb->usb_out_formats_mask);
+            if (format_list) {
+                str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_SUP_FORMATS, format_list);
+                free(format_list);
+            }
+        }
+
+        // supported channel counts
+        if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_CHANNELS)) {
+            char* channels_list = usb_get_channel_count_strs(aproxy_usb, aproxy_usb->usb_out_channels_mask, USB_OUT);
+            if (channels_list) {
+                str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_SUP_CHANNELS, channels_list);
+                free(channels_list);
+            }
+        }
+
+        // supported sample rates
+        if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES)) {
+            char* rates_list = usb_get_sample_rate_strs(aproxy_usb->usb_out_rates_mask);
+            if (rates_list) {
+                str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES, rates_list);
+                free(rates_list);
+            }
+        }
+    }
+
+    return 0;
+}
+
+int proxy_usb_setparam_playback_stream(void *proxy_usb, void *parameters)
+{
+    struct audio_proxy_usb *aproxy_usb = (struct audio_proxy_usb *)proxy_usb;
+    int ret = 0;
+    int card = -1;
+    int device = -1;
+
+    if (!parse_card_device_params((const char *)parameters, &card, &device)) {
+        // nothing to do
+        return ret;
+    }
+
+#if 0 //FIXME: check again when below code is need or not
+    alsa_device_profile *profile = &aproxy_usb->usb_out_profile;
+
+    if (card >= 0 && device >= 0) {
+        int saved_card = profile->card;
+        int saved_device = profile->device;
+
+        if (saved_card != card || saved_device != device) {
+            profile->card = card;
+            profile->device = device;
+            ret = profile_read_device_info(profile) ? 0 : -EINVAL;
+            if (ret != 0) {
+                profile->card = saved_card;
+                profile->device = saved_device;
+                ALOGI("%s-%s: updated USB Card %d Device %d", "usb-out",
+                      __func__, profile->card, profile->device);
+            }
+        } else
+            ALOGV("%s-%s: requested same USB Card %d Device %d", "usb-out",
+                  __func__, profile->card, profile->device);
+    }
+#endif
+    return ret;
+}
+
+void proxy_usb_capture_prepare(void *proxy_usb, bool set_default)
+{
+    struct audio_proxy_usb *aproxy_usb = (struct audio_proxy_usb *)proxy_usb;
+
+    // Configure sample rate based on flag
+    // set_default: 'false' means to configuration 48KHz, 16bit, 2CH or supported
+    // set_default: 'true' means single clock source USB device therefore
+    // use USB output configuration
+    if (set_default) {
+        // Get default or playback Sample rate based on USB clock source
+        usb_get_best_matching_config(&aproxy_usb->usbcapture_devlist,
+            DEFAULT_USB_MEDIA_FORMAT,
+            DEFAULT_USB_MEDIA_CHANNELS,
+            ((is_usb_single_clksource() && aproxy_usb->usb_out_connected) ?
+            aproxy_usb->usb_out_active_pcmconfig.rate : DEFAULT_USB_MEDIA_SAMPLING_RATE),
+            &aproxy_usb->usb_in_active_pcmconfig);
+    } else { // CPCall fixed or supported configuration
+        usb_get_best_matching_config(&aproxy_usb->usbcapture_devlist,
+            DEFAULT_USB_MEDIA_FORMAT,
+            DEFAULT_USB_MEDIA_CHANNELS,
+            DEFAULT_USB_MEDIA_SAMPLING_RATE,
+            &aproxy_usb->usb_in_active_pcmconfig);
+    }
+
+    ALOGI("proxy-%s: configured USB InProxy SR(%d) CH(%d) FMT(%d)", __func__,
+            aproxy_usb->usb_in_active_pcmconfig.rate,
+            aproxy_usb->usb_in_active_pcmconfig.channels,
+            aproxy_usb->usb_in_active_pcmconfig.format);
+
+    return;
+}
+
+int proxy_usb_getparam_capture_stream(void *proxy_usb, void *query_params, void *reply_params)
+{
+    struct audio_proxy_usb *aproxy_usb = (struct audio_proxy_usb *)proxy_usb;
+    struct str_parms *query = (struct str_parms *)query_params;
+    struct str_parms *reply = (struct str_parms *)reply_params;
+
+    if (aproxy_usb->usb_in_connected) {
+        // supported sample formats
+        if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_FORMATS)) {
+            char* format_list = usb_get_format_strs(aproxy_usb->usb_in_formats_mask);
+            if (format_list) {
+                str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_SUP_FORMATS, format_list);
+                free(format_list);
+            }
+        }
+
+        // supported channel counts
+        if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_CHANNELS)) {
+            char* channels_list = usb_get_channel_count_strs(aproxy_usb, aproxy_usb->usb_in_channels_mask, USB_IN);
+            if (channels_list) {
+                str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_SUP_CHANNELS, channels_list);
+                free(channels_list);
+            }
+        }
+
+        /* supported sample rates */
+        if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES)) {
+            char* rates_list = usb_get_sample_rate_strs(aproxy_usb->usb_in_rates_mask);
+            if (rates_list) {
+                str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES, rates_list);
+                free(rates_list);
+            }
+        }
+    }
+
+    return 0;
+}
+
+int proxy_usb_setparam_capture_stream(void *proxy_usb, void *parameters)
+{
+    struct audio_proxy_usb *aproxy_usb = (struct audio_proxy_usb *)proxy_usb;
+    int card = -1;
+    int device = -1;
+    int ret = 0;
+
+    if (!parse_card_device_params((const char *)parameters, &card, &device)) {
+        // nothing to do
+        return ret;
+    }
+
+#if 0 //FIXME: Check again whether below code is required or not
+    alsa_device_profile *profile = &aproxy_usb->usb_in_profile;
+
+    if (card >= 0 && device >= 0) {
+        int saved_card = profile->card;
+        int saved_device = profile->device;
+
+        if (saved_card != card || saved_device != device) {
+            profile->card = card;
+            profile->device = device;
+            ret = profile_read_device_info(profile) ? 0 : -EINVAL;
+            if (ret != 0) {
+                profile->card = saved_card;
+                profile->device = saved_device;
+                ALOGE("%s-%s: failed to read device info", "usb-in", __func__);
+            } else {
+                ALOGI("%s-%s: USB Capture device initialized for Card %d Device %d",
+                      "usb-in", __func__, profile->card, profile->device);
+
+                //prepare_capture_usbproxy(apstream);
+            }
+        } else
+            ALOGV("%s-%s: requested same USB Card %d Device %d", "usb-in",
+                  __func__, profile->card, profile->device);
+    }
+#endif
+    return ret;
+}
+
+bool proxy_usb_out_pick_best_pcmconfig(
+    void *proxy_usb,
+    struct pcm_config cur_pcmconfig)
+{
+    struct audio_proxy_usb *aproxy_usb = (struct audio_proxy_usb *)proxy_usb;
+    bool is_updated = false;
+
+    ALOGI("%s: current config rate[%d] format[%d] channels[%d]",
+        __func__, cur_pcmconfig.rate,
+        cur_pcmconfig.format,
+        cur_pcmconfig.channels);
+
+    /* select best configs compared to usb best picked config */
+    if (cur_pcmconfig.rate > aproxy_usb->active_playback_picked_rate) {
+        aproxy_usb->active_playback_picked_rate = cur_pcmconfig.rate;
+        is_updated = true;
+    }
+
+    if (IS_HIGHEST_PCMFORMAT(cur_pcmconfig.format, aproxy_usb->active_playback_picked_format)) {
+        aproxy_usb->active_playback_picked_format = cur_pcmconfig.format;
+        is_updated = true;
+    }
+
+    if (cur_pcmconfig.channels > aproxy_usb->active_playback_picked_channels) {
+        aproxy_usb->active_playback_picked_channels = cur_pcmconfig.channels;
+        is_updated = true;
+    }
+
+    ALOGI_IF(is_updated, "%s: Selected config rate[%d] format[%d] channels[%d]",
+        __func__, aproxy_usb->active_playback_picked_rate,
+        aproxy_usb->active_playback_picked_format,
+        aproxy_usb->active_playback_picked_channels);
+
+    return is_updated;
+}
+
+bool proxy_usb_out_reconfig_needed(void *proxy_usb)
+{
+    struct audio_proxy_usb *aproxy_usb = (struct audio_proxy_usb *)proxy_usb;
+    bool reconfig_needed = false;
+    struct pcm_config sup_pcmconfig;
+
+    pthread_mutex_lock(&aproxy_usb->usb_lock);
+
+    /* get usb matching for selected stream config */
+    usb_get_best_matching_config(&aproxy_usb->usbplayback_devlist,
+    aproxy_usb->active_playback_picked_format,
+    aproxy_usb->active_playback_picked_channels,
+    aproxy_usb->active_playback_picked_rate,
+    &sup_pcmconfig);
+
+    if (aproxy_usb->usb_out_connected) {
+        /* check whether best pcmconfig is supported by USB device */
+        if (aproxy_usb->usb_out_active_pcmconfig.rate != sup_pcmconfig.rate ||
+            aproxy_usb->usb_out_active_pcmconfig.format != sup_pcmconfig.format ||
+            aproxy_usb->usb_out_active_pcmconfig.channels != sup_pcmconfig.channels)
+            reconfig_needed = true;
+    }
+
+    ALOGI_IF(reconfig_needed, "%s: need reconfig rate[%d] format[%d] channels[%d]",
+        __func__, aproxy_usb->active_playback_picked_rate,
+        aproxy_usb->active_playback_picked_format,
+        aproxy_usb->active_playback_picked_channels);
+
+    pthread_mutex_unlock(&aproxy_usb->usb_lock);
+
+    return reconfig_needed;
+}
+
+void proxy_usb_out_reset_config(void *proxy_usb)
+{
+    struct audio_proxy_usb *aproxy_usb = (struct audio_proxy_usb *)proxy_usb;
+    pthread_mutex_lock(&aproxy_usb->usb_lock);
+
+    //Initialize playback picked pcm config to default values
+    aproxy_usb->active_playback_picked_rate = DEFAULT_USB_MEDIA_SAMPLING_RATE;
+    aproxy_usb->active_playback_picked_format = DEFAULT_USB_MEDIA_FORMAT;
+    aproxy_usb->active_playback_picked_channels = DEFAULT_USB_MEDIA_CHANNELS;
+
+    ALOGI("%s-%s: reset rate[%d] format[%d] channels[%d]", "usb-out", __func__,
+        aproxy_usb->active_playback_picked_rate,
+        aproxy_usb->active_playback_picked_format,
+        aproxy_usb->active_playback_picked_channels);
+
+    pthread_mutex_unlock(&aproxy_usb->usb_lock);
+
+    return;
+}
+
+void proxy_usb_open_out_proxy(void *proxy_usb)
+{
+    struct audio_proxy_usb *aproxy_usb = (struct audio_proxy_usb *)proxy_usb;
+    pthread_mutex_lock(&aproxy_usb->usb_lock);
+
+    usb_open_out_proxy(aproxy_usb);
+
+    pthread_mutex_unlock(&aproxy_usb->usb_lock);
+
+    return;
+}
+void proxy_usb_close_out_proxy(void *proxy_usb)
+{
+    struct audio_proxy_usb *aproxy_usb = (struct audio_proxy_usb *)proxy_usb;
+    pthread_mutex_lock(&aproxy_usb->usb_lock);
+
+    usb_close_out_proxy(aproxy_usb);
+
+    pthread_mutex_unlock(&aproxy_usb->usb_lock);
+
+    return;
+}
+void proxy_usb_open_in_proxy(void *proxy_usb)
+{
+    struct audio_proxy_usb *aproxy_usb = (struct audio_proxy_usb *)proxy_usb;
+    pthread_mutex_lock(&aproxy_usb->usb_lock);
+
+    usb_open_in_proxy(aproxy_usb);
+
+    pthread_mutex_unlock(&aproxy_usb->usb_lock);
+
+    return;
+}
+void proxy_usb_close_in_proxy(void *proxy_usb)
+{
+    struct audio_proxy_usb *aproxy_usb = (struct audio_proxy_usb *)proxy_usb;
+    pthread_mutex_lock(&aproxy_usb->usb_lock);
+
+    usb_close_in_proxy(aproxy_usb);
+
+    pthread_mutex_unlock(&aproxy_usb->usb_lock);
+
+    return;
+}
+
+void proxy_usb_set_gain(void *proxy_usb, char *path_name)
+{
+    struct audio_proxy_usb *aproxy_usb = (struct audio_proxy_usb *)proxy_usb;
+    char gain_name[MAX_USB_PATH_LEN];
+
+    if (!aproxy_usb->usb_gaincontrol_needed)
+        return ;
+
+    strlcpy(gain_name, path_name, MAX_USB_PATH_LEN);
+    strlcat(gain_name, "-gain", MAX_USB_PATH_LEN);
+    audio_route_apply_and_update_path(aproxy_usb->usb_ar, gain_name);
+    ALOGI("proxy-%s: routed to %s", __func__, gain_name);
+
+    return;
+}
+
+void proxy_usb_reset_gain(void *proxy_usb, char *path_name)
+{
+    struct audio_proxy_usb *aproxy_usb = (struct audio_proxy_usb *)proxy_usb;
+    char gain_name[MAX_USB_PATH_LEN];
+
+    if (!aproxy_usb->usb_gaincontrol_needed)
+        return ;
+
+    strlcpy(gain_name, path_name, MAX_USB_PATH_LEN);
+    strlcat(gain_name, "-gain", MAX_USB_PATH_LEN);
+    audio_route_reset_and_update_path(aproxy_usb->usb_ar, gain_name);
+    ALOGI("proxy-%s: routed to %s", __func__, gain_name);
+
+    return;
+}
+
+int proxy_usb_set_parameters(void *proxy_usb, void *parameters)
+{
+    struct audio_proxy_usb *aproxy_usb = (struct audio_proxy_usb *)proxy_usb;
+    struct str_parms *parms = (struct str_parms *)parameters;
+    int val;
+    int ret = 0;     // for parameter handling
+    int status = 0;  // for return value
+
+    ret = str_parms_get_int(parms, AUDIO_PARAMETER_DEVICE_CONNECT, &val);
+    if (ret >= 0) {
+        if ((audio_devices_t)val == AUDIO_DEVICE_OUT_USB_DEVICE ||
+            (audio_devices_t)val == AUDIO_DEVICE_OUT_USB_HEADSET) {
+            int card = -1, device = -1;
+
+            ret = str_parms_get_int(parms, AUDIO_PARAMETER_DEVICE_CARD, &val);
+            if (ret >= 0)
+                card = val;
+
+            ret = str_parms_get_int(parms, AUDIO_PARAMETER_DEVICE_DEVICE, &val);
+            if (ret >= 0)
+                device = val;
+
+            ALOGI("proxy-%s: connected USB Out Device with card %d / device %d", __func__, card, device);
+
+            if (!aproxy_usb->usb_out_connected && (card != -1 && device != -1)) {
+                pthread_mutex_lock(&aproxy_usb->usb_lock);
+                aproxy_usb->usb_out_connected = true;
+                aproxy_usb->usb_out_pcm_card = card;
+                aproxy_usb->usb_out_pcm_device = device;
+
+                // reset mask values before updating
+                aproxy_usb->usb_out_formats_mask = 0;
+                aproxy_usb->usb_out_channels_mask = 0;
+                aproxy_usb->usb_out_rates_mask = 0;
+
+                /* get usb output profile information */
+                usb_get_profile_capability(proxy_usb, USB_OUT);
+                usb_print_device_info(proxy_usb, USB_OUT);
+                usb_get_best_matching_config(&aproxy_usb->usbplayback_devlist,
+                    aproxy_usb->active_playback_picked_format,
+                    aproxy_usb->active_playback_picked_channels,
+                    aproxy_usb->active_playback_picked_rate,
+                    &aproxy_usb->usb_out_active_pcmconfig);
+                //check and enable gain-control for connected USB-Device
+                usb_audio_gain_control_enable(aproxy_usb);
+                pthread_mutex_unlock(&aproxy_usb->usb_lock);
+            }
+        } else if ((audio_devices_t)val == AUDIO_DEVICE_IN_USB_DEVICE ||
+                   (audio_devices_t)val == AUDIO_DEVICE_IN_USB_HEADSET) {
+            int card = -1, device = -1;
+
+            ret = str_parms_get_int(parms, AUDIO_PARAMETER_DEVICE_CARD, &val);
+            if (ret >= 0)
+                card = val;
+
+            ret = str_parms_get_int(parms, AUDIO_PARAMETER_DEVICE_DEVICE, &val);
+            if (ret >= 0)
+                device = val;
+
+            ALOGI("proxy-%s: connected USB In Device with card %d / device %d", __func__, card, device);
+
+            if (!aproxy_usb->usb_in_connected && (card != -1 && device != -1)) {
+                pthread_mutex_lock(&aproxy_usb->usb_lock);
+                aproxy_usb->usb_in_connected = true;
+                aproxy_usb->usb_in_pcm_card = card;
+                aproxy_usb->usb_in_pcm_device = device;
+
+                // reset mask values before updating
+                aproxy_usb->usb_in_formats_mask = 0;
+                aproxy_usb->usb_in_channels_mask = 0;
+                aproxy_usb->usb_in_rates_mask = 0;
+
+                /* get usb input profile information */
+                usb_get_profile_capability(proxy_usb, USB_IN);
+                usb_print_device_info(proxy_usb, USB_IN);
+                usb_get_best_matching_config(&aproxy_usb->usbcapture_devlist,
+                    DEFAULT_USB_MEDIA_FORMAT,
+                    DEFAULT_USB_MEDIA_CHANNELS,
+                    DEFAULT_USB_MEDIA_SAMPLING_RATE,
+                    &aproxy_usb->usb_in_active_pcmconfig);
+                //check and enable gain-control for connected USB-Device
+                usb_audio_gain_control_enable(aproxy_usb);
+                pthread_mutex_unlock(&aproxy_usb->usb_lock);
+            }
+        }
+
+        // Check and update usb device clock source information
+        if (aproxy_usb->usb_out_connected ||
+            aproxy_usb->usb_in_connected) {
+            update_usb_clksource_info(true);
+        }
+    }
+
+    ret = str_parms_get_int(parms, AUDIO_PARAMETER_DEVICE_DISCONNECT, &val);
+    if (ret >= 0) {
+        if ((audio_devices_t)val == AUDIO_DEVICE_OUT_USB_DEVICE ||
+            (audio_devices_t)val == AUDIO_DEVICE_OUT_USB_HEADSET) {
+            ALOGI("proxy-%s: disconnected USB Out Device with card %d / device %d", __func__,
+                aproxy_usb->usb_out_pcm_card, aproxy_usb->usb_out_pcm_device);
+
+            if (aproxy_usb->usb_out_connected) {
+                pthread_mutex_lock(&aproxy_usb->usb_lock);
+                usb_close_out_proxy(aproxy_usb);
+                usb_remove_device_info(proxy_usb, USB_OUT);
+
+                aproxy_usb->usb_out_pcm_card = -1;
+                aproxy_usb->usb_out_pcm_device = -1;
+                aproxy_usb->usb_out_connected = false;
+                aproxy_usb->usb_out_formats_mask = 0;
+                aproxy_usb->usb_out_channels_mask = 0;
+                aproxy_usb->usb_out_rates_mask = 0;
+
+                //check and enable gain-control for connected USB-Device
+                usb_audio_gain_control_disable(aproxy_usb);
+                pthread_mutex_unlock(&aproxy_usb->usb_lock);
+            }
+        } else if ((audio_devices_t)val == AUDIO_DEVICE_IN_USB_DEVICE ||
+                   (audio_devices_t)val == AUDIO_DEVICE_IN_USB_HEADSET) {
+            ALOGI("proxy-%s: disconnected USB In Device with card %d / device %d", __func__,
+                aproxy_usb->usb_in_pcm_card, aproxy_usb->usb_in_pcm_device);
+
+            if (aproxy_usb->usb_in_connected) {
+                pthread_mutex_lock(&aproxy_usb->usb_lock);
+                usb_close_in_proxy(aproxy_usb);
+                usb_remove_device_info(proxy_usb, USB_IN);
+
+                aproxy_usb->usb_in_pcm_card = -1;
+                aproxy_usb->usb_in_pcm_device = -1;
+                aproxy_usb->usb_in_connected = false;
+                aproxy_usb->usb_in_formats_mask = 0;
+                aproxy_usb->usb_in_channels_mask = 0;
+                aproxy_usb->usb_in_rates_mask = 0;
+
+                //check and enable gain-control for connected USB-Device
+                usb_audio_gain_control_disable(aproxy_usb);
+                pthread_mutex_unlock(&aproxy_usb->usb_lock);
+            }
+        }
+
+        // Check and update usb device clock source information
+        if (((audio_devices_t)val == AUDIO_DEVICE_OUT_USB_DEVICE ||
+            (audio_devices_t)val == AUDIO_DEVICE_OUT_USB_HEADSET ||
+            (audio_devices_t)val == AUDIO_DEVICE_IN_USB_DEVICE ||
+            (audio_devices_t)val == AUDIO_DEVICE_IN_USB_HEADSET) &&
+            (!aproxy_usb->usb_out_connected && !aproxy_usb->usb_in_connected)) {
+            update_usb_clksource_info(false);
+        }
+    }
+
+    return status;
+}
+
+void * proxy_usb_init(void)
+{
+    struct audio_proxy_usb *aproxy_usb;
+
+    /* Get audio_proxy_usb singleton instance*/
+    aproxy_usb = getUSBInstance();
+    if (!aproxy_usb) {
+        ALOGE("proxy-%s: failed to create for audio_proxy_usb", __func__);
+        return NULL;
+    }
+    // USB PCM Devices
+    pthread_mutex_init(&aproxy_usb->usb_lock, (const pthread_mutexattr_t *) NULL);
+
+    pthread_mutex_lock(&aproxy_usb->usb_lock);
+    aproxy_usb->usb_out_connected = false;
+    aproxy_usb->usb_out_status = false;
+    aproxy_usb->usb_out_pcm_card = -1;
+    aproxy_usb->usb_out_pcm_device = -1;
+    aproxy_usb->usb_out_cpcall_prepared = false;
+
+    aproxy_usb->usb_in_connected = false;
+    aproxy_usb->usb_in_pcm_card = -1;
+    aproxy_usb->usb_in_pcm_device = -1;
+
+    //Initialize gain-control varibles
+    aproxy_usb->usb_gaincontrol_needed = false;
+    aproxy_usb->usb_vid = -1;
+    aproxy_usb->usb_pid = -1;
+
+    //Initialize playback picked pcm config to default values
+    aproxy_usb->active_playback_picked_rate = DEFAULT_USB_MEDIA_SAMPLING_RATE;
+    aproxy_usb->active_playback_picked_channels = DEFAULT_USB_MEDIA_CHANNELS;
+    aproxy_usb->active_playback_picked_format = DEFAULT_USB_MEDIA_FORMAT;
+
+    list_init(&aproxy_usb->usbplayback_devlist);
+    list_init(&aproxy_usb->usbcapture_devlist);
+    aproxy_usb->usb_out_pcm = NULL;
+    aproxy_usb->usb_in_pcm = NULL;
+    aproxy_usb->usb_out_formats_mask = 0;
+    aproxy_usb->usb_out_channels_mask = 0;
+    aproxy_usb->usb_out_rates_mask = 0;
+    aproxy_usb->usb_in_formats_mask = 0;
+    aproxy_usb->usb_in_channels_mask = 0;
+    aproxy_usb->usb_in_rates_mask = 0;
+
+    pthread_mutex_unlock(&aproxy_usb->usb_lock);
+
+    ALOGI("proxy-%s: opened & initialized USB Audio Proxy", __func__);
+
+    return (void *)aproxy_usb;
+}
+
+void proxy_usb_deinit(void* proxy_usb)
+{
+    struct audio_proxy_usb *aproxy_usb = (struct audio_proxy_usb *)proxy_usb;
+    pthread_mutex_destroy(&aproxy_usb->usb_lock);
+
+    destroyUSBInstance();
+    ALOGI("proxy-%s: audio_proxy_usb instance destroyed", __func__);
+
+    return ;
+}
diff --git a/audio/proxy/audio_usb_proxy.h b/audio/proxy/audio_usb_proxy.h
new file mode 100644
index 0000000..39403d5
--- /dev/null
+++ b/audio/proxy/audio_usb_proxy.h
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AUDIO_USB_PROXY_H
+#define AUDIO_USB_PROXY_H
+
+#include <system/audio.h>
+#include <hardware/hardware.h>
+#include <hardware/audio.h>
+#include <audio_route/audio_route.h>
+#include <cutils/list.h>
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+
+#define DEFAULT_USB_PERIOD_COUNT        4
+#define DEFAULT_USB_PLAYBACK_DURATION   10 //10ms
+#define DEFAULT_USB_CAPTURE_DURATION    10 //10ms
+
+// Supported formats
+int supported_usb_formats[] = {PCM_FORMAT_S32_LE, PCM_FORMAT_S24_3LE, PCM_FORMAT_S24_LE, PCM_FORMAT_S16_LE, PCM_FORMAT_S8};
+static const uint32_t MAX_NUM_USB_FORMAT = ARRAY_SIZE(supported_usb_formats);
+char *  const supported_usb_format_strs[] = {
+    "AUDIO_FORMAT_PCM_32_BIT",
+    "AUDIO_FORMAT_PCM_24_BIT_PACKED",
+    "AUDIO_FORMAT_PCM_8_24_BIT",
+    "AUDIO_FORMAT_PCM_16_BIT",
+    "AUDIO_FORMAT_PCM_8_BIT"};
+
+// Supported channels
+#define MAX_NUM_USB_CHANNELS            8
+char * const supported_usb_channel_strs[] = {
+    /* 0 */"AUDIO_CHANNEL_NONE", /* will never be taken as this is a terminator */
+    /* 1 */"AUDIO_CHANNEL_INDEX_MASK_1",
+    /* 2 */"AUDIO_CHANNEL_INDEX_MASK_2",
+    /* 3 */"AUDIO_CHANNEL_INDEX_MASK_3",
+    /* 4 */"AUDIO_CHANNEL_INDEX_MASK_4",
+    /* 5 */"AUDIO_CHANNEL_INDEX_MASK_5",
+    /* 6 */"AUDIO_CHANNEL_INDEX_MASK_6",
+    /* 7 */"AUDIO_CHANNEL_INDEX_MASK_7",
+    /* 8 */"AUDIO_CHANNEL_INDEX_MASK_8",
+};
+
+char * const supported_usb_out_channel_strs[] = {
+    /* 0 */"AUDIO_CHANNEL_NONE", /* will never be taken as this is a terminator */
+    /* 1 */"AUDIO_CHANNEL_OUT_MONO",
+    /* 2 */"AUDIO_CHANNEL_OUT_STEREO",
+};
+
+char * const supported_usb_in_channel_strs[] = {
+    /* 0 */"AUDIO_CHANNEL_NONE", /* will never be taken as this is a terminator */
+    /* 1 */"AUDIO_CHANNEL_IN_MONO",
+    /* 2 */"AUDIO_CHANNEL_IN_STEREO",
+};
+
+// Supported Sampling Rate
+unsigned int supported_usb_samplingrates[] = {384000, 192000, 96000, 48000, 44100, 32000, 16000, 8000};
+
+static const uint32_t MAX_NUM_USB_SR = ARRAY_SIZE(supported_usb_samplingrates);
+char *  const supported_usb_samplingrate_strs[] = {
+    "384000",
+    "192000",
+    "96000",
+    "48000",
+    "44100",
+    "32000",
+    "16000",
+    "8000"};
+
+typedef enum usb_direction_type{
+    USB_OUT = 0,
+    USB_IN,
+} usb_direction_type_t;
+
+struct usb_device_info
+{
+    struct listnode node;
+    enum pcm_format format;
+    unsigned int bit_width;
+    unsigned int channels;
+    unsigned int rate_size;
+    unsigned int rates[MAX_NUM_USB_SR];
+};
+
+struct audio_proxy_usb
+{
+    pthread_mutex_t usb_lock;
+
+    struct listnode usbplayback_devlist;
+    int  usb_out_pcm_card;
+    int  usb_out_pcm_device;
+    unsigned int usb_out_formats_mask;
+    unsigned int usb_out_channels_mask;
+    unsigned int usb_out_rates_mask;
+    struct pcm_config usb_out_active_pcmconfig;
+    struct pcm *usb_out_pcm;
+    bool usb_out_connected;
+    bool usb_out_status;
+    bool usb_out_cpcall_prepared;
+
+    struct listnode usbcapture_devlist;
+    int  usb_in_pcm_card;
+    int  usb_in_pcm_device;
+    unsigned int usb_in_formats_mask;
+    unsigned int usb_in_channels_mask;
+    unsigned int usb_in_rates_mask;
+    struct pcm_config usb_in_active_pcmconfig;
+    struct pcm *usb_in_pcm;
+    bool usb_in_connected;
+
+    bool usb_gaincontrol_needed;
+    int usb_vid;
+    int usb_pid;
+    struct audio_route *usb_ar;
+
+    // active Playback streams best PCM config
+    unsigned int active_playback_picked_rate;
+    unsigned int active_playback_picked_channels;
+    enum pcm_format active_playback_picked_format;
+};
+
+/* Default values for Media PCM Configuration */
+#define DEFAULT_USB_CAPTURE_CHANNELS        1                   // Mono
+#define DEFAULT_USB_MEDIA_CHANNELS          2                   // Stereo
+#define DEFAULT_USB_MEDIA_SAMPLING_RATE     48000               // 48KHz
+#define DEFAULT_USB_MEDIA_FORMAT            PCM_FORMAT_S16_LE   // 16bit PCM
+
+#define MAX_USB_PATH_LEN                    256
+#define USB_READ_SIZE                       128
+
+
+#define AUDIO_PARAMETER_DEVICE_CARD   "card"
+#define AUDIO_PARAMETER_DEVICE_DEVICE "device"
+
+/* USB Bundle Device VID (Vendor ID): PID (Product ID) definitions */
+#define USB_BUNDLE_VID                      0x04e8
+#define USB_BUNDLE_WHITE_PID                0xa037
+#define USB_BUNDLE_GRAY_HEADPHONE_PID       0xa04b
+#define USB_BUNDLE_GRAY_HEADSET_PID         0xa04c
+
+/* USB Device VID (Vendor ID): PID (Product ID) definitions */
+#define USB_BUNDLE_WHITE_GAIN_XML_MIXER_PATH    "/vendor/etc/mixer_usb_white.xml"
+#define USB_BUNDLE_GRAY_GAIN_XML_MIXER_PATH     "/vendor/etc/mixer_usb_gray.xml"
+
+extern void update_usb_clksource_info(bool flag);
+extern bool is_usb_single_clksource();
+
+/* PCM format in increasing preference order */
+static const int pcm_format_order_weight[] = {
+    2,  /* PCM_FORMAT_S16_LE, 16-bit signed */
+    5,  /* PCM_FORMAT_S32_LE, 32-bit signed */
+    1,  /* PCM_FORMAT_S8, 8-bit signed */
+    3,  /* PCM_FORMAT_S24_LE, 24-bits in 4-bytes */
+    4,  /* PCM_FORMAT_S24_3LE, 24-bits in 3-bytes */
+};
+
+#define IS_HIGHEST_PCMFORMAT(a, b) (pcm_format_order_weight[a] > pcm_format_order_weight[b])
+
+#endif /* AUDIO_USB_PROXY_H */
diff --git a/audio/proxy/audio_usb_proxy_interface.h b/audio/proxy/audio_usb_proxy_interface.h
new file mode 100644
index 0000000..e1c0bb3
--- /dev/null
+++ b/audio/proxy/audio_usb_proxy_interface.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AUDIO_USB_PROXY_INTERFACE_H
+#define AUDIO_USB_PROXY_INTERFACE_H
+
+/* USB Proxy interface function prototypes */
+int proxy_is_usb_playback_CPCall_prepared(void *proxy_usb);
+int proxy_is_usb_playback_device_connected(void *proxy_usb);
+int proxy_is_usb_capture_device_connected(void *proxy_usb);
+unsigned int proxy_usb_get_capture_samplerate(void *proxy_usb);
+unsigned int proxy_usb_get_capture_channels(void *proxy_usb);
+int proxy_usb_get_capture_format(void *proxy_usb);
+int proxy_usb_get_playback_samplerate(void *proxy_usb);
+int proxy_usb_get_playback_channels(void *proxy_usb);
+int proxy_usb_get_playback_format(void *proxy_usb);
+int proxy_usb_get_playback_bitwidth(void *proxy_usb);
+int proxy_usb_get_playback_highest_supported_channels(void *proxy_usb);
+
+// Audio Stream USB Proxy Playback Functions
+void proxy_usb_playback_prepare(void *proxy_usb, bool set_default);
+int  proxy_usb_getparam_playback_stream(void *proxy_usb, void *query_params, void *reply_params);
+int  proxy_usb_setparam_playback_stream(void *proxy_usb, void *parameters);
+
+// Audio Stream USB Proxy Capture Functions
+void proxy_usb_capture_prepare(void *proxy_usb, bool set_default);
+int  proxy_usb_getparam_capture_stream(void *proxy_usb, void *query_params, void *reply_params);
+int  proxy_usb_setparam_capture_stream(void *proxy_usb, void *parameters);
+
+// Audio USB Device Proxy Functions
+bool proxy_usb_out_pick_best_pcmconfig(void *proxy_usb, struct pcm_config cur_pcmconfig);
+int proxy_usb_out_reconfig_needed(void *proxy_usb);
+void proxy_usb_out_reset_config(void *proxy_usb);
+void proxy_usb_open_out_proxy(void *proxy_usb);
+void proxy_usb_close_out_proxy(void *proxy_usb);
+void proxy_usb_open_in_proxy(void *proxy_usb);
+void proxy_usb_close_in_proxy(void *proxy_usb);
+
+// set parameters function carries USB configuration inforamtion
+void proxy_usb_set_gain(void *proxy_usb, char *path_name);
+void proxy_usb_reset_gain(void *proxy_usb, char *path_name);
+int proxy_usb_set_parameters(void *proxy_usb, void *parameters);
+void *proxy_usb_init(void);
+void proxy_usb_deinit(void* proxy_usb);
+
+#endif /* AUDIO_USB_PROXY_INTERFACE_H */