exynos: Import alternative audio HAL

* From https://gitlab.com/Linaro/96boards/e850-96/platform/hardware/samsung_slsi/-/tree/3e8336d6f04504fb2377a52909c98cd38ac1d368/exynos/libaudio/audiohal

Change-Id: I46d50402adb1794cad204056c2cec90b92e9b60e
diff --git a/include/libaudio/audiohal/audio_definition.h b/include/libaudio/audiohal/audio_definition.h
new file mode 100644
index 0000000..69191db
--- /dev/null
+++ b/include/libaudio/audiohal/audio_definition.h
@@ -0,0 +1,66 @@
+/*
+ * 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_AUDIOHAL_DEFINITION_H__
+#define __EXYNOS_AUDIOHAL_DEFINITION_H__
+
+/* This header file has common definitions for AudioHAL and AudioProxy */
+
+#define PREDEFINED_CAPTURE_DURATION     20   // 20ms
+#define LOW_LATENCY_CAPTURE_SAMPLE_RATE 48000
+
+#define MAX_MIXER_LENGTH    256
+#define DEFAULT_MIXER_PATH  "/vendor/etc/"
+#define DEFAULT_MIXER_FILE  "mixer_paths.xml"
+#define MIXER_PATH_INFO     "/proc/device-tree/sound/mixer-paths"
+
+// Duration for Normal Capture
+#define PREDEFINED_MEDIA_CAPTURE_DURATION   20  // 20ms
+#define PREDEFINED_LOW_CAPTURE_DURATION     4   // 4ms
+
+// Duration for USB Playback and Capture
+#define PREDEFINED_USB_PLAYBACK_DURATION    20  // 20ms
+#define PREDEFINED_USB_CAPTURE_DURATION     10  // 10ms
+
+
+#define DEFAULT_MEDIA_BIT_WIDTH         16
+#define DEFAULT_MEDIA_SAMPLING_RATE     48000
+
+#define UHQA_MEDIA_BIT_WIDTH            24
+#define UHQA_MEDIA_SAMPLING_RATE        192000
+
+#define SUHQA_MEDIA_BIT_WIDTH           32
+#define SUHQA_MEDIA_SAMPLING_RATE       384000
+
+
+/**
+ ** Customization
+ ** If these are defined at other header file, please disable this if block
+ **/
+#define AUDIO_PARAMETER_KEY_FMRADIO_MODE                "fm_mode"
+#define AUDIO_PARAMETER_KEY_FMRADIO_VOLUME              "fm_radio_volume"
+
+// Factory Mode
+#define AUDIO_PARAMETER_KEY_FACTORY_RMS_TEST            "factory_test_mic_check"
+
+#define AUDIO_PARAMETER_FACTORY_TEST_LOOPBACK           "factory_test_loopback"
+#define AUDIO_PARAMETER_FACTORY_TEST_TYPE               "factory_test_type"
+#define AUDIO_PARAMETER_FACTORY_TEST_PATH               "factory_test_path"
+#define AUDIO_PARAMETER_FACTORY_TEST_ROUTE              "factory_test_route"
+
+#define AUDIO_PARAMETER_SEAMLESS_VOICE                  "seamless_voice"
+
+#endif  // __EXYNOS_AUDIOHAL_DEFINITION_H__
diff --git a/include/libaudio/audiohal/audio_devices.h b/include/libaudio/audiohal/audio_devices.h
new file mode 100644
index 0000000..b4b0bac
--- /dev/null
+++ b/include/libaudio/audiohal/audio_devices.h
@@ -0,0 +1,91 @@
+/*
+ * 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_AUDIOHAL_DEVICE_H__
+#define __EXYNOS_AUDIOHAL_DEVICE_H__
+
+/**
+ ** Audio Input/Output Device based on Target Device
+ **/
+typedef enum {
+    DEVICE_MIN                    = 0,
+
+    // Playback Devices
+    DEVICE_EARPIECE               = 0,   // handset or receiver
+    DEVICE_SPEAKER,
+    DEVICE_HEADSET,                      // headphone + mic
+    DEVICE_HEADPHONE,                    // headphone or earphone
+    DEVICE_SPEAKER_AND_HEADSET,
+    DEVICE_SPEAKER_AND_HEADPHONE,
+    DEVICE_BT_HEADSET,
+    DEVICE_FM_EXTERNAL,
+    DEVICE_SPEAKER_AND_BT_HEADSET,
+    DEVICE_USB_HEADSET,
+    DEVICE_AUX_DIGITAL,
+    DEVICE_LINE_OUT,
+    DEVICE_SPEAKER_AND_LINEOUT,
+
+    // Special Playback Devices
+    DEVICE_CALL_FWD,
+
+    // Capture Devices
+    DEVICE_MAIN_MIC,
+    DEVICE_HEADSET_MIC,
+    DEVICE_HEADSET_MAIN_MIC,
+    DEVICE_BT_HEADSET_MIC,
+    DEVICE_BT_NREC_HEADSET_MIC,
+    DEVICE_USB_HEADSET_MIC,
+
+    DEVICE_HANDSET_MIC,
+    DEVICE_SPEAKER_MIC,
+    DEVICE_HEADPHONE_MIC,
+
+    DEVICE_SUB_MIC,
+    DEVICE_STEREO_MIC,
+    DEVICE_FULL_MIC,
+    DEVICE_HCO_MIC,
+    DEVICE_VCO_MIC,
+
+    DEVICE_FM_TUNER,
+    DEVICE_LINE_OUT_MIC,
+
+    DEVICE_NONE,
+    DEVICE_MAX,
+    DEVICE_CNT                   = DEVICE_MAX
+} device_type;
+
+
+/**
+ ** Audio Input/Output Sampling Rate Modifier
+ **/
+typedef enum {
+    MODIFIER_MIN          = 0,
+
+    /* RX modifier */
+    MODIFIER_BT_SCO_RX_NB = 0,
+    MODIFIER_BT_SCO_RX_WB,
+
+    /* TX modifier */
+    MODIFIER_BT_SCO_TX_NB,
+    MODIFIER_BT_SCO_TX_WB,
+
+    MODIFIER_NONE,
+    MODIFIER_MAX,
+    MODIFIER_CNT          = MODIFIER_MAX
+} modifier_type;
+
+
+#endif  // __EXYNOS_AUDIOHAL_DEVICE_H__
diff --git a/include/libaudio/audiohal/audio_log.h b/include/libaudio/audiohal/audio_log.h
new file mode 100644
index 0000000..c950ba2
--- /dev/null
+++ b/include/libaudio/audiohal/audio_log.h
@@ -0,0 +1,35 @@
+/*
+ * 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_AUDIOHAL_LOG_H__
+#define __EXYNOS_AUDIOHAL_LOG_H__
+
+
+char * audiomode_table[AUDIO_MODE_CNT] = {
+    [AUDIO_MODE_NORMAL]             = "normal mode",
+    [AUDIO_MODE_RINGTONE]           = "ringtone mode",
+    [AUDIO_MODE_IN_CALL]            = "in_call mode",
+    [AUDIO_MODE_IN_COMMUNICATION]   = "in_comm mode",
+};
+
+char * callmode_table[CALL_MODE_CNT] = {
+    [CALL_OFF]      = "Call Off",
+    [VOICE_CALL]    = "Voice Call Mode",
+    [VOLTE_CALL]    = "VoLTE Call Mode",
+    [VOWIFI_CALL]   = "VoWiFi Call Mode",
+};
+
+#endif  // __EXYNOS_AUDIOHAL_LOG_H__
\ No newline at end of file
diff --git a/include/libaudio/audiohal/audio_mixers.h b/include/libaudio/audiohal/audio_mixers.h
new file mode 100644
index 0000000..4480135
--- /dev/null
+++ b/include/libaudio/audiohal/audio_mixers.h
@@ -0,0 +1,36 @@
+/*
+ * 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_MIXERS_H
+#define AUDIO_MIXERS_H
+
+/* Mixer Values Definition */
+enum {
+    MIXER_VALUE_OFF   = 0,
+    MIXER_VALUE_ON,
+};
+
+#define MIXER_CTL_VAL_INVALID       -1
+
+/* Specific Mixer Name */
+// To use Virtual PCM Device for APCall
+#define ABOX_APCALLBUFFTYPE_CONTROL_NAME    "ABOX PCM ext APCALL BUFFTYPE"
+#define ABOX_APCALL_SPEECH_PARAM_CONTROL_NAME    "ABOX Speech Param"
+#define ABOX_APCALL_MUTE_CONTROL_NAME    "ABOX ERAP info Mute Primary"
+#define ABOX_APCALL_MUTE_COUNT    20
+#define ABOX_BT_MUTE_COUNT    30
+
+#endif /* AUDIO_MIXERS */
diff --git a/include/libaudio/audiohal/audio_offload.h b/include/libaudio/audiohal/audio_offload.h
new file mode 100644
index 0000000..6b28cca
--- /dev/null
+++ b/include/libaudio/audiohal/audio_offload.h
@@ -0,0 +1,36 @@
+/*
+ * 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_AUDIOHAL_OFFLOAD_H__
+#define __EXYNOS_AUDIOHAL_OFFLOAD_H__
+
+#define OFFLOAD_EFFECT_LIBRARY_PATH ""
+
+/**
+ ** Compress Offload Message List
+ **/
+typedef enum {
+    OFFLOAD_MSG_INVALID              = 0,
+
+    OFFLOAD_MSG_WAIT_WRITE,
+    OFFLOAD_MSG_WAIT_DRAIN,
+    OFFLOAD_MSG_WAIT_PARTIAL_DRAIN,
+    OFFLOAD_MSG_EXIT,
+
+    OFFLOAD_MSG_MAX,
+} offload_msg_type;
+
+#endif  // __EXYNOS_AUDIOHAL_OFFLOAD_H__
diff --git a/include/libaudio/audiohal/audio_proxy_interface.h b/include/libaudio/audiohal/audio_proxy_interface.h
new file mode 100644
index 0000000..437bd48
--- /dev/null
+++ b/include/libaudio/audiohal/audio_proxy_interface.h
@@ -0,0 +1,162 @@
+/*
+ * 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_INTERFACE_H
+#define AUDIO_PROXY_INTERFACE_H
+
+
+/* Volume Type */
+enum {
+    VOLUME_TYPE_OFFLOAD = 0,
+};
+
+/* Compress Function Type */
+enum {
+    COMPRESS_TYPE_WAIT = 0,
+    COMPRESS_TYPE_NEXTTRACK,
+    COMPRESS_TYPE_PARTIALDRAIN,
+    COMPRESS_TYPE_DRAIN,
+};
+
+/* Special Audio Device Type */
+enum {
+    BUILTIN_EARPIECE = 0,
+    BUILTIN_SPEAKER,
+    BUILTIN_MIC,
+    PROXIMITY_SENSOR,
+};
+
+/* Audio Device Configuration Type */
+enum {
+    DEVICE_CONFIG_NONE = 0,
+    DEVICE_CONFIG_INTERNAL,
+    DEVICE_CONFIG_EXTERNAL,
+};
+
+enum {
+    DEVICE_BLUETOOTH = 0,
+    DEVICE_FMRADIO,
+};
+
+/* A-Box Configuration Type */
+enum {
+    NEED_VOICEPCM_REOPEN = 0,
+    SUPPORT_USB_BY_PRIMARY,
+    SUPPORT_A2DP_BY_PRIMARY,
+
+};
+
+
+// Audio Capability Check  Utility Functions
+int  get_supported_device_number(void *proxy, int device_type);
+int  get_supported_config(void *proxy, int device_type);
+bool is_needed_config(void *proxy, int config_type);
+
+// Audio Usage Check Utility Functions
+bool is_active_usage_APCall(void *proxy);
+bool is_usage_CPCall(audio_usage ausage);
+bool is_active_usage_CPCall(void *proxy);
+bool is_usage_APCall(audio_usage ausage);
+
+// Audio Stream Proxy Get/Set Fungtions
+uint32_t proxy_get_actual_channel_count(void *proxy_stream);    // Return Actual Channel Count
+uint32_t proxy_get_actual_sampling_rate(void *proxy_stream);    // Return Actual Samplung Rate
+uint32_t proxy_get_actual_period_size(void *proxy_stream);
+uint32_t proxy_get_actual_period_count(void *proxy_stream);
+int32_t  proxy_get_actual_format(void *proxy_stream);           // Return Actual Android Audio Format, not PCM Format
+
+// Audio Stream Proxy Offload Functions
+void  proxy_offload_set_nonblock(void *proxy_stream);
+int   proxy_offload_compress_func(void *proxy_stream, int func_type);
+int   proxy_offload_pause(void *proxy_stream);
+int   proxy_offload_resume(void *proxy_stream);
+
+// Audio Stream Proxy Playback Stream Functions
+void *proxy_create_playback_stream(void *proxy, int type, void *config, char *address);
+void  proxy_destroy_playback_stream(void *proxy_stream);
+int   proxy_close_playback_stream(void *proxy_stream);
+int   proxy_open_playback_stream(void *proxy_stream, int32_t min_size_frames, void *mmap_info);
+int   proxy_start_playback_stream(void *proxy_stream);
+int   proxy_write_playback_buffer(void *proxy_stream, void *buffer, int bytes);
+int   proxy_stop_playback_stream(void *proxy_stream);
+int   proxy_reconfig_playback_stream(void *proxy_stream, int type, void *config);
+int   proxy_get_render_position(void *proxy_stream, uint32_t *frames);
+int   proxy_get_presen_position(void *proxy_stream, uint64_t *frames, struct timespec *timestamp);
+int   proxy_getparam_playback_stream(void *proxy_stream, void *query_params, void *reply_params);
+int   proxy_setparam_playback_stream(void *proxy_stream, void *parameters);
+uint32_t proxy_get_playback_latency(void *proxy_stream);
+void  proxy_dump_playback_stream(void *proxy_stream, int fd);
+
+// Audio Stream Proxy Capture Stream Functions
+void *proxy_create_capture_stream(void *proxy, int type, int usage, void *config, char *address);
+void  proxy_destroy_capture_stream(void *proxy_stream);
+int   proxy_close_capture_stream(void *proxy_stream);
+int   proxy_open_capture_stream(void *proxy_stream, int32_t min_size_frames, void *mmap_info);
+int   proxy_start_capture_stream(void *proxy_stream);
+int   proxy_read_capture_buffer(void *proxy_stream, void *buffer, int bytes);
+int   proxy_stop_capture_stream(void *proxy_stream);
+int   proxy_reconfig_capture_stream(void *proxy_stream, int type, void *config);
+int   proxy_reconfig_capture_usage(void *proxy_stream, int type, int usage);
+int   proxy_get_capture_pos(void *proxy_stream, int64_t *frames, int64_t *time);
+int   proxy_get_active_microphones(void *proxy_stream, void *array, int *count);
+int   proxy_getparam_capture_stream(void *proxy_stream, void *query_params, void *reply_params);
+int   proxy_setparam_capture_stream(void *proxy_stream, void *parameters);
+void  proxy_dump_capture_stream(void *proxy_stream, int fd);
+void  proxy_update_capture_usage(void *proxy_stream, int usage);
+
+int   proxy_get_mmap_position(void *proxy_stream, void *pos);
+
+// Audio Device Proxy Path Route Functions
+bool  proxy_init_route(void *proxy, char *path);
+void  proxy_deinit_route(void *proxy);
+bool  proxy_update_route(void *proxy, int ausage, int device);
+bool  proxy_set_route(void *proxy, int ausage, int device, int modifier, bool set);
+
+// Audio Device Proxy Functions
+void  proxy_stop_voice_call(void *proxy);
+void  proxy_start_voice_call(void *proxy);
+void  proxy_stop_fm_radio(void *proxy);
+void  proxy_start_fm_radio(void *proxy);
+
+int   proxy_get_mixer_value_int(void *proxy, const char *name);
+int   proxy_get_mixer_value_array(void *proxy, const char *name, void *value, int count);
+void  proxy_set_mixer_value_int(void *proxy, const char *name, int value);
+void  proxy_set_mixer_value_string(void *proxy, const char *name, const char *value);
+void  proxy_set_mixer_value_array(void *proxy, const char *name, const void *value, int count);
+
+void  proxy_set_audiomode(void *proxy, int audiomode);
+void  proxy_set_volume(void *proxy, int volume_type, float left, float right);
+void  proxy_set_communication_volume(void *proxy, int volume);
+void  proxy_set_upscale(void *proxy, int sampling_rate, int pcm_format);
+#ifdef SUPPORT_STHAL_INTERFACE
+int   proxy_check_sthalstate(void *proxy);
+#endif
+void  proxy_call_status(void *proxy, int status);
+int   proxy_set_parameters(void *proxy, void *parameters);
+int   proxy_get_microphones(void *proxy, void *array, int *count);
+
+void proxy_init_offload_effect_lib(void *proxy);
+void proxy_update_offload_effect(void *proxy_stream, int type);
+
+// Audio Device Proxy Dump Function
+int   proxy_fw_dump(int fd);
+
+// Audio Device Proxy Creation/Destruction
+bool  proxy_is_initialized(void);
+void *proxy_init(void);
+void  proxy_deinit(void *proxy);
+
+#endif /* AUDIO_PROXY_INTERFACE_H */
diff --git a/include/libaudio/audiohal/audio_streams.h b/include/libaudio/audiohal/audio_streams.h
new file mode 100644
index 0000000..ffc9d9a
--- /dev/null
+++ b/include/libaudio/audiohal/audio_streams.h
@@ -0,0 +1,54 @@
+/*
+ * 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_AUDIOHAL_STREAM_H__
+#define __EXYNOS_AUDIOHAL_STREAM_H__
+
+/*
+ * Audio Streams based on Audio Profile in Audio Policy Configuration
+ */
+typedef enum {
+    ASTREAM_MIN                   = 0,
+
+    ASTREAM_PLAYBACK_NO_ATTRIBUTE = 0,  // For No Attributes Output Profile
+    ASTREAM_PLAYBACK_PRIMARY,           // For Primary Output Profile
+    ASTREAM_PLAYBACK_FAST,              // For Fast Output Profile
+    ASTREAM_PLAYBACK_DEEP_BUFFER,       // For Deep Buffer Output Profile
+    ASTREAM_PLAYBACK_LOW_LATENCY,       // For Low Latency Output Profile
+    ASTREAM_PLAYBACK_COMPR_OFFLOAD,     // For Compress Offload Profile
+    ASTREAM_PLAYBACK_MMAP,              // For MMAP NoIRQ Output Profile
+    ASTREAM_PLAYBACK_USB_DEVICE,        // For USB Output Profile
+    ASTREAM_PLAYBACK_AUX_DIGITAL,       // For HDMI/DP Profile
+    ASTREAM_PLAYBACK_INCALL_MUSIC,      // For music uplink during Call
+
+    ASTREAM_CAPTURE_NO_ATTRIBUTE,       // For No Attributes Input Profile
+    ASTREAM_CAPTURE_PRIMARY,            // For Primary Input Profile
+    ASTREAM_CAPTURE_CALL,               // For Call Recording
+    ASTREAM_CAPTURE_LOW_LATENCY,        // For Low Latency Input Profile
+    ASTREAM_CAPTURE_MMAP,               // For MMAP NoIRQ Input Profile
+    ASTREAM_CAPTURE_USB_DEVICE,         // For USB Input Profile
+    ASTREAM_CAPTURE_FM_TUNER,           // For FM Radio Playback
+    ASTREAM_CAPTURE_FM_RECORDING,       // For FM Radio Recording
+#ifdef SUPPORT_STHAL_INTERFACE
+    ASTREAM_CAPTURE_HOTWORD,            // For VTS seamless Input Profile
+#endif
+
+    ASTREAM_NONE,
+    ASTREAM_MAX,
+    ASTREAM_CNT                   = ASTREAM_MAX
+} audio_stream_type;
+
+#endif  // __EXYNOS_AUDIOHAL_STREAM_H__
diff --git a/include/libaudio/audiohal/audio_tables.h b/include/libaudio/audiohal/audio_tables.h
new file mode 100644
index 0000000..c9d9dab
--- /dev/null
+++ b/include/libaudio/audiohal/audio_tables.h
@@ -0,0 +1,225 @@
+/*
+ * 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_AUDIOHAL_TABLE_H__
+#define __EXYNOS_AUDIOHAL_TABLE_H__
+
+/*
+ * Audio Streams Table for readable log messages
+ */
+char * stream_table[ASTREAM_CNT] = {
+    [ASTREAM_PLAYBACK_NO_ATTRIBUTE]  = "no_attribute_out",
+    [ASTREAM_PLAYBACK_PRIMARY]       = "primary_out",
+    [ASTREAM_PLAYBACK_FAST]          = "fast_out",
+    [ASTREAM_PLAYBACK_DEEP_BUFFER]   = "deep_out",
+    [ASTREAM_PLAYBACK_LOW_LATENCY]   = "low_out",
+    [ASTREAM_PLAYBACK_COMPR_OFFLOAD] = "offload_out",
+    [ASTREAM_PLAYBACK_MMAP]          = "mmap_out",
+    [ASTREAM_PLAYBACK_USB_DEVICE]    = "usb_out",
+    [ASTREAM_PLAYBACK_AUX_DIGITAL]   = "aux_out",
+    [ASTREAM_PLAYBACK_INCALL_MUSIC]  = "incall_music",
+
+    [ASTREAM_CAPTURE_NO_ATTRIBUTE]   = "no_attribute_in",
+    [ASTREAM_CAPTURE_PRIMARY]        = "primary_in",
+    [ASTREAM_CAPTURE_CALL]           = "callrec_in",
+    [ASTREAM_CAPTURE_LOW_LATENCY]    = "low_in",
+    [ASTREAM_CAPTURE_MMAP]           = "mmap_in",
+    [ASTREAM_CAPTURE_USB_DEVICE]     = "usb_in",
+    [ASTREAM_CAPTURE_FM_TUNER]       = "fm_tuner",
+    [ASTREAM_CAPTURE_FM_RECORDING]   = "fmrec_in",
+#ifdef SUPPORT_STHAL_INTERFACE
+    [ASTREAM_CAPTURE_HOTWORD]        = "hotword_in",
+#endif
+
+    [ASTREAM_NONE]                   = "none"
+};
+
+/**
+ ** Audio Usage Table for readable log messages
+ **/
+char * usage_table[AUSAGE_CNT] = {
+    [AUSAGE_MEDIA]                  = "media",
+    [AUSAGE_RECORDING]              = "recording",
+    [AUSAGE_CAMCORDER]              = "camcoder",
+
+    [AUSAGE_VOICE_CALL_NB]          = "voice_call_nb",
+    [AUSAGE_VOICE_CALL_NB_HAC]      = "voice_call_nb_hac",
+    [AUSAGE_VOICE_CALL_WB]          = "voice_call_wb",
+    [AUSAGE_VOICE_CALL_WB_HAC]      = "voice_call_wb_hac",
+    [AUSAGE_VOLTE_CALL_NB]          = "volte_call_nb",
+    [AUSAGE_VOLTE_CALL_WB]          = "volte_call_wb",
+    [AUSAGE_VOLTE_CALL_SWB]         = "volte_vt_call_swb",
+    [AUSAGE_VOLTE_VT_CALL_NB]       = "volte_vt_call_nb",
+    [AUSAGE_VOLTE_VT_CALL_WB]       = "volte_vt_call_wb",
+    [AUSAGE_VOLTE_VT_CALL_SWB]      = "volte_call_swb",
+    [AUSAGE_TTY]                    = "tty_mode",
+    [AUSAGE_INCALL_MUSIC]           = "incall_music",
+
+    [AUSAGE_WIFI_CALL_NB]           = "vowifi_call_nb",
+    [AUSAGE_WIFI_CALL_WB]           = "vowifi_call_wb",
+    [AUSAGE_WIFI_CALL_SWB]          = "vowifi_call_swb",
+    [AUSAGE_VIDEO_CALL]             = "video_call",
+    [AUSAGE_VOIP_CALL]              = "voip_call",
+    [AUSAGE_COMMUNICATION]          = "voip_call",
+    [AUSAGE_AP_TTY]                 = "ap_tty_mode",
+
+    [AUSAGE_INCALL_UPLINK]          = "callrecord_uplink",
+    [AUSAGE_INCALL_DOWNLINK]        = "callrecord_downlink",
+    [AUSAGE_INCALL_UPLINK_DOWNLINK] = "callrecord",
+
+    [AUSAGE_RECOGNITION]            = "recognition",
+
+    [AUSAGE_FM_RADIO_TUNER]         = "fm_radio",
+    [AUSAGE_FM_RADIO_CAPTURE]       = "fm_radio",
+#ifdef SUPPORT_STHAL_INTERFACE
+    [AUSAGE_HOTWORD_SEAMLESS]       = "hotword_seamless",
+    [AUSAGE_HOTWORD_RECORD]         = "hotword_record",
+#endif
+
+    [AUSAGE_LOOPBACK]               = "factory_loopback",
+    [AUSAGE_LOOPBACK_NODELAY]       = "factory_loopback_nodelay",
+    [AUSAGE_LOOPBACK_REALTIME]      = "factory_loopback_realtime",
+    [AUSAGE_LOOPBACK_CODEC]         = "factory_loopback_codec",
+    [AUSAGE_RMS]                    = "factory_rms",
+
+    [AUSAGE_NONE]                   = "none",
+};
+
+/**
+ ** Usage Path(AP/CP to Codec) Configuration based on Audio Usage
+ **/
+char * usage_path_table[AUSAGE_CNT] = {
+    [AUSAGE_MEDIA]                  = "media",
+    [AUSAGE_RECORDING]              = "recording",
+    [AUSAGE_CAMCORDER]              = "camcorder",
+
+    [AUSAGE_VOICE_CALL_NB]          = "incall_nb",
+    [AUSAGE_VOICE_CALL_NB_HAC]      = "incall_nb_hac",
+    [AUSAGE_VOICE_CALL_WB]          = "incall_wb",
+    [AUSAGE_VOICE_CALL_WB_HAC]      = "incall_wb_hac",
+    [AUSAGE_VOLTE_CALL_NB]          = "incall_nb",
+    [AUSAGE_VOLTE_CALL_WB]          = "incall_nb",
+    [AUSAGE_VOLTE_CALL_SWB]         = "incall_nb",
+    [AUSAGE_VOLTE_VT_CALL_NB]       = "incall_nb",
+    [AUSAGE_VOLTE_VT_CALL_WB]       = "incall_nb",
+    [AUSAGE_VOLTE_VT_CALL_SWB]      = "incall_nb",
+    [AUSAGE_TTY]                    = "tty_mode",
+    [AUSAGE_INCALL_MUSIC]           = "incall_music",
+
+    [AUSAGE_WIFI_CALL_NB]           = "wificall_nb",
+    [AUSAGE_WIFI_CALL_WB]           = "wificall_wb",
+    [AUSAGE_WIFI_CALL_SWB]          = "wificall_evs",
+    [AUSAGE_VIDEO_CALL]             = "video_call",
+    [AUSAGE_VOIP_CALL]              = "voip",
+    [AUSAGE_COMMUNICATION]          = "communication",
+    [AUSAGE_AP_TTY]                 = "ap_tty_mode",
+
+    [AUSAGE_INCALL_UPLINK]          = "callrecord_uplink",
+    [AUSAGE_INCALL_DOWNLINK]        = "callrecord_downlink",
+    [AUSAGE_INCALL_UPLINK_DOWNLINK] = "callrecord",
+
+    [AUSAGE_RECOGNITION]            = "recognition",
+    [AUSAGE_FM_RADIO_TUNER]         = "fm_radio",
+    [AUSAGE_FM_RADIO_CAPTURE]       = "fm_radio",
+#ifdef SUPPORT_STHAL_INTERFACE
+    [AUSAGE_HOTWORD_SEAMLESS]       = "hotword_seamless",    //dummy definition not used
+    [AUSAGE_HOTWORD_RECORD]         = "hotword_record",    //dummy definition not used
+#endif
+
+    [AUSAGE_LOOPBACK]               = "loopback_packet",
+    [AUSAGE_LOOPBACK_NODELAY]       = "loopback",
+    [AUSAGE_LOOPBACK_REALTIME]      = "realtimeloopback",
+    [AUSAGE_LOOPBACK_CODEC]         = "loopback_codec",
+    [AUSAGE_RMS]                    = "echo_test",
+
+    [AUSAGE_NONE]                   = "none",
+};
+
+/**
+ ** Device Path(Codec to Device) Configuration based on Audio Input/Output Device
+ **/
+char * device_table[DEVICE_CNT] = {
+    // Playback Devices
+    [DEVICE_EARPIECE]               = "handset",
+    [DEVICE_SPEAKER]                = "speaker",
+    [DEVICE_HEADSET]                = "headset",
+    [DEVICE_HEADPHONE]              = "headphone",
+    [DEVICE_SPEAKER_AND_HEADSET]    = "speaker-headset",
+    [DEVICE_SPEAKER_AND_HEADPHONE]  = "speaker-headphone",
+    [DEVICE_BT_HEADSET]             = "bt-sco-headset",
+    [DEVICE_FM_EXTERNAL]            = "external",
+    [DEVICE_SPEAKER_AND_BT_HEADSET] = "speaker-bt-sco-headset",
+    [DEVICE_USB_HEADSET]            = "usb-headset",
+    [DEVICE_AUX_DIGITAL]            = "aux-digital",
+    [DEVICE_LINE_OUT]               = "lineout",
+    [DEVICE_SPEAKER_AND_LINEOUT]    = "speaker-lineout",
+
+    // Special Playback Devices
+    [DEVICE_CALL_FWD]               = "",
+
+    // Capture Devices
+    [DEVICE_MAIN_MIC]               = "mic",
+    [DEVICE_HEADSET_MIC]            = "headset-mic",
+    [DEVICE_HEADSET_MAIN_MIC]       = "headset-main-mic",
+    [DEVICE_BT_HEADSET_MIC]         = "bt-sco-headset-in",
+    [DEVICE_BT_NREC_HEADSET_MIC]    = "bt-sco-nrec-headset-in",
+    [DEVICE_USB_HEADSET_MIC]        = "usb-headset-mic",
+
+    [DEVICE_HANDSET_MIC]            = "handset-mic",
+    [DEVICE_SPEAKER_MIC]            = "speaker-mic",
+    [DEVICE_HEADPHONE_MIC]          = "headphone-mic",
+
+    [DEVICE_SUB_MIC]                = "2nd-mic",
+    [DEVICE_STEREO_MIC]             = "dualmic",
+    [DEVICE_FULL_MIC]               = "full-mic",
+    [DEVICE_HCO_MIC]                = "hco-mic",
+    [DEVICE_VCO_MIC]                = "vco-mic",
+
+    [DEVICE_FM_TUNER]               = "fm-tuner",
+
+    [DEVICE_LINE_OUT_MIC]           = "lineout-mic",
+
+    [DEVICE_NONE]                   = "none",
+};
+
+/**
+ ** Sampling Rate Modifier Configuration based on Audio Input/Output Device
+ **/
+char * modifier_table[MODIFIER_MAX] = {
+    /* RX modifier */
+    [MODIFIER_BT_SCO_RX_NB]  = "set-bt-sco-rx-rate-nb",
+    [MODIFIER_BT_SCO_RX_WB]  = "set-bt-sco-rx-rate-wb",
+
+    /* TX modifier */
+    [MODIFIER_BT_SCO_TX_NB]  = "set-bt-sco-tx-rate-nb",
+    [MODIFIER_BT_SCO_TX_WB]  = "set-bt-sco-tx-rate-wb",
+
+    [MODIFIER_NONE]            = "none",
+};
+
+/**
+ ** Offload Message Table for readable log messages
+ **/
+char * offload_msg_table[OFFLOAD_MSG_MAX] = {
+    [OFFLOAD_MSG_INVALID]            = "Offload Message_Invalid",
+    [OFFLOAD_MSG_WAIT_WRITE]         = "Offload Message_Wait to write",
+    [OFFLOAD_MSG_WAIT_DRAIN]         = "Offload Message_Wait to drain",
+    [OFFLOAD_MSG_WAIT_PARTIAL_DRAIN] = "Offload Message_Wait to drain partially",
+    [OFFLOAD_MSG_EXIT]               = "Offload Message_Wait to exit",
+};
+
+
+#endif  // __EXYNOS_AUDIOHAL_TABLE_H__
diff --git a/include/libaudio/audiohal/audio_usages.h b/include/libaudio/audiohal/audio_usages.h
new file mode 100644
index 0000000..5b21af4
--- /dev/null
+++ b/include/libaudio/audiohal/audio_usages.h
@@ -0,0 +1,97 @@
+/*
+ * 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_AUDIOHAL_USAGE_H__
+#define __EXYNOS_AUDIOHAL_USAGE_H__
+
+/**
+ ** Audio Usages Definition
+ **/
+typedef enum {
+    AUSAGE_PLAYBACK,
+    AUSAGE_CAPTURE,
+} audio_usage_type;
+
+typedef enum {
+    AUSAGE_MIN                 = 0,
+
+    // Media Playback/Recording Usages
+    // These audio usages are defined from stream own usage
+    AUSAGE_MEDIA               = 0,
+    AUSAGE_RECORDING,
+    AUSAGE_CAMCORDER,
+
+    // Call Usages
+    // These audio usages are defined from Audio Mode and Voice Status
+    AUSAGE_CPCALL_MIN,
+    AUSAGE_VOICE_CALL_NB = AUSAGE_CPCALL_MIN,
+    AUSAGE_VOICE_CALL_NB_HAC,
+    AUSAGE_VOICE_CALL_WB,
+    AUSAGE_VOICE_CALL_WB_HAC,
+    AUSAGE_VOLTE_CALL_NB,
+    AUSAGE_VOLTE_CALL_WB,
+    AUSAGE_VOLTE_CALL_SWB,
+    AUSAGE_VOLTE_VT_CALL_NB,
+    AUSAGE_VOLTE_VT_CALL_WB,
+    AUSAGE_VOLTE_VT_CALL_SWB,
+    AUSAGE_TTY,
+    AUSAGE_INCALL_MUSIC,     //Music playback during CP call, sent to other device as CP Tx
+    AUSAGE_CPCALL_MAX = AUSAGE_INCALL_MUSIC,
+
+    AUSAGE_APCALL_MIN,
+    AUSAGE_WIFI_CALL_NB = AUSAGE_APCALL_MIN,
+    AUSAGE_WIFI_CALL_WB,
+    AUSAGE_WIFI_CALL_SWB,
+    AUSAGE_VIDEO_CALL,
+    AUSAGE_VOIP_CALL,
+    AUSAGE_COMMUNICATION,
+    AUSAGE_AP_TTY,
+    AUSAGE_APCALL_MAX = AUSAGE_AP_TTY,
+
+    // Call Recording Usages
+    AUSAGE_INCALL_UPLINK,
+    AUSAGE_INCALL_DOWNLINK,
+    AUSAGE_INCALL_UPLINK_DOWNLINK,
+
+    // Voice Recognition Usages
+    AUSAGE_RECOGNITION,
+
+    // Other Audio Usages
+    AUSAGE_FM_RADIO_TUNER,         // for FM radio playback
+    AUSAGE_FM_RADIO_CAPTURE, // for FM radio capture
+
+    // Voice WakeUp Usages
+#ifdef SUPPORT_STHAL_INTERFACE
+    AUSAGE_HOTWORD_SEAMLESS,
+    AUSAGE_HOTWORD_RECORD,
+#endif
+
+    // Factory Mode Test Usages
+    AUSAGE_LOOPBACK_MIN,
+    AUSAGE_LOOPBACK = AUSAGE_LOOPBACK_MIN, //packet
+    AUSAGE_LOOPBACK_NODELAY,               //packet_nodelay
+    AUSAGE_LOOPBACK_REALTIME,
+    AUSAGE_LOOPBACK_CODEC,
+    AUSAGE_LOOPBACK_MAX = AUSAGE_LOOPBACK_CODEC,
+
+    AUSAGE_RMS,                            //RMS Test
+
+    AUSAGE_NONE,
+    AUSAGE_MAX,
+    AUSAGE_CNT            = AUSAGE_MAX
+} audio_usage;
+
+#endif  // __EXYNOS_AUDIOHAL_USAGE_H__
diff --git a/include/libaudio/audiohal/voice_definition.h b/include/libaudio/audiohal/voice_definition.h
new file mode 100644
index 0000000..0489ee3
--- /dev/null
+++ b/include/libaudio/audiohal/voice_definition.h
@@ -0,0 +1,62 @@
+/*
+ * 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 __AUDIOHAL_VOICE_DEFINITION_H__
+#define __AUDIOHAL_VOICE_DEFINITION_H__
+
+/**
+ ** Custermization
+ ** If these are defined at other header file, please disable this if block
+ **/
+
+#define CP1 0 // DualCP CP1, DualMode Sim1
+#define CP2 1 // DualCP CP2, DualMode Sim2
+
+enum bt_nrec_status {
+    BT_NREC_INITIALIZED = -1,
+    BT_NREC_ON = 0,
+    BT_NREC_OFF = 1
+};
+
+#define TTY_MODE_OFF             0x00000010
+#define TTY_MODE_FULL            0x00000020
+#define TTY_MODE_VCO             0x00000040
+#define TTY_MODE_HCO             0x00000080
+#define TTY_MODE_CLEAR           0xFFFFFF0F
+
+#define TTY_MODE_OFF_RIL         0
+#define TTY_MODE_FULL_RIL        1
+#define TTY_MODE_HCO_RIL         2
+#define TTY_MODE_VCO_RIL         3
+
+#define HAC_MODE_OFF             0x00000100
+#define HAC_MODE_ON              0x00000200
+#define HAC_MODE_CLEAR           0xFFFFF0FF
+
+#define AUDIO_PARAMETER_KEY_EXTRA_VOLUME                "extraVolume"
+#define AUDIO_PARAMETER_KEY_CALL_FORWARDING             "call_forwarding"
+
+#define AUDIO_PARAMETER_VOLTE_STATUS   "VoLTEstate"
+
+
+#define SWB      2
+#define WB       1
+#define NB       0
+#define SWB_SAMPLING_RATE 32000
+#define WB_SAMPLING_RATE  16000
+#define NB_SAMPLING_RATE  8000
+
+#endif  // __AUDIOHAL_VOICE_DEFINITION_H__
diff --git a/libaudio/audiohal/Android.mk b/libaudio/audiohal/Android.mk
new file mode 100644
index 0000000..d9273c3
--- /dev/null
+++ b/libaudio/audiohal/Android.mk
@@ -0,0 +1,47 @@
+# 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.
+
+#
+# Primary Audio HAL
+#
+ifeq ($(BOARD_USE_AUDIOHAL), true)
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+	audio_hw.c \
+	voice_manager.c \
+	factory_manager.c
+
+LOCAL_C_INCLUDES += \
+	$(TOP)/hardware/samsung_slsi-linaro/exynos/include/libaudio/audiohal \
+	$(TOP)/hardware/samsung_slsi-linaro/exynos/libaudio/audioril-sit \
+	$(TOP)/hardware/samsung_slsi-linaro/exynos/libaudio/audioril-sit/include
+
+LOCAL_HEADER_LIBRARIES := libhardware_headers
+LOCAL_SHARED_LIBRARIES := liblog libcutils libprocessgroup libaudioproxy
+LOCAL_SHARED_LIBRARIES += libaudio-ril
+
+ifeq ($(BOARD_USE_SOUNDTRIGGER_HAL),true)
+LOCAL_CFLAGS += -DSUPPORT_STHAL_INTERFACE
+endif
+
+LOCAL_MODULE := audio.primary.$(TARGET_SOC)
+LOCAL_PROPRIETARY_MODULE := true
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_SHARED_LIBRARY)
+endif
diff --git a/libaudio/audiohal/NOTICE b/libaudio/audiohal/NOTICE
new file mode 100644
index 0000000..316b4eb
--- /dev/null
+++ b/libaudio/audiohal/NOTICE
@@ -0,0 +1,190 @@
+
+   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.
+
+   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.
+
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
diff --git a/libaudio/audiohal/audio_hw.c b/libaudio/audiohal/audio_hw.c
new file mode 100644
index 0000000..1bcdbcd
--- /dev/null
+++ b/libaudio/audiohal/audio_hw.c
@@ -0,0 +1,4626 @@
+/*
+ * 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_primary"
+#define LOG_NDEBUG 0
+
+#include <stdlib.h>
+#include <errno.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <sys/resource.h>
+#include <sys/prctl.h>
+#include <system/thread_defs.h>
+
+#include <log/log.h>
+#include <cutils/str_parms.h>
+#include <cutils/sched_policy.h>
+
+#include "audio_hw.h"
+#include "audio_tables.h"
+#include "audio_mixers.h"
+#include "audio_proxy_interface.h"
+
+#include "audio_log.h"
+
+
+
+/******************************************************************************/
+/** Note: the following macro is used for extremely verbose logging message. **/
+/** In order to run with ALOG_ASSERT turned on, we need to have LOG_NDEBUG   **/
+/** set to 0; but one side effect of this is to turn all LOGV's as well. Some**/
+/** messages are so verbose that we want to suppress them even when we have  **/
+/** ALOG_ASSERT turned on.  Do not uncomment the #def below unless you       **/
+/** really know what you are doing and want to see all of the extremely      **/
+/** verbose messages.                                                        **/
+/******************************************************************************/
+//#define VERY_VERY_VERBOSE_LOGGING
+#ifdef VERY_VERY_VERBOSE_LOGGING
+#define ALOGVV ALOGD
+#else
+#define ALOGVV(a...) do { } while(0)
+#endif
+
+//#define ROUTING_VERBOSE_LOGGING
+#ifdef ROUTING_VERBOSE_LOGGING
+#define ALOGRV ALOGD
+#else
+#define ALOGRV(a...) do { } while(0)
+#endif
+
+
+
+/******************************************************************************/
+/**                                                                          **/
+/** Audio Device is Singleton                                                **/
+/**                                                                          **/
+/******************************************************************************/
+
+/*
+ * There are some race condition in HW Binder to open/close HAL.
+ * In order to avoid abnormal audio device open and close, adev_init_lock will
+ * protect opening before close.
+ */
+static pthread_mutex_t adev_init_lock = PTHREAD_MUTEX_INITIALIZER;
+static struct audio_device *instance = NULL;
+static unsigned int adev_ref_count = 0;
+
+static struct audio_device* getAudioDeviceInstance(void)
+{
+    if (instance == NULL) {
+        instance = calloc(1, sizeof(struct audio_device));
+        ALOGI("proxy-%s: created Audio HW Device Instance!", __func__);
+    }
+    return instance;
+}
+
+static void destroyAudioDeviceInstance(void)
+{
+    if (instance) {
+        free(instance);
+        instance = NULL;
+        ALOGI("proxy-%s: destroyed Audio HW Device Instance!", __func__);
+    }
+    return;
+}
+
+
+/******************************************************************************/
+/**                                                                          **/
+/** The Local Functions for Mode Selection                                   **/
+/**                                                                          **/
+/******************************************************************************/
+/* CP Centric Call Mode or not */
+static bool isCPCallMode(struct audio_device *adev)
+{
+    audio_mode_t mode = adev->amode;
+
+    if (mode == AUDIO_MODE_IN_CALL)
+        return true;
+    else
+        return false;
+}
+
+/* AP Centric Call Mode or not */
+static bool isAPCallMode(struct audio_device *adev)
+{
+    audio_mode_t mode = adev->amode;
+
+    if (mode == AUDIO_MODE_IN_COMMUNICATION)
+        return true;
+    else
+        return false;
+}
+
+static bool isCallMode(struct audio_device *adev)
+{
+    if (isCPCallMode(adev) || isAPCallMode(adev))
+        return true;
+    else
+        return false;
+}
+
+/* Factory Mode or not */
+static bool isFactoryMode(struct audio_device *adev)
+{
+    if (adev->factory && adev->factory->mode != FACTORY_MODE_NONE)
+        return true;
+    else
+        return false;
+}
+
+static bool isCallRecording(audio_source_t source)
+{
+    if (source == AUDIO_SOURCE_VOICE_UPLINK ||
+        source == AUDIO_SOURCE_VOICE_DOWNLINK ||
+        source == AUDIO_SOURCE_VOICE_CALL)
+        return true;
+    else
+        return false;
+}
+
+static bool isFMRadioOn(struct audio_device *adev)
+{
+    if (adev->fm_state == FM_ON || adev->fm_state == FM_RECORDING) return true;
+    else return false;
+}
+
+/* VoIP SE (Speech Enhancement) Triggering or not */
+static bool need_voipse_on(struct audio_device *adev)
+{
+    if (isAPCallMode(adev) && adev->voipse_on == false)
+        return true;
+    else
+        return false;
+}
+
+static bool isUSBHeadsetConnect(struct audio_device *adev)
+{
+    if(adev->actual_playback_device == AUDIO_DEVICE_OUT_USB_DEVICE || adev->actual_playback_device == AUDIO_DEVICE_OUT_USB_ACCESSORY ||
+        adev->actual_playback_device == AUDIO_DEVICE_OUT_USB_HEADSET)
+        return true;
+    else
+        return false;
+}
+
+
+/******************************************************************************/
+/**                                                                          **/
+/** The Local Functions for Customer Features                                **/
+/**                                                                          **/
+/******************************************************************************/
+static char *bool_to_str(int value)
+{
+    return value?"True":"False";
+}
+
+/******************************************************************************/
+/**                                                                          **/
+/** The Local Functions for Audio Path Routing                               **/
+/**                                                                          **/
+/******************************************************************************/
+// Factory Mode Usage
+static audio_usage adev_get_ausage_for_factory(struct audio_device *adev)
+{
+    audio_usage ausage = AUSAGE_NONE;
+
+    if (adev->factory && adev->factory->mode == FACTORY_MODE_LOOPBACK) {
+        ALOGI("device-%s: AUSAGE_MODE_LOOPBACK", __func__);
+        if(adev->factory->loopback_mode == FACTORY_LOOPBACK_PACKET ) {
+            ausage = AUSAGE_LOOPBACK;
+        } else if(adev->factory->loopback_mode == FACTORY_LOOPBACK_CODEC) {
+            ausage = AUSAGE_LOOPBACK_CODEC;
+        } else if(adev->factory->loopback_mode == FACTORY_LOOPBACK_REALTIME) {
+            ausage = AUSAGE_LOOPBACK_REALTIME;
+        } else if(adev->factory->loopback_mode == FACTORY_LOOPBACK_PACKET_NODELAY) {
+            ausage = AUSAGE_LOOPBACK_NODELAY;
+        } else {
+            ausage = AUSAGE_LOOPBACK;
+        }
+    } else if (adev->factory && adev->factory->mode == FACTORY_MODE_RMS) {
+        ALOGI("device-%s: AUSAGE_MODE_RMS", __func__);
+        ausage = AUSAGE_RMS;
+    }
+
+    return ausage;
+}
+
+// VoLTE Call Usage
+static audio_usage adev_get_ausage_for_volte(struct audio_device *adev)
+{
+    volte_status_t volte_status = VOLTE_OFF;
+    int samplingrate = VOICE_SR_NB;
+    audio_usage ausage = AUSAGE_NONE;
+
+    if (adev->voice) {
+        volte_status = voice_get_volte_status(adev->voice);
+        if (volte_status == VOLTE_VOICE) {
+            /* VoLTE Voice Call Usage */
+            samplingrate = voice_get_samplingrate(adev->voice);
+            switch (samplingrate) {
+                case VOICE_SR_SWB:
+                    ausage = AUSAGE_VOLTE_CALL_SWB;
+                    break;
+
+                case VOICE_SR_WB:
+                    ausage = AUSAGE_VOLTE_CALL_WB;
+                    break;
+
+                case VOICE_SR_NB:
+                default:
+                    ausage = AUSAGE_VOLTE_CALL_NB;
+                    break;
+            }
+        } else if (volte_status == VOLTE_VIDEO) {
+            /* VoLTE Video Call Usage */
+            samplingrate = voice_get_samplingrate(adev->voice);
+            switch (samplingrate) {
+                case VOICE_SR_SWB:
+                    ausage = AUSAGE_VOLTE_VT_CALL_SWB;
+                    break;
+
+                case VOICE_SR_WB:
+                    ausage = AUSAGE_VOLTE_VT_CALL_WB;
+                    break;
+
+                case VOICE_SR_NB:
+                default:
+                    ausage = AUSAGE_VOLTE_VT_CALL_NB;
+                    break;
+            }
+        }
+    }
+
+    return ausage;
+}
+
+// Voice Call or VoLTE Call Usage
+static audio_usage adev_get_ausage_for_call(struct audio_device *adev)
+{
+    audio_usage ausage = AUSAGE_NONE;
+
+    if (adev->voice) {
+        ALOGI("%s: incallmusic_on (%d)", __func__, adev->incallmusic_on);
+        /* Check Special Call Usage */
+        if (adev->voice->tty_mode != TTY_MODE_OFF)
+            return AUSAGE_TTY;
+        else if (adev->incallmusic_on)
+            return AUSAGE_INCALL_MUSIC;
+
+        /* Check Normal Call Usage(Voice Call or VoLTE Call) */
+        if (voice_get_volte_status(adev->voice) != VOLTE_OFF)
+            ausage = adev_get_ausage_for_volte(adev);
+        else {
+            int samplingrate = voice_get_samplingrate(adev->voice);
+            switch (samplingrate) {
+                case VOICE_SR_WB:
+                    if (adev->voice->hac_mode == HAC_MODE_ON)
+                        ausage = AUSAGE_VOICE_CALL_WB_HAC;
+                    else
+                        ausage = AUSAGE_VOICE_CALL_WB;
+                    break;
+
+                case VOICE_SR_NB:
+                default:
+                    if (adev->voice->hac_mode == HAC_MODE_ON)
+                        ausage = AUSAGE_VOICE_CALL_NB_HAC;
+                    else
+                        ausage = AUSAGE_VOICE_CALL_NB;
+                    break;
+            }
+        }
+    }
+
+    return ausage;
+}
+
+// VoIP Call Usage such as VoWiFi Call
+static audio_usage adev_get_ausage_for_voip(struct audio_device *adev)
+{
+    audio_usage ausage = AUSAGE_COMMUNICATION;
+
+    if (adev->voice && adev->voice->csvtcall) {
+        ausage = AUSAGE_VIDEO_CALL;
+    } else if (adev->voice && adev->voice->voip_wificalling) {
+        if (adev->voice->tty_mode != TTY_MODE_OFF) {
+            ausage = AUSAGE_AP_TTY;
+        } else {
+            if (adev->primary_output->common.requested_devices & AUDIO_DEVICE_OUT_ALL_SCO) {
+                if (adev->voice->bluetooth_samplerate == WB_SAMPLING_RATE)
+                    ausage = AUSAGE_WIFI_CALL_WB;
+                else
+                    ausage = AUSAGE_WIFI_CALL_NB;
+            } else {
+                int vowifi_band = voice_get_vowifi_band(adev->voice);
+                switch (vowifi_band) {
+                    case VOICE_SR_SWB:
+                        ausage = AUSAGE_WIFI_CALL_SWB;
+                        break;
+
+                    case VOICE_SR_WB:
+                        ausage = AUSAGE_WIFI_CALL_WB;
+                        break;
+
+                    case VOICE_SR_NB:
+                    default:
+                        ausage = AUSAGE_WIFI_CALL_NB;
+                        break;
+                }
+            }
+        }
+    } else {
+        if (adev->active_input) {
+            if (adev->active_input->requested_source == AUDIO_SOURCE_MIC)
+                ausage = AUSAGE_VOIP_CALL;
+        }
+    }
+
+    return ausage;
+}
+
+static audio_usage adev_get_playback_ausage(struct audio_device *adev)
+{
+    audio_usage ausage = AUSAGE_NONE;
+
+    if (isFactoryMode(adev)) {
+        ausage = adev_get_ausage_for_factory(adev);
+    } else if (isCPCallMode(adev)) {
+        ausage = adev_get_ausage_for_call(adev);
+    } else if (isAPCallMode(adev)) {
+        ausage = adev_get_ausage_for_voip(adev);
+    } else if (isFMRadioOn(adev) && (popcount(adev->primary_output->common.requested_devices) == 1)) {
+        ausage = AUSAGE_FM_RADIO_TUNER;
+    } else {
+        ausage = AUSAGE_NONE;
+    }
+
+    return ausage;
+}
+
+static audio_usage adev_get_capture_ausage(struct audio_device *adev, struct stream_in *in)
+{
+    audio_usage ausage = AUSAGE_RECORDING;
+
+    if (isFactoryMode(adev)) {
+        ausage = adev_get_ausage_for_factory(adev);
+    } else if (isCPCallMode(adev)) {
+        if (in->requested_source == AUDIO_SOURCE_VOICE_UPLINK)
+            ausage = AUSAGE_INCALL_UPLINK;
+        else if (in->requested_source == AUDIO_SOURCE_VOICE_DOWNLINK)
+            ausage = AUSAGE_INCALL_DOWNLINK;
+        else if (in->requested_source == AUDIO_SOURCE_VOICE_CALL)
+            ausage = AUSAGE_INCALL_UPLINK_DOWNLINK;
+
+    } else if (isAPCallMode(adev)) {
+        ausage = adev_get_ausage_for_voip(adev);
+    } else {
+        if (in->requested_source == AUDIO_SOURCE_CAMCORDER) {
+            ausage = AUSAGE_CAMCORDER;
+        } else if (in->requested_source == AUDIO_SOURCE_VOICE_RECOGNITION) {
+            ausage = AUSAGE_RECOGNITION;
+        }
+    }
+
+    return ausage;
+}
+
+static audio_usage adev_get_ausage_from_stream(void *stream, audio_usage_type usage_type)
+{
+    struct audio_device *adev = NULL;
+    audio_usage selected_usage = AUSAGE_NONE;
+
+    if (usage_type == AUSAGE_PLAYBACK) {
+        struct stream_out *stream_out = (struct stream_out *)stream;
+        adev = stream_out->adev;
+
+        selected_usage = adev_get_playback_ausage(adev);
+        if (selected_usage == AUSAGE_NONE)
+            selected_usage = stream_out->common.stream_usage;
+    } else {
+        struct stream_in *stream_in = (struct stream_in *)stream;
+        adev = stream_in->adev;
+
+        selected_usage = adev_get_capture_ausage(adev, stream);
+        if (selected_usage == AUSAGE_NONE)
+            selected_usage = stream_in->common.stream_usage;
+    }
+
+    return selected_usage;
+}
+
+device_type get_indevice_id_from_outdevice(struct audio_device *adev, device_type devices)
+{
+    if (isCallMode(adev)) {
+        device_type in = DEVICE_NONE;
+
+        switch (devices) {
+            case DEVICE_EARPIECE:
+                in = DEVICE_HANDSET_MIC;
+                break;
+            case DEVICE_SPEAKER:
+                in = DEVICE_SPEAKER_MIC;
+                break;
+            case DEVICE_HEADSET:
+                in = DEVICE_HEADSET_MIC;
+                break;
+            case DEVICE_HEADPHONE:
+                in = DEVICE_HEADPHONE_MIC;
+                break;
+            case DEVICE_BT_HEADSET:
+                if (isAPCallMode(adev)) {
+                    if (adev->voice->bluetooth_nrec) {
+                        in = DEVICE_BT_HEADSET_MIC; // nrec is supported by BT side
+                    } else {
+                        in = DEVICE_BT_NREC_HEADSET_MIC;
+                    }
+                } else {
+                    in = DEVICE_BT_HEADSET_MIC;
+                }
+                break;
+            case DEVICE_USB_HEADSET:
+                if (adev->actual_capture_device != AUDIO_DEVICE_IN_USB_DEVICE)
+                    in = DEVICE_HANDSET_MIC;
+                else
+                    in = DEVICE_USB_HEADSET_MIC;
+                break;
+            case DEVICE_LINE_OUT:
+                in = DEVICE_LINE_OUT_MIC;
+                break;
+            case DEVICE_NONE:
+                in = DEVICE_NONE;
+                break;
+            default:
+                if(adev->support_reciever) {
+                    in = DEVICE_HANDSET_MIC;
+                } else {
+                    in = DEVICE_SPEAKER_MIC;
+                }
+                break;
+        }
+
+        if ((adev->voice && (adev->voice->tty_mode != TTY_MODE_OFF))
+            && (devices & (DEVICE_HEADPHONE|DEVICE_HEADSET|DEVICE_SPEAKER|DEVICE_LINE_OUT))) {
+            switch (adev->voice->tty_mode) {
+                case TTY_MODE_FULL:
+                    in = DEVICE_FULL_MIC;
+                    break;
+                case TTY_MODE_HCO:
+                    if (devices & (DEVICE_HEADPHONE|DEVICE_HEADSET|DEVICE_LINE_OUT)) {
+                        in = DEVICE_HCO_MIC;
+                    }
+                    break;
+                case TTY_MODE_VCO:
+                    in = DEVICE_VCO_MIC;
+                    break;
+                default:
+                    ALOGE("%s: Invalid TTY mode (%#x)", __func__, adev->voice->tty_mode);
+            }
+        }
+
+        return in;
+    }
+
+    switch (devices) {
+        case DEVICE_SPEAKER:
+        case DEVICE_EARPIECE:
+        case DEVICE_HEADPHONE:
+        case DEVICE_SPEAKER_AND_HEADPHONE:
+        case DEVICE_AUX_DIGITAL:
+        case DEVICE_LINE_OUT:
+        case DEVICE_SPEAKER_AND_LINEOUT:
+            return DEVICE_MAIN_MIC;
+
+        case DEVICE_HEADSET:
+        case DEVICE_SPEAKER_AND_HEADSET:
+            return DEVICE_HEADSET_MIC;
+
+        case DEVICE_BT_HEADSET:
+        case DEVICE_SPEAKER_AND_BT_HEADSET:
+            return DEVICE_BT_HEADSET_MIC;
+
+        case DEVICE_USB_HEADSET:
+            return DEVICE_USB_HEADSET_MIC;
+
+        default:
+            return DEVICE_NONE;
+    }
+
+    return DEVICE_NONE;
+}
+
+device_type get_device_id(struct audio_device *adev, audio_devices_t devices)
+{
+    device_type ret = DEVICE_NONE;
+
+    if (isCallMode(adev)) {
+        if (devices > AUDIO_DEVICE_BIT_IN) {
+            /* Input Devices */
+            return get_indevice_id_from_outdevice(adev,
+                       get_device_id(adev, adev->primary_output->common.requested_devices));
+        } else {
+            switch (devices) {
+                case AUDIO_DEVICE_OUT_EARPIECE:
+                    ret = DEVICE_EARPIECE;
+                    break;
+                case AUDIO_DEVICE_OUT_SPEAKER:
+                    ret = DEVICE_SPEAKER;
+                    break;
+                case AUDIO_DEVICE_OUT_WIRED_HEADSET:
+                    ret = DEVICE_HEADSET;
+                    break;
+                case AUDIO_DEVICE_OUT_WIRED_HEADPHONE:
+                    ret = DEVICE_HEADPHONE;
+                    break;
+                case AUDIO_DEVICE_OUT_BLUETOOTH_SCO:
+                case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET:
+                case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT:
+                case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET|AUDIO_DEVICE_OUT_SPEAKER:
+                    ret = DEVICE_BT_HEADSET;
+                    break;
+                case AUDIO_DEVICE_OUT_USB_DEVICE:
+                    ret = DEVICE_USB_HEADSET;
+                    break;
+                case AUDIO_DEVICE_OUT_LINE:
+                    ret = DEVICE_LINE_OUT;
+                    break;
+                case AUDIO_DEVICE_OUT_TELEPHONY_TX:
+                    /* Assuming primary-out routing might have already requested, as call started */
+                    ret = get_device_id(adev, adev->primary_output->common.requested_devices);
+                    break;
+                case AUDIO_DEVICE_NONE:
+                    ret = DEVICE_NONE;
+                    break;
+                default:
+                    if(adev->support_reciever) {
+                        ret = DEVICE_EARPIECE;
+                    } else {
+                        ret = DEVICE_SPEAKER;
+                    }
+                    break;
+            }
+
+            if ((adev->voice->tty_mode != TTY_MODE_OFF)
+                    && (devices & (AUDIO_DEVICE_OUT_WIRED_HEADPHONE|AUDIO_DEVICE_OUT_LINE|
+                               AUDIO_DEVICE_OUT_WIRED_HEADSET|AUDIO_DEVICE_OUT_SPEAKER))) {
+                switch (adev->voice->tty_mode) {
+                    case TTY_MODE_FULL:
+                        ret = DEVICE_HEADSET;
+                        break;
+                    case TTY_MODE_HCO:
+                        if (devices & (AUDIO_DEVICE_OUT_WIRED_HEADPHONE|AUDIO_DEVICE_OUT_WIRED_HEADSET|
+                            AUDIO_DEVICE_OUT_LINE)) {
+                            ret = DEVICE_EARPIECE;
+                        }
+                        break;
+                    case TTY_MODE_VCO:
+                        ret = DEVICE_HEADSET;
+                        break;
+                    default:
+                        ALOGE("%s: Invalid TTY mode (%#x)", __func__, adev->voice->tty_mode);
+                }
+            }
+
+            if (isCPCallMode(adev)) {
+                if (adev->voice->call_forwarding)
+                    ret = DEVICE_CALL_FWD;
+            }
+        }
+
+        if (ret != DEVICE_NONE)
+            return ret;
+    }
+
+    if (devices > AUDIO_DEVICE_BIT_IN) {
+        /* Input Devices */
+        if (popcount(devices) >= 2) {
+            switch (devices) {
+                case AUDIO_DEVICE_IN_BUILTIN_MIC:           return DEVICE_MAIN_MIC;
+                case AUDIO_DEVICE_IN_WIRED_HEADSET:         return DEVICE_HEADSET_MIC;
+                case AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET: return DEVICE_BT_HEADSET_MIC;
+                case AUDIO_DEVICE_IN_BACK_MIC:              return DEVICE_SUB_MIC;
+                case AUDIO_DEVICE_IN_USB_ACCESSORY:
+                case AUDIO_DEVICE_IN_USB_DEVICE:
+                case AUDIO_DEVICE_IN_USB_HEADSET:           return DEVICE_USB_HEADSET_MIC;
+                case AUDIO_DEVICE_IN_FM_TUNER:              return DEVICE_FM_TUNER;
+                default:                                    return DEVICE_MAIN_MIC;
+            }
+        }
+    } else {
+        /* Output Devices */
+        if (adev->fm_via_a2dp && isFMRadioOn(adev)) {
+            return DEVICE_FM_EXTERNAL;
+        }
+
+        if (popcount(devices) == 1) {
+            /* Single Device */
+            switch (devices) {
+                case AUDIO_DEVICE_OUT_EARPIECE:             return DEVICE_EARPIECE;
+                case AUDIO_DEVICE_OUT_SPEAKER:              return DEVICE_SPEAKER;
+                case AUDIO_DEVICE_OUT_WIRED_HEADSET:        return DEVICE_HEADSET;
+                case AUDIO_DEVICE_OUT_WIRED_HEADPHONE:      return DEVICE_HEADPHONE;
+                case AUDIO_DEVICE_OUT_BLUETOOTH_SCO:
+                case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET:
+                case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT: return DEVICE_BT_HEADSET;
+                case AUDIO_DEVICE_OUT_AUX_DIGITAL:          return DEVICE_AUX_DIGITAL;
+                case AUDIO_DEVICE_OUT_USB_ACCESSORY:
+                case AUDIO_DEVICE_OUT_USB_DEVICE:
+                case AUDIO_DEVICE_OUT_USB_HEADSET:          return DEVICE_USB_HEADSET;
+                case AUDIO_DEVICE_OUT_LINE:                 return DEVICE_LINE_OUT;
+
+                case AUDIO_DEVICE_NONE:
+                default:                                    return DEVICE_NONE;
+            }
+        } else if (popcount(devices) == 2) {
+            /* Dual Device */
+            if (devices == (AUDIO_DEVICE_OUT_SPEAKER | AUDIO_DEVICE_OUT_WIRED_HEADSET))
+                return DEVICE_SPEAKER_AND_HEADSET;
+            if (devices == (AUDIO_DEVICE_OUT_SPEAKER | AUDIO_DEVICE_OUT_WIRED_HEADPHONE))
+                return DEVICE_SPEAKER_AND_HEADPHONE;
+            if ((devices & AUDIO_DEVICE_OUT_ALL_SCO) && (devices & AUDIO_DEVICE_OUT_SPEAKER))
+                return DEVICE_SPEAKER_AND_BT_HEADSET;
+            if ((devices & AUDIO_DEVICE_OUT_USB_DEVICE) && (devices & AUDIO_DEVICE_OUT_SPEAKER))
+                return DEVICE_SPEAKER;
+            if (devices == (AUDIO_DEVICE_OUT_SPEAKER | AUDIO_DEVICE_OUT_LINE))
+                return DEVICE_SPEAKER_AND_LINEOUT;
+        }
+    }
+
+    return ret;
+}
+
+static int get_apcall_speech_param(struct stream_out *out)
+{
+    struct audio_device *adev = out->adev;
+    device_type device = get_device_id(adev, out->common.requested_devices);
+    int ret = 8;
+    //Voip WB
+    if(device == DEVICE_EARPIECE)return 8;
+    if(device == DEVICE_SPEAKER)return 9;
+    if(device == DEVICE_HEADSET || device == DEVICE_SPEAKER_AND_HEADSET)return 11;
+    if(device == DEVICE_HEADPHONE || device == DEVICE_SPEAKER_AND_HEADPHONE)return 10;
+    if(device == DEVICE_LINE_OUT || device == DEVICE_SPEAKER_AND_LINEOUT)return 12;
+    if(device == DEVICE_BT_HEADSET || device == DEVICE_SPEAKER_AND_BT_HEADSET) {
+        if (adev->voice) {
+            if (adev->voice->bluetooth_nrec) {
+                ALOGI("device-%s NREC OFF :%d", __func__, adev->voice->bluetooth_nrec);
+                return 6;
+            } else {
+                ALOGI("device-%s NREC OFF :%d", __func__, adev->voice->bluetooth_nrec);
+                return 7;
+            }
+        } else {
+            return 7;
+        }
+    }
+    return ret;
+}
+
+static device_type adev_get_device(void *stream, audio_usage_type usage_type)
+{
+    struct audio_device *adev = NULL;
+    device_type selected_device = DEVICE_NONE;
+
+    if (usage_type == AUSAGE_PLAYBACK) {
+        struct stream_out *out = (struct stream_out *)stream;
+        adev = out->adev;
+
+        if (adev->factory && adev->factory->mode != FACTORY_MODE_NONE)
+            selected_device = get_device_id(adev, adev->factory->out_device);
+        else
+            selected_device = get_device_id(adev, out->common.requested_devices);
+    } else {
+        struct stream_in *in = (struct stream_in *)stream;
+        adev = in->adev;
+
+        if (adev->factory && adev->factory->mode != FACTORY_MODE_NONE)
+            selected_device = get_device_id(adev, adev->factory->in_device);
+        else
+            selected_device = get_device_id(adev, in->common.requested_devices);
+    }
+
+    return selected_device;
+}
+
+static device_type adev_get_capture_device(void *stream, audio_usage_type usage_type)
+{
+    struct audio_device *adev = NULL;
+    device_type selected_device = DEVICE_NONE;
+
+    if (usage_type == AUSAGE_PLAYBACK) {
+        struct stream_out *out = (struct stream_out *)stream;
+        adev = out->adev;
+
+        if(adev->factory && adev->factory->mode != FACTORY_MODE_NONE)
+            selected_device = get_device_id(adev, adev->factory->in_device);
+        else
+            selected_device = get_indevice_id_from_outdevice(adev, get_device_id(adev, out->common.requested_devices));
+    } else {
+        struct stream_in *in = (struct stream_in *)stream;
+        adev = in->adev;
+
+        if(adev->factory && adev->factory->mode != FACTORY_MODE_NONE)
+            selected_device = get_device_id(adev, adev->factory->in_device);
+        else
+            selected_device = get_device_id(adev, in->common.requested_devices);
+    }
+
+    return selected_device;
+}
+
+// Modifier Selection
+static modifier_type adev_get_modifier(struct audio_device *adev, device_type device)
+{
+    modifier_type type = MODIFIER_NONE;
+
+    switch (device) {
+        case DEVICE_BT_HEADSET:
+        case DEVICE_SPEAKER_AND_BT_HEADSET:
+            if (adev->voice && adev->voice->bluetooth_samplerate == WB_SAMPLING_RATE)
+                type = MODIFIER_BT_SCO_RX_WB;
+            else
+                type = MODIFIER_BT_SCO_RX_NB;
+            break;
+
+        case DEVICE_BT_HEADSET_MIC:
+        case DEVICE_BT_NREC_HEADSET_MIC:
+            if (adev->voice && adev->voice->bluetooth_samplerate == WB_SAMPLING_RATE)
+                type = MODIFIER_BT_SCO_TX_WB;
+            else
+                type = MODIFIER_BT_SCO_TX_NB;
+            break;
+
+        default:
+            ALOGVV("device-%s: (%d) device, skip to set mixer", __func__, device);
+            break;
+    }
+
+    ALOGVV("device-%s return type:%d", __func__, type);
+    return type;
+}
+
+// Active Stream Count
+static int get_active_playback_count(struct audio_device *adev, struct stream_out *out)
+{
+    int active_count = 0;
+    struct listnode *node;
+    struct playback_stream *out_node;
+    struct stream_out *temp_out;
+
+    list_for_each(node, &adev->playback_list)
+    {
+        out_node = node_to_item(node, struct playback_stream, node);
+        if (out_node) {
+            temp_out = out_node->out;
+            if ((temp_out != out) &&
+                (temp_out->common.stream_type != ASTREAM_PLAYBACK_AUX_DIGITAL &&
+                 temp_out->common.stream_type != ASTREAM_PLAYBACK_USB_DEVICE) &&
+                (temp_out->common.stream_status > STATUS_STANDBY))
+                active_count++;
+        }
+    }
+
+    return active_count;
+}
+
+static int get_active_capture_count(struct audio_device *adev)
+{
+    int active_count = 0;
+    struct listnode *node;
+    struct capture_stream *in_node;
+    struct stream_in *in;
+
+    list_for_each(node, &adev->capture_list)
+    {
+        in_node = node_to_item(node, struct capture_stream, node);
+        if (in_node) {
+            in = in_node->in;
+            if ((in->common.stream_type != ASTREAM_CAPTURE_CALL) &&
+                (in->common.stream_status > STATUS_STANDBY))
+                active_count++;
+        }
+    }
+
+    return active_count;
+}
+
+void update_call_stream(struct stream_out *out, audio_devices_t current_devices, audio_devices_t new_devices)
+{
+    struct audio_device *adev = out->adev;
+    struct listnode *node, *auxi;
+    struct playback_stream *out_node;
+    struct capture_stream  *in_node;
+    device_type cur_device = get_device_id(adev, current_devices);
+    device_type new_device = get_device_id(adev, new_devices);
+    device_type cur_in_device = DEVICE_NONE;
+    device_type new_in_device = DEVICE_NONE;
+    bool path_changed = false;
+    bool call_state_changed = false;
+    bool call_state_BT = false;
+
+    ALOGI("%s-%s: entered", stream_table[out->common.stream_type], __func__);
+
+    pthread_mutex_t *lock[ASTREAM_MAX] = {NULL, };
+
+    if (isCallMode(adev)) {
+        cur_in_device = adev->active_capture_device;
+        new_in_device = get_indevice_id_from_outdevice(adev, new_device);
+    }
+
+    if ((cur_device != new_device) ||
+        ((cur_in_device != new_in_device)
+        && ((cur_in_device == DEVICE_USB_HEADSET_MIC) || (new_in_device == DEVICE_USB_HEADSET_MIC)))) {
+        path_changed = true;
+    }
+
+    if ((isAPCallMode(adev) && !is_active_usage_APCall(adev->proxy)) ||
+        (isCPCallMode(adev) && is_active_usage_APCall(adev->proxy)) ||
+        (!isCallMode(adev) && (cur_device == DEVICE_EARPIECE)) ||
+        (!isCallMode(adev) && (cur_device == DEVICE_SPEAKER))) {
+        call_state_changed = true;
+    }
+
+    if((adev->previous_amode == AUDIO_MODE_RINGTONE) && !is_active_usage_CPCall(adev->proxy) && isCPCallMode(adev) && new_device == DEVICE_BT_HEADSET) {
+        call_state_changed = true;
+        call_state_BT = true;
+    }
+
+    list_for_each_safe(node, auxi, &adev->playback_list) {
+        out_node = node_to_item(node, struct playback_stream, node);
+        if (out_node && out_node->out &&
+            (call_state_BT || ((cur_device == DEVICE_EARPIECE) || (new_device == DEVICE_EARPIECE)) ||
+            ((cur_device == DEVICE_SPEAKER) || (new_device == DEVICE_SPEAKER)))) {
+            lock[out_node->out->common.stream_type] = &out_node->out->common.lock;
+            if (lock[out_node->out->common.stream_type]) {
+                pthread_mutex_lock(lock[out_node->out->common.stream_type]);
+                 /* RDMA PCM re-open for rcv <-> other path during call or when ending call*/
+                if ((path_changed || call_state_changed) &&
+                    out_node->out->common.proxy_stream && out_node->out->common.stream_status != STATUS_STANDBY) {
+                    proxy_stop_playback_stream((void *)(out_node->out->common.proxy_stream));
+                    proxy_close_playback_stream((void *)(out_node->out->common.proxy_stream));
+                    out_node->out->common.stream_status = STATUS_STANDBY;
+                } else {
+                    pthread_mutex_unlock(lock[out_node->out->common.stream_type]);
+                    lock[out_node->out->common.stream_type] = NULL;
+                }
+            }
+        }
+    }
+
+    list_for_each_safe(node, auxi, &adev->capture_list) {
+    in_node = node_to_item(node, struct capture_stream, node);
+        if (in_node && in_node->in) {
+            lock[in_node->in->common.stream_type] = &in_node->in->common.lock;
+             if (lock[in_node->in->common.stream_type] &&
+                ((in_node->in->common.stream_type == ASTREAM_CAPTURE_PRIMARY)
+                || (in_node->in->common.stream_type == ASTREAM_CAPTURE_CALL))) {
+                pthread_mutex_lock(lock[in_node->in->common.stream_type]);
+                /* WDMA PCM re-open for path change during call or when entering or ending call*/
+                if (((path_changed && isCallMode(adev)) ||
+                    (call_state_changed && isAPCallMode(adev)) ||
+                    (isCPCallMode(adev) && (in_node->in->common.stream_type == ASTREAM_CAPTURE_PRIMARY) && isCallRecording(in_node->in->requested_source)) ||
+                    (!isCPCallMode(adev) && (in_node->in->common.stream_type == ASTREAM_CAPTURE_CALL || in_node->in->common.stream_type == ASTREAM_CAPTURE_PRIMARY))) &&
+                    in_node->in->common.proxy_stream && in_node->in->common.stream_status == STATUS_PLAYING) {
+                    proxy_stop_capture_stream((void *)(in_node->in->common.proxy_stream));
+                    proxy_close_capture_stream((void *)(in_node->in->common.proxy_stream));
+                    in_node->in->pcm_reconfig = true;
+                } else {
+                    pthread_mutex_unlock(lock[in_node->in->common.stream_type]);
+                    lock[in_node->in->common.stream_type] = NULL;
+                }
+            }
+        }
+    }
+
+    pthread_mutex_lock(&adev->lock);
+    if ((path_changed || adev->active_playback_ausage == AUSAGE_INCALL_MUSIC) &&
+        adev->voice && voice_is_call_active(adev->voice)) {
+        if (!adev->voice->mute_voice)
+            voice_set_rx_mute(adev->voice, true);
+
+        voice_set_call_active(adev->voice, false);
+        proxy_stop_voice_call(adev->proxy);
+    }
+
+    /* Do actual routing */
+    if (isCallMode(adev))
+        adev_set_route((void *)out, AUSAGE_PLAYBACK, ROUTE, CALL_DRIVE);
+    else if (out->common.stream_status == STATUS_STANDBY)
+        adev_set_route((void *)out, AUSAGE_PLAYBACK, UNROUTE, CALL_DRIVE); // to disable call rx/tx path
+    else
+        ALOGI("%s-%s: skip route", stream_table[out->common.stream_type], __func__);
+
+    pthread_mutex_unlock(&adev->lock);
+
+    for(int idx = 0; idx < ASTREAM_MAX; idx++) {
+        if(lock[idx] != NULL)
+            pthread_mutex_unlock(lock[idx]);
+    }
+}
+
+void update_capture_stream(struct stream_in *in, audio_devices_t current_devices, audio_devices_t new_devices)
+{
+    struct audio_device *adev = in->adev;
+    device_type cur_in_device = get_device_id(adev, current_devices);
+    device_type new_in_device = get_device_id(adev, new_devices);
+
+    if(!isAPCallMode(adev) && !isCPCallMode(adev)) {
+        if((cur_in_device == DEVICE_BT_HEADSET_MIC && new_in_device != DEVICE_BT_HEADSET_MIC)
+            || (cur_in_device != DEVICE_BT_HEADSET_MIC && new_in_device == DEVICE_BT_HEADSET_MIC)) {
+            if (in->common.stream_status > STATUS_STANDBY) {
+                in->pcm_reconfig = true;
+                ALOGI("%s pcm_reconfig=true", __func__);
+            }
+        }
+    }
+}
+
+/* This function checks that output stream is Primary Output Stream or not */
+static bool is_primary_output(struct audio_device *adev, struct stream_out *out)
+{
+    return out == adev->primary_output;
+}
+
+/* This function checks that output stream can control Voice Call */
+static bool output_drives_call(struct audio_device *adev, struct stream_out *out)
+{
+    /* Only Primary Output Stream can control Voice Call */
+    return (out == adev->primary_output ||
+                out->common.stream_usage == AUSAGE_INCALL_MUSIC);
+}
+
+static bool adev_init_route(struct audio_device *adev)
+{
+    FILE *fp = NULL;
+    char mixer_info[MAX_MIXER_LENGTH] = MIXER_PATH_INFO;
+    char mixer_file[MAX_MIXER_LENGTH];
+    char mixer_path[MAX_MIXER_LENGTH];
+    bool use_default = true;
+    bool ret;
+
+    fp = fopen(mixer_info, "r");
+    if (fp) {
+        int readBytes = fread(mixer_file, sizeof(char), sizeof(mixer_file), fp);
+        if (readBytes > 0) {
+            mixer_file[readBytes] = 0;  // add termination character
+
+            memset(mixer_path, 0, MAX_MIXER_LENGTH);
+            strcpy(mixer_path, DEFAULT_MIXER_PATH);
+            strcat(mixer_path, mixer_file);
+
+            ALOGI("proxy-%s: there is mixer_info, will use specific mixer file(%s)",
+                             __func__, mixer_path);
+            ret = proxy_init_route(adev->proxy, mixer_path);
+            if (ret)
+                use_default = false;
+        }
+        fclose(fp);
+    }
+
+    if (use_default) {
+        memset(mixer_path, 0, MAX_MIXER_LENGTH);
+        strcpy(mixer_path, DEFAULT_MIXER_PATH);
+        strcat(mixer_path, DEFAULT_MIXER_FILE);
+
+        ALOGI("proxy-%s: no mixer_info or there is error, will use default mixer file(%s)",
+                         __func__, mixer_path);
+        ret = proxy_init_route(adev->proxy, mixer_path);
+    }
+
+    return ret;
+}
+
+static void adev_deinit_route(struct audio_device *adev)
+{
+    proxy_deinit_route(adev->proxy);
+    return ;
+}
+
+bool adev_set_route(void *stream, audio_usage_type usage_type, bool set, force_route force)
+{
+    struct audio_device *adev = NULL;
+    struct stream_out *out = NULL;
+    struct stream_in *in = NULL;
+
+    bool drive_capture_route = false;
+    bool capture_set = set;
+
+    bool ret = true;
+
+    ALOGD("adev_set_route");
+    // Check Audio Path Routing Skip
+    {
+        if (usage_type == AUSAGE_PLAYBACK) {
+            out = (struct stream_out *)stream;
+            adev = out->adev;
+        }
+        else if (usage_type == AUSAGE_CAPTURE) {
+            in = (struct stream_in *)stream;
+            adev = in->adev;
+        }
+
+        //
+        if ((usage_type == AUSAGE_CAPTURE) && isAPCallMode(adev)) {
+            if (set) {
+                if (in->common.stream_status > STATUS_STANDBY) {
+                    ALOGI("%s: need to routing tx/rx both for ap call case", __func__);
+                    adev_set_route((void *)adev->primary_output, AUSAGE_PLAYBACK, ROUTE, CALL_DRIVE);
+                    return ret;
+                }
+            } else {
+                ALOGI("%s: disable only tx for ap call case", __func__);
+            }
+        }
+    }
+
+    // Playback(Output) Path Control
+    if (usage_type == AUSAGE_PLAYBACK) {
+        audio_usage   new_playback_ausage   = AUSAGE_NONE;
+        device_type   new_playback_device   = DEVICE_NONE;
+        modifier_type new_playback_modifier = MODIFIER_NONE;
+
+        audio_usage   old_playback_ausage   = AUSAGE_NONE;
+        device_type   old_playback_device   = DEVICE_NONE;
+        modifier_type old_playback_modifier = MODIFIER_NONE;
+
+        out = (struct stream_out *)stream;
+        adev = out->adev;
+
+        if (output_drives_call(adev, out) && force == CALL_DRIVE) {
+            drive_capture_route = true;
+
+            if ((isAPCallMode(adev) || (!isCPCallMode(adev) && is_active_usage_CPCall(adev->proxy)))
+                && !(adev->active_input && (adev->active_input->common.stream_status > STATUS_STANDBY))) {
+                    capture_set = UNROUTE; // need to enable rx and disable rx/tx both
+            }
+            ALOGI("%s: %s rx and %s tx both for CALL_DRIVE state",
+                    __func__, set ? "enable" : "disable", capture_set ? "enable" : "disable");
+        }
+
+        if (set) {
+            // Selection Audio Usage & Audio Device & Modifier
+            new_playback_ausage   = adev_get_ausage_from_stream(stream, usage_type);
+            new_playback_device   = adev_get_device(stream, usage_type);
+            new_playback_modifier = adev_get_modifier(adev, new_playback_device);
+
+            /*
+            ** In cases of DP Audio or USB Audio Playback, special DMA is used
+            ** without any relation to audio path routing. So, keep previous path.
+            */
+            if (new_playback_ausage == AUSAGE_MEDIA &&
+               (new_playback_device == DEVICE_AUX_DIGITAL || new_playback_device == DEVICE_USB_HEADSET)) {
+                ALOGI("%s-%s: keep current route for device(%s) and usage(%s)",
+                              stream_table[out->common.stream_type], __func__,
+                              device_table[adev->active_playback_device],
+                              usage_table[adev->active_playback_ausage]);
+                return ret;
+            }
+
+            if (adev->is_playback_path_routed) {
+                /* Route Change Case */
+                if ((adev->active_playback_ausage == new_playback_ausage) &&
+                    (adev->active_playback_device == new_playback_device)) {
+                    // Requested same usage and same device, skip!!!
+                    ALOGI("%s-%s-1: skip re-route as same device(%s) and same usage(%s)",
+                          stream_table[out->common.stream_type], __func__,
+                          device_table[new_playback_device], usage_table[new_playback_ausage]);
+                } else {
+                    // Requested different usage or device, re-route!!!
+                    proxy_set_route(adev->proxy, (int)new_playback_ausage,
+                                   (int)new_playback_device, (int)new_playback_modifier, ROUTE);
+                    ALOGI("%s-%s-1: re-routes to device(%s) for usage(%s)",
+                          stream_table[out->common.stream_type], __func__,
+                          device_table[new_playback_device], usage_table[new_playback_ausage]);
+                }
+            } else {
+                /* New Route Case */
+                proxy_set_route(adev->proxy, (int)new_playback_ausage,
+                               (int)new_playback_device, (int)new_playback_modifier, ROUTE);
+                ALOGI("%s-%s-1: routes to device(%s) for usage(%s)",
+                      stream_table[out->common.stream_type], __func__,
+                      device_table[new_playback_device], usage_table[new_playback_ausage]);
+
+                adev->is_playback_path_routed = true;
+            }
+        } else {
+            // Get current active Audio Usage & Audio Device & Modifier
+            old_playback_ausage   = adev->active_playback_ausage;
+            old_playback_device   = adev->active_playback_device;
+            old_playback_modifier = adev->active_playback_modifier;
+
+            if (adev->is_playback_path_routed) {
+                /* Route Reset Case */
+                if ((force != FORCE_ROUTE) &&
+                    ((get_active_playback_count(adev, out) > 0) || isCPCallMode(adev)
+                    || (adev->factory && adev->factory->mode == FACTORY_MODE_LOOPBACK)
+                    || (isFMRadioOn(adev)))) {
+                    // There are some active playback stream or CP Call Mode or Loopback Mode or FM Radio is ON
+                    ALOGI("%s-%s-1: current device(%s) is still in use by other streams or CP Call Mode or Loopback Mode or FM Radio is ON",
+                          stream_table[out->common.stream_type], __func__,
+                          device_table[old_playback_device]);
+
+                    new_playback_ausage   = old_playback_ausage;
+                    new_playback_device   = old_playback_device;
+                    new_playback_modifier = old_playback_modifier;
+                } else {
+                    // There are no active playback stream
+                    proxy_set_route(adev->proxy, (int)old_playback_ausage,
+                                   (int)old_playback_device, (int)old_playback_modifier, UNROUTE);
+
+                    ALOGI("%s-%s-1: unroutes to device(%s) for usage(%s)",
+                          stream_table[out->common.stream_type], __func__,
+                          device_table[old_playback_device], usage_table[old_playback_ausage]);
+
+                    adev->is_playback_path_routed = false;
+                }
+            } else {
+                /* Abnormal Case */
+                ALOGE("%s-%s-1: already unrouted", stream_table[out->common.stream_type], __func__);
+            }
+        }
+
+        adev->active_playback_ausage   = new_playback_ausage;
+        adev->active_playback_device   = new_playback_device;
+        adev->active_playback_modifier = new_playback_modifier;
+    }
+
+    // Capture(Input) Path Control
+    if (usage_type == AUSAGE_CAPTURE ||
+       (usage_type == AUSAGE_PLAYBACK && drive_capture_route)) {
+        audio_usage   new_capture_ausage   = AUSAGE_NONE;
+        device_type   new_capture_device   = DEVICE_NONE;
+        modifier_type new_capture_modifier = MODIFIER_NONE;
+
+        audio_usage   old_capture_ausage   = AUSAGE_NONE;
+        device_type   old_capture_device   = DEVICE_NONE;
+        modifier_type old_capture_modifier = MODIFIER_NONE;
+
+        // In case of Call, Primary Playback Stream will drive Capture(Input) Path Control
+        if (drive_capture_route) {
+            if (capture_set) {
+                // Selection Audio Usage & Audio Device & Modifier
+                new_capture_ausage   = adev_get_ausage_from_stream(stream, usage_type);
+                new_capture_device   = adev_get_capture_device(stream, usage_type);
+                new_capture_modifier = adev_get_modifier(adev, new_capture_device);
+
+                if (adev->is_capture_path_routed) {
+                    /* Route Change Case */
+                    if ((adev->active_capture_ausage == new_capture_ausage) &&
+                        (adev->active_capture_device == new_capture_device)) {
+                        // Requested same usage and same device, skip!!!
+                        ALOGI("%s-%s-2: skip re-route as same device(%s) and same usage(%s)",
+                              stream_table[out->common.stream_type], __func__,
+                              device_table[new_capture_device], usage_table[new_capture_ausage]);
+                    } else {
+                        // Requested different usage or device, re-route!!!
+                        proxy_set_route(adev->proxy, (int)new_capture_ausage,
+                                       (int)new_capture_device, (int)new_capture_modifier, ROUTE);
+                        ALOGI("%s-%s-2: re-routes to device(%s) for usage(%s)",
+                              stream_table[out->common.stream_type], __func__,
+                              device_table[new_capture_device], usage_table[new_capture_ausage]);
+                    }
+                } else {
+                    /* New Route Case */
+                    proxy_set_route(adev->proxy, (int)new_capture_ausage,
+                                   (int)new_capture_device, (int)new_capture_modifier, ROUTE);
+                    ALOGI("%s-%s-2: routes to device(%s) for usage(%s)",
+                          stream_table[out->common.stream_type], __func__,
+                          device_table[new_capture_device], usage_table[new_capture_ausage]);
+
+                    adev->is_capture_path_routed = true;
+                }
+            } else {
+                // Get current active Audio Usage & Audio Device & Modifier
+                old_capture_ausage   = adev->active_capture_ausage;
+                old_capture_device   = adev->active_capture_device;
+                old_capture_modifier = adev->active_capture_modifier;
+
+                if (adev->is_capture_path_routed) {
+                    /* Route Reset Case */
+                    if (get_active_capture_count(adev) > 0) {
+                        // There are some active capture stream
+                        ALOGI("%s-%s-2: current device(%s) is still in use by other streams",
+                              stream_table[out->common.stream_type], __func__,
+                              device_table[old_capture_device]);
+
+                        new_capture_ausage   = old_capture_ausage;
+                        new_capture_device   = old_capture_device;
+                        new_capture_modifier = old_capture_modifier;
+                    } else {
+                        // There are no active capture stream
+                        proxy_set_route(adev->proxy, (int)old_capture_ausage,
+                                       (int)old_capture_device, (int)old_capture_modifier, UNROUTE);
+
+                        ALOGI("%s-%s-2: unroutes to device(%s) for usage(%s)",
+                              stream_table[out->common.stream_type], __func__,
+                              device_table[old_capture_device], usage_table[old_capture_ausage]);
+
+                        adev->is_capture_path_routed = false;
+                    }
+                } else {
+                    /* Abnormal Case */
+                    ALOGE("%s-%s-2: already unrouted", stream_table[out->common.stream_type], __func__);
+                }
+            }
+        }
+        // General Capture Stream
+        else {
+            in = (struct stream_in *)stream;
+            adev = in->adev;
+
+            if (set) {
+                // Selection Audio Usage & Audio Device & Modifier
+                new_capture_ausage   = adev_get_ausage_from_stream(stream, usage_type);
+                new_capture_device   = adev_get_device(stream, usage_type);
+                new_capture_modifier = adev_get_modifier(adev, new_capture_device);
+
+                if (adev->is_capture_path_routed) {
+                    /* Route Change Case */
+                    if ((adev->fm_need_route == false)&&(((adev->active_capture_ausage == new_capture_ausage) &&
+                        (adev->active_capture_device == new_capture_device))||
+                        ((isFMRadioOn(adev)) && (new_capture_ausage != AUSAGE_CAMCORDER)))) {
+                        // Requested same usage and same device, skip!!!
+                        ALOGI("%s-%s-3: skip re-route as same device(%s) and same usage(%s)",
+                              stream_table[in->common.stream_type], __func__,
+                              device_table[new_capture_device], usage_table[new_capture_ausage]);
+                    } else {
+                        // Requested different usage or device, re-route!!!
+                        proxy_set_route(adev->proxy, (int)new_capture_ausage,
+                                       (int)new_capture_device, (int)new_capture_modifier, ROUTE);
+                        ALOGI("%s-%s-3: re-routes to device(%s) for usage(%s)",
+                              stream_table[in->common.stream_type], __func__,
+                              device_table[new_capture_device], usage_table[new_capture_ausage]);
+                    }
+                } else {
+                    /* New Route Case */
+                    proxy_set_route(adev->proxy, (int)new_capture_ausage,
+                                   (int)new_capture_device, (int)new_capture_modifier, ROUTE);
+                    ALOGI("%s-%s-3: routes to device(%s) for usage(%s)",
+                          stream_table[in->common.stream_type], __func__,
+                          device_table[new_capture_device], usage_table[new_capture_ausage]);
+
+                    adev->is_capture_path_routed = true;
+                }
+            } else {
+                // Get current active Audio Usage & Audio Device & Modifier
+                old_capture_ausage   = adev->active_capture_ausage;
+                old_capture_device   = adev->active_capture_device;
+                old_capture_modifier = adev->active_capture_modifier;
+
+                if (adev->is_capture_path_routed) {
+                    /* Route Reset Case */
+                    if ((force != FORCE_ROUTE) &&
+                        ((get_active_capture_count(adev) > 0) || isCPCallMode(adev))) {
+                        // There are some active capture stream
+                        ALOGI("%s-%s-3: current device(%s) is still in use by other streams or CallMode",
+                              stream_table[in->common.stream_type], __func__,
+                              device_table[old_capture_device]);
+
+                        new_capture_ausage   = old_capture_ausage;
+                        new_capture_device   = old_capture_device;
+                        new_capture_modifier = old_capture_modifier;
+                    } else {
+                        // There are no active capture stream
+                        proxy_set_route(adev->proxy, (int)old_capture_ausage,
+                                       (int)old_capture_device, (int)old_capture_modifier, UNROUTE);
+
+                        ALOGI("%s-%s-3: unroutes to device(%s) for usage(%s)",
+                              stream_table[in->common.stream_type], __func__,
+                              device_table[old_capture_device], usage_table[old_capture_ausage]);
+
+                        adev->is_capture_path_routed = false;
+                    }
+                } else {
+                    /* Abnormal Case */
+                    ALOGE("%s-%s-3: already unrouted", stream_table[in->common.stream_type], __func__);
+                }
+            }
+        }
+
+        adev->active_capture_ausage   = new_capture_ausage;
+        adev->active_capture_device   = new_capture_device;
+        adev->active_capture_modifier = new_capture_modifier;
+    }
+
+    return ret;
+}
+
+// set call fwd path
+void set_call_forwarding(struct audio_device *adev, bool mode)
+{
+    ALOGI("%s: enter : %s", __func__, mode ? "on" : "off");
+    if (adev->voice && voice_is_call_mode(adev->voice)) {
+        pthread_mutex_unlock(&adev->lock);
+        if (adev->primary_output && adev->primary_output->common.requested_devices != 0)
+            update_call_stream(adev->primary_output, adev->primary_output->common.requested_devices, adev->primary_output->common.requested_devices);
+        pthread_mutex_lock(&adev->lock);
+
+        /* Start Call */
+        if (adev->proxy)
+            proxy_start_voice_call(adev->proxy);
+        voice_set_call_active(adev->voice, true);
+    } else {
+        if (adev->primary_output)
+            adev_set_route((void *)adev->primary_output, AUSAGE_PLAYBACK, ROUTE, CALL_DRIVE);
+    }
+}
+
+
+/****************************************************************************/
+/**                                                                        **/
+/** Compress Offload Specific Functions Implementation                     **/
+/**                                                                        **/
+/****************************************************************************/
+static int send_offload_msg(struct stream_out *out, offload_msg_type msg)
+{
+    struct offload_msg *msg_node = NULL;
+    int ret = 0;
+
+    msg_node = (struct offload_msg *)calloc(1, sizeof(struct offload_msg));
+    if (msg_node) {
+        msg_node->msg = msg;
+
+        list_add_tail(&out->offload.msg_list, &msg_node->node);
+        pthread_cond_signal(&out->offload.msg_cond);
+
+        ALOGVV("offload_out-%s: Sent Message = %s", __func__, offload_msg_table[msg]);
+    } else {
+        ALOGE("offload_out-%s: Failed to allocate memory for Offload MSG", __func__);
+        ret = -ENOMEM;
+    }
+
+    return ret;
+}
+
+static offload_msg_type recv_offload_msg(struct stream_out *out)
+{
+    struct listnode *offload_msg_list = &(out->offload.msg_list);
+
+    struct listnode *head = list_head(offload_msg_list);
+    struct offload_msg *msg_node = node_to_item(head, struct offload_msg, node);
+    offload_msg_type msg = msg_node->msg;
+
+    list_remove(head);
+    free(msg_node);
+
+    ALOGVV("offload_out-%s: Received Message = %s", __func__, offload_msg_table[msg]);
+    return msg;
+}
+
+static void *offload_cbthread_loop(void *context)
+{
+    struct stream_out *out = (struct stream_out *) context;
+    bool get_exit = false;
+    int ret = 0;
+
+    setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_AUDIO);
+    set_sched_policy(0, SP_FOREGROUND);
+    prctl(PR_SET_NAME, (unsigned long)"Offload Callback", 0, 0, 0);
+
+    ALOGI("%s-%s: Started running Offload Callback Thread", stream_table[out->common.stream_type], __func__);
+
+    pthread_mutex_lock(&out->common.lock);
+    do {
+        offload_msg_type msg = OFFLOAD_MSG_INVALID;
+        stream_callback_event_t event;
+        bool need_callback = true;
+
+        if (list_empty(&out->offload.msg_list)) {
+            ALOGVV("%s-%s: transit to sleep", stream_table[out->common.stream_type], __func__);
+            pthread_cond_wait(&out->offload.msg_cond, &out->common.lock);
+            ALOGVV("%s-%s: transit to wake-up", stream_table[out->common.stream_type], __func__);
+        }
+
+        if (!list_empty(&out->offload.msg_list))
+            msg = recv_offload_msg(out);
+
+        if (msg == OFFLOAD_MSG_EXIT) {
+            get_exit = true;
+            continue;
+        }
+
+        out->offload.callback_thread_blocked = true;
+        pthread_mutex_unlock(&out->common.lock);
+
+        switch (msg) {
+            case OFFLOAD_MSG_WAIT_WRITE:
+                // call compress_wait
+                ret = proxy_offload_compress_func(out->common.proxy_stream, COMPRESS_TYPE_WAIT);
+                // In case of Wait(Write Block), Error Callback is not needed.
+                event = STREAM_CBK_EVENT_WRITE_READY;
+                break;
+
+            case OFFLOAD_MSG_WAIT_PARTIAL_DRAIN:
+                // call compress_next_track
+                ret = proxy_offload_compress_func(out->common.proxy_stream, COMPRESS_TYPE_NEXTTRACK);
+
+                // call compress_partial_drain
+                ret = proxy_offload_compress_func(out->common.proxy_stream, COMPRESS_TYPE_PARTIALDRAIN);
+                if (ret) {
+                    event = STREAM_CBK_EVENT_ERROR;
+                    ALOGE("%s-%s: will Callback Error", stream_table[out->common.stream_type], __func__);
+                } else
+                    event = STREAM_CBK_EVENT_DRAIN_READY;
+
+                /* gapless playback requires compress_start for kernel 4.4 while moving to Next track
+                   therefore once partial drain is completed state changed to IDLE and when next
+                   compress_write is called state is changed back to PLAYING */
+                pthread_mutex_lock(&out->common.lock);
+                proxy_stop_playback_stream(out->common.proxy_stream);
+                out->common.stream_status = STATUS_IDLE;
+                pthread_mutex_unlock(&out->common.lock);
+                ALOGI("%s-%s: Transit to Idle", stream_table[out->common.stream_type], __func__);
+                break;
+
+            case OFFLOAD_MSG_WAIT_DRAIN:
+                // call compress_drain
+                ret = proxy_offload_compress_func(out->common.proxy_stream, COMPRESS_TYPE_DRAIN);
+                if (ret) {
+                    event = STREAM_CBK_EVENT_ERROR;
+                    ALOGE("%s-%s: will Callback Error", stream_table[out->common.stream_type], __func__);
+                } else
+                    event = STREAM_CBK_EVENT_DRAIN_READY;
+                break;
+
+            default:
+                ALOGE("Invalid message = %u", msg);
+                need_callback = false;
+                break;
+        }
+
+        pthread_mutex_lock(&out->common.lock);
+        out->offload.callback_thread_blocked = false;
+        pthread_cond_signal(&out->offload.sync_cond);
+
+        if (need_callback) {
+            out->offload.callback(event, NULL, out->offload.cookie);
+            if (event == STREAM_CBK_EVENT_DRAIN_READY)
+                ALOGD("%s-%s: Callback to Platform with %d", stream_table[out->common.stream_type],
+                                                             __func__, event);
+        }
+    } while(!get_exit);
+
+    /* Clean the message list */
+    pthread_cond_signal(&out->offload.sync_cond);
+    while(!list_empty(&out->offload.msg_list))
+        recv_offload_msg(out);
+    pthread_mutex_unlock(&out->common.lock);
+
+    ALOGI("%s-%s: Stopped running Offload Callback Thread", stream_table[out->common.stream_type], __func__);
+    return NULL;
+}
+
+static int create_offload_callback_thread(struct stream_out *out)
+{
+    pthread_cond_init(&out->offload.msg_cond, (const pthread_condattr_t *) NULL);
+    pthread_cond_init(&out->offload.sync_cond, (const pthread_condattr_t *) NULL);
+
+    pthread_create(&out->offload.callback_thread, (const pthread_attr_t *) NULL, offload_cbthread_loop, out);
+    out->offload.callback_thread_blocked = false;
+
+    return 0;
+}
+
+static int destroy_offload_callback_thread(struct stream_out *out)
+{
+    int ret = 0;
+
+    pthread_mutex_lock(&out->common.lock);
+    ret = send_offload_msg(out, OFFLOAD_MSG_EXIT);
+    pthread_mutex_unlock(&out->common.lock);
+
+    pthread_join(out->offload.callback_thread, (void **) NULL);
+    ALOGI("%s-%s: Joined Offload Callback Thread!", stream_table[out->common.stream_type], __func__);
+
+    pthread_cond_destroy(&out->offload.sync_cond);
+    pthread_cond_destroy(&out->offload.msg_cond);
+
+    return 0;
+}
+
+/****************************************************************************/
+/**                                                                        **/
+/** The Stream_Out Function Implementation                                 **/
+/**                                                                        **/
+/****************************************************************************/
+static uint32_t out_get_sample_rate(const struct audio_stream *stream)
+{
+    struct stream_out *out = (struct stream_out *)stream;
+
+    ALOGVV("%s-%s: exit with sample rate = %u", stream_table[out->common.stream_type], __func__,
+                                                out->common.requested_sample_rate);
+    return out->common.requested_sample_rate;
+}
+
+static int out_set_sample_rate(struct audio_stream *stream __unused, uint32_t rate __unused)
+{
+    return -ENOSYS;
+}
+
+static size_t out_get_buffer_size(const struct audio_stream *stream)
+{
+    struct stream_out *out = (struct stream_out *)stream;
+    size_t buffer_size = 0;
+
+    ALOGVV("%s-%s: enter", stream_table[out->common.stream_type], __func__);
+
+    // will return buffer size based on requested PCM configuration
+    if (out->common.stream_type == ASTREAM_PLAYBACK_COMPR_OFFLOAD)
+        buffer_size = proxy_get_actual_period_size(out->common.proxy_stream);
+    else
+    buffer_size = proxy_get_actual_period_size(out->common.proxy_stream) *
+                  (unsigned int)audio_stream_out_frame_size((const struct audio_stream_out *)stream);
+
+    ALOGVV("%s-%s: exit with %d bytes", stream_table[out->common.stream_type], __func__, (int)buffer_size);
+    return buffer_size;
+}
+
+static audio_channel_mask_t out_get_channels(const struct audio_stream *stream)
+{
+    struct stream_out *out = (struct stream_out *)stream;
+
+    ALOGVV("%s-%s: exit with channel mask = 0x%x", stream_table[out->common.stream_type], __func__,
+                                                  out->common.requested_channel_mask);
+    return out->common.requested_channel_mask;
+}
+
+static audio_format_t out_get_format(const struct audio_stream *stream)
+{
+    struct stream_out *out = (struct stream_out *)stream;
+
+    ALOGVV("%s-%s: exit with audio format = 0x%x", stream_table[out->common.stream_type], __func__,
+                                                   out->common.requested_format);
+    return out->common.requested_format;
+}
+
+static int out_set_format(struct audio_stream *stream __unused, audio_format_t format __unused)
+{
+    return -ENOSYS;
+}
+
+static int out_standby(struct audio_stream *stream)
+{
+    struct stream_out *out = (struct stream_out *)stream;
+    struct audio_device *adev = out->adev;
+
+    ALOGVV("%s-%s: enter", stream_table[out->common.stream_type], __func__);
+
+    pthread_mutex_lock(&out->common.lock);
+    if (out->common.stream_status > STATUS_STANDBY) {
+        /* Stops stream & transit to Idle. */
+        if (out->common.stream_status > STATUS_IDLE) {
+            if (out->common.stream_type == ASTREAM_PLAYBACK_COMPR_OFFLOAD &&
+                out->offload.callback_thread_blocked)
+                pthread_cond_wait(&out->offload.sync_cond, &out->common.lock);
+
+            proxy_stop_playback_stream((void *)(out->common.proxy_stream));
+            out->common.stream_status = STATUS_IDLE;
+            ALOGI("%s-%s: transited to Idle", stream_table[out->common.stream_type], __func__);
+        }
+
+        /* Closes device & transit to Standby. */
+        proxy_close_playback_stream((void *)(out->common.proxy_stream));
+        out->common.stream_status = STATUS_STANDBY;
+        ALOGI("%s-%s: transited to Standby", stream_table[out->common.stream_type], __func__);
+
+        // Check VoIP SE Untrigger
+        if (out->common.stream_type == ASTREAM_PLAYBACK_PRIMARY && adev->voipse_on) {
+            proxy_set_mixer_value_int(adev->proxy, ABOX_APCALLBUFFTYPE_CONTROL_NAME, MIXER_VALUE_OFF);
+            pthread_mutex_lock(&adev->lock);
+            adev->voipse_on = false;
+            pthread_mutex_unlock(&adev->lock);
+            ALOGI("%s-%s: VoIP SE Un-Triggered!", stream_table[out->common.stream_type], __func__);
+        }
+
+        // Have to unroute Audio Path after close PCM Device
+        pthread_mutex_lock(&adev->lock);
+        if (adev->is_playback_path_routed) {
+            if (out->common.stream_type == ASTREAM_PLAYBACK_INCALL_MUSIC &&
+                adev->incallmusic_on && isCPCallMode(adev)) {
+                ALOGI("%s-%s: try to re-route to call path for standby", stream_table[out->common.stream_type], __func__);
+                // Incall-music should be disabled before re-routing call path, to get proper call path
+                adev->incallmusic_on = false;
+                if (adev->primary_output){
+                    pthread_mutex_unlock(&adev->lock);
+                    pthread_mutex_unlock(&out->common.lock);
+                    update_call_stream(adev->primary_output, adev->primary_output->common.requested_devices, adev->primary_output->common.requested_devices);
+                    proxy_start_voice_call(adev->proxy);
+                    pthread_mutex_lock(&out->common.lock);
+                    pthread_mutex_lock(&adev->lock);
+                }
+                else
+                    ALOGW("%s-%s: Call routing skipped", stream_table[out->common.stream_type], __func__);
+            } else {
+                ALOGI("%s-%s: try to unroute for standby", stream_table[out->common.stream_type], __func__);
+                if (out->common.stream_type == ASTREAM_PLAYBACK_INCALL_MUSIC)
+                    adev->incallmusic_on = false;
+                adev_set_route((void *)out, AUSAGE_PLAYBACK, UNROUTE, NON_FORCE_ROUTE);
+            }
+        }
+        out->force = NON_FORCE_ROUTE;
+        out->rollback_devices = AUDIO_DEVICE_NONE;
+
+        pthread_mutex_unlock(&adev->lock);
+    }
+    pthread_mutex_unlock(&out->common.lock);
+
+    ALOGVV("%s-%s: exit", stream_table[out->common.stream_type], __func__);
+    return 0;
+}
+
+static int out_dump(const struct audio_stream *stream, int fd)
+{
+    struct stream_out *out = (struct stream_out *)stream;
+
+    ALOGV("%s-%s: enter with fd(%d)", stream_table[out->common.stream_type], __func__, fd);
+
+    const size_t len = 256;
+    char buffer[len];
+    snprintf(buffer, len, "\nAudio Stream Out(%x)::dump\n", out->requested_flags);
+    write(fd,buffer,strlen(buffer));
+    bool justLocked = pthread_mutex_trylock(&out->common.lock) == 0;
+    snprintf(buffer, len, "\tMutex: %s\n", justLocked ? "locked" : "unlocked");
+    write(fd,buffer,strlen(buffer));
+    if(justLocked)
+        pthread_mutex_unlock(&out->common.lock);
+
+    snprintf(buffer, len, "\toutput devices %d\n",out->common.requested_devices);
+    write(fd,buffer,strlen(buffer));
+
+    snprintf(buffer, len, "\toutput flgas: %x\n",out->requested_flags);
+    write(fd,buffer,strlen(buffer));
+    snprintf(buffer, len, "\toutput sample rate: %u\n",out->common.requested_sample_rate);
+    write(fd,buffer,strlen(buffer));
+    snprintf(buffer, len, "\toutput channel mask: %d\n",out->common.requested_channel_mask);
+    write(fd,buffer,strlen(buffer));
+    snprintf(buffer, len, "\toutput format: %d\n",out->common.requested_format);
+    write(fd,buffer,strlen(buffer));
+    snprintf(buffer, len, "\toutput audio usage: %d\n",out->common.stream_usage);
+    write(fd,buffer,strlen(buffer));
+    snprintf(buffer, len, "\toutput standby state: %d\n",out->common.stream_status);
+    write(fd,buffer,strlen(buffer));
+
+    proxy_dump_playback_stream(out->common.proxy_stream, fd);
+
+    ALOGV("%s-%s: exit with fd(%d)", stream_table[out->common.stream_type], __func__, fd);
+
+    return 0;
+}
+
+static audio_devices_t out_get_device(const struct audio_stream *stream)
+{
+    struct stream_out *out = (struct stream_out *)stream;
+
+    ALOGVV("%s-%s: exit with device = %u", stream_table[out->common.stream_type], __func__,
+                                                   out->common.requested_devices);
+    return out->common.requested_devices;
+}
+
+static int out_set_device(struct audio_stream *stream __unused, audio_devices_t device __unused)
+{
+    return -ENOSYS;
+}
+
+static int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
+{
+    struct stream_out *out = (struct stream_out *)stream;
+    struct audio_device *adev = out->adev;
+
+    struct str_parms *parms;
+    char value[32];
+    int ret = 0;
+
+    ALOGD("%s-%s: enter with param = %s", stream_table[out->common.stream_type], __func__, kvpairs);
+
+    parms = str_parms_create_str(kvpairs);
+
+    pthread_mutex_lock(&out->common.lock);
+    if (out->common.stream_type == ASTREAM_PLAYBACK_COMPR_OFFLOAD) {
+        proxy_setparam_playback_stream(out->common.proxy_stream, (void *)parms);
+    }
+
+    ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING, value, sizeof(value));
+    if (ret >= 0) {
+        audio_devices_t requested_devices = atoi(value);
+        audio_devices_t current_devices = out->common.requested_devices;
+        bool need_routing = false;
+
+        if(out->common.stream_type == ASTREAM_PLAYBACK_INCALL_MUSIC && isUSBHeadsetConnect(adev) && requested_devices == AUDIO_DEVICE_OUT_TELEPHONY_TX && isCallMode(adev)){
+            requested_devices = AUDIO_DEVICE_OUT_EARPIECE;
+            ALOGD("%s-%s: incall music (usb) -> requested_devices = AUDIO_DEVICE_OUT_EARPIECE", stream_table[out->common.stream_type], __func__);
+        }
+        /*
+         * AudioFlinger informs Audio path is this device.
+         * AudioHAL has to decide to do actual routing or not.
+         */
+        if (requested_devices != AUDIO_DEVICE_NONE) {
+            ALOGI("%s-%s: requested to change route from %s to %s",
+                  stream_table[out->common.stream_type], __func__,
+                  device_table[get_device_id(adev, current_devices)],
+                  device_table[get_device_id(adev, requested_devices)]);
+
+            /* Assign requested device to Output Stream */
+            out->common.requested_devices = requested_devices;
+
+            if(out->common.stream_type == ASTREAM_PLAYBACK_COMPR_OFFLOAD){
+                adev->update_offload_volume = true;
+            }
+
+            pthread_mutex_lock(&adev->lock);
+
+            /* Check actual routing is needed or not */
+            // Check Force Routing for Alarm sound/Shutter tone or Call Routing
+            if (is_primary_output(adev, out) && (popcount(requested_devices) == 2)) {
+                need_routing = true;
+            }
+            // Actual routing is needed at CP Voice Call routing request or device change request
+            if ((output_drives_call(adev, out) && isCallMode(adev)) ||
+                (adev->is_playback_path_routed || (out->common.stream_status > STATUS_STANDBY))) {
+                need_routing = true;
+            }
+
+            pthread_mutex_unlock(&adev->lock);
+
+            if (need_routing) {
+                /* Check routing type */
+                out->force = NON_FORCE_ROUTE;
+                if (is_primary_output(adev, out) && (popcount(requested_devices) == 2)) {
+                    // Force Routing for Alarm sound/Shutter tone, It needs rollback to previous device
+                    out->force = FORCE_ROUTE;
+                    out->rollback_devices = adev->current_devices;
+                    ALOGD("%s-%s: rollback_devices = %d", stream_table[out->common.stream_type], __func__, out->rollback_devices);
+                } else if (output_drives_call(adev, out)) {
+                    // CALL_DRIVE routing is for both playback and capture device change
+                    // case 1. Device change during CP call mode
+                    // case 2. To reset call rx/tx devices When disconnect CP call
+                    // case 3. Device change when it has active input during AP call mode
+                    if (isCPCallMode(adev)
+                        || (!isCPCallMode(adev) && is_active_usage_CPCall(adev->proxy))
+                        || (isAPCallMode(adev) && adev->active_input && (adev->active_input->common.stream_status > STATUS_STANDBY)))
+                        out->force = CALL_DRIVE;
+
+                    // update incall-music if routing is request for incall-music stream
+                    if (out->common.stream_type == ASTREAM_PLAYBACK_INCALL_MUSIC && isCPCallMode(adev) &&
+                        requested_devices != AUDIO_DEVICE_NONE) {
+                        adev->incallmusic_on = true;
+                        ALOGD("%s-%s: enable Incall Music = %d", stream_table[out->common.stream_type], __func__, adev->incallmusic_on);
+                    }
+                } else {
+                    adev->current_devices = requested_devices;
+                    ALOGD("%s-%s: adev->current_devices = %d", stream_table[out->common.stream_type], __func__, adev->current_devices);
+                }
+
+                pthread_mutex_lock(&adev->lock);
+                if (output_drives_call(adev, out) && isCallMode(adev)) {
+                    pthread_mutex_unlock(&adev->lock);
+                    pthread_mutex_unlock(&out->common.lock);
+                    update_call_stream(out, current_devices, requested_devices);
+                    pthread_mutex_lock(&out->common.lock);
+                } else {
+                    /* Do actual routing */
+                    adev_set_route((void *)out, AUSAGE_PLAYBACK, ROUTE, out->force);
+                    pthread_mutex_unlock(&adev->lock);
+                }
+
+                /* Primary output stream can be handled routing for CP Centric call */
+                if (output_drives_call(adev, out) && isCPCallMode(adev)) {
+                    if (adev->voice) {
+                        /* Set Path to RIL-Client */
+                        // In order to reduce set_path latency, call it before Voice PCM Create/Start
+                        voice_set_path(adev->voice, out->common.requested_devices);
+                        ALOGV("%s-%s: RIL Route Updated for %s",
+                              stream_table[out->common.stream_type], __func__,
+                              device_table[get_device_id(adev, out->common.requested_devices)]);
+
+                        if (!voice_is_call_active(adev->voice)) {
+                            /* Start Call */
+                            proxy_start_voice_call(adev->proxy);
+                            voice_set_call_active(adev->voice, true);
+                            ALOGI("%s-%s: *** Started CP Voice Call ***",
+                                  stream_table[out->common.stream_type], __func__);
+                        }
+
+                        /* Set Volume to RIL-Client */
+                        voice_set_volume(adev->voice, adev->voice_volume);
+                        ALOGV("%s-%s: RIL Volume Updated with %f",
+                              stream_table[out->common.stream_type],__func__, adev->voice_volume);
+                    }
+                }
+            } else {
+                if (!is_primary_output(adev, out)) {
+                    adev->current_devices = requested_devices;
+                    ALOGD("%s-%s: adev->current_devices = %d", stream_table[out->common.stream_type], __func__, adev->current_devices);
+                }
+                ALOGV("%s-%s: real routing is not needed", stream_table[out->common.stream_type], __func__);
+            }
+        } else {
+            /* When audio device will be changed, AudioFlinger requests to route with AUDIO_DEVICE_NONE */
+            ALOGV("%s-%s: requested to change route to AUDIO_DEVICE_NONE",
+                  stream_table[out->common.stream_type], __func__);
+        }
+    }
+
+    /*
+     * Android Audio System can change PCM Configurations(Format, Channel and Rate) for Audio Stream
+     * when this Audio Stream is not working.
+     */
+    // Change Audio Format
+    ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_FORMAT, value, sizeof(value));
+    if (ret >= 0) {
+        if (out->common.stream_status > STATUS_READY)
+            goto not_acceptable;
+        else {
+            audio_format_t new_format = (audio_format_t)atoi(value);
+            if ((new_format != out->common.requested_format) && (new_format != AUDIO_FORMAT_DEFAULT)) {
+                struct audio_config new_config;
+
+                out->common.requested_format = new_format;
+
+                new_config.sample_rate = out->common.requested_sample_rate;
+                new_config.channel_mask = out->common.requested_channel_mask;
+                new_config.format = new_format;
+                proxy_reconfig_playback_stream(out->common.proxy_stream, out->common.stream_type,
+                                               &new_config);
+                ALOGD("%s-%s: changed format to %#x from %#x",
+                                      stream_table[out->common.stream_type], __func__,
+                                      new_format, out->common.requested_format);
+            } else
+                ALOGD("%s-%s: requested to change same format to %#x",
+                                      stream_table[out->common.stream_type], __func__, new_format);
+        }
+    }
+
+    // Change Audio Channel Mask
+    ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_CHANNELS, value, sizeof(value));
+    if (ret >= 0) {
+        if (out->common.stream_status > STATUS_READY)
+            goto not_acceptable;
+        else {
+            audio_channel_mask_t new_chmask = (audio_channel_mask_t)atoi(value);
+            if ((new_chmask != out->common.requested_channel_mask) && (new_chmask != AUDIO_CHANNEL_NONE)) {
+                struct audio_config new_config;
+
+                out->common.requested_channel_mask = new_chmask;
+
+                new_config.sample_rate = out->common.requested_sample_rate;
+                new_config.channel_mask = new_chmask;
+                new_config.format = out->common.requested_format;
+                proxy_reconfig_playback_stream(out->common.proxy_stream, out->common.stream_type,
+                                               &new_config);
+                ALOGD("%s-%s: changed channel mask to %#x from %#x",
+                                      stream_table[out->common.stream_type], __func__,
+                                      new_chmask, out->common.requested_channel_mask);
+            } else
+                ALOGD("%s-%s: requested to change same channel mask to %#x",
+                                      stream_table[out->common.stream_type], __func__, new_chmask);
+        }
+    }
+
+    // Change Audio Sampling Rate
+    ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_SAMPLING_RATE, value, sizeof(value));
+    if (ret >= 0) {
+        if (out->common.stream_status > STATUS_READY)
+            goto not_acceptable;
+        else {
+            uint32_t new_rate = (uint32_t)atoi(value);
+            if ((new_rate != out->common.requested_sample_rate) && (new_rate != 0)) {
+                struct audio_config new_config;
+
+                out->common.requested_sample_rate = new_rate;
+
+                new_config.sample_rate = new_rate;
+                new_config.channel_mask = out->common.requested_channel_mask;
+                new_config.format = out->common.requested_format;
+                proxy_reconfig_playback_stream(out->common.proxy_stream, out->common.stream_type,
+                                               &new_config);
+                ALOGD("%s-%s: changed sampling rate to %dHz from %dHz",
+                                      stream_table[out->common.stream_type], __func__,
+                                      new_rate, out->common.requested_sample_rate);
+            } else
+                ALOGD("%s-%s: requested to change same sampling rate to %dHz",
+                                      stream_table[out->common.stream_type], __func__, new_rate);
+        }
+    }
+    pthread_mutex_unlock(&out->common.lock);
+
+    str_parms_destroy(parms);
+    ALOGVV("%s-%s: exit", stream_table[out->common.stream_type], __func__);
+    return 0;
+
+not_acceptable:
+    pthread_mutex_unlock(&out->common.lock);
+    str_parms_destroy(parms);
+    ALOGE("%s-%s: This parameter cannot accept as Stream is working",
+                                                  stream_table[out->common.stream_type], __func__);
+    return -ENOSYS;
+}
+
+static char * out_get_parameters(const struct audio_stream *stream, const char *keys)
+{
+    struct stream_out *out = (struct stream_out *)stream;
+    struct str_parms *query = str_parms_create_str(keys);
+    struct str_parms *reply = str_parms_create();
+    char * result_str;
+
+    ALOGD("%s-%s: enter with param = %s", stream_table[out->common.stream_type], __func__, keys);
+
+    pthread_mutex_lock(&out->common.lock);
+
+    // Get Current Devices
+    if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_ROUTING)) {
+        str_parms_add_int(reply, AUDIO_PARAMETER_STREAM_ROUTING, (int)out->common.requested_devices);
+    }
+
+    // Get Current Audio Format
+    if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_FORMAT)) {
+        str_parms_add_int(reply, AUDIO_PARAMETER_STREAM_FORMAT, (int)out->common.requested_format);
+    }
+
+    // Get Current Audio Frame Count
+    if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_FRAME_COUNT)) {
+        str_parms_add_int(reply, AUDIO_PARAMETER_STREAM_FRAME_COUNT,
+                                      (int)proxy_get_actual_period_size(out->common.proxy_stream));
+    }
+
+    // Some parameters can be gotten from Audio Stream Proxy
+    proxy_getparam_playback_stream(out->common.proxy_stream, query, reply);
+
+    result_str = str_parms_to_str(reply);
+    str_parms_destroy(query);
+    str_parms_destroy(reply);
+    pthread_mutex_unlock(&out->common.lock);
+
+    ALOGD("%s-%s: exit with %s", stream_table[out->common.stream_type], __func__, result_str);
+    return result_str;
+}
+
+static int out_add_audio_effect(const struct audio_stream *stream __unused, effect_handle_t effect __unused)
+{
+    return 0;
+}
+
+static int out_remove_audio_effect(const struct audio_stream *stream __unused, effect_handle_t effect __unused)
+{
+    return 0;
+}
+
+static uint32_t out_get_latency(const struct audio_stream_out *stream)
+{
+    struct stream_out *out = (struct stream_out *)stream;
+
+    return proxy_get_playback_latency(out->common.proxy_stream);
+}
+
+static int out_set_volume(struct audio_stream_out *stream, float left, float right)
+{
+    struct stream_out *out = (struct stream_out *)stream;
+    struct audio_device *adev = out->adev;
+    int ret = 0;
+
+    ALOGVV("%s-%s: enter", stream_table[out->common.stream_type], __func__);
+
+    if (out->common.stream_type == ASTREAM_PLAYBACK_COMPR_OFFLOAD) {
+        if (out->vol_left != left || out->vol_right != right|| adev->update_offload_volume) {
+            out->vol_left = left;
+            out->vol_right = right;
+
+            proxy_set_volume(adev->proxy, VOLUME_TYPE_OFFLOAD, left, right);
+
+            if (adev->update_offload_volume)
+                adev->update_offload_volume = false;
+        }
+    } else{
+        ALOGE("%s-%s: Don't support volume control for this stream",
+              stream_table[out->common.stream_type], __func__);
+        ret = -ENOSYS;
+    }
+
+    ALOGVV("%s-%s: exit", stream_table[out->common.stream_type], __func__);
+    return ret;
+}
+
+static ssize_t out_write(struct audio_stream_out *stream, const void* buffer, size_t bytes)
+{
+    struct stream_out *out = (struct stream_out *)stream;
+    struct audio_device *adev = out->adev;
+    int ret = 0, wrote = 0;
+    int voip_speech_param = 0;
+    bool voip_need_mute = false;
+    //ALOGVV("%s-%s: enter", stream_table[out->common.stream_type], __func__);
+
+    pthread_mutex_lock(&out->common.lock);
+    if (out->common.stream_status == STATUS_STANDBY) {
+        out->common.stream_status = STATUS_READY;
+        ALOGI("%s-%s: transited to Ready", stream_table[out->common.stream_type], __func__);
+
+        // Have to route Audio Path before open PCM Device
+        pthread_mutex_lock(&adev->lock);
+        if (out->common.stream_type == ASTREAM_PLAYBACK_INCALL_MUSIC && isCPCallMode(adev)) {
+            ALOGI("%s-%s: try to route incall-music call path", stream_table[out->common.stream_type], __func__);
+            /* Incall-music should be enabled before routing call path, to get proper call path,
+                 incase if standby is called and re-started */
+            adev->incallmusic_on = true;
+            adev_set_route((void *)out, AUSAGE_PLAYBACK, ROUTE, CALL_DRIVE);
+        } else if (!adev->is_playback_path_routed) {
+            ALOGI("%s-%s: try to route for playback", stream_table[out->common.stream_type], __func__);
+            adev_set_route((void *)out, AUSAGE_PLAYBACK, ROUTE, NON_FORCE_ROUTE);
+        }
+        pthread_mutex_unlock(&adev->lock);
+
+        // Check VoIP SE Trigger
+        if (need_voipse_on(adev) && out->common.stream_type == ASTREAM_PLAYBACK_PRIMARY &&
+            is_active_usage_APCall(adev->proxy)) {
+            proxy_set_mixer_value_int(adev->proxy, ABOX_APCALLBUFFTYPE_CONTROL_NAME, MIXER_VALUE_ON);
+            pthread_mutex_lock(&adev->lock);
+            adev->voipse_on = true;
+            pthread_mutex_unlock(&adev->lock);
+            ALOGI("%s-%s: VoIP SE Triggered-1!", stream_table[out->common.stream_type], __func__);
+            //Speech param should call after AP CALL BUFFTYE - SE Solution works properly.
+            voip_speech_param = get_apcall_speech_param(out);
+            proxy_set_mixer_value_int(adev->proxy, ABOX_APCALL_SPEECH_PARAM_CONTROL_NAME, voip_speech_param);
+            ALOGI("%s-%s: VoIP SE speech param : %d !", stream_table[out->common.stream_type], __func__,voip_speech_param);
+            voip_need_mute = true;
+        }
+
+        ret = proxy_open_playback_stream((void *)(out->common.proxy_stream), 0, NULL);
+        if (ret != 0) {
+            ALOGE("%s-%s: failed to open Proxy Playback Stream!",
+                  stream_table[out->common.stream_type], __func__);
+            pthread_mutex_unlock(&out->common.lock);
+            return ret;
+        } else {
+            out->common.stream_status = STATUS_IDLE;
+            ALOGI("%s-%s: transited to Idle", stream_table[out->common.stream_type], __func__);
+        }
+    }
+
+    if (out->common.stream_status > STATUS_READY) {
+        if (buffer && bytes > 0) {
+            /* Pre-Processing */
+            // Check VoIP SE Trigger
+            if (need_voipse_on(adev) && out->common.stream_type == ASTREAM_PLAYBACK_PRIMARY &&
+                is_active_usage_APCall(adev->proxy)) {
+                // In case of check VoIP after PCM Open, this PCM device needs to re-open
+                proxy_close_playback_stream((void *)(out->common.proxy_stream));
+
+                proxy_set_mixer_value_int(adev->proxy, ABOX_APCALLBUFFTYPE_CONTROL_NAME, MIXER_VALUE_ON);
+                pthread_mutex_lock(&adev->lock);
+                adev->voipse_on = true;
+                pthread_mutex_unlock(&adev->lock);
+                ALOGI("%s-%s: VoIP SE Triggered-2!", stream_table[out->common.stream_type], __func__);
+
+                voip_speech_param = get_apcall_speech_param(out);
+                proxy_set_mixer_value_int(adev->proxy, ABOX_APCALL_SPEECH_PARAM_CONTROL_NAME, voip_speech_param);
+                ALOGI("%s-%s: VoIP SE speech param : %d ", stream_table[out->common.stream_type], __func__,voip_speech_param);
+
+                proxy_open_playback_stream((void *)(out->common.proxy_stream), 0, NULL);
+                voip_need_mute = true;
+            } else if (out->common.stream_type == ASTREAM_PLAYBACK_PRIMARY && adev->voipse_on && !isAPCallMode(adev)) {
+                // In case of check VoIP after PCM Open, this PCM device needs to re-open
+                proxy_close_playback_stream((void *)(out->common.proxy_stream));
+
+                proxy_set_mixer_value_int(adev->proxy, ABOX_APCALLBUFFTYPE_CONTROL_NAME, MIXER_VALUE_OFF);
+                pthread_mutex_lock(&adev->lock);
+                adev->voipse_on = false;
+                pthread_mutex_unlock(&adev->lock);
+                ALOGI("%s-%s: VoIP SE Un-Triggered!", stream_table[out->common.stream_type], __func__);
+
+                proxy_open_playback_stream((void *)(out->common.proxy_stream), 0, NULL);
+                voip_need_mute = true;
+            }
+
+            if(out->common.stream_type == ASTREAM_PLAYBACK_INCALL_MUSIC &&
+                (isUSBHeadsetConnect(adev) || !isCallMode(adev)) && out->common.stream_status == STATUS_PLAYING) {
+                pthread_mutex_unlock(&out->common.lock);
+                return 0;
+            } else {
+               wrote = proxy_write_playback_buffer((void *)(out->common.proxy_stream), (void *)buffer, (int)bytes);
+               if (wrote >= 0) {
+                   if (out->common.stream_status == STATUS_IDLE) {
+                       if (out->common.stream_type == ASTREAM_PLAYBACK_COMPR_OFFLOAD) {
+                           // Update Offload Effects, if needed
+                       }
+
+                       ret = proxy_start_playback_stream((void *)(out->common.proxy_stream));
+                       if (ret != 0) {
+                           ALOGE("%s-%s: failed to start Proxy Playback Stream!",
+                               stream_table[out->common.stream_type], __func__);
+                           pthread_mutex_unlock(&out->common.lock);
+                           return ret;
+                       } else {
+                           out->common.stream_status = STATUS_PLAYING;
+                           ALOGI("%s-%s: transited to Playing",
+                               stream_table[out->common.stream_type], __func__);
+                       }
+                   }
+                   if(voip_need_mute){
+                       ALOGI("%s-%s: Mute for voip se transition",
+                           stream_table[out->common.stream_type], __func__);
+                       usleep(2000);
+                       proxy_set_mixer_value_int(adev->proxy, ABOX_APCALL_MUTE_CONTROL_NAME, ABOX_APCALL_MUTE_COUNT);
+                   }
+
+                   if ((out->common.stream_type == ASTREAM_PLAYBACK_COMPR_OFFLOAD) && (wrote < (ssize_t)bytes)) {
+                       /* Compress Device has no available buffer, we have to wait */
+                       ALOGVV("%s-%s: There are no available buffer in Compress Device, Need to wait",
+                       stream_table[out->common.stream_type], __func__);
+                       ret = send_offload_msg(out, OFFLOAD_MSG_WAIT_WRITE);
+                   }
+                }
+            }
+        }
+    }
+    pthread_mutex_unlock(&out->common.lock);
+
+    //ALOGVV("%s-%s: exit", stream_table[out->common.stream_type], __func__);
+    return wrote;
+}
+
+static int out_get_render_position(const struct audio_stream_out *stream, uint32_t *dsp_frames)
+{
+    struct stream_out *out = (struct stream_out *)stream;
+
+    pthread_mutex_lock(&out->common.lock);
+    int ret = proxy_get_render_position(out->common.proxy_stream, dsp_frames);
+    pthread_mutex_unlock(&out->common.lock);
+
+    return ret;
+}
+
+static int out_get_next_write_timestamp(const struct audio_stream_out *stream __unused,
+                                        int64_t *timestamp __unused)
+{
+    return -ENOSYS;
+}
+
+static int out_get_presentation_position(const struct audio_stream_out *stream,
+                                         uint64_t *frames, struct timespec *timestamp)
+{
+    struct stream_out *out = (struct stream_out *)stream;
+
+    pthread_mutex_lock(&out->common.lock);
+    int ret = proxy_get_presen_position(out->common.proxy_stream, frames, timestamp);
+    pthread_mutex_unlock(&out->common.lock);
+
+    return ret;
+}
+
+static int out_set_callback(struct audio_stream_out *stream, stream_callback_t callback, void *cookie)
+{
+    struct stream_out *out = (struct stream_out *)stream;
+    int ret = -EINVAL;
+
+    ALOGV("%s-%s: entered", stream_table[out->common.stream_type], __func__);
+
+    pthread_mutex_lock(&out->common.lock);
+    if (out->common.stream_type == ASTREAM_PLAYBACK_COMPR_OFFLOAD) {
+        if (callback && cookie) {
+            out->offload.callback = callback;
+            out->offload.cookie = cookie;
+            ALOGD("%s-%s: set callback function & cookie", stream_table[out->common.stream_type], __func__);
+
+            ret = 0;
+        }
+    }
+    pthread_mutex_unlock(&out->common.lock);
+
+    ALOGV("%s-%s: exit", stream_table[out->common.stream_type], __func__);
+    return ret;
+}
+
+static int out_pause(struct audio_stream_out* stream)
+{
+    struct stream_out *out = (struct stream_out *)stream;
+
+    int ret = -ENOSYS;
+
+    ALOGV("%s-%s: entered", stream_table[out->common.stream_type], __func__);
+
+    pthread_mutex_lock(&out->common.lock);
+    if (out->common.stream_type == ASTREAM_PLAYBACK_COMPR_OFFLOAD) {
+        if (out->common.stream_status == STATUS_PLAYING) {
+            // Stop Visualizer
+
+            ret = proxy_offload_pause(out->common.proxy_stream);
+            if (ret == 0) {
+                out->common.stream_status = STATUS_PAUSED;
+                ALOGI("%s-%s: transit to Paused", stream_table[out->common.stream_type], __func__);
+            } else {
+                ALOGE("%s-%s: failed to pause", stream_table[out->common.stream_type], __func__);
+            }
+        } else {
+            ALOGV("%s-%s: abnormal status(%u) for pausing", stream_table[out->common.stream_type],
+                  __func__, out->common.stream_status);
+        }
+    }
+    pthread_mutex_unlock(&out->common.lock);
+
+    ALOGV("%s-%s: exit", stream_table[out->common.stream_type], __func__);
+    return ret;
+}
+
+static int out_resume(struct audio_stream_out* stream)
+{
+    struct stream_out *out = (struct stream_out *)stream;
+    int ret = -ENOSYS;
+
+    ALOGV("%s-%s: entered", stream_table[out->common.stream_type], __func__);
+
+    pthread_mutex_lock(&out->common.lock);
+    if (out->common.stream_type == ASTREAM_PLAYBACK_COMPR_OFFLOAD) {
+        if (out->common.stream_status== STATUS_PAUSED) {
+            ret = proxy_offload_resume(out->common.proxy_stream);
+            if (ret == 0) {
+                out->common.stream_status = STATUS_PLAYING;
+                ALOGI("%s-%s: transit to Playing", stream_table[out->common.stream_type], __func__);
+
+                // Start Visualizer
+            } else {
+                ALOGE("%s-%s: failed to resume", stream_table[out->common.stream_type], __func__);
+            }
+        } else {
+            ALOGV("%s-%s: abnormal State(%u) for resuming", stream_table[out->common.stream_type],
+                  __func__, out->common.stream_status);
+        }
+    }
+    pthread_mutex_unlock(&out->common.lock);
+
+    ALOGV("%s-%s: exit", stream_table[out->common.stream_type], __func__);
+    return ret;
+}
+
+static int out_drain(struct audio_stream_out* stream, audio_drain_type_t type )
+{
+    struct stream_out *out = (struct stream_out *)stream;
+    int ret = -ENOSYS;
+
+    ALOGV("%s-%s: entered with type = %d", stream_table[out->common.stream_type], __func__, type);
+
+    pthread_mutex_lock(&out->common.lock);
+    if (out->common.stream_type == ASTREAM_PLAYBACK_COMPR_OFFLOAD) {
+        if (out->common.stream_status > STATUS_IDLE) {
+            if (type == AUDIO_DRAIN_EARLY_NOTIFY)
+                ret = send_offload_msg(out, OFFLOAD_MSG_WAIT_PARTIAL_DRAIN);
+            else
+                ret = send_offload_msg(out, OFFLOAD_MSG_WAIT_DRAIN);
+        } else {
+            out->offload.callback(STREAM_CBK_EVENT_DRAIN_READY, NULL, out->offload.cookie);
+            ALOGD("%s-%s: State is IDLE. Return callback with drain_ready",
+                  stream_table[out->common.stream_type], __func__);
+        }
+    }
+    pthread_mutex_unlock(&out->common.lock);
+
+    ALOGV("%s-%s: exit", stream_table[out->common.stream_type], __func__);
+    return ret;
+}
+
+static int out_flush(struct audio_stream_out* stream)
+{
+    struct stream_out *out = (struct stream_out *)stream;
+    int ret = -ENOSYS;
+
+    ALOGV("%s-%s: entered", stream_table[out->common.stream_type], __func__);
+
+    pthread_mutex_lock(&out->common.lock);
+    if (out->common.stream_type == ASTREAM_PLAYBACK_COMPR_OFFLOAD) {
+        if (out->common.stream_status > STATUS_IDLE) {
+            ret = proxy_stop_playback_stream((void *)(out->common.proxy_stream));
+            out->common.stream_status = STATUS_IDLE;
+            ALOGI("%s-%s: transit to Idle due to flush", stream_table[out->common.stream_type], __func__);
+        } else {
+            ret = 0;
+            ALOGV("%s-%s: this stream is already stopped", stream_table[out->common.stream_type], __func__);
+        }
+    }
+    pthread_mutex_unlock(&out->common.lock);
+
+    ALOGV("%s-%s: exit", stream_table[out->common.stream_type], __func__);
+    return ret;
+}
+
+// For MMAP NOIRQ Stream
+static int out_stop(const struct audio_stream_out* stream)
+{
+    struct stream_out *out = (struct stream_out *)stream;
+    int ret = -ENOSYS;
+
+    ALOGV("%s-%s: entered", stream_table[out->common.stream_type], __func__);
+
+    pthread_mutex_lock(&out->common.lock);
+    if (out->common.stream_type == ASTREAM_PLAYBACK_MMAP) {
+        if (out->common.stream_status == STATUS_PLAYING) {
+            /* Stops stream & transit to Idle. */
+            proxy_stop_playback_stream((void *)(out->common.proxy_stream));
+            out->common.stream_status = STATUS_IDLE;
+            ALOGI("%s-%s: transited to Idle", stream_table[out->common.stream_type], __func__);
+
+        } else
+            ALOGV("%s-%s: invalid operation - stream status (%d)",
+                  stream_table[out->common.stream_type], __func__, out->common.stream_status);
+    }
+    pthread_mutex_unlock(&out->common.lock);
+
+    ALOGV("%s-%s: exit", stream_table[out->common.stream_type], __func__);
+    return ret;
+}
+
+static int out_start(const struct audio_stream_out* stream)
+{
+    struct stream_out *out = (struct stream_out *)stream;
+    int ret = -ENOSYS;
+
+    ALOGV("%s-%s: entered", stream_table[out->common.stream_type], __func__);
+
+    pthread_mutex_lock(&out->common.lock);
+    if (out->common.stream_type == ASTREAM_PLAYBACK_MMAP) {
+        if (out->common.stream_status == STATUS_IDLE) {
+            /* Starts stream & transit to Playing. */
+            ret = proxy_start_playback_stream((void *)(out->common.proxy_stream));
+            if (ret != 0) {
+                ALOGE("%s-%s: failed to start Proxy Playback Stream!",
+                      stream_table[out->common.stream_type], __func__);
+            } else {
+                out->common.stream_status = STATUS_PLAYING;
+                ALOGI("%s-%s: transited to Playing",
+                      stream_table[out->common.stream_type], __func__);
+            }
+        } else
+            ALOGV("%s-%s: invalid operation - stream status (%d)",
+                  stream_table[out->common.stream_type], __func__, out->common.stream_status);
+    }
+    pthread_mutex_unlock(&out->common.lock);
+
+    ALOGV("%s-%s: exit", stream_table[out->common.stream_type], __func__);
+    return ret;
+}
+
+static int out_create_mmap_buffer(const struct audio_stream_out *stream,
+                                  int32_t min_size_frames,
+                                  struct audio_mmap_buffer_info *info)
+{
+    struct stream_out *out = (struct stream_out *)stream;
+    struct audio_device *adev = out->adev;
+    int ret = 0;
+
+    ALOGD("%s-%s: entered", stream_table[out->common.stream_type], __func__);
+
+    pthread_mutex_lock(&out->common.lock);
+
+    if (info == NULL || min_size_frames == 0) {
+        ALOGE("%s-%s: info = %p, min_size_frames = %d", stream_table[out->common.stream_type],
+                                                        __func__, info, min_size_frames);
+        ret = -EINVAL;
+        goto exit;
+    }
+
+    if (out->common.stream_type != ASTREAM_PLAYBACK_MMAP || out->common.stream_status != STATUS_STANDBY) {
+        ALOGE("%s-%s: invalid operation - stream status (%d)", stream_table[out->common.stream_type],
+                                                               __func__, out->common.stream_status);
+        ret = -ENOSYS;
+        goto exit;
+    } else {
+        out->common.stream_status = STATUS_READY;
+        ALOGI("%s-%s: transited to Ready", stream_table[out->common.stream_type], __func__);
+
+        // Have to route Audio Path before open PCM Device
+        pthread_mutex_lock(&adev->lock);
+        if (!adev->is_playback_path_routed) {
+            ALOGI("%s-%s: try to route for playback", stream_table[out->common.stream_type], __func__);
+            adev_set_route((void *)out, AUSAGE_PLAYBACK, ROUTE, NON_FORCE_ROUTE);
+        }
+        pthread_mutex_unlock(&adev->lock);
+
+        /* Opens stream & transit to Idle. */
+        ret = proxy_open_playback_stream((void *)(out->common.proxy_stream), min_size_frames, (void *)info);
+        if (ret != 0) {
+            ALOGE("%s-%s: failed to open Proxy Playback Stream!",
+                  stream_table[out->common.stream_type], __func__);
+
+            out->common.stream_status = STATUS_STANDBY;
+            ALOGI("%s-%s: transited to StandBy", stream_table[out->common.stream_type], __func__);
+        } else {
+            out->common.stream_status = STATUS_IDLE;
+            ALOGI("%s-%s: transited to Idle", stream_table[out->common.stream_type], __func__);
+        }
+    }
+
+exit:
+    pthread_mutex_unlock(&out->common.lock);
+    ALOGD("%s-%s: exited", stream_table[out->common.stream_type], __func__);
+    return ret;
+}
+
+static int out_get_mmap_position(const struct audio_stream_out *stream,
+                                 struct audio_mmap_position *position)
+{
+    struct stream_out *out = (struct stream_out *)stream;
+    int ret = 0;
+
+    ALOGV("%s-%s: entered", stream_table[out->common.stream_type], __func__);
+
+    if (position == NULL) return -EINVAL;
+    if (out->common.stream_type != ASTREAM_PLAYBACK_MMAP) return -ENOSYS;
+
+    ret = proxy_get_mmap_position((void *)(out->common.proxy_stream), (void *)position);
+
+    ALOGV("%s-%s: exited", stream_table[out->common.stream_type], __func__);
+    return ret;
+}
+
+static void out_update_source_metadata(struct audio_stream_out *stream,
+                                       const struct source_metadata* source_metadata  __unused)
+{
+    struct stream_out *out = (struct stream_out *)stream;
+
+    ALOGD("%s-%s: called, but not implemented yet", stream_table[out->common.stream_type], __func__);
+    if (source_metadata->track_count > 0) {
+        ALOGD("%s-%s: This stream has %zu tracks", stream_table[out->common.stream_type], __func__,
+                                                   source_metadata->track_count);
+
+        for (int i = 0; i < (int)source_metadata->track_count; i++) {
+            ALOGD("%d Track has Usage(%d), Content Type(%d), Gain(%f)", i+1,
+                                                       (int)source_metadata->tracks[i].usage,
+                                                       (int)source_metadata->tracks[i].content_type,
+                                                            source_metadata->tracks[i].gain);
+        }
+    }
+
+    return ;
+
+}
+
+
+/****************************************************************************/
+/**                                                                        **/
+/** The Stream_In Function Implementation                                 **/
+/**                                                                        **/
+/****************************************************************************/
+static uint32_t in_get_sample_rate(const struct audio_stream *stream)
+{
+    struct stream_in *in = (struct stream_in *)stream;
+
+    ALOGVV("%s-%s: exit with sample rate = %u", stream_table[in->common.stream_type], __func__,
+                                                in->common.requested_sample_rate);
+    return in->common.requested_sample_rate;
+}
+
+static int in_set_sample_rate(struct audio_stream *stream __unused, uint32_t rate __unused)
+{
+    return -ENOSYS;
+}
+
+static size_t in_get_buffer_size(const struct audio_stream *stream)
+{
+    struct stream_in *in = (struct stream_in *)stream;
+    size_t buffer_size = 0;
+
+    ALOGVV("%s-%s: enter", stream_table[in->common.stream_type], __func__);
+
+    // will return buffer size based on requested PCM configuration
+    if (in->common.requested_sample_rate != proxy_get_actual_sampling_rate(in->common.proxy_stream)) {
+        if (in->common.stream_type == ASTREAM_CAPTURE_PRIMARY)
+            buffer_size = (in->common.requested_sample_rate * PREDEFINED_MEDIA_CAPTURE_DURATION) / 1000;
+        else if (in->common.stream_type == ASTREAM_CAPTURE_LOW_LATENCY)
+            buffer_size = (in->common.requested_sample_rate * PREDEFINED_LOW_CAPTURE_DURATION) / 1000;
+        else
+            buffer_size = proxy_get_actual_period_size(in->common.proxy_stream);
+    } else
+        buffer_size = proxy_get_actual_period_size(in->common.proxy_stream);
+
+    buffer_size *= (unsigned int)audio_stream_in_frame_size((const struct audio_stream_in *)stream);
+    ALOGVV("%s-%s: exit with %d bytes", stream_table[in->common.stream_type], __func__, (int)buffer_size);
+    return buffer_size;
+}
+
+static audio_channel_mask_t in_get_channels(const struct audio_stream *stream)
+{
+    struct stream_in *in = (struct stream_in *)stream;
+
+    ALOGVV("%s-%s: exit with channel mask = 0x%x", stream_table[in->common.stream_type], __func__,
+                                                  in->common.requested_channel_mask);
+    return in->common.requested_channel_mask;
+}
+
+static audio_format_t in_get_format(const struct audio_stream *stream)
+{
+    struct stream_in *in = (struct stream_in *)stream;
+
+    ALOGVV("%s-%s: exit with audio format = 0x%x", stream_table[in->common.stream_type], __func__,
+                                                   in->common.requested_format);
+    return in->common.requested_format;
+}
+
+static int in_set_format(struct audio_stream *stream __unused, audio_format_t format __unused)
+{
+    return -ENOSYS;
+}
+
+static int in_standby(struct audio_stream *stream)
+{
+    struct stream_in *in = (struct stream_in *)stream;
+    struct audio_device *adev = in->adev;
+
+    ALOGVV("%s-%s: enter", stream_table[in->common.stream_type], __func__);
+
+    pthread_mutex_lock(&in->common.lock);
+    if (in->common.stream_status > STATUS_STANDBY) {
+        /* Stops stream & transit to Idle. */
+        if (in->common.stream_status > STATUS_IDLE) {
+            proxy_stop_capture_stream((void *)(in->common.proxy_stream));
+            in->common.stream_status = STATUS_IDLE;
+            ALOGI("%s-%s: transited to Idle", stream_table[in->common.stream_type], __func__);
+        }
+
+        /* Closes device & transit to Standby. */
+        proxy_close_capture_stream((void *)(in->common.proxy_stream));
+        in->common.stream_status = STATUS_STANDBY;
+        ALOGI("%s-%s: transited to Standby", stream_table[in->common.stream_type], __func__);
+
+        // Have to unroute Audio Path after close PCM Device
+        pthread_mutex_lock(&adev->lock);
+#ifdef SUPPORT_STHAL_INTERFACE
+        if (in->common.stream_type != ASTREAM_CAPTURE_HOTWORD &&
+            adev->is_capture_path_routed)
+#else
+        if (adev->is_capture_path_routed)
+#endif
+        {
+            ALOGI("%s-%s: try to unroute for standby", stream_table[in->common.stream_type], __func__);
+            adev_set_route((void *)in, AUSAGE_CAPTURE, UNROUTE, NON_FORCE_ROUTE);
+        }
+        if (adev->active_input)
+            adev->active_input = NULL;
+
+        pthread_mutex_unlock(&adev->lock);
+    }
+    pthread_mutex_unlock(&in->common.lock);
+
+    ALOGVV("%s-%s: exit", stream_table[in->common.stream_type], __func__);
+    return 0;
+}
+
+static int in_dump(const struct audio_stream *stream, int fd)
+{
+    struct stream_in *in = (struct stream_in *)stream;
+
+    ALOGVV("%s-%s: enter with fd(%d)", stream_table[in->common.stream_type], __func__, fd);
+
+    const size_t len = 256;
+    char buffer[len];
+    bool justLocked = false;
+
+    snprintf(buffer, len, "Audio Stream Input::dump\n");
+    write(fd,buffer,strlen(buffer));
+    justLocked = pthread_mutex_trylock(&in->common.lock) == 0;
+    if(justLocked)
+        pthread_mutex_unlock(&in->common.lock);
+    snprintf(buffer, len, "\tinput Mutex: %s\n", justLocked ? "locked" : "unlocked");
+    write(fd,buffer,strlen(buffer));
+
+    snprintf(buffer, len, "\tinput devices: %d\n", in->common.requested_devices);
+    write(fd,buffer,strlen(buffer));
+    snprintf(buffer, len, "\tinput source: %d\n", in->requested_source);
+    write(fd,buffer,strlen(buffer));
+    snprintf(buffer, len, "\tinput flags: %x\n",in->requested_flags);
+    write(fd,buffer,strlen(buffer));
+    snprintf(buffer, len, "\tinput sample rate: %u\n",in->common.requested_sample_rate);
+    write(fd,buffer,strlen(buffer));
+    snprintf(buffer, len, "\tinput channel mask: %u\n",in->common.requested_channel_mask);
+    write(fd,buffer,strlen(buffer));
+    snprintf(buffer, len, "\tinput format: %d\n",in->common.requested_format);
+    write(fd,buffer,strlen(buffer));
+    snprintf(buffer, len, "\tinput audio usage: %d\n",in->common.stream_usage);
+    write(fd,buffer,strlen(buffer));
+    snprintf(buffer, len, "\tinut standby state: %d\n",in->common.stream_status);
+    write(fd,buffer,strlen(buffer));
+    //snprintf(buffer, len, "\tinput mixer_path_setup: %s\n",bool_to_str(in->mixer_path_setup));
+    //write(fd,buffer,strlen(buffer));
+
+    proxy_dump_capture_stream(in->common.proxy_stream, fd);
+
+    ALOGVV("%s-%s: exit with fd(%d)", stream_table[in->common.stream_type], __func__, fd);
+    return 0;
+}
+
+static audio_devices_t in_get_device(const struct audio_stream *stream)
+{
+    struct stream_in *in = (struct stream_in *)stream;
+
+    ALOGVV("%s-%s: exit with device = %u", stream_table[in->common.stream_type], __func__,
+                                                   in->common.requested_devices);
+    return in->common.requested_devices;
+}
+
+static int in_set_device(struct audio_stream *stream __unused, audio_devices_t device __unused)
+{
+    return -ENOSYS;
+}
+
+void stop_active_input(struct stream_in *in)
+{
+    struct audio_device *adev = in->adev;
+
+    if (in->common.stream_status > STATUS_STANDBY) {
+        in->common.stream_status = STATUS_STANDBY;
+        pthread_mutex_lock(&adev->lock);
+        proxy_stop_capture_stream((void *)(in->common.proxy_stream));
+        proxy_close_capture_stream((void *)(in->common.proxy_stream));
+        pthread_mutex_unlock(&adev->lock);
+    }
+}
+
+static int in_set_parameters(struct audio_stream *stream, const char *kvpairs)
+{
+    struct stream_in *in = (struct stream_in *)stream;
+    struct audio_device *adev = in->adev;
+
+    struct str_parms *parms;
+    char value[32];
+    int ret = 0;
+
+    ALOGD("%s-%s: enter with param = %s", stream_table[in->common.stream_type], __func__, kvpairs);
+
+#ifdef SUPPORT_STHAL_INTERFACE
+        if (in->common.stream_type == ASTREAM_CAPTURE_HOTWORD) {
+            ALOGD("%s-%s: exit", stream_table[in->common.stream_type], __func__);
+            return 0;
+        }
+#endif
+
+    if (in->common.stream_type == ASTREAM_CAPTURE_USB_DEVICE) {
+        pthread_mutex_lock(&in->common.lock);
+        proxy_setparam_capture_stream(in->common.proxy_stream, (void *)kvpairs);
+        pthread_mutex_unlock(&in->common.lock);
+    }
+
+    parms = str_parms_create_str(kvpairs);
+
+    pthread_mutex_lock(&in->common.lock);
+    ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING, value, sizeof(value));
+    if (ret >= 0) {
+        audio_devices_t requested_devices = atoi(value);
+        audio_devices_t current_devices = in->common.requested_devices;
+        bool need_routing = false;
+
+        /*
+         * AudioFlinger informs Audio path is this device.
+         * AudioHAL has to decide to do actual routing or not.
+         */
+        if (requested_devices != AUDIO_DEVICE_NONE) {
+            ALOGI("%s-%s: requested to change route from %s to %s",
+                  stream_table[in->common.stream_type], __func__,
+                  device_table[get_device_id(adev, current_devices)],
+                  device_table[get_device_id(adev, requested_devices)]);
+
+            /* Assign requested device to Input Stream */
+            in->common.requested_devices = requested_devices;
+
+            update_capture_stream(in, current_devices, requested_devices);
+
+            pthread_mutex_lock(&adev->lock);
+            /* Check actual routing is needed or not */
+            // Actual routing is needed at device change request
+            if (adev->is_capture_path_routed || (in->common.stream_status > STATUS_STANDBY)) {
+                if (!isCPCallMode(adev))
+                    need_routing = true;
+            }
+            pthread_mutex_unlock(&adev->lock);
+
+            if (need_routing) {
+                pthread_mutex_lock(&adev->lock);
+                /* Do actual routing */
+                adev_set_route((void *)in, AUSAGE_CAPTURE, ROUTE, NON_FORCE_ROUTE);
+                pthread_mutex_unlock(&adev->lock);
+            }
+        } else {
+            /* When audio device will be changed, AudioFlinger requests to route with AUDIO_DEVICE_NONE */
+            ALOGV("%s-%s: requested to change route to AUDIO_DEVICE_NONE",
+                  stream_table[in->common.stream_type], __func__);
+            //pthread_mutex_lock(&adev->lock);
+            //adev_set_route((void *)in, AUSAGE_CAPTURE, UNROUTE, NON_FORCE_ROUTE);
+            //pthread_mutex_unlock(&adev->lock);
+        }
+    }
+
+    /*
+     * Android Audio System can change PCM Configurations(Format, Channel and Rate) for Audio Stream
+     * when this Audio Stream is not working.
+     */
+    // Change Audio Format
+    ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_FORMAT, value, sizeof(value));
+    if (ret >= 0) {
+        if (in->common.stream_status > STATUS_READY)
+            goto not_acceptable;
+        else {
+            audio_format_t new_format = (audio_format_t)atoi(value);
+            if ((new_format != in->common.requested_format) && (new_format != AUDIO_FORMAT_DEFAULT)) {
+                struct audio_config new_config;
+
+                in->common.requested_format = new_format;
+
+                new_config.sample_rate = in->common.requested_sample_rate;
+                new_config.channel_mask = in->common.requested_channel_mask;
+                new_config.format = new_format;
+                proxy_reconfig_capture_stream(in->common.proxy_stream, in->common.stream_type,
+                                              &new_config);
+                ALOGD("%s-%s: changed format to %#x from %#x",
+                                      stream_table[in->common.stream_type], __func__,
+                                      new_format, in->common.requested_format);
+            } else
+                ALOGD("%s-%s: requested to change same format to %#x",
+                                      stream_table[in->common.stream_type], __func__, new_format);
+        }
+    }
+
+    // Change Audio Channel Mask
+    ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_CHANNELS, value, sizeof(value));
+    if (ret >= 0) {
+        if (in->common.stream_status > STATUS_READY)
+            goto not_acceptable;
+        else {
+            audio_channel_mask_t new_chmask = (audio_channel_mask_t)atoi(value);
+            if ((new_chmask != in->common.requested_channel_mask) && (new_chmask != AUDIO_CHANNEL_NONE)) {
+                struct audio_config new_config;
+
+                in->common.requested_channel_mask = new_chmask;
+
+                new_config.sample_rate = in->common.requested_sample_rate;
+                new_config.channel_mask = new_chmask;
+                new_config.format = in->common.requested_format;
+                proxy_reconfig_capture_stream(in->common.proxy_stream, in->common.stream_type,
+                                              &new_config);
+                ALOGD("%s-%s: changed channel mask to %#x from %#x",
+                                      stream_table[in->common.stream_type], __func__,
+                                      new_chmask, in->common.requested_channel_mask);
+            } else
+                ALOGD("%s-%s: requested to change same channel mask to %#x",
+                                      stream_table[in->common.stream_type], __func__, new_chmask);
+        }
+    }
+
+    // Change Audio Sampling Rate
+    ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_SAMPLING_RATE, value, sizeof(value));
+    if (ret >= 0) {
+        if (in->common.stream_status > STATUS_READY)
+            goto not_acceptable;
+        else {
+            uint32_t new_rate = (uint32_t)atoi(value);
+            if ((new_rate != in->common.requested_sample_rate) && (new_rate != 0)) {
+                struct audio_config new_config;
+
+                in->common.requested_sample_rate = new_rate;
+
+                new_config.sample_rate = new_rate;
+                new_config.channel_mask = in->common.requested_channel_mask;
+                new_config.format = in->common.requested_format;
+                proxy_reconfig_capture_stream(in->common.proxy_stream, in->common.stream_type,
+                                              &new_config);
+                ALOGD("%s-%s: changed sampling rate to %dHz from %dHz",
+                                      stream_table[in->common.stream_type], __func__,
+                                      new_rate, in->common.requested_sample_rate);
+            } else
+                ALOGD("%s-%s: requested to change same sampling rate to %dHz",
+                                      stream_table[in->common.stream_type], __func__, new_rate);
+        }
+    }
+
+    // Change Audio Input Source
+    ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_INPUT_SOURCE, value, sizeof(value));
+    if (ret >= 0) {
+        if (in->common.stream_status > STATUS_READY)
+            goto not_acceptable;
+        else {
+            unsigned int new_source = (unsigned int)atoi(value);
+            if ((new_source != in->requested_source) && (new_source != AUDIO_SOURCE_DEFAULT)) {
+                in->requested_source = new_source;
+
+                if (in->requested_source == AUDIO_SOURCE_VOICE_CALL) {
+                    in->common.stream_usage = adev_get_capture_ausage(adev, in);
+                    proxy_update_capture_usage((void *)(in->common.proxy_stream),(int)in->common.stream_usage);
+                }
+                ALOGD("%s-%s: changed source to %d from %d ", stream_table[in->common.stream_type],
+                                                       __func__, new_source, in->requested_source);
+            } else
+                ALOGD("%s-%s: requested to change same source to %d",
+                                      stream_table[in->common.stream_type], __func__, new_source);
+        }
+    }
+    pthread_mutex_unlock(&in->common.lock);
+
+    str_parms_destroy(parms);
+    ALOGVV("%s-%s: exit", stream_table[in->common.stream_type], __func__);
+    return 0;
+
+not_acceptable:
+    pthread_mutex_unlock(&in->common.lock);
+    str_parms_destroy(parms);
+    ALOGE("%s-%s: This parameter cannot accept as Stream is working",
+                                                  stream_table[in->common.stream_type], __func__);
+    return -ENOSYS;
+}
+
+static char * in_get_parameters(const struct audio_stream *stream, const char *keys)
+{
+    struct stream_in *in = (struct stream_in *)stream;
+    struct str_parms *query = str_parms_create_str(keys);
+    struct str_parms *reply = str_parms_create();
+    char * result_str;
+
+    ALOGD("%s-%s: enter with param = %s", stream_table[in->common.stream_type], __func__, keys);
+
+    pthread_mutex_lock(&in->common.lock);
+
+    // Get Current Devices
+    if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_ROUTING)) {
+        str_parms_add_int(reply, AUDIO_PARAMETER_STREAM_ROUTING, (int)in->common.requested_devices);
+    }
+
+    // Get Current Audio Format
+    if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_FORMAT)) {
+        str_parms_add_int(reply, AUDIO_PARAMETER_STREAM_FORMAT, (int)in->common.requested_format);
+    }
+
+    // Get Current Audio Frame Count
+    if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_FRAME_COUNT)) {
+        str_parms_add_int(reply, AUDIO_PARAMETER_STREAM_FRAME_COUNT,
+                                      (int)proxy_get_actual_period_size(in->common.proxy_stream));
+    }
+
+    // Get Current Audio Input Source
+    if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_INPUT_SOURCE)) {
+        str_parms_add_int(reply, AUDIO_PARAMETER_STREAM_INPUT_SOURCE, (int)in->requested_source);
+    }
+
+    // Some parameters can be gotten from Audio Stream Proxy
+    proxy_getparam_capture_stream(in->common.proxy_stream, query, reply);
+
+    result_str = str_parms_to_str(reply);
+    str_parms_destroy(query);
+    str_parms_destroy(reply);
+    pthread_mutex_unlock(&in->common.lock);
+
+    ALOGD("%s-%s: exit with %s", stream_table[in->common.stream_type], __func__, result_str);
+    return result_str;
+}
+
+static int in_add_audio_effect(const struct audio_stream *stream __unused, effect_handle_t effect __unused)
+{
+    return 0;
+}
+
+static int in_remove_audio_effect(const struct audio_stream *stream __unused, effect_handle_t effect __unused)
+{
+    return 0;
+}
+
+static int in_set_gain(struct audio_stream_in *stream __unused, float gain __unused)
+{
+    return 0;
+}
+
+static ssize_t in_read(struct audio_stream_in *stream, void* buffer, size_t bytes)
+{
+    struct stream_in *in = (struct stream_in *)stream;
+    struct audio_device *adev = in->adev;
+    int ret = 0;
+    bool need_reconfig = false;
+
+    //ALOGVV("%s-%s: enter", stream_table[in->common.stream_type], __func__);
+
+    pthread_mutex_lock(&in->common.lock);
+
+    if (in->pcm_reconfig) {
+        ALOGD(" %s: pcm reconfig", __func__);
+        stop_active_input(in);
+        in->pcm_reconfig = false;
+        need_reconfig = true;
+    }
+
+    if (in->common.stream_status == STATUS_STANDBY) {
+        in->common.stream_status = STATUS_READY;
+        ALOGI("%s-%s: transited to Ready", stream_table[in->common.stream_type], __func__);
+
+        if ((isCPCallMode(adev) && is_active_usage_CPCall(adev->proxy) && (in->common.stream_type != ASTREAM_CAPTURE_CALL))
+            || (!isCPCallMode(adev) && !is_active_usage_CPCall(adev->proxy) && (in->common.stream_type == ASTREAM_CAPTURE_CALL || (need_reconfig && in->common.stream_type == ASTREAM_CAPTURE_PRIMARY)))) {
+            audio_stream_type new_stream_type = in->common.stream_type;
+            if (isCPCallMode(adev) && isCallRecording(in->requested_source)) {
+                new_stream_type = ASTREAM_CAPTURE_CALL;
+                ALOGD(" %s: pcm reconfig as ASTREAM_CAPTURE_CALL", __func__);
+            } else {
+                new_stream_type = ASTREAM_CAPTURE_PRIMARY;
+                ALOGD(" %s: pcm reconfig as ASTREAM_CAPTURE_PRIMARY", __func__);
+            }
+            in->common.stream_usage = adev_get_capture_ausage(adev, in);
+            ALOGI("%s-%s: updated capture usage(%s)", stream_table[in->common.stream_type], __func__, usage_table[in->common.stream_usage]);
+
+            in->common.stream_type = new_stream_type;
+            in->common.stream_usage = adev_get_capture_ausage(adev, in);
+            ALOGI("%s-%s: updated capture usage(%s)", stream_table[in->common.stream_type], __func__, usage_table[in->common.stream_usage]);
+
+            proxy_reconfig_capture_usage((void *)(in->common.proxy_stream),
+                                          (int)in->common.stream_type,
+                                          (int)in->common.stream_usage);
+
+        }
+
+        // Have to route Audio Path before open PCM Device
+        pthread_mutex_lock(&adev->lock);
+        adev->active_input = in;
+
+#ifdef SUPPORT_STHAL_INTERFACE
+        if (in->common.stream_type != ASTREAM_CAPTURE_HOTWORD &&
+            !adev->is_capture_path_routed)
+#else
+        if (!adev->is_capture_path_routed)
+#endif
+        {
+            if (is_factory_bt_realtime_loopback_mode(adev->factory)) {
+                ALOGI("%s skip routing for BT realtime loopback", __func__);
+            } else if (in->common.stream_type == ASTREAM_CAPTURE_CALL) {
+                ALOGI("%s skip routing for call recording", __func__);
+            } else {
+                ALOGI("%s-%s: try to route for capture", stream_table[in->common.stream_type], __func__);
+                adev_set_route((void *)in, AUSAGE_CAPTURE, ROUTE, NON_FORCE_ROUTE);
+            }
+        }
+        pthread_mutex_unlock(&adev->lock);
+
+        ret = proxy_open_capture_stream((void *)(in->common.proxy_stream), 0, NULL);
+        if (ret != 0) {
+            ALOGE("%s-%s: failed to open Proxy Capture Stream!",
+                  stream_table[in->common.stream_type], __func__);
+            pthread_mutex_unlock(&in->common.lock);
+            return (ssize_t)ret;
+        } else {
+            in->common.stream_status = STATUS_IDLE;
+            ALOGI("%s-%s: transited to Idle", stream_table[in->common.stream_type], __func__);
+        }
+    }
+
+    if (in->common.stream_status == STATUS_IDLE) {
+        ret = proxy_start_capture_stream((void *)(in->common.proxy_stream));
+        if (ret != 0) {
+            ALOGE("%s-%s: failed to start Proxy Capture Stream!",
+                  stream_table[in->common.stream_type], __func__);
+            pthread_mutex_unlock(&in->common.lock);
+            return (ssize_t)ret;
+        } else {
+            in->common.stream_status = STATUS_PLAYING;
+            ALOGI("%s-%s: transited to Capturing",
+                  stream_table[in->common.stream_type], __func__);
+        }
+    }
+
+    if ((in->common.stream_status == STATUS_PLAYING) && (buffer && bytes > 0)) {
+        ret = proxy_read_capture_buffer((void *)(in->common.proxy_stream),
+                                        (void *)buffer, (int)bytes);
+
+        /* Post-Processing */
+        // Instead of writing zeroes here, we could trust the hardware to always provide zeroes when muted.
+        if(adev->mic_mute && (isAPCallMode(adev)||!isCallRecording(in->requested_source))) {
+           if (ret >= 0)
+                memset(buffer, 0, bytes);
+        }
+    }
+    pthread_mutex_unlock(&in->common.lock);
+
+    //ALOGVV("%s-%s: exit", stream_table[in->common.stream_type], __func__);
+    return (ssize_t)ret;
+}
+
+static uint32_t in_get_input_frames_lost(struct audio_stream_in *stream __unused)
+{
+    return 0;
+}
+
+static int in_get_capture_position(const struct audio_stream_in *stream,
+                                     int64_t *frames, int64_t *time)
+{
+    struct stream_in *in = (struct stream_in *)stream;
+
+    pthread_mutex_lock(&in->common.lock);
+    int ret = proxy_get_capture_pos(in->common.proxy_stream, frames, time);
+    pthread_mutex_unlock(&in->common.lock);
+
+    return ret;
+}
+
+// For MMAP NOIRQ Stream
+static int in_stop(const struct audio_stream_in* stream)
+{
+    struct stream_in *in = (struct stream_in *)stream;
+    int ret = -ENOSYS;
+
+    ALOGV("%s-%s: entered", stream_table[in->common.stream_type], __func__);
+
+    pthread_mutex_lock(&in->common.lock);
+    if (in->common.stream_type == ASTREAM_CAPTURE_MMAP) {
+        if (in->common.stream_status == STATUS_PLAYING) {
+            /* Stops stream & transit to Idle. */
+            proxy_stop_capture_stream((void *)(in->common.proxy_stream));
+            in->common.stream_status = STATUS_IDLE;
+            ALOGI("%s-%s: transited to Idle", stream_table[in->common.stream_type], __func__);
+
+        } else
+            ALOGV("%s-%s: invalid operation - stream status (%d)",
+                  stream_table[in->common.stream_type], __func__, in->common.stream_status);
+    }
+    pthread_mutex_unlock(&in->common.lock);
+
+    ALOGV("%s-%s: exit", stream_table[in->common.stream_type], __func__);
+    return ret;
+}
+
+static int in_start(const struct audio_stream_in* stream)
+{
+    struct stream_in *in = (struct stream_in *)stream;
+    int ret = -ENOSYS;
+
+    ALOGV("%s-%s: entered", stream_table[in->common.stream_type], __func__);
+
+    pthread_mutex_lock(&in->common.lock);
+    if (in->common.stream_type == ASTREAM_CAPTURE_MMAP) {
+        if (in->common.stream_status == STATUS_IDLE) {
+            /* Starts stream & transit to Playing. */
+            ret = proxy_start_capture_stream((void *)(in->common.proxy_stream));
+            if (ret != 0) {
+                ALOGE("%s-%s: failed to start Proxy Capture Stream!",
+                      stream_table[in->common.stream_type], __func__);
+            } else {
+                in->common.stream_status = STATUS_PLAYING;
+                ALOGI("%s-%s: transited to Playing",
+                      stream_table[in->common.stream_type], __func__);
+            }
+        } else
+            ALOGV("%s-%s: invalid operation - stream status (%d)",
+                  stream_table[in->common.stream_type], __func__, in->common.stream_status);
+    }
+    pthread_mutex_unlock(&in->common.lock);
+
+    ALOGV("%s-%s: exit", stream_table[in->common.stream_type], __func__);
+    return ret;
+}
+
+static int in_create_mmap_buffer(const struct audio_stream_in *stream,
+                                  int32_t min_size_frames,
+                                  struct audio_mmap_buffer_info *info)
+{
+    struct stream_in *in = (struct stream_in *)stream;
+    struct audio_device *adev = in->adev;
+    int ret = 0;
+
+    ALOGD("%s-%s: entered", stream_table[in->common.stream_type], __func__);
+
+    pthread_mutex_lock(&in->common.lock);
+
+    if (info == NULL || min_size_frames == 0) {
+        ALOGE("%s-%s: info = %p, min_size_frames = %d", stream_table[in->common.stream_type],
+                                                        __func__, info, min_size_frames);
+        ret = -EINVAL;
+        goto exit;
+    }
+
+    if (in->common.stream_type != ASTREAM_CAPTURE_MMAP || in->common.stream_status != STATUS_STANDBY) {
+        ALOGE("%s-%s: invalid operation - stream status (%d)", stream_table[in->common.stream_type],
+                                                               __func__, in->common.stream_status);
+        ret = -ENOSYS;
+        goto exit;
+    } else {
+        in->common.stream_status = STATUS_READY;
+        ALOGI("%s-%s: transited to Ready", stream_table[in->common.stream_type], __func__);
+
+        // Have to route Audio Path before open PCM Device
+        pthread_mutex_lock(&adev->lock);
+        if (!adev->is_capture_path_routed) {
+            ALOGI("%s-%s: try to route for capture", stream_table[in->common.stream_type], __func__);
+            adev_set_route((void *)in, AUSAGE_CAPTURE, ROUTE, NON_FORCE_ROUTE);
+        }
+        pthread_mutex_unlock(&adev->lock);
+
+        /* Opens stream & transit to Idle. */
+        ret = proxy_open_capture_stream((void *)(in->common.proxy_stream), min_size_frames, (void *)info);
+        if (ret != 0) {
+            ALOGE("%s-%s: failed to open Proxy Capture Stream!",
+                  stream_table[in->common.stream_type], __func__);
+
+            in->common.stream_status = STATUS_STANDBY;
+            ALOGI("%s-%s: transited to StandBy", stream_table[in->common.stream_type], __func__);
+        } else {
+            in->common.stream_status = STATUS_IDLE;
+            ALOGI("%s-%s: transited to Idle", stream_table[in->common.stream_type], __func__);
+        }
+    }
+
+exit:
+    pthread_mutex_unlock(&in->common.lock);
+    ALOGD("%s-%s: exited", stream_table[in->common.stream_type], __func__);
+    return ret;
+}
+
+static int in_get_mmap_position(const struct audio_stream_in *stream,
+                                  struct audio_mmap_position *position)
+{
+    struct stream_in *in = (struct stream_in *)stream;
+    int ret = 0;
+
+    ALOGV("%s-%s: entered", stream_table[in->common.stream_type], __func__);
+
+    if (position == NULL) return -EINVAL;
+    if (in->common.stream_type != ASTREAM_CAPTURE_MMAP) return -ENOSYS;
+
+    ret = proxy_get_mmap_position((void *)(in->common.proxy_stream), (void *)position);
+
+    ALOGV("%s-%s: exited", stream_table[in->common.stream_type], __func__);
+
+    return 0;
+}
+
+static int in_get_active_microphones(const struct audio_stream_in *stream,
+                                     struct audio_microphone_characteristic_t *mic_array,
+                                     size_t *mic_count)
+{
+    struct stream_in *in = (struct stream_in *)stream;
+    int ret = 0;
+
+    ALOGVV("%s-%s: entered", stream_table[in->common.stream_type], __func__);
+
+    if (mic_array == NULL || mic_count == NULL) return -EINVAL;
+
+    ret = proxy_get_active_microphones(in->common.proxy_stream, (void *)mic_array, (int *)mic_count);
+
+    ALOGVV("%s-%s: exited", stream_table[in->common.stream_type], __func__);
+    return ret;
+}
+
+static void in_update_sink_metadata(struct audio_stream_in *stream,
+                                    const struct sink_metadata* sink_metadata)
+{
+    struct stream_in *in = (struct stream_in *)stream;
+
+    ALOGD("%s-%s: called, but not implemented yet", stream_table[in->common.stream_type], __func__);
+    if (sink_metadata->track_count > 0) {
+        ALOGD("%s-%s: This stream has %zu tracks", stream_table[in->common.stream_type], __func__,
+                                                   sink_metadata->track_count);
+
+        for (int i = 0; i < (int)sink_metadata->track_count; i++) {
+            ALOGD("%d Track has Source(%d), Gain(%f)", i+1, (int)sink_metadata->tracks[i].source,
+                                                                 sink_metadata->tracks[i].gain);
+        }
+    }
+
+    return ;
+
+}
+
+/*****************************************************************************/
+/**                                                                       **/
+/** The Audio Device Function Implementation                              **/
+/**                                                                       **/
+/*****************************************************************************/
+static uint32_t adev_get_supported_devices(const struct audio_hw_device *dev __unused)
+{
+    ALOGVV("device-%s: enter", __func__);
+
+    ALOGVV("device-%s: exit", __func__);
+    return 0;
+}
+
+static int adev_init_check(const struct audio_hw_device *dev)
+{
+    struct audio_device *adev = (struct audio_device *)dev;
+    int ret = -ENODEV;
+
+    ALOGVV("device-%s: enter", __func__);
+
+    if (adev) {
+        if (adev->proxy) {
+            if (adev->is_route_created)
+                ret = 0;
+            else
+                ALOGE("device-%s: Audio Route is not created yet", __func__);
+        } else
+            ALOGE("device-%s: Audio Proxy is not created yet", __func__);
+    } else
+        ALOGE("device-%s: Primary Audio HW Device is not created yet", __func__);
+
+    ALOGVV("device-%s: exit", __func__);
+    return ret;
+}
+
+static int adev_set_voice_volume(struct audio_hw_device *dev, float volume)
+{
+    struct audio_device *adev = (struct audio_device *)dev;
+    struct stream_out *primary_output = adev->primary_output;
+
+    if(volume < 0.0f || volume > 1.0f) {
+        ALOGD("device-%s: invalid volume (%f)", __func__, volume);
+        return -EINVAL;
+    }
+
+    pthread_mutex_lock(&adev->lock);
+    if (adev->voice && voice_is_call_mode(adev->voice))
+        voice_set_volume(adev->voice, volume);
+    else if (adev->voice_volume == 0.0 &&
+            (get_active_playback_count(adev, primary_output) > 0) &&
+            (primary_output->force == FORCE_ROUTE && primary_output->rollback_devices != AUDIO_DEVICE_NONE)) {
+        /*
+         * When Force-Route stream such as Alarm sound/Shutter tone starts, voice_volume sets 0.
+         * And when this stream stopped, voice_volume is also rolled back.
+         * This is right route rollback time without abnormal routing during 3 seconds standby.
+         */
+        ALOGI("device-%s: try to roll back", __func__);
+        primary_output->common.requested_devices = primary_output->rollback_devices;
+        adev_set_route((void *)primary_output, AUSAGE_PLAYBACK, ROUTE, NON_FORCE_ROUTE);
+    }
+    else if(isAPCallMode(adev))
+    {
+        int apvolume = 0;
+        if(adev->voice)
+            apvolume = voice_get_volume_index(adev->voice,volume);
+        ALOGI("device-%s: AP Call set volume to (%d)", __func__,apvolume);
+        if (adev->proxy)
+            proxy_set_communication_volume(adev->proxy,apvolume);
+    }
+    adev->voice_volume = volume;
+    ALOGD("device-%s: set volume to (%f)", __func__, volume);
+    pthread_mutex_unlock(&adev->lock);
+
+    return 0;
+}
+
+static int adev_set_mode(struct audio_hw_device *dev, audio_mode_t mode)
+{
+    struct audio_device *adev = (struct audio_device *)dev;
+
+    ALOGD("device-%s: enter", __func__);
+
+    pthread_mutex_lock(&adev->lock);
+
+    /* Add code to keep mode 2 during realcall state, prevent call mute issue */
+    if (adev->voice) {
+        if ((mode == AUDIO_MODE_IN_COMMUNICATION) && isCPCallMode(adev) && adev->voice->realcall) {
+            mode = adev->amode; // AUDIO_MODE_IN_CALL
+            adev->voice->keep_call_mode = true;
+            ALOGI("%s: Keep the mode %d while CP Voice call is active", __func__, mode);
+        } else if ((mode == AUDIO_MODE_IN_CALL) && adev->voice->keep_call_mode) {
+            /* Reset pre mode, don't need to backup voip mode after call end (2->3->2)*/
+            adev->voice->keep_call_mode = false;
+        }
+    }
+
+    if (adev->amode != mode) {
+        /* Changing Android Audio Mode */
+        adev->previous_amode = adev->amode;;
+        adev->amode = mode;
+        ALOGD("device-%s: changed audio mode from (%s) to (%s)", __func__,
+              audiomode_table[(int)adev->previous_amode], audiomode_table[(int)adev->amode]);
+
+        proxy_set_audiomode(adev->proxy, (int)mode);
+
+        if (adev->voice) {
+            if ((mode == AUDIO_MODE_NORMAL || mode == AUDIO_MODE_IN_COMMUNICATION) &&
+                 voice_is_call_active(adev->voice)) {
+                /* Change from Voice Call Mode to Normal Mode */
+                /* Reset keep mode state, don't need to backup voip mode after call end */
+                adev->voice->keep_call_mode = false;
+
+                /* Stop Voice Call */
+                voice_set_call_active(adev->voice, false);
+                proxy_stop_voice_call(adev->proxy);
+                ALOGD("device-%s: *** Stopped CP Voice Call ***", __func__);
+
+                pthread_mutex_unlock(&adev->lock);
+                update_call_stream(adev->primary_output, adev->primary_output->common.requested_devices, adev->primary_output->common.requested_devices);
+                pthread_mutex_lock(&adev->lock);
+
+                /* Changing Call Status */
+                voice_set_call_mode(adev->voice, false);
+
+                proxy_call_status(adev->proxy, false);
+            } else if (mode == AUDIO_MODE_IN_CALL) {
+                /* Change from Normal/Ringtone Mode to Voice Call Mode */
+                /* We cannot start Voice Call right now because we don't know which device will be used.
+                   So, we need to delay Voice Call start when get the routing information for Voice Call */
+                if(adev->previous_amode == AUDIO_MODE_RINGTONE && get_device_id(adev, adev->primary_output->common.requested_devices) == DEVICE_BT_HEADSET) {
+                    proxy_set_mixer_value_int(adev->proxy, ABOX_APCALL_MUTE_CONTROL_NAME, ABOX_BT_MUTE_COUNT);
+                }
+
+                /* Changing Call Status */
+                voice_set_call_mode(adev->voice, true);
+
+                proxy_call_status(adev->proxy, true);
+            }
+        } else
+            ALOGE("device-%s: There is no Voice manager", __func__);
+    }
+    pthread_mutex_unlock(&adev->lock);
+
+    ALOGD("device-%s: exit", __func__);
+    return 0;
+}
+
+static int adev_set_mic_mute(struct audio_hw_device *dev, bool state)
+{
+    struct audio_device *adev = (struct audio_device *)dev;
+
+    pthread_mutex_lock(&adev->lock);
+    if (adev->voice && (adev->mic_mute != state))
+        voice_set_mic_mute(adev->voice, state);
+    adev->mic_mute = state;
+    ALOGD("device-%s: set MIC Mute to (%d)", __func__, (int)state);
+    pthread_mutex_unlock(&adev->lock);
+
+    return 0;
+}
+
+static int adev_get_mic_mute(const struct audio_hw_device *dev, bool *state)
+{
+    struct audio_device *adev = (struct audio_device *)dev;
+
+    pthread_mutex_lock(&adev->lock);
+    *state = adev->mic_mute;
+    pthread_mutex_unlock(&adev->lock);
+
+    return 0;
+}
+
+static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs)
+{
+    struct audio_device *adev = (struct audio_device *)dev;
+    struct stream_out *primary_out = adev->primary_output;
+
+    struct str_parms *parms;
+    char value[256];
+    int val;
+    int ret = 0;     // for parameter handling
+    int status = 0;  // for return value
+
+    ALOGD("device-%s: enter with key(%s)", __func__, kvpairs);
+
+    pthread_mutex_lock(&adev->lock);
+
+    parms = str_parms_create_str(kvpairs);
+
+    status = proxy_set_parameters(adev->proxy, parms);
+    if (status != 0) goto done;
+
+    ret = str_parms_get_int(parms, AUDIO_PARAMETER_DEVICE_CONNECT, &val);
+    if (ret >= 0) {
+        audio_devices_t device = (audio_devices_t)val;
+
+        if (device > AUDIO_DEVICE_BIT_IN) {
+            adev->previous_capture_device = adev->actual_capture_device;
+            adev->actual_capture_device = device;
+
+            if (device & AUDIO_DEVICE_IN_USB_DEVICE) {
+                voice_set_usb_mic(adev->voice, true);
+            }
+        } else {
+            adev->previous_playback_device = adev->actual_playback_device;
+            adev->actual_playback_device = device;
+        }
+
+        ALOGI("device-%s: connected device(%s)", __func__, device_table[get_device_id(adev, device)]);
+        str_parms_del(parms, AUDIO_PARAMETER_DEVICE_CONNECT);
+    }
+
+    ret = str_parms_get_int(parms, AUDIO_PARAMETER_DEVICE_DISCONNECT, &val);
+    if (ret >= 0) {
+        audio_devices_t device = (audio_devices_t)val;
+        ALOGI("device-%s: disconnected device(%s)", __func__, device_table[get_device_id(adev, device)]);
+
+        if (device > AUDIO_DEVICE_BIT_IN) {
+            adev->actual_capture_device = adev->previous_capture_device;
+            adev->previous_capture_device = device;
+
+            if (device & AUDIO_DEVICE_IN_USB_DEVICE) {
+                voice_set_usb_mic(adev->voice, false);
+            }
+        } else {
+            adev->actual_playback_device = adev->previous_playback_device;
+            adev->previous_playback_device = device;
+        }
+        str_parms_del(parms, AUDIO_PARAMETER_DEVICE_DISCONNECT);
+    }
+
+    ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_SCREEN_STATE, value, sizeof(value));
+    if (ret >= 0) {
+        ALOGI("device-%s: Screen State = %s)", __func__, value);
+        if (strcmp(value, AUDIO_PARAMETER_VALUE_ON) == 0)
+            adev->screen_on = true;
+        else
+            adev->screen_on = false;
+
+        str_parms_del(parms, AUDIO_PARAMETER_KEY_SCREEN_STATE);
+    }
+
+    ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_FMRADIO_MODE, value, sizeof(value));
+    if (ret >= 0) {
+        ALOGV("device-%s: FM_Mode = %s", __func__, value);
+        if(strncmp(value, "on", 2) == 0) {
+            ALOGI("device-%s: FM Radio Start", __func__);
+        } else {
+            if (adev->fm_state == FM_ON || adev->fm_state == FM_RECORDING) adev->fm_state = FM_OFF;
+        }
+        str_parms_del(parms, AUDIO_PARAMETER_KEY_FMRADIO_MODE);
+    }
+
+    ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_FMRADIO_VOLUME, value, sizeof(value));
+    if (ret >= 0) {
+        ALOGV("device-%s: FM_Radio_Volume = %s", __func__, value);
+        if(strncmp(value, "on", 2) == 0) {
+            adev_set_route((void *)primary_out, AUSAGE_PLAYBACK, ROUTE, NON_FORCE_ROUTE);
+            proxy_start_fm_radio(adev->proxy);
+        } else {
+            proxy_stop_fm_radio(adev->proxy);
+
+            if (is_active_usage_APCall(adev->proxy) || (adev->voice && voice_is_call_active(adev->voice)))
+                ALOGV("device-%s: FM_Radio_Volume = %s, skip unroute path during call", __func__, value);
+            else {
+                if(adev->primary_output->common.stream_status == STATUS_STANDBY)
+                    adev_set_route((void *)primary_out, AUSAGE_PLAYBACK, UNROUTE, NON_FORCE_ROUTE);
+            }
+        }
+        str_parms_del(parms, AUDIO_PARAMETER_KEY_FMRADIO_VOLUME);
+    }
+
+    ret = str_parms_get_str(parms, AUDIO_PARAMETER_SEAMLESS_VOICE, value, sizeof(value));
+    if (ret >= 0) {
+        bool seamless_mode = (strcmp(value, "on")) ? false : true;
+
+        if(seamless_mode && !adev->seamless_enabled) {
+            adev->seamless_enabled = true;
+        } else if(!seamless_mode && adev->seamless_enabled) {
+            adev->seamless_enabled = false;
+        }
+        ALOGV("seamless_enabled = %d", adev->seamless_enabled);
+        str_parms_del(parms, AUDIO_PARAMETER_SEAMLESS_VOICE);
+    }
+
+    // For Voice Manager
+    if (adev->voice)
+        voice_set_parameters(adev, parms);
+
+    // For Factory Manager
+    if (adev->factory && adev->voice)
+        factory_set_parameters(adev, parms);
+
+done:
+    str_parms_destroy(parms);
+    pthread_mutex_unlock(&adev->lock);
+
+    ALOGD("device-%s: exit", __func__);
+    return status;
+}
+
+static char * adev_get_parameters(const struct audio_hw_device *dev, const char *keys)
+{
+    struct audio_device *adev = (struct audio_device *)dev;
+    struct str_parms *reply = str_parms_create();
+    struct str_parms *query = str_parms_create_str(keys);
+    char *str;
+
+    ALOGVV("device-%s: enter with key(%s)", __func__, keys);
+
+    pthread_mutex_lock(&adev->lock);
+
+    int ret = 0;
+    char value[32];
+
+    //requested by phone app to check call_forwarding status.
+    ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_CALL_FORWARDING, value, sizeof(value));
+    if (ret >= 0) {
+        strlcpy(value, ((adev->voice && adev->voice->call_forwarding) ? "true" : "false"), sizeof(value));
+        ALOGI("device-%s: call_forwarding is %s", __func__, value);
+        str_parms_add_str(reply, AUDIO_PARAMETER_KEY_CALL_FORWARDING, value);
+    }
+
+    ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_EXTRA_VOLUME, value, sizeof(value));
+    if (ret >= 0) {
+        strlcpy(value, ((adev->voice && adev->voice->extra_volume) ? "true" : "false"), sizeof(value));
+        ALOGI("device-%s: extra_volume is %s", __func__, value);
+        str_parms_add_str(reply, AUDIO_PARAMETER_KEY_EXTRA_VOLUME, value);
+    }
+
+    str = str_parms_to_str(reply);
+    str_parms_destroy(query);
+    str_parms_destroy(reply);
+
+    pthread_mutex_unlock(&adev->lock);
+
+    ALOGVV("device-%s: exit with %s", __func__, str);
+    return str;
+}
+
+static size_t adev_get_input_buffer_size(
+            const struct audio_hw_device *dev __unused,
+            const struct audio_config *config)
+{
+    size_t size = 0;
+    unsigned int period_size = 0;
+
+    ALOGVV("device-%s: enter with SR(%d Hz), Channel(%d)", __func__,
+           config->sample_rate, audio_channel_count_from_in_mask(config->channel_mask));
+
+    /*
+     * To calcurate actual buffer size, it needs period size.
+     * However, it cannot fix period size at this time.
+     * So, pre-defined period size will be using.
+     */
+
+    // return buffer size based on requested PCM configuration
+    period_size = (config->sample_rate * PREDEFINED_CAPTURE_DURATION) / 1000;
+    size = period_size * audio_bytes_per_sample(config->format) *
+           audio_channel_count_from_in_mask(config->channel_mask);
+    ALOGVV("device-%s: exit with %d bytes for %d ms", __func__, (int)size, PREDEFINED_CAPTURE_DURATION);
+    return size;
+}
+
+static int adev_open_output_stream(
+        struct audio_hw_device *dev,
+        audio_io_handle_t handle,
+        audio_devices_t devices,
+        audio_output_flags_t flags,
+        struct audio_config *config,
+        struct audio_stream_out **stream_out,
+        const char *address)
+{
+    struct audio_device *adev = (struct audio_device *)dev;
+    struct stream_out *out = NULL;
+    int ret;
+
+    ALOGD("device-%s: enter: io_handle (%d), sample_rate(%u) channel_mask(%#x) format(%#x) framecount(%u) devices(%#x) flags(%#x)",
+          __func__, handle, config->sample_rate, config->channel_mask, config->format, config->frame_count, devices, flags);
+
+    *stream_out = NULL;
+
+    /* Allocates the memory for structure audio_stream_out. */
+    out = (struct stream_out *)calloc(1, sizeof(struct stream_out));
+    if (!out) {
+        ALOGE("device-%s: failed to allocate memory for stream_out", __func__);
+        return -ENOMEM;
+    }
+    out->adev = adev;
+
+    /* Saves the requested parameters from Android Platform. */
+    out->common.handle = handle;
+    out->common.requested_devices = devices;
+    out->common.requested_sample_rate = config->sample_rate;
+    out->common.requested_channel_mask = config->channel_mask;
+    out->common.requested_format = config->format;
+    out->common.requested_frame_count = config->frame_count;
+    out->requested_flags = flags;
+
+    /*
+     * Sets Stream Type & Audio Usage Type from Audio Flags and Devices.
+     * These information can be used to decide Mixer Path.
+     */
+    out->common.stream_type = ASTREAM_NONE;
+    out->common.stream_usage = AUSAGE_NONE;
+
+    if (flags == AUDIO_OUTPUT_FLAG_NONE) {
+        /* Case: No Attributes Playback Stream */
+        if (devices == AUDIO_DEVICE_OUT_AUX_DIGITAL) {
+            /* Sub-Case: Playback with Aux Digital */
+            ALOGI("device-%s: requested to open AUX-DIGITAL playback stream", __func__);
+            out->common.stream_type = ASTREAM_PLAYBACK_AUX_DIGITAL;
+            out->common.stream_usage = AUSAGE_MEDIA;
+        } else if ((devices == AUDIO_DEVICE_OUT_USB_ACCESSORY) || (devices == AUDIO_DEVICE_OUT_USB_DEVICE) ||
+                   (devices == AUDIO_DEVICE_OUT_USB_HEADSET)) {
+            ALOGI("device-%s: requested to open USB Device playback stream with address (%s)",
+                   __func__, address);
+            out->common.stream_type = ASTREAM_PLAYBACK_USB_DEVICE;
+            out->common.stream_usage = AUSAGE_MEDIA;
+        } else {
+            ALOGI("device-%s: requested to open No Attributes playback stream", __func__);
+            out->common.stream_type = ASTREAM_PLAYBACK_NO_ATTRIBUTE;
+            out->common.stream_usage = AUSAGE_MEDIA;
+        }
+    } else if ((flags & AUDIO_OUTPUT_FLAG_DIRECT) != 0) {
+        /* Case: Direct Playback Stream */
+        if (((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) &&
+            ((flags & AUDIO_OUTPUT_FLAG_NON_BLOCKING) != 0)) {
+            /* Sub-Case: Direct Playback Stream with Non-Blocking Compress Offload */
+            ALOGI("device-%s: requested to open Compress Offload playback stream", __func__);
+            out->common.stream_type = ASTREAM_PLAYBACK_COMPR_OFFLOAD;
+            out->common.stream_usage = AUSAGE_MEDIA;
+
+            /* Maps the function pointers in structure audio_stream_out as actual function. */
+            out->stream.set_callback = out_set_callback;
+            out->stream.pause = out_pause;
+            out->stream.resume = out_resume;
+            out->stream.drain = out_drain;
+            out->stream.flush = out_flush;
+
+            pthread_mutex_lock(&adev->lock);
+            if (adev->compress_output == NULL)
+                adev->compress_output = out;
+            pthread_mutex_unlock(&adev->lock);
+         } else if ((flags & AUDIO_OUTPUT_FLAG_MMAP_NOIRQ) != 0) {
+            /* Case: MMAP No IRQ Playback Stream */
+            ALOGI("device-%s: requested to open MMAP No IRQ playback stream", __func__);
+
+            out->common.stream_type = ASTREAM_PLAYBACK_MMAP;
+            out->common.stream_usage = AUSAGE_MEDIA;
+
+            /* Maps the function pointers in structure audio_stream_out as actual function. */
+            out->stream.start = out_start;
+            out->stream.stop = out_stop;
+            out->stream.create_mmap_buffer = out_create_mmap_buffer;
+            out->stream.get_mmap_position = out_get_mmap_position;
+         }
+    } else if ((flags & AUDIO_OUTPUT_FLAG_PRIMARY) != 0) {
+        /*
+        * Initializes Voice Manager.
+        * Voice Manager is handling Voice to support Call scenarios.
+        */
+        if (!adev->voice) {
+            adev->voice = voice_init();
+            if(!adev->voice)
+                ALOGE("device-%s: failed to init Voice Manager!", __func__);
+            else
+                ALOGD("device-%s: initialized Voice Manager!", __func__);
+        }
+
+        /* Case: Primary Playback Stream */
+        ALOGI("device-%s: requested to open Primary playback stream", __func__);
+
+        pthread_mutex_lock(&adev->lock);
+        if (adev->primary_output == NULL)
+            adev->primary_output = out;
+        else {
+            ALOGE("device-%s: Primary playback stream is already opened", __func__);
+            ret = -EEXIST;
+            pthread_mutex_unlock(&adev->lock);
+            goto err_open;
+        }
+        pthread_mutex_unlock(&adev->lock);
+
+        out->common.stream_type = ASTREAM_PLAYBACK_PRIMARY;
+        out->common.stream_usage = AUSAGE_MEDIA;
+    } else if ((flags & AUDIO_OUTPUT_FLAG_FAST) != 0) {
+        /* Case: Fast Playback Stream */
+        if ((flags & AUDIO_OUTPUT_FLAG_RAW) != 0) {
+            /* Sub-Case: Low Latency Playback Stream for ProAudio */
+            ALOGI("device-%s: requested to open Low Latency playback stream", __func__);
+
+            out->common.stream_type = ASTREAM_PLAYBACK_LOW_LATENCY;
+        } else {
+            /* Sub-Case: Normal Fast Playback Stream */
+            ALOGI("device-%s: requested to open Fast playback stream", __func__);
+
+            out->common.stream_type = ASTREAM_PLAYBACK_FAST;
+        }
+        out->common.stream_usage = AUSAGE_MEDIA;
+    } else if ((flags & AUDIO_OUTPUT_FLAG_DEEP_BUFFER) != 0) {
+        /* Case: Deep Buffer Playback Stream */
+        ALOGI("device-%s: requested to open Deep Buffer playback stream", __func__);
+
+        out->common.stream_type = ASTREAM_PLAYBACK_DEEP_BUFFER;
+        out->common.stream_usage = AUSAGE_MEDIA;
+    }  else if ((flags & AUDIO_OUTPUT_FLAG_INCALL_MUSIC) != 0) {
+        /* Case: Incall Music Playback Stream */
+        ALOGI("device-%s: requested to open Incall Music playback stream", __func__);
+
+        out->common.stream_type = ASTREAM_PLAYBACK_INCALL_MUSIC;
+        out->common.stream_usage = AUSAGE_INCALL_MUSIC;
+    } else {
+        /* Error Case: Not Supported usage */
+        ALOGI("device-%s: requested to open un-supported output", __func__);
+
+        ret = -EINVAL;
+        goto err_open;
+    }
+
+    /* Maps the function pointers in structure audio_stream_out as actual function. */
+    out->stream.common.get_sample_rate = out_get_sample_rate;
+    out->stream.common.set_sample_rate = out_set_sample_rate;
+    out->stream.common.get_buffer_size = out_get_buffer_size;
+    out->stream.common.get_channels = out_get_channels;
+    out->stream.common.get_format = out_get_format;
+    out->stream.common.set_format = out_set_format;
+    out->stream.common.standby = out_standby;
+    out->stream.common.dump = out_dump;
+    out->stream.common.get_device = out_get_device;
+    out->stream.common.set_device = out_set_device;
+    out->stream.common.set_parameters = out_set_parameters;
+    out->stream.common.get_parameters = out_get_parameters;
+    out->stream.common.add_audio_effect = out_add_audio_effect;
+    out->stream.common.remove_audio_effect = out_remove_audio_effect;
+
+    out->stream.get_latency = out_get_latency;
+    out->stream.set_volume = out_set_volume;
+    out->stream.write = out_write;
+    out->stream.get_render_position = out_get_render_position;
+    out->stream.get_next_write_timestamp = out_get_next_write_timestamp;
+    out->stream.get_presentation_position = out_get_presentation_position;
+
+    // For AudioHAL V4
+    out->stream.update_source_metadata = out_update_source_metadata;
+
+    /* Sets platform-specific information. */
+    pthread_mutex_init(&out->common.lock, (const pthread_mutexattr_t *) NULL);
+    pthread_mutex_lock(&out->common.lock);
+
+    // Creates Proxy Stream
+    out->common.proxy_stream = proxy_create_playback_stream(adev->proxy,
+                                                            (int)out->common.stream_type,
+                                                            (void *)config, (char *)address);
+    if (!out->common.proxy_stream) {
+        ALOGE("%s-%s: failed to create Audio Proxy Stream", stream_table[out->common.stream_type], __func__);
+
+        ret = -EINVAL;
+        pthread_mutex_unlock(&out->common.lock);
+        goto err_open;
+    }
+
+    // Special Process for Compress Offload
+    if (out->common.stream_type == ASTREAM_PLAYBACK_COMPR_OFFLOAD) {
+        /* Creates Callback Thread for supporting Non-Blocking Mode */
+        if (flags & AUDIO_OUTPUT_FLAG_NON_BLOCKING) {
+            ALOGV("%s-%s: Need to work as Nonblock Mode!", stream_table[out->common.stream_type], __func__);
+            proxy_offload_set_nonblock(out->common.proxy_stream);
+            out->offload.nonblock_flag = 1;
+
+            create_offload_callback_thread(out);
+            list_init(&out->offload.msg_list);
+        }
+
+        /* Connects Offload Effect Libraries */
+        out->common.offload_audio_format = AUDIO_FORMAT_PCM_16_BIT;
+    }
+
+    // Special Process for USB Device or DP Audio
+    // In general, this stream will be opened at Null Configuration.
+    // So it needs to update configuration as actual value
+    if (out->common.stream_type == ASTREAM_PLAYBACK_USB_DEVICE ||
+        out->common.stream_type == ASTREAM_PLAYBACK_AUX_DIGITAL) {
+        if ((config->sample_rate == 0) || (out->common.stream_type == ASTREAM_PLAYBACK_USB_DEVICE)) {
+            // In case of Sampling Rate for USB, it needs to update anytime
+            // because Sampling Rate can be changed by alsa_util library.
+            config->sample_rate = proxy_get_actual_sampling_rate(out->common.proxy_stream);
+            out->common.requested_sample_rate = config->sample_rate;
+        }
+
+        if (config->channel_mask == AUDIO_CHANNEL_NONE) {
+            config->channel_mask = audio_channel_out_mask_from_count(
+                                         proxy_get_actual_channel_count(out->common.proxy_stream));
+            out->common.requested_channel_mask = config->channel_mask;
+        }
+
+        if (config->format == AUDIO_FORMAT_DEFAULT) {
+            config->format = (audio_format_t)proxy_get_actual_format(out->common.proxy_stream);
+            out->common.requested_format = config->format;
+        }
+    }
+
+    out->common.stream_status = STATUS_STANDBY;   // Not open PCM Device, yet
+    ALOGI("%s-%s: transited to Standby", stream_table[out->common.stream_type], __func__);
+
+    // Adds this stream into playback list
+    pthread_mutex_lock(&adev->lock);
+    struct playback_stream *out_node = (struct playback_stream *)calloc(1, sizeof(struct playback_stream));
+    out_node->out = out;
+    list_add_tail(&adev->playback_list, &out_node->node);
+    pthread_mutex_unlock(&adev->lock);
+
+    out->force = NON_FORCE_ROUTE;
+    out->rollback_devices = AUDIO_DEVICE_NONE;
+    pthread_mutex_unlock(&out->common.lock);
+
+    /* Sets the structure audio_stream_out for return. */
+    *stream_out = &out->stream;
+
+    ALOGI("device-%s: opened %s stream", __func__, stream_table[out->common.stream_type]);
+    return 0;
+
+err_open:
+    if (out->common.proxy_stream) {
+        proxy_destroy_playback_stream(out->common.proxy_stream);
+        out->common.proxy_stream = NULL;
+    }
+
+    pthread_mutex_lock(&adev->lock);
+    if (out->common.stream_type == ASTREAM_PLAYBACK_PRIMARY)
+        adev->primary_output = NULL;
+    pthread_mutex_unlock(&adev->lock);
+
+    free(out);
+    *stream_out = NULL;
+
+    ALOGI("device-%s: failed to open this stream as error(%d)", __func__, ret);
+    return ret;
+}
+
+static void adev_close_output_stream(
+            struct audio_hw_device *dev,
+            struct audio_stream_out *stream)
+{
+    struct audio_device *adev = (struct audio_device *)dev;
+    struct stream_out *out = (struct stream_out *)stream;
+
+    struct listnode *node, *auxi;
+    struct playback_stream *out_node;
+
+    ALOGVV("device-%s: enter", __func__);
+
+    if (out) {
+        ALOGI("%s-%s: try to close plyback stream", stream_table[out->common.stream_type], __func__);
+        out_standby(&stream->common);
+
+        pthread_mutex_lock(&out->common.lock);
+        pthread_mutex_lock(&adev->lock);
+
+        // Removes this stream from playback list
+        list_for_each_safe(node, auxi, &adev->playback_list)
+        {
+            out_node = node_to_item(node, struct playback_stream, node);
+            if (out_node->out == out) {
+                list_remove(node);
+                free(out_node);
+            }
+        }
+
+        if (adev->primary_output == out) {
+            ALOGI("%s-%s: requested to close Primary playback stream",
+                                                   stream_table[out->common.stream_type], __func__);
+            adev->primary_output = NULL;
+        }
+
+        if (adev->compress_output == out) {
+            ALOGI("%s-%s: requested to close Compress Offload playback stream",
+                                                   stream_table[out->common.stream_type], __func__);
+            adev->compress_output = NULL;
+        }
+
+        pthread_mutex_unlock(&adev->lock);
+        pthread_mutex_unlock(&out->common.lock);
+
+        if (out->common.stream_type == ASTREAM_PLAYBACK_COMPR_OFFLOAD) {
+            if (out->offload.nonblock_flag)
+                destroy_offload_callback_thread(out);
+        }
+
+        if (out->common.stream_type == ASTREAM_PLAYBACK_INCALL_MUSIC) {
+            adev->incallmusic_on = false;
+        }
+
+        pthread_mutex_lock(&out->common.lock);
+        proxy_destroy_playback_stream(out->common.proxy_stream);
+        out->common.proxy_stream = NULL;
+        pthread_mutex_unlock(&out->common.lock);
+
+        pthread_mutex_destroy(&out->common.lock);
+
+        ALOGI("%s-%s: closed playback stream", stream_table[out->common.stream_type], __func__);
+        free(out);
+    }
+
+    ALOGVV("device-%s: exit", __func__);
+    return;
+}
+
+static int adev_open_input_stream(
+        struct audio_hw_device *dev,
+        audio_io_handle_t handle,
+        audio_devices_t devices,
+        struct audio_config *config,
+        struct audio_stream_in **stream_in,
+        audio_input_flags_t flags,
+        const char *address,
+        audio_source_t source)
+{
+    struct audio_device *adev = (struct audio_device *)dev;
+    struct stream_in *in = NULL;
+    int ret;
+
+    ALOGD("device-%s: enter: io_handle (%d), sample_rate(%d) channel_mask(%#x) format(%#x) framecount(%u) devices(%#x) flags(%#x) sources(%d)",
+          __func__, handle, config->sample_rate, config->channel_mask, config->format, config->frame_count, devices, flags, source);
+
+    *stream_in = NULL;
+
+    /* Allocates the memory for structure audio_stream_in. */
+    in = (struct stream_in *)calloc(1, sizeof(struct stream_in));
+    if (!in) {
+        ALOGE("device-%s: failed to allocate memory for stream_in", __func__);
+        return -ENOMEM;
+    }
+    in->adev = adev;
+
+    /* Saves the requested parameters from Android Platform. */
+    in->common.handle = handle;
+    in->common.requested_devices = devices;
+    in->common.requested_sample_rate = config->sample_rate;
+    in->common.requested_channel_mask = config->channel_mask;
+    in->common.requested_format = config->format;
+    in->common.requested_frame_count = config->frame_count;
+    in->requested_flags = flags;
+    in->requested_source = source;
+
+    /*
+     * Sets Stream Type & Audio Usage Type from Audio Flags, Sources and Devices.
+     * These information can be used to decide Mixer Path.
+     */
+    in->common.stream_type = ASTREAM_NONE;
+    in->common.stream_usage = AUSAGE_NONE;
+
+    if ((flags & AUDIO_INPUT_FLAG_FAST) != 0) {
+        if (isCallMode(adev) && config->sample_rate != LOW_LATENCY_CAPTURE_SAMPLE_RATE) {
+            flags &= ~AUDIO_INPUT_FLAG_FAST;
+            ALOGD("device-%s: Denied to open Low Latency input. flags changed(%#x)", __func__, flags);
+        }
+    }
+
+#ifdef SUPPORT_STHAL_INTERFACE
+    if (source == AUDIO_SOURCE_HOTWORD ||
+        (adev->seamless_enabled == true && source == AUDIO_SOURCE_VOICE_RECOGNITION) ||
+        (((flags & AUDIO_INPUT_FLAG_HW_HOTWORD) != 0) && source == AUDIO_SOURCE_VOICE_RECOGNITION)) {
+        /* Case: Use ST HAL interface for Capture */
+        in->common.stream_type = ASTREAM_CAPTURE_HOTWORD;
+        if (source == AUDIO_SOURCE_HOTWORD ||
+        (adev->seamless_enabled == true && source == AUDIO_SOURCE_VOICE_RECOGNITION)) {
+            in->common.stream_usage = AUSAGE_HOTWORD_SEAMLESS;
+            ALOGD("device-%s: Requested to open VTS Seamless input", __func__);
+        } else {
+            in->common.stream_usage = AUSAGE_HOTWORD_RECORD;
+            ALOGD("device-%s: Requested to open VTS Record input", __func__);
+        }
+    } else if (flags == AUDIO_INPUT_FLAG_NONE)
+#else
+    if (flags == AUDIO_INPUT_FLAG_NONE)
+#endif
+    {
+      if (isCPCallMode(adev) &&
+          is_usage_CPCall(adev->active_capture_ausage) &&
+          isCallRecording(in->requested_source)) {
+            /* Case: CP Voice Call Recording Stream */
+            ALOGI("device-%s: requested to open CP Voice Call Recording stream", __func__);
+            in->common.stream_type = ASTREAM_CAPTURE_CALL;
+
+            switch (source) {
+                case AUDIO_SOURCE_VOICE_UPLINK:
+                    ALOGI("device-%s: needs only uplink voice", __func__);
+                    in->common.stream_usage = AUSAGE_INCALL_UPLINK;
+                    break;
+
+                case AUDIO_SOURCE_VOICE_DOWNLINK:
+                    ALOGI("device-%s: needs only downlink voice", __func__);
+                    in->common.stream_usage = AUSAGE_INCALL_DOWNLINK;
+                    break;
+
+                case AUDIO_SOURCE_VOICE_CALL:
+                    ALOGI("device-%s: needs uplink/downlink voice both", __func__);
+                    in->common.stream_usage = AUSAGE_INCALL_UPLINK_DOWNLINK;
+                    break;
+
+                default:
+                    ALOGI("device-%s: needs only uplink voice from normal source", __func__);
+                    in->common.stream_usage = AUSAGE_INCALL_UPLINK;
+                    break;
+            }
+        }
+        else if ((source == AUDIO_SOURCE_FM_TUNER ) && (devices == AUDIO_DEVICE_IN_FM_TUNER)) {
+                ALOGI("device-%s: requested to open FM Radio Tuner stream", __func__);
+                adev->fm_state = FM_ON;
+                adev->fm_need_route = true;
+                in->common.stream_type  = ASTREAM_CAPTURE_FM_TUNER;
+                in->common.stream_usage = AUSAGE_FM_RADIO_TUNER;
+                // FM Tuner routing
+                adev_set_route((void *)in, AUSAGE_CAPTURE, ROUTE, NON_FORCE_ROUTE);
+                adev->fm_need_route = false;
+
+        } else {
+            /* Case: Normal Recording Stream */
+            if ((devices == AUDIO_DEVICE_IN_USB_ACCESSORY) || (devices == AUDIO_DEVICE_IN_USB_DEVICE) ||
+                (devices == AUDIO_DEVICE_IN_USB_HEADSET)) {
+                /* Case: USB Capture Stream */
+                ALOGI("device-%s: requested to open USB Device capture stream with address (%s)",
+                      __func__, address);
+                in->common.stream_type = ASTREAM_CAPTURE_USB_DEVICE;
+                in->common.stream_usage = AUSAGE_RECORDING;
+            } else if ((devices == AUDIO_DEVICE_IN_DEFAULT) && (source == AUDIO_SOURCE_DEFAULT)) {
+                /* Case: No Attributes Capture Stream */
+                ALOGI("device-%s: requested to open No Attribute capture stream", __func__);
+                in->common.stream_type = ASTREAM_CAPTURE_NO_ATTRIBUTE;
+                in->common.stream_usage = AUSAGE_RECORDING;
+            } else if(devices == AUDIO_DEVICE_IN_TELEPHONY_RX && isUSBHeadsetConnect(adev)) {
+                /* Error Case: Not Supported samspling rate */
+                ALOGI("device-%s: requested to open AUDIO_DEVICE_IN_TELEPHONY_RX", __func__);
+                ret = -EINVAL;
+                goto err_open;
+            } else {
+                /* Case: Primary Capture Stream */
+                ALOGI("device-%s: requested to open Primay capture stream", __func__);
+                in->common.stream_type = ASTREAM_CAPTURE_PRIMARY;
+
+                switch (source) {
+                    case AUDIO_SOURCE_MIC:
+                        in->common.stream_usage = AUSAGE_RECORDING;
+                        break;
+
+                    case AUDIO_SOURCE_CAMCORDER:
+                        in->common.stream_usage = AUSAGE_CAMCORDER;
+                        break;
+
+                    case AUDIO_SOURCE_VOICE_RECOGNITION:
+                        in->common.stream_usage = AUSAGE_RECOGNITION;
+                        break;
+
+                    case AUDIO_SOURCE_DEFAULT:
+                    default:
+                        in->common.stream_usage = AUSAGE_RECORDING;
+                        break;
+                }
+            }
+        }
+    } else if ((flags & AUDIO_INPUT_FLAG_FAST) != 0) {
+        /* Case: Low Latency Capture Stream */
+        ALOGI("device-%s: requested to open Low Latency capture stream", __func__);
+        in->common.stream_type = ASTREAM_CAPTURE_LOW_LATENCY;
+        in->common.stream_usage = AUSAGE_MEDIA;
+    } else if ((flags & AUDIO_INPUT_FLAG_MMAP_NOIRQ) != 0) {
+        if (config->sample_rate == LOW_LATENCY_CAPTURE_SAMPLE_RATE) {
+            /* Case: MMAP No IRQ Capture Stream */
+            ALOGI("device-%s: requested to open MMAP No IRQ capture stream", __func__);
+
+            in->common.stream_type = ASTREAM_CAPTURE_MMAP;
+            in->common.stream_usage = AUSAGE_MEDIA;
+
+            /* Maps the function pointers in structure audio_stream_in as actual function. */
+            in->stream.start = in_start;
+            in->stream.stop = in_stop;
+            in->stream.create_mmap_buffer = in_create_mmap_buffer;
+            in->stream.get_mmap_position = in_get_mmap_position;
+        } else {
+            /* Error Case: Not Supported samspling rate */
+            ALOGI("device-%s: requested to open MMAP input with abnormal sampling rate(%d)",
+                  __func__, config->sample_rate);
+
+            ret = -EINVAL;
+            goto err_open;
+        }
+    } else {
+        /* Error Case: Not Supported usage */
+        ALOGI("device-%s: requested to open un-supported output", __func__);
+
+        ret = -EINVAL;
+        goto err_open;
+    }
+
+
+    /* Maps the function pointers in structure audio_stream_in as actual function. */
+    in->stream.common.get_sample_rate = in_get_sample_rate;
+    in->stream.common.set_sample_rate = in_set_sample_rate;
+    in->stream.common.get_buffer_size = in_get_buffer_size;
+    in->stream.common.get_channels = in_get_channels;
+    in->stream.common.get_format = in_get_format;
+    in->stream.common.set_format = in_set_format;
+    in->stream.common.standby = in_standby;
+    in->stream.common.dump = in_dump;
+    in->stream.common.get_device = in_get_device;
+    in->stream.common.set_device = in_set_device;
+    in->stream.common.set_parameters = in_set_parameters;
+    in->stream.common.get_parameters = in_get_parameters;
+    in->stream.common.add_audio_effect = in_add_audio_effect;
+    in->stream.common.remove_audio_effect = in_remove_audio_effect;
+
+    in->stream.set_gain = in_set_gain;
+    in->stream.read = in_read;
+    in->stream.get_input_frames_lost = in_get_input_frames_lost;
+    in->stream.get_capture_position = in_get_capture_position;
+
+    // For AudioHAL V4
+    in->stream.get_active_microphones = in_get_active_microphones;
+    in->stream.update_sink_metadata = in_update_sink_metadata;
+
+    /* Sets Platform-specific information. */
+    pthread_mutex_init(&in->common.lock, (const pthread_mutexattr_t *) NULL);
+    pthread_mutex_lock(&in->common.lock);
+
+    // Creates Proxy Stream
+    in->common.proxy_stream = proxy_create_capture_stream(adev->proxy,
+                                                          (int)in->common.stream_type,
+                                                          (int)in->common.stream_usage,
+                                                          (void *)config, (char *)address);
+    if (!in->common.proxy_stream) {
+        ALOGE("%s-%s: failed to create Audio Proxy Stream", stream_table[in->common.stream_type], __func__);
+
+        ret = -EINVAL;
+        pthread_mutex_unlock(&in->common.lock);
+        goto err_open;
+    }
+
+    // Process for USB Device
+    if (in->common.stream_type == ASTREAM_CAPTURE_USB_DEVICE) {
+        if (config->sample_rate == 0) {
+            config->sample_rate = proxy_get_actual_sampling_rate(in->common.proxy_stream);
+            in->common.requested_sample_rate = config->sample_rate;
+        }
+
+        if (config->channel_mask == AUDIO_CHANNEL_NONE) {
+            config->channel_mask = audio_channel_in_mask_from_count(
+                                         proxy_get_actual_channel_count(in->common.proxy_stream));
+            in->common.requested_channel_mask = config->channel_mask;
+        }
+
+        if (config->format == AUDIO_FORMAT_DEFAULT) {
+            config->format = (audio_format_t)proxy_get_actual_format(in->common.proxy_stream);
+            in->common.requested_format = config->format;
+        }
+    }
+
+    in->common.stream_status = STATUS_STANDBY;   // Not open PCM Device, yet
+    ALOGI("%s-%s: transited to Standby", stream_table[in->common.stream_type], __func__);
+
+    // Adds this stream into capture list
+    pthread_mutex_lock(&adev->lock);
+    struct capture_stream *in_node = (struct capture_stream *)calloc(1, sizeof(struct capture_stream));
+    in_node->in = in;
+    list_add_tail(&adev->capture_list, &in_node->node);
+
+    // Customer Specific
+    adev->pcmread_latency = proxy_get_actual_period_size(in->common.proxy_stream) * 1000 /
+                            proxy_get_actual_sampling_rate(in->common.proxy_stream);
+    in->pcm_reconfig = false;
+
+    pthread_mutex_unlock(&adev->lock);
+
+    pthread_mutex_unlock(&in->common.lock);
+
+    /* Sets the structure audio_stream_in for return. */
+    *stream_in = &in->stream;
+
+    ALOGI("device-%s: opened %s stream", __func__, stream_table[in->common.stream_type]);
+    return 0;
+
+err_open:
+    if (in)
+        free(in);
+    *stream_in = NULL;
+
+    ALOGI("device-%s: failed to open this stream as error(%d)", __func__, ret);
+    return ret;
+}
+
+static void adev_close_input_stream(
+        struct audio_hw_device *dev,
+        struct audio_stream_in *stream)
+{
+    struct audio_device *adev = (struct audio_device *)dev;
+    struct stream_in *in = (struct stream_in *)stream;
+
+    struct listnode *node, *auxi;
+    struct capture_stream *in_node;
+
+    ALOGI("device-%s: enter", __func__);
+
+    if (in) {
+        ALOGI("%s-%s: try to close capture stream", stream_table[in->common.stream_type], __func__);
+        in_standby(&stream->common);
+
+        pthread_mutex_lock(&in->common.lock);
+        pthread_mutex_lock(&adev->lock);
+
+        // disable fm radio stream
+        if (in->common.stream_usage == AUSAGE_FM_RADIO_TUNER) {
+            adev->fm_state = FM_OFF;
+            adev_set_route((void *)in, AUSAGE_CAPTURE, UNROUTE, NON_FORCE_ROUTE);
+        }
+
+        if (in->common.stream_usage == AUSAGE_FM_RADIO_CAPTURE) {
+            adev->fm_state = FM_ON;
+            adev_set_route((void *)in, AUSAGE_CAPTURE, UNROUTE, NON_FORCE_ROUTE);
+        }
+
+        // Removes this stream from capture list
+        list_for_each_safe(node, auxi, &adev->capture_list)
+        {
+            in_node = node_to_item(node, struct capture_stream, node);
+            if (in_node->in == in) {
+                list_remove(node);
+                free(in_node);
+            }
+        }
+        pthread_mutex_unlock(&adev->lock);
+
+        proxy_destroy_capture_stream(in->common.proxy_stream);
+        in->common.proxy_stream = NULL;
+
+        pthread_mutex_unlock(&in->common.lock);
+        pthread_mutex_destroy(&in->common.lock);
+
+        ALOGI("%s-%s: closed capture stream", stream_table[in->common.stream_type], __func__);
+        free(in);
+    }
+
+    ALOGVV("device-%s: exit", __func__);
+    return;
+}
+
+
+static int adev_get_microphones(const audio_hw_device_t *device,
+                                struct audio_microphone_characteristic_t *mic_array,
+                                size_t *mic_count)
+{
+    struct audio_device *adev = (struct audio_device *)device;
+    int ret = 0;
+
+    ALOGVV("device-%s: entered", __func__);
+
+    if (mic_array == NULL || mic_count == NULL) return -EINVAL;
+
+    ret = proxy_get_microphones(adev->proxy, (void *)mic_array, (int *)mic_count);
+
+    ALOGVV("device-%s: exited", __func__);
+    return ret;
+}
+
+static int adev_dump(const audio_hw_device_t *device, int fd)
+{
+    struct audio_device *adev = (struct audio_device *)device;
+
+    ALOGV("device-%s: enter with file descriptor(%d)", __func__, fd);
+
+    const size_t len = 256;
+    char buffer[len];
+
+    snprintf(buffer, len, "\nAudioDevice HAL::dump\n");
+    write(fd,buffer,strlen(buffer));
+
+    bool justLocked = pthread_mutex_trylock(&adev->lock) == 0;
+    snprintf(buffer, len, "\tMutex: %s\n", justLocked ? "locked" : "unlocked");
+    write(fd,buffer,strlen(buffer));
+    if(justLocked)
+        pthread_mutex_unlock(&adev->lock);
+
+    snprintf(buffer, len, "1. Common part\n");
+    write(fd,buffer,strlen(buffer));
+    snprintf(buffer, len, "\tAudio Mode: %d\n",adev->amode);
+    write(fd,buffer,strlen(buffer));
+    snprintf(buffer, len, "\tAudio Previous Mode: %d\n",adev->previous_amode);
+    write(fd,buffer,strlen(buffer));
+
+    snprintf(buffer, len, "\n2. About Call part\n");
+    write(fd,buffer,strlen(buffer));
+    if(adev->voice) {
+        snprintf(buffer, len, "\tCall Active: %d\n", adev->voice->call_status);
+        write(fd,buffer,strlen(buffer));
+        snprintf(buffer, len, "\tRealCall: %s\n",bool_to_str(adev->voice->realcall));
+        write(fd,buffer,strlen(buffer));
+        snprintf(buffer, len, "\tVoLTE state: %s\n",bool_to_str(adev->voice->volte_status));
+        write(fd,buffer,strlen(buffer));
+        snprintf(buffer, len, "\tPrevious VoLTE state: %s\n",bool_to_str(adev->voice->previous_volte_status));
+        write(fd,buffer,strlen(buffer));
+        snprintf(buffer, len, "\tcurrent modem: %d\n",adev->voice->cur_modem);
+        write(fd,buffer,strlen(buffer));
+        snprintf(buffer, len, "\tVoice Volume: %f\n",adev->voice_volume);
+        write(fd,buffer,strlen(buffer));
+        snprintf(buffer, len, "\tVoice Volume Max Index: %d\n",adev->voice->volume_steps_max);
+        write(fd,buffer,strlen(buffer));
+        snprintf(buffer, len, "\tMute Voice: %s\n",bool_to_str(adev->voice->mute_voice));
+        write(fd,buffer,strlen(buffer));
+        snprintf(buffer, len, "\twb_amr: %d\n",adev->voice->voice_samplingrate);
+        write(fd,buffer,strlen(buffer));
+        snprintf(buffer, len, "\textra volume: %s\n",bool_to_str(adev->voice->extra_volume));
+        write(fd,buffer,strlen(buffer));
+        snprintf(buffer, len, "\tcall forwarding: %s\n",bool_to_str(adev->voice->call_forwarding)) ;
+        write(fd,buffer,strlen(buffer));
+        snprintf(buffer, len, "\tTTY mode: %d\n",adev->voice->tty_mode) ;
+        write(fd,buffer,strlen(buffer));
+    }
+    snprintf(buffer, len, "\tMic Mute: %s\n",bool_to_str(adev->mic_mute));
+    write(fd,buffer,strlen(buffer));
+    //snprintf(buffer, len, "\tspectro: %s\n",bool_to_str(adev->spectro)) ;
+    //write(fd,buffer,strlen(buffer));
+
+    snprintf(buffer, len, "\n3. About Communications part\n");
+    write(fd,buffer,strlen(buffer));
+    if(adev->voice) {
+        snprintf(buffer, len, "\tVoip wificalling: %s\n",bool_to_str(adev->voice->voip_wificalling));
+        write(fd,buffer,strlen(buffer));
+        snprintf(buffer, len, "\tCSVT Call: %s\n",bool_to_str(adev->voice->csvtcall));
+        write(fd,buffer,strlen(buffer));
+        snprintf(buffer, len, "\tVoIP RX active: %s\n",bool_to_str(adev->voice->voip_rx_active)) ;
+        write(fd,buffer,strlen(buffer));
+    }
+
+    snprintf(buffer, len, "\n4. About Connectivity part\n");
+    write(fd,buffer,strlen(buffer));
+    if(adev->voice) {
+        snprintf(buffer, len, "\tBluetooth_nrec: %d\n",adev->voice->bluetooth_nrec);
+        write(fd,buffer,strlen(buffer));
+        snprintf(buffer, len, "\tBluetooth samplerate: %u\n",adev->voice->bluetooth_samplerate);
+        write(fd,buffer,strlen(buffer));
+    }
+
+    snprintf(buffer, len, "\n5. About Device Routing part\n");
+    write(fd,buffer,strlen(buffer));
+    snprintf(buffer, len, "\tAudio Playback Usage Mode: %d\n",adev->active_playback_ausage);
+    write(fd,buffer,strlen(buffer));
+    snprintf(buffer, len, "\tAudio Capture Usage Mode: %d\n",adev->active_capture_ausage);
+    write(fd,buffer,strlen(buffer));
+    snprintf(buffer, len, "\tSupport rev: %s\n",bool_to_str(adev->support_reciever));
+    write(fd,buffer,strlen(buffer));
+    snprintf(buffer, len, "\tSupport backmic: %s\n",bool_to_str(adev->support_backmic));
+    write(fd,buffer,strlen(buffer));
+    snprintf(buffer, len, "\tSupport thirdmic: %s\n",bool_to_str(adev->support_thirdmic));
+    write(fd,buffer,strlen(buffer));
+
+    snprintf(buffer, len, "\n6. About Offload Playback part\n");
+    write(fd,buffer,strlen(buffer));
+
+    if(adev->factory) {
+        snprintf(buffer, len, "\n7. About Factory Test part\n");
+        write(fd,buffer,strlen(buffer));
+        snprintf(buffer, len, "\tLoopback Out Device: %x\n",adev->factory->out_device);
+        write(fd,buffer,strlen(buffer));
+        snprintf(buffer, len, "\tLoopback In Device: %x\n",adev->factory->in_device);
+        write(fd,buffer,strlen(buffer));
+        snprintf(buffer, len, "\tFactory mode: %s\n",bool_to_str(adev->factory->mode));
+        write(fd,buffer,strlen(buffer));
+        snprintf(buffer, len, "\tis RMS Enable: %s\n",bool_to_str(adev->factory->rms_test_enable));
+        write(fd,buffer,strlen(buffer));
+        snprintf(buffer, len, "\tfactory loopback mode: %d\n\n",adev->factory->loopback_mode);
+        write(fd,buffer,strlen(buffer));
+    }
+
+    snprintf(buffer, len, "\n9. FM Radio part\n");
+    write(fd,buffer,strlen(buffer));
+    snprintf(buffer, len, "\tFM Radio State: %s\n",adev->fm_state == FM_ON ? "FM_ON" : "FM_OFF");
+    write(fd,buffer,strlen(buffer));
+    snprintf(buffer, len, "\tFM Radio via BT: %s\n",bool_to_str(adev->fm_via_a2dp));
+    write(fd,buffer,strlen(buffer));
+    snprintf(buffer, len, "\tFM Radio Mute: %s\n",bool_to_str(adev->fm_radio_mute));
+    write(fd,buffer,strlen(buffer));
+
+    voice_ril_dump(fd);
+
+    if(adev->primary_output)
+        out_dump((struct audio_stream *)adev->primary_output,fd);
+    if(adev->active_input)
+        in_dump((struct audio_stream *)adev->active_input,fd);
+
+    proxy_fw_dump(fd);
+
+    ALOGV("device-%s: exit with file descriptor(%d)", __func__, fd);
+    return 0;
+}
+
+static int adev_close(hw_device_t *device)
+{
+    struct audio_device *adev = (struct audio_device *)device;
+
+    ALOGI("device-%s: enter", __func__);
+
+    if (adev) {
+        pthread_mutex_lock(&adev_init_lock);
+
+        if ((--adev_ref_count) == 0) {
+            /* Clean up Platform-specific information. */
+            pthread_mutex_lock(&adev->lock);
+
+            if (adev->voice) {
+                voice_deinit(adev->voice);
+                adev->voice = NULL;
+            }
+
+            adev_deinit_route(adev);
+
+            /* Clear external structures. */
+            if (adev->proxy) {
+                proxy_deinit(adev->proxy);
+                adev->proxy = NULL;
+            }
+
+            pthread_mutex_unlock(&adev->lock);
+            pthread_mutex_destroy(&adev->lock);
+
+            destroyAudioDeviceInstance();
+            ALOGI("device-%s: closed Primary Audio HW Device(ref = %d)", __func__, adev_ref_count);
+        } else
+            ALOGI("device-%s: closed existing Primary Audio HW Device(ref = %d)", __func__, adev_ref_count);
+
+        pthread_mutex_unlock(&adev_init_lock);
+    }
+
+    return 0;
+}
+
+static int adev_open(
+        const hw_module_t* module,
+        const char* name,
+        hw_device_t** device)
+{
+    struct audio_device *adev = NULL;
+
+    ALOGI("device-%s: enter", __func__);
+
+    /* Check Interface Name. It must be AUDIO_HARDWARE_INTERFACE. */
+    if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0) {
+        ALOGE("device-%s: invalid request: Interface Name = %s", __func__, name);
+        return -EINVAL;
+    }
+
+    pthread_mutex_lock(&adev_init_lock);
+    /* Create globally unique instance for Structure audio_device. */
+    adev = getAudioDeviceInstance();
+    if (!adev) {
+        ALOGE("device-%s: failed to allocate memory for audio_device", __func__);
+        pthread_mutex_unlock(&adev_init_lock);
+        return -ENOMEM;
+    }
+
+    if (adev_ref_count != 0) {
+        *device = &adev->hw_device.common;
+        adev_ref_count++;
+        ALOGI("device-%s: opened existing Primary Audio HW Device(ref = %d)", __func__, adev_ref_count);
+        pthread_mutex_unlock(&adev_init_lock);
+        return 0;
+    }
+
+    /* Initialize Audio Device Mutex Lock. */
+    pthread_mutex_init(&adev->lock, (const pthread_mutexattr_t *) NULL);
+
+    /*
+     * Map function pointers in Structure audio_hw_device as real function.
+     */
+    adev->hw_device.common.tag = HARDWARE_DEVICE_TAG;
+    adev->hw_device.common.version = AUDIO_DEVICE_API_VERSION_2_0;
+    adev->hw_device.common.module = (struct hw_module_t *) module;
+    adev->hw_device.common.close = adev_close;
+
+    /* Enumerates what devices are supported by audio_hw_device implementation. */
+    adev->hw_device.get_supported_devices = adev_get_supported_devices;
+    /* Checks to see if the audio hardware interface has been initialized. */
+    adev->hw_device.init_check = adev_init_check;
+    /* Sets the audio volume of a voice call. */
+    adev->hw_device.set_voice_volume = adev_set_voice_volume;
+    /* Sets/Gets the master volume value for the HAL. */
+    // Not Supported
+    adev->hw_device.set_master_volume = NULL;
+    adev->hw_device.get_master_volume = NULL;
+    /* Called when the audio mode changes. */
+    adev->hw_device.set_mode = adev_set_mode;
+    /* Treats mic mute. */
+    adev->hw_device.set_mic_mute = adev_set_mic_mute;
+    adev->hw_device.get_mic_mute = adev_get_mic_mute;
+    /* Sets/Gets global audio parameters. */
+    adev->hw_device.set_parameters = adev_set_parameters;
+    adev->hw_device.get_parameters = adev_get_parameters;
+    /* Returns audio input buffer size according to parameters passed. */
+    adev->hw_device.get_input_buffer_size = adev_get_input_buffer_size;
+    /* Creates ,opens, closes and destroys the audio hardware input/output stream. */
+    adev->hw_device.open_output_stream = adev_open_output_stream;
+    adev->hw_device.close_output_stream = adev_close_output_stream;
+    adev->hw_device.open_input_stream = adev_open_input_stream;
+    adev->hw_device.close_input_stream = adev_close_input_stream;
+    /* Read available microphones characteristics for AudioHAL V4. */
+    adev->hw_device.get_microphones = adev_get_microphones;
+    /* Dumps the status of the audio hardware. */
+    adev->hw_device.dump = adev_dump;
+    /* Set/Get the master mute status for the HAL. */
+    // Not Supported
+    adev->hw_device.set_master_mute = NULL;
+    adev->hw_device.get_master_mute = NULL;
+
+    /* Creates and releases an audio patch between several source and sink ports. */
+    // Not Supported
+    adev->hw_device.create_audio_patch = NULL;
+    adev->hw_device.release_audio_patch = NULL;
+    /* Sets/Gets audio port configuration. */
+    // Not Supported
+    adev->hw_device.get_audio_port = NULL;
+    adev->hw_device.set_audio_port_config = NULL;
+
+
+    pthread_mutex_lock(&adev->lock);
+
+    /*
+     * Initializes Audio Proxy.
+     * Audio Proxy is handling ALSA & Audio Routes to support SoC dependency.
+     */
+    adev->proxy = proxy_init();
+    if (!adev->proxy) {
+        ALOGE("device-%s: failed to init Audio Proxy", __func__);
+        goto err_open;
+    }
+
+    /* Initializes Audio Route. */
+    if (adev_init_route(adev) == false) {
+        ALOGE("device-%s: failed to init Audio Route", __func__);
+        goto err_open;
+    }
+    adev->is_route_created = true;
+
+    adev->actual_playback_device = AUDIO_DEVICE_OUT_SPEAKER;
+    adev->actual_capture_device  = AUDIO_DEVICE_IN_BUILTIN_MIC;
+    adev->previous_playback_device = AUDIO_DEVICE_NONE;
+    adev->previous_capture_device  = AUDIO_DEVICE_NONE;
+
+    adev->is_playback_path_routed  = false;
+    adev->active_playback_ausage   = AUSAGE_NONE;
+    adev->active_playback_device   = DEVICE_NONE;
+    adev->active_playback_modifier = MODIFIER_NONE;
+
+    adev->is_capture_path_routed  = false;
+    adev->active_capture_ausage   = AUSAGE_NONE;
+    adev->active_capture_device   = DEVICE_NONE;
+    adev->active_capture_modifier = MODIFIER_NONE;
+
+    /* Initialize Audio Stream Lists */
+    list_init(&adev->playback_list);
+    list_init(&adev->capture_list);
+
+    /* Sets initial values. */
+    adev->primary_output = NULL;
+    adev->active_input = NULL;
+
+    adev->amode = AUDIO_MODE_NORMAL;
+    adev->previous_amode = AUDIO_MODE_NORMAL;
+    adev->call_mode = CALL_OFF;
+    adev->incallmusic_on = false;
+
+    adev->voipse_on = false;
+
+    adev->voice_volume = 0;
+    adev->mic_mute = false;
+
+    adev->fm_state = FM_OFF;
+    adev->fm_need_route = false;
+
+   /*
+     * Initializes Factory Manager.
+     * Factory Manager is handling factory mode test scenario.
+     */
+    adev->factory = factory_init();
+    if (!adev->factory)
+        ALOGE("device-%s: failed to init Factory Manager!", __func__);
+    else
+        ALOGD("device-%s: initialized Factory Manager!", __func__);
+
+    /* Customer Specific initial values */
+    adev->support_reciever = false;
+    adev->support_backmic = false;
+    adev->support_thirdmic = false;
+    adev->fm_via_a2dp= false;
+    adev->fm_radio_mute = false;
+
+    adev->pcmread_latency = 0;
+    adev->update_offload_volume = false;
+    adev->current_devices = AUDIO_DEVICE_NONE;
+
+    proxy_init_offload_effect_lib(adev->proxy);
+
+    pthread_mutex_unlock(&adev->lock);
+
+    /* Sets Structure audio_hw_device for return. */
+    *device = &adev->hw_device.common;
+    adev_ref_count++;
+    ALOGI("device-%s: opened Primary Audio HW Device(ref = %d)", __func__, adev_ref_count);
+    pthread_mutex_unlock(&adev_init_lock);
+    return 0;
+
+err_open:
+    if (adev->proxy)
+        proxy_deinit(adev->proxy);
+
+    pthread_mutex_unlock(&adev->lock);
+    pthread_mutex_destroy(&adev->lock);
+
+    free(adev);
+    *device = NULL;
+
+    ALOGI("device-%s: failed to open Primary Audio HW Device", __func__);
+    pthread_mutex_unlock(&adev_init_lock);
+    return -ENOSYS;
+}
+
+/* Entry Point for AudioHAL (Primary Audio HW Module for Android) */
+static struct hw_module_methods_t hal_module_methods = {
+    .open = adev_open,
+};
+
+struct audio_module HAL_MODULE_INFO_SYM = {
+    .common = {
+        .tag = HARDWARE_MODULE_TAG,
+        .module_api_version = AUDIO_MODULE_API_VERSION_CURRENT,
+        .hal_api_version = HARDWARE_HAL_API_VERSION,
+        .id = AUDIO_HARDWARE_MODULE_ID,
+        .name = "Exynos Primary AudioHAL",
+        .author = "Samsung",
+        .methods = &hal_module_methods,
+    },
+};
diff --git a/libaudio/audiohal/audio_hw.h b/libaudio/audiohal/audio_hw.h
new file mode 100644
index 0000000..074b351
--- /dev/null
+++ b/libaudio/audiohal/audio_hw.h
@@ -0,0 +1,259 @@
+/*
+ * 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 __EXYNOS_AUDIOHAL_H__
+#define __EXYNOS_AUDIOHAL_H__
+
+/* Definition of AudioHAL */
+#include <system/audio.h>
+#include <hardware/hardware.h>
+#include <hardware/audio.h>
+
+#include <cutils/list.h>
+
+#include "audio_streams.h"
+#include "audio_usages.h"
+#include "audio_devices.h"
+#include "audio_offload.h"
+#include "audio_definition.h"
+
+/* Voice call - RIL interface */
+#include "voice_manager.h"
+
+/* Factory Mode Test */
+#include "factory_manager.h"
+
+
+/**
+ ** Stream Status
+ **/
+typedef enum {
+    STATUS_STANDBY   = 0,   // Stream is opened, but Device(PCM or Compress) is not opened yet.
+    STATUS_READY,           // Stream is opened, but Device(PCM or Compress) is not opened yet. But, started something
+    STATUS_IDLE,            // Stream is opened & Device(PCM or Compress) is opened.
+    STATUS_PLAYING,         // Stream is opened & Device(PCM or Compress) is opened & Device is working.
+    STATUS_PAUSED,          // Stream is opened & Device(Compress) is opened & Device is pausing.(only available for Compress Offload Stream)
+} stream_status;
+
+/**
+ ** Call Mode
+ **/
+typedef enum {
+    CALL_OFF   = 0,         // No Call Mode
+    VOICE_CALL,             // CP Centric Voice Call Mode
+    VOLTE_CALL,             // CP Centric VOLTE Call Mode
+    VOWIFI_CALL,            // AP Centric VoWiFi Call Mode
+
+    CALL_MODE_CNT,
+    CALL_MODE_MAX   = CALL_MODE_CNT - 1,
+} call_mode;
+
+/**
+ ** FM State
+ **/
+typedef enum {
+    FM_OFF   = 0,
+    FM_ON,
+    FM_RECORDING,
+} fm_state;
+
+/* Macro for Routing */
+#define ROUTE               true
+#define UNROUTE             false
+
+typedef enum {
+    NON_FORCE_ROUTE     = 0,
+    FORCE_ROUTE,
+    CALL_DRIVE
+} force_route;
+
+
+/**
+ ** Structure for Audio Output Stream
+ ** Implements audio_stream_out structure
+ **/
+struct stream_common {
+    pthread_mutex_t         lock;
+
+    // Audio Proxy to provide HW Services
+    void *proxy_stream;
+
+    /* These variables are needed to save Android Request
+       becuase requested PCM Config and Real PCM Config can be different */
+    audio_io_handle_t       handle;
+    audio_devices_t         requested_devices;
+    uint32_t                requested_sample_rate;
+    audio_channel_mask_t    requested_channel_mask;
+    audio_format_t          requested_format;
+    uint32_t                requested_frame_count;
+    audio_format_t          offload_audio_format;
+
+    /* These variables show the purpose of stream */
+    audio_stream_type       stream_type;
+    audio_usage             stream_usage;
+    stream_status           stream_status;
+};
+
+/* Compress Offload Specific Variables */
+struct offload_msg {
+    struct listnode node;
+    offload_msg_type msg;
+};
+
+struct stream_offload {
+    int nonblock_flag;
+
+    stream_callback_t callback;
+    void *cookie;
+
+    pthread_t callback_thread;
+
+    pthread_cond_t msg_cond;
+    struct listnode msg_list;
+
+    pthread_cond_t sync_cond;
+    bool callback_thread_blocked;
+};
+
+struct stream_out {
+    struct audio_stream_out stream;
+    struct stream_common common;
+
+    audio_output_flags_t    requested_flags;
+
+    struct audio_device *   adev;
+
+    struct stream_offload offload;
+    float  vol_left, vol_right;
+
+    /* Force Routing */
+    force_route force;
+    audio_devices_t rollback_devices;
+};
+
+struct playback_stream {
+    struct listnode node;
+    struct stream_out *out;
+};
+
+/**
+ ** Structure for Audio Input Stream
+ ** Implements audio_stream_in structure
+ **/
+struct stream_in {
+    struct audio_stream_in stream;
+    struct stream_common common;
+
+    audio_input_flags_t    requested_flags;
+    audio_source_t          requested_source;
+
+    bool pcm_reconfig;
+
+    struct audio_device *   adev;
+};
+
+struct capture_stream {
+    struct listnode node;
+    struct stream_in *in;
+};
+
+/**
+ ** Structure for Audio Primary HW Module
+ ** Implements audio_hw_device structure
+ **/
+struct audio_device {
+    struct audio_hw_device hw_device;
+    pthread_mutex_t lock;
+
+    // Audio Proxy to provide HW Services
+    void *proxy;
+
+    // Stream Information
+    struct listnode playback_list;
+    struct listnode capture_list;
+
+    // Routing Information
+    audio_devices_t actual_playback_device;
+    audio_devices_t actual_capture_device;
+    audio_devices_t previous_playback_device;
+    audio_devices_t previous_capture_device;
+
+    bool is_route_created;
+
+    bool is_playback_path_routed;
+    audio_usage active_playback_ausage;
+    device_type active_playback_device;
+    modifier_type active_playback_modifier;
+
+    bool is_capture_path_routed;
+    audio_usage active_capture_ausage;
+    device_type active_capture_device;
+    modifier_type active_capture_modifier;
+
+    audio_devices_t current_devices;
+
+    // Voice
+    struct voice_manager *voice;
+    float voice_volume;
+    bool mic_mute;
+
+    // Factory
+    struct factory_manager *factory;
+
+    // Important Streams
+    struct stream_out *primary_output;
+    struct stream_in  *active_input;
+    struct stream_out *compress_output;
+
+    // Audio/Call Modes
+    audio_mode_t amode;
+    audio_mode_t previous_amode;
+    call_mode    call_mode;
+
+    //special incall-music stream
+    bool incallmusic_on;
+
+    // VoIP SE
+    bool voipse_on;
+
+    bool bluetooth_nrec;
+    bool screen_on;
+
+    fm_state fm_state;
+    bool fm_need_route;
+
+    bool seamless_enabled;
+
+    // Customer Specific varibales
+    bool support_reciever;
+    bool support_backmic;
+    bool support_thirdmic;
+    bool fm_via_a2dp;
+    bool fm_radio_mute;
+    int  pcmread_latency;
+    bool update_offload_volume;
+};
+
+
+/* Functions for External Usage */
+bool adev_set_route(void *stream, audio_usage_type usage_type, bool set, force_route force);
+void set_call_forwarding(struct audio_device *adev, bool mode);
+
+//void update_uhqa_stream(struct stream_out *out);
+void update_call_stream(struct stream_out *out, audio_devices_t current_devices, audio_devices_t new_devices);
+void update_capture_stream(struct stream_in *in, audio_devices_t current_devices, audio_devices_t new_devices);
+
+#endif  // __EXYNOS_AUDIOHAL_H__
diff --git a/libaudio/audiohal/factory_manager.c b/libaudio/audiohal/factory_manager.c
new file mode 100644
index 0000000..e6fbfa9
--- /dev/null
+++ b/libaudio/audiohal/factory_manager.c
@@ -0,0 +1,310 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "audio_hw_primary_factory"
+//#define LOG_NDEBUG 0
+
+#include <stdlib.h>
+#include <errno.h>
+
+#include <log/log.h>
+#include <cutils/str_parms.h>
+
+#include "factory_manager.h"
+#include "audio_definition.h"
+#include "audio_proxy_interface.h"
+
+
+/******************************************************************************/
+/**                                                                          **/
+/** The Factory Functions                                                    **/
+/**                                                                          **/
+/******************************************************************************/
+bool is_factory_mode(struct factory_manager *factory)
+{
+    if(factory && factory->mode != FACTORY_MODE_NONE)
+        return true;
+    else
+        return false;
+}
+
+bool is_factory_loopback_mode(struct factory_manager *factory)
+{
+    if(factory && factory->mode == FACTORY_MODE_LOOPBACK)
+        return true;
+    else
+        return false;
+}
+
+bool is_factory_bt_realtime_loopback_mode(struct factory_manager *factory)
+{
+    if (factory && (factory->loopback_mode == FACTORY_LOOPBACK_REALTIME)
+            && (factory->out_device == AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET) && (factory->in_device == AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET)) {
+        return true;
+    }
+    return false;
+}
+
+bool is_factory_rms_mode(struct factory_manager *factory)
+{
+    if(factory && factory->mode == FACTORY_MODE_RMS)
+        return true;
+    else
+        return false;
+}
+
+
+static void factory_set_path_for_loopback(struct factory_manager *factory, const char *value)
+{
+    ALOGD("%s: enter with value(%s)", __func__, value);
+
+    ALOGI("%s :  loopback = %s ",__func__, value);
+    if(strncmp(value, "ear_ear", 7) == 0) {
+        factory->out_device = (AUDIO_DEVICE_OUT_WIRED_HEADSET);
+        factory->in_device = (AUDIO_DEVICE_IN_WIRED_HEADSET);
+    } else if(strncmp(value, "mic1_spk", 8) == 0) {
+        factory->out_device = (AUDIO_DEVICE_OUT_SPEAKER);
+        factory->in_device = (AUDIO_DEVICE_IN_BUILTIN_MIC);
+    } else if(strncmp(value, "mic2_spk", 8) == 0) {
+        factory->out_device = (AUDIO_DEVICE_OUT_SPEAKER);
+        factory->in_device = (AUDIO_DEVICE_IN_BACK_MIC);
+    } else if(strncmp(value, "mic1_rcv", 8) == 0) {
+        factory->out_device = (AUDIO_DEVICE_OUT_EARPIECE);
+        factory->in_device = (AUDIO_DEVICE_IN_BUILTIN_MIC);
+    } else if(strncmp(value, "mic2_rcv", 8) == 0) {
+        factory->out_device = (AUDIO_DEVICE_OUT_EARPIECE);
+        factory->in_device = (AUDIO_DEVICE_IN_BACK_MIC);
+    } else if(strncmp(value, "mic1_ear", 8) == 0) {
+        factory->out_device = (AUDIO_DEVICE_OUT_WIRED_HEADSET);
+        factory->in_device = (AUDIO_DEVICE_IN_BUILTIN_MIC);
+    } else if(strncmp(value, "mic2_ear", 8) == 0) {
+        factory->out_device = (AUDIO_DEVICE_OUT_WIRED_HEADSET);
+        factory->in_device = (AUDIO_DEVICE_IN_BACK_MIC);
+    } else if(strncmp(value, "bt_bt", 5) == 0) {
+        factory->out_device = (AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET);
+        factory->in_device = (AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET);
+    } else {
+        ALOGW("factory test path doesn't exist. default set earpiece.");
+        factory->out_device = (AUDIO_DEVICE_OUT_EARPIECE);
+        factory->in_device = (AUDIO_DEVICE_IN_BUILTIN_MIC);
+    }
+
+    return;
+}
+
+static void factory_set_path_for_force_route(struct factory_manager *factory, const char *value)
+{
+
+    if (!factory->rms_test_enable)
+        factory->mode = FACTORY_MODE_FORCE_ROUTE;
+
+    if (!strcmp(value, "spk")) {
+        ALOGD("%s factory_test_route : spk", __func__);
+        factory->out_device = (AUDIO_DEVICE_OUT_SPEAKER & AUDIO_DEVICE_OUT_ALL);
+    } else if (!strcmp(value, "rcv")) {
+        ALOGD("%s factory_test_route : rcv", __func__);
+        factory->out_device = (AUDIO_DEVICE_OUT_EARPIECE & AUDIO_DEVICE_OUT_ALL);
+    } else if (!strcmp(value, "ear")) {
+        ALOGD("%s factory_test_route : ear", __func__);
+        factory->out_device = (AUDIO_DEVICE_OUT_WIRED_HEADSET & AUDIO_DEVICE_OUT_ALL);
+    } else if (!strcmp(value, "off")) {
+        ALOGD("%s factory_test_route : off", __func__);
+        factory->mode = FACTORY_MODE_NONE;
+        factory->out_device = (AUDIO_DEVICE_NONE);
+    }
+
+    return;
+}
+
+static void factory_set_path_for_rms(struct factory_manager *factory, const char *value)
+{
+    if (strcmp(value, "on") == 0) {
+        ALOGD("%s factory_test_mic_check=on", __func__);
+        factory->mode = FACTORY_MODE_RMS;
+        factory->rms_test_enable = true;
+    }  else if (strcmp(value, "main") == 0) {
+        ALOGD("%s factory_test_mic_check=main", __func__);
+        factory->in_device = (AUDIO_DEVICE_IN_BUILTIN_MIC);
+    }  else if (strcmp(value, "sub") == 0) {
+        ALOGD("%s factory_test_mic_check=sub", __func__);
+        factory->in_device = (AUDIO_DEVICE_IN_BACK_MIC);
+    }  else if (strcmp(value, "spk_mic1") == 0) {    /*at + looptest=0,3,4 */
+        ALOGD("%s factory_test_mic_check=spk_mic1", __func__);
+        factory->in_device = (AUDIO_DEVICE_IN_BUILTIN_MIC);
+    }  else if (strcmp(value, "off") == 0) {
+        ALOGD("%s factory_test_mic_check=off", __func__);
+        factory->mode = FACTORY_MODE_NONE;
+        factory->in_device = (AUDIO_DEVICE_NONE);
+        factory->rms_test_enable = false;
+    }
+
+    return;
+}
+
+void factory_set_parameters(struct audio_device *adev, struct str_parms *parms)
+{
+    struct factory_manager *factory = adev->factory;
+    char *kv_pairs = str_parms_to_str(parms);
+    //ALOGV_IF(kv_pairs != NULL, "%s: enter: %s", __func__, kv_pairs);
+
+    char value[32];
+    int err = 0;
+
+    err = str_parms_get_str(parms, AUDIO_PARAMETER_FACTORY_TEST_TYPE, value, sizeof(value));
+    if (err >= 0 && factory) {
+        if (!strcmp(value, "codec")) {
+            factory->loopback_mode= FACTORY_LOOPBACK_CODEC;
+        } else if (!strcmp(value, "realtime")) {
+            factory->loopback_mode = FACTORY_LOOPBACK_REALTIME;
+        } else if (!strcmp(value, "pcm")) {
+            factory->loopback_mode = FACTORY_LOOPBACK_PCM;
+        } else if (!strcmp(value, "packet")) {
+            factory->loopback_mode = FACTORY_LOOPBACK_PACKET;
+        } else if (!strcmp(value, "packet_nodelay")) {
+            factory->loopback_mode = FACTORY_LOOPBACK_PACKET_NODELAY;
+        }
+        ALOGD("%s: FACTORY_TEST_TYPE=%d", __func__, factory->loopback_mode);
+        str_parms_del(parms, AUDIO_PARAMETER_FACTORY_TEST_TYPE);
+    }
+
+    err = str_parms_get_str(parms, AUDIO_PARAMETER_FACTORY_TEST_LOOPBACK, value, sizeof(value));
+    if (err >= 0 && factory) {
+        if (!strcmp(value, AUDIO_PARAMETER_VALUE_ON)) {
+            ALOGD("%s: FACTORY_TEST_LOOPBACK=on", __func__);
+            factory->mode = FACTORY_MODE_LOOPBACK;
+#ifdef SUPPORT_STHAL_INTERFACE
+            proxy_call_status(adev->proxy, true);
+#endif
+        } else if (!strcmp(value, AUDIO_PARAMETER_VALUE_OFF)) {
+            ALOGD("%s: FACTORY_TEST_LOOPBACK=off", __func__);
+            factory->mode = FACTORY_MODE_NONE;
+            factory->out_device = (AUDIO_DEVICE_NONE);
+            factory->in_device = (AUDIO_DEVICE_NONE);
+
+            /* 1. pcm device close */
+            if (factory->loopback_mode != FACTORY_LOOPBACK_REALTIME) {
+                voice_set_loopback_device(adev->voice, FACTORY_LOOPBACK_OFF,
+                                          AUDIO_DEVICE_OUT_EARPIECE, AUDIO_DEVICE_IN_BUILTIN_MIC);
+                proxy_stop_voice_call(adev->proxy);
+            }
+            factory->loopback_mode = FACTORY_LOOPBACK_OFF;
+
+            /* 2. reset device */
+            if (adev->primary_output != NULL) {
+                if (adev->primary_output->common.stream_status != STATUS_STANDBY)
+                    adev_set_route((void *)adev->primary_output, AUSAGE_PLAYBACK, ROUTE, CALL_DRIVE);
+                else
+                    adev_set_route((void *)adev->primary_output, AUSAGE_PLAYBACK, UNROUTE, CALL_DRIVE);
+            }
+            if (factory->loopback_mode != FACTORY_LOOPBACK_REALTIME) {
+                voice_set_call_mode(adev->voice, false);
+            }
+#ifdef SUPPORT_STHAL_INTERFACE
+            proxy_call_status(adev->proxy, false);
+#endif
+        }
+        str_parms_del(parms, AUDIO_PARAMETER_FACTORY_TEST_LOOPBACK);
+    }
+
+    err = str_parms_get_str(parms, AUDIO_PARAMETER_FACTORY_TEST_PATH, value, sizeof(value));
+    if (err > 0 && factory) {
+        factory_set_path_for_loopback(factory, value);
+
+        /* 1. set ril device */
+        if (factory->loopback_mode != FACTORY_LOOPBACK_REALTIME) {
+            voice_set_loopback_device(adev->voice, adev->factory->loopback_mode,
+                                      adev->factory->out_device, adev->factory->in_device);
+        }
+
+        /* 2. pcm device close for reset */
+        proxy_stop_voice_call(adev->proxy);
+
+        /* 3. set route */
+        if (adev->primary_output != NULL)
+            adev_set_route((void *)adev->primary_output, AUSAGE_PLAYBACK, ROUTE, CALL_DRIVE);
+
+        if (factory->loopback_mode != FACTORY_LOOPBACK_REALTIME) {
+            /* 4. pcm device open */
+            proxy_start_voice_call(adev->proxy);
+
+            /* 5. set volume */
+            voice_set_volume(adev->voice, adev->voice_volume);
+
+             /* 6. mic unmute */
+            voice_set_mic_mute(adev->voice, false);
+        }
+        str_parms_del(parms, AUDIO_PARAMETER_FACTORY_TEST_PATH);
+    }
+
+    err = str_parms_get_str(parms, AUDIO_PARAMETER_FACTORY_TEST_ROUTE, value, sizeof(value));
+    if (err > 0 && factory) {
+        factory_set_path_for_force_route(factory, value);
+        if (adev->primary_output != NULL) {
+            if (adev->primary_output->common.stream_status != STATUS_STANDBY)
+                adev_set_route((void *)adev->primary_output, AUSAGE_PLAYBACK, ROUTE, FORCE_ROUTE);
+            else
+                adev_set_route((void *)adev->primary_output, AUSAGE_PLAYBACK, UNROUTE, FORCE_ROUTE);
+        }
+
+        str_parms_del(parms, AUDIO_PARAMETER_FACTORY_TEST_ROUTE);
+    }
+
+    err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_FACTORY_RMS_TEST, value, sizeof(value));
+    if (err >= 0 && factory) {
+        factory_set_path_for_rms(factory, value);
+        if (adev->active_input != NULL
+            && !(adev->active_input->requested_flags & AUDIO_INPUT_FLAG_HW_HOTWORD)
+            && strcmp(value, "on") != 0)
+            adev_set_route((void *)adev->active_input, AUSAGE_CAPTURE, ROUTE, NON_FORCE_ROUTE);
+        str_parms_del(parms, AUDIO_PARAMETER_KEY_FACTORY_RMS_TEST);
+    }
+
+    //ALOGD("%s: exit", __func__);
+
+    free(kv_pairs);
+    return ;
+}
+
+
+void factory_deinit(struct factory_manager *factory)
+{
+    if (factory)
+        free(factory);
+
+    return ;
+}
+
+struct factory_manager* factory_init()
+{
+    struct factory_manager *factory = NULL;
+
+    factory = calloc(1, sizeof(struct factory_manager));
+    if (factory) {
+        factory->mode = FACTORY_MODE_NONE;
+        factory->loopback_mode= FACTORY_LOOPBACK_OFF;
+        factory->out_device = AUDIO_DEVICE_NONE;
+        factory->in_device = AUDIO_DEVICE_NONE;
+        factory->rms_test_enable = false;
+        factory->is_dspk_changed = false;
+
+        // false : SPK2 (rcv side spk) test, using mixer string "speaker2"
+        // true : SPK CAL test, using mixer string "dual-speaker"
+        factory->is_calibration_test = false;
+    }
+
+    return factory;
+}
+
diff --git a/libaudio/audiohal/factory_manager.h b/libaudio/audiohal/factory_manager.h
new file mode 100644
index 0000000..192328e
--- /dev/null
+++ b/libaudio/audiohal/factory_manager.h
@@ -0,0 +1,69 @@
+/*
+ * 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_AUDIOHAL_FACTORY_H__
+#define __EXYNOS_AUDIOHAL_FACTORY_H__
+
+#include <system/audio.h>
+#include <hardware/audio.h>
+
+#include "audio_hw.h"
+
+typedef enum {
+    FACTORY_MODE_NONE,
+    FACTORY_MODE_FORCE_ROUTE,
+    FACTORY_MODE_LOOPBACK,
+    FACTORY_MODE_RMS,
+} factory_mode_status;
+
+typedef enum factory_loopback_types {
+    FACTORY_LOOPBACK_OFF = 0,
+    FACTORY_LOOPBACK_PCM = 1,
+    FACTORY_LOOPBACK_PACKET = 2,
+    FACTORY_LOOPBACK_PCM_NODELAY = 3,
+    FACTORY_LOOPBACK_PACKET_NODELAY = 4,
+    FACTORY_LOOPBACK_CODEC = 5,
+    FACTORY_LOOPBACK_REALTIME = 6
+} loopback_type;
+
+typedef enum {
+    FACTORY_SET_PARAM_OK            = 0,
+    FACTORY_TEST_OFF,
+    FACTORY_LOOPBACK_TEST,
+    FACTORY_FORCEROUTE_TEST,
+    FACTORY_RMS_TEST
+} factory_set_param_return;
+
+struct factory_manager {
+    factory_mode_status mode;
+    loopback_type loopback_mode;
+    audio_devices_t out_device;
+    audio_devices_t in_device;
+    bool rms_test_enable;
+    bool is_calibration_test;
+    bool is_dspk_changed;
+};
+
+bool is_factory_mode(struct factory_manager *factory);
+bool is_factory_loopback_mode(struct factory_manager *factory);
+bool is_factory_rms_mode(struct factory_manager *factory);
+bool is_factory_bt_realtime_loopback_mode(struct factory_manager *factory);
+
+void factory_set_parameters(struct audio_device *adev, struct str_parms *parms);
+void factory_deinit(struct factory_manager *factory);
+struct factory_manager * factory_init(void);
+
+#endif  // __EXYNOS_AUDIOHAL_FACTORY_H__
diff --git a/libaudio/audiohal/sit_specific.h b/libaudio/audiohal/sit_specific.h
new file mode 100644
index 0000000..ec340f6
--- /dev/null
+++ b/libaudio/audiohal/sit_specific.h
@@ -0,0 +1,150 @@
+/*
+ * 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 __AUDIOHAL_SITSPECIFIC_H__
+#define __AUDIOHAL_SITSPECIFIC_H__
+
+
+// RIL Client for Audio
+#define RIL_CLIENT_LIBPATH "/system/lib/libsitril-audio.so"
+
+#define AUDIO_PARAMETER_VOLTE_STATUS   "VoLTEstate"
+
+
+/* Syncup with RIL Audio Client */
+
+/* Voice Audio Path */
+enum ril_audio_path {
+    VOICE_AUIDO_PATH_NONE                   = 0,
+
+    VOICE_AUDIO_PATH_HANDSET                = 1,
+    VOICE_AUIDO_PATH_HEADSET                = 2,
+    VOICE_AUIDO_PATH_HANDSFREE              = 3,
+    VOICE_AUIDO_PATH_BLUETOOTH              = 4,
+    VOICE_AUIDO_PATH_STEREO_BLUETOOTH       = 5,
+    VOICE_AUIDO_PATH_SPEAKRERPHONE          = 6,
+    VOICE_AUIDO_PATH_35PI_HEADSET           = 7,
+    VOICE_AUIDO_PATH_BT_NS_EC_OFF           = 8,
+    VOICE_AUIDO_PATH_WB_BLUETOOTH           = 9,
+    VOICE_AUIDO_PATH_WB_BT_NS_EC_OFF        = 10,
+    VOICE_AUIDO_PATH_HANDSET_HAC            = 11,
+
+    VOICE_AUIDO_PATH_VOLTE_HANDSET          = 65,
+    VOICE_AUIDO_PATH_VOLTE_HEADSET          = 66,
+    VOICE_AUIDO_PATH_VOLTE_HFK              = 67,
+    VOICE_AUIDO_PATH_VOLTE_BLUETOOTH        = 68,
+    VOICE_AUIDO_PATH_VOLTE_STEREO_BLUETOOTH = 69,
+    VOICE_AUIDO_PATH_VOLTE_SPEAKRERPHONE    = 70,
+    VOICE_AUIDO_PATH_VOLTE_35PI_HEADSET     = 71,
+    VOICE_AUIDO_PATH_VOLTE_BT_NS_EC_OFF     = 72,
+    VOICE_AUIDO_PATH_VOLTE_WB_BLUETOOTH     = 73,
+    VOICE_AUIDO_PATH_VOLTE_WB_BT_NS_EC_OFF  = 74,
+    VOICE_AUIDO_PATH_MAX
+};
+
+/* Voice Audio Multi-MIC */
+enum ril_audio_multimic {
+    VOICE_MULTI_MIC_OFF,
+    VOICE_MULTI_MIC_ON,
+};
+
+/* Voice Audio Volume */
+enum ril_audio_volume {
+    VOICE_AUDIO_VOLUME_INVALID   = -1,
+    VOICE_AUDIO_VOLUME_LEVEL0    = 0,
+    VOICE_AUDIO_VOLUME_LEVEL1,
+    VOICE_AUDIO_VOLUME_LEVEL2,
+    VOICE_AUDIO_VOLUME_LEVEL3,
+    VOICE_AUDIO_VOLUME_LEVEL4,
+    VOICE_AUDIO_VOLUME_LEVEL5,
+    VOICE_AUDIO_VOLUME_LEVEL_MAX = VOICE_AUDIO_VOLUME_LEVEL5,
+};
+
+/* Voice Audio Mute */
+enum ril_audio_mute {
+    VOICE_AUDIO_MUTE_DISABLED,
+    VOICE_AUDIO_MUTE_ENABLED,
+};
+
+/* Voice Audio Clock */
+enum ril_audio_clockmode {
+    VOICE_AUDIO_TURN_OFF_I2S,
+    VOICE_AUDIO_TURN_ON_I2S,
+};
+
+/* Voice Loopback */
+enum ril_audio_loopback {
+    VOICE_AUDIO_LOOPBACK_STOP,
+    VOICE_AUDIO_LOOPBACK_START,
+};
+
+enum ril_audio_loopback_path {
+    VOICE_AUDIO_LOOPBACK_PATH_NA                    = 0,    //0: N/A
+
+    VOICE_AUDIO_LOOPBACK_PATH_HANDSET               = 1,    //1: handset
+    VOICE_AUDIO_LOOPBACK_PATH_HEADSET               = 2,    //2: headset
+    VOICE_AUDIO_LOOPBACK_PATH_HANDSFREE             = 3,    //3: handsfree
+    VOICE_AUDIO_LOOPBACK_PATH_BT                    = 4,    //4: Bluetooth
+    VOICE_AUDIO_LOOPBACK_PATH_STEREO_BT             = 5,    //5: stereo Bluetooth
+    VOICE_AUDIO_LOOPBACK_PATH_SPK                   = 6,    //6: speaker phone
+    VOICE_AUDIO_LOOPBACK_PATH_35PI_HEADSET          = 7,    //7: 3.5pi headset
+    VOICE_AUDIO_LOOPBACK_PATH_BT_NS_EC_OFF          = 8,    //8: BT NS/EC off
+    VOICE_AUDIO_LOOPBACK_PATH_WB_BT                 = 9,    //9: WB Bluetooth
+    VOICE_AUDIO_LOOPBACK_PATH_WB_BT_NS_EC_OFF       = 10,   //10: WB BT NS/EC
+    VOICE_AUDIO_LOOPBACK_PATH_HANDSET_HAC           = 11,   //11: handset HAC
+
+    VOICE_AUDIO_LOOPBACK_PATH_VOLTE_HANDSET         = 65,   //65: VOLTE handset
+    VOICE_AUDIO_LOOPBACK_PATH_VOLTE_HEADSET         = 66,   //66: VOLTE headset
+    VOICE_AUDIO_LOOPBACK_PATH_VOLTE_HANDSFREE       = 67,   //67: VOLTE hands
+    VOICE_AUDIO_LOOPBACK_PATH_VOLTE_BT              = 68,   //68: VOLTE Bluetooth
+    VOICE_AUDIO_LOOPBACK_PATH_VOLTE_STEREO_BT       = 69,   //69: VOLTE stere
+    VOICE_AUDIO_LOOPBACK_PATH_VOLTE_SPK             = 70,   //70: VOLTE speaker phone
+    VOICE_AUDIO_LOOPBACK_PATH_VOLTE_35PI_HEADSET    = 71,   //71: VOLTE 3.5pi
+    VOICE_AUDIO_LOOPBACK_PATH_VOLTE_BT_NS_EC_OFF    = 72,   //72: VOLTE BT NS
+    VOICE_AUDIO_LOOPBACK_PATH_VOLTE_WB_BT           = 73,   //73: VOLTE WB Blueto
+    VOICE_AUDIO_LOOPBACK_PATH_VOLTE_WB_BT_NS_EC_OFF = 74,   //74: VOLTE W
+
+    VOICE_AUDIO_LOOPBACK_PATH_HEADSET_MIC1          = 129,  //129: Headset ? MIC1
+    VOICE_AUDIO_LOOPBACK_PATH_HEADSET_MIC2          = 130,  //130: Headset ? MIC2
+    VOICE_AUDIO_LOOPBACK_PATH_HEADSET_MIC3          = 131,  //131: Headset ? MIC3
+};
+
+
+/* Event from RIL Audio Client */
+#define VOICE_AUDIO_EVENT_BASE                     10000
+#define VOICE_AUDIO_EVENT_RINGBACK_STATE_CHANGED   (VOICE_AUDIO_EVENT_BASE + 1)
+#define VOICE_AUDIO_EVENT_IMS_SRVCC_HANDOVER       (VOICE_AUDIO_EVENT_BASE + 2)
+
+
+/* RIL Audio Client Interface Structure */
+struct rilclient_intf {
+    /* The pointer of interface library for RIL Client*/
+    void *handle;
+
+    /* Function pointers */
+    int (*ril_open_client)(void);
+    int (*ril_close_client)(void);
+    int (*ril_register_callback)(void *, int *);
+    int (*ril_set_audio_volume)(int);
+    int (*ril_set_audio_path)(int);
+    int (*ril_set_multi_mic)(int);
+    int (*ril_set_mute)(int);
+    int (*ril_set_audio_clock)(int);
+    int (*ril_set_audio_loopback)(int, int);
+    int (*ril_set_tty_mode)(int);
+};
+
+#endif  // __AUDIOHAL_SITSPECIFIC_H__
diff --git a/libaudio/audiohal/voice_manager.c b/libaudio/audiohal/voice_manager.c
new file mode 100644
index 0000000..a8c3073
--- /dev/null
+++ b/libaudio/audiohal/voice_manager.c
@@ -0,0 +1,496 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "voice_manager"
+#define LOG_NDEBUG 0
+
+#include <stdlib.h>
+#include <errno.h>
+
+#include <log/log.h>
+#include <cutils/str_parms.h>
+#include <cutils/properties.h>
+
+#include "audio_hw.h"
+#include "voice_manager.h"
+#include "sitril_interface.h"
+
+#include "audio_proxy_interface.h"
+
+#define VOLUME_STEPS_DEFAULT  "5"
+#define VOLUME_STEPS_PROPERTY "ro.vendor.config.vc_call_vol_steps"
+
+
+#define DEVICE_INVALID           -1
+
+
+
+/*
+ * Local Functions
+ */
+static int voice_set_sco_solution(struct voice_manager *voice, bool echo_cancel, int sample_rate)
+{
+    int ret = 0;
+    if (voice) {
+        SitRilSetScoSolution(echo_cancel, sample_rate);
+    }
+    return ret;
+}
+
+static int voice_set_volte_status(struct voice_manager *voice, int status)
+{
+    int ret = 0;
+    if (voice) {
+        SitRilSetVoLTEState(status);
+    }
+    return ret;
+}
+
+static int voice_set_hac_mode(struct voice_manager *voice, bool status)
+{
+    int ret = 0;
+    if (voice) {
+        SitRilSetHacModeState(status);
+    }
+    return ret;
+}
+
+/*
+ * Status Check Functions
+ */
+bool voice_is_call_mode(struct voice_manager *voice)
+{
+    // True means Android Audio Mode is IN_CALL Mode
+    return (voice->call_status >= CALL_STATUS_INCALLMODE);
+}
+
+bool voice_is_call_active(struct voice_manager *voice)
+{
+    // True means Voice Call is working (Audio PCM for CP Call is Opened)
+    return (voice->call_status == CALL_STATUS_ACTIVE);
+}
+
+
+/*
+ * Set Functions
+ */
+int voice_set_call_mode(struct voice_manager *voice, bool on)
+{
+    int ret = 0;
+
+    if (voice->call_status == CALL_STATUS_INVALID && on) {
+        // RIL Audio Client is not connected yet, Re-Try!!!
+        ALOGD("vm-%s: RilClient is not opened yet! Retry!", __func__);
+        ret = SitRilOpen();
+        if (ret == 0)
+            voice->call_status = CALL_STATUS_CONNECTED;
+        else
+            voice->call_status = CALL_STATUS_INVALID;
+    }
+
+    if (voice->call_status == CALL_STATUS_CONNECTED && on)
+        voice->call_status = CALL_STATUS_INCALLMODE;
+    else if (voice->call_status == CALL_STATUS_INCALLMODE && !on)
+        voice->call_status = CALL_STATUS_CONNECTED;
+    else
+        ALOGE("vm-%s: Invalid Voice Call Status(%d) with %d", __func__, voice->call_status, on);
+
+    return ret;
+}
+
+int voice_set_call_active(struct voice_manager *voice, bool on)
+{
+    int ret = 0;
+
+    if (voice->call_status == CALL_STATUS_INCALLMODE && on) {
+        voice->call_status = CALL_STATUS_ACTIVE;
+        SitRilSetSoundClkMode(1);
+    } else if (voice->call_status == CALL_STATUS_ACTIVE && !on) {
+        voice->call_status = CALL_STATUS_INCALLMODE;
+        SitRilSetSoundClkMode(0);
+    } else
+        ALOGE("vm-%s: Invalid Voice Call Status(%d) with %d", __func__, voice->call_status, on);
+
+    return ret;
+}
+
+int voice_set_audio_mode(struct voice_manager *voice, int mode, bool status)
+{
+    int ret = 0;
+    if (voice) {
+        SitRilSetAudioMode(mode, status);
+    }
+    return ret;
+}
+
+int voice_set_volume(struct voice_manager *voice, float volume)
+{
+    int ret = 0;
+
+    if (voice->call_status == CALL_STATUS_ACTIVE) {
+        SitRilSetVoiceVolume(voice->out_device, (int)(volume * voice->volume_steps_max), volume);
+        ALOGD("vm-%s: Volume = %d(%f)!", __func__, (int)(volume * voice->volume_steps_max), volume);
+    } else {
+        ALOGE("vm-%s: Voice is not Active", __func__);
+        ret = -1;
+    }
+
+    return ret;
+}
+
+int voice_set_extra_volume(struct voice_manager *voice, bool on)
+{
+    int ret = 0;
+    if (voice) {
+        SitRilSetExtraVolume(on);
+    }
+    return ret;
+}
+
+int voice_set_path(struct voice_manager *voice, audio_devices_t devices)
+{
+    int ret = 0;
+    int mode = AUDIO_MODE_IN_CALL;
+
+    if (voice_is_call_mode(voice)) {
+        voice->out_device = devices;
+        SitRilSetVoicePath(mode, devices);
+    } else {
+        ALOGE("%s: Voice is not created", __func__);
+        ret = -1;
+    }
+
+    return ret;
+}
+
+int voice_set_mic_mute(struct voice_manager *voice, bool status)
+{
+    int ret = 0;
+    if (voice_is_call_mode(voice) || (voice->loopback_mode != FACTORY_LOOPBACK_OFF)) {
+        SitRilSetTxMute(status);
+    }
+    ALOGD("vm-%s: MIC Mute = %d!", __func__, status);
+    return ret;
+}
+
+int voice_set_rx_mute(struct voice_manager *voice, bool status)
+{
+    int ret = 0;
+    if (voice) {
+        SitRilSetRxMute(status);
+    }
+    return ret;
+}
+
+int voice_set_usb_mic(struct voice_manager *voice, bool status)
+{
+    int ret = 0;
+    if (voice) {
+        SitRilSetUSBMicState(status);
+    }
+    return ret;
+}
+
+void voice_set_call_forwarding(struct voice_manager *voice, bool callfwd)
+{
+    if (voice) {
+        SitRilSetCallFowardingMode(callfwd);
+    }
+    return;
+}
+
+void voice_set_cur_indevice_id(struct voice_manager *voice, int device)
+{
+    voice->in_device_id = device;
+    return;
+}
+
+void voice_set_parameters(struct audio_device *adev, struct str_parms *parms)
+{
+    struct voice_manager *voice = adev->voice;
+    char value[40];
+    int ret = 0;
+
+    char *kv_pairs = str_parms_to_str(parms);
+
+    //ALOGV_IF(kv_pairs != NULL, "%s: enter: %s", __func__, kv_pairs);
+
+    // VoLTE Status Configuration
+    ret = str_parms_get_str(parms, AUDIO_PARAMETER_VOLTE_STATUS, value, sizeof(value));
+    if (ret >= 0) {
+        if (!strcmp(value, "voice")) {
+            voice->volte_status = VOLTE_VOICE;
+            ALOGD("vm-%s: VoLTE Voice Call Start!!", __func__);
+        } else if (!strcmp(value, "end")) {
+            voice->volte_status = VOLTE_OFF;
+            ALOGD("vm-%s: VoLTE Voice Call End!!", __func__);
+        } else
+            ALOGD("vm-%s: Unknown VoLTE parameters = %s!!", __func__, value);
+
+        voice_set_volte_status(voice, voice->volte_status);
+    }
+
+    // BT SCO NREC Configuration
+    ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_BT_NREC, value, sizeof(value));
+    if (ret >= 0) {
+        if (!strcmp(value, AUDIO_PARAMETER_VALUE_ON)) {
+            voice->bluetooth_nrec = BT_NREC_ON;
+        } else if (!strcmp(value, AUDIO_PARAMETER_VALUE_OFF)) {
+            voice->bluetooth_nrec = BT_NREC_OFF;
+        }
+
+        str_parms_del(parms, AUDIO_PARAMETER_KEY_BT_NREC);
+    }
+
+    // BT SCO WideBand Configuration
+    ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_BT_SCO_WB, value, sizeof(value));
+    if (ret >= 0) {
+        if (!strcmp(value, AUDIO_PARAMETER_VALUE_ON)) {
+            voice->bluetooth_samplerate = WB_SAMPLING_RATE;
+        } else if (!strcmp(value, AUDIO_PARAMETER_VALUE_OFF)) {
+            voice->bluetooth_samplerate = NB_SAMPLING_RATE;
+        }
+
+        uint32_t device = 0;
+        if (adev->primary_output)
+            device = adev->primary_output->common.requested_devices & AUDIO_DEVICE_OUT_ALL_SCO;
+
+        voice_set_sco_solution(voice, voice->bluetooth_nrec, voice->bluetooth_samplerate);
+
+        if(voice_is_call_active(voice) && (device != 0)) {
+            voice_set_path(voice, adev->primary_output->common.requested_devices);
+        }
+
+        str_parms_del(parms, AUDIO_PARAMETER_KEY_BT_SCO_WB);
+    }
+
+    // TTY Status Configuration
+    ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_TTY_MODE, value, sizeof(value));
+    if (ret >= 0) {
+        if (!strcmp(value, AUDIO_PARAMETER_VALUE_TTY_OFF)) {
+            voice->tty_mode = TTY_MODE_OFF;
+            voice_set_tty_mode(voice,TTY_MODE_OFF_RIL);
+            ALOGD("vm-%s: TTY_MODE_OFF", __func__);
+        } else if (!strcmp(value, AUDIO_PARAMETER_VALUE_TTY_VCO)) {
+            voice->tty_mode = TTY_MODE_VCO;
+            voice_set_tty_mode(voice,TTY_MODE_VCO_RIL);
+            ALOGD("vm-%s: TTY_MODE_VCO", __func__);
+        } else if (!strcmp(value, AUDIO_PARAMETER_VALUE_TTY_HCO)) {
+            voice->tty_mode = TTY_MODE_HCO;
+            voice_set_tty_mode(voice,TTY_MODE_HCO_RIL);
+            ALOGD("vm-%s: TTY_MODE_HCO", __func__);
+        } else if (!strcmp(value, AUDIO_PARAMETER_VALUE_TTY_FULL)) {
+            voice->tty_mode = TTY_MODE_FULL;
+            voice_set_tty_mode(voice,TTY_MODE_FULL_RIL);
+            ALOGD("vm-%s: TTY_MODE_FULL", __func__);
+        } else
+            ALOGD("vm-%s: Unknown TTY_MODE parameters = %s!!", __func__, value);
+
+        str_parms_del(parms, AUDIO_PARAMETER_KEY_TTY_MODE);
+    }
+
+    // HAC(Hearing Aid Compatibility) Status Configuration
+    ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_HAC, value, sizeof(value));
+    if (ret >= 0) {
+        if (!strcmp(value, AUDIO_PARAMETER_VALUE_HAC_ON)) {
+            voice->hac_mode = HAC_MODE_ON;
+            voice_set_hac_mode(voice,true);
+            ALOGD("vm-%s: HAC_MODE_ON", __func__);
+        } else if (!strcmp(value, AUDIO_PARAMETER_VALUE_HAC_OFF)) {
+            voice->hac_mode = HAC_MODE_OFF;
+            voice_set_hac_mode(voice,false);
+            ALOGD("vm-%s: HAC_MODE_OFF", __func__);
+        } else
+            ALOGD("vm-%s: Unknown HAC_MODE parameters = %s!!", __func__, value);
+
+        if (voice_is_call_active(voice)
+           && adev->primary_output
+           && adev->primary_output->common.requested_devices != 0) {
+            voice_set_path(voice, adev->primary_output->common.requested_devices);
+        }
+
+        str_parms_del(parms, AUDIO_PARAMETER_KEY_HAC);
+    }
+
+    //ALOGV("%s: exit with code(%d)", __func__, ret);
+
+    free(kv_pairs);
+    return ;
+}
+
+int voice_set_callback(struct voice_manager * voice __unused, void * callback_func )
+{
+    int ret = 0;
+
+    SitRilRegisterCallback(0, callback_func);
+    return ret;
+}
+
+
+/*
+ * Get Functions
+ */
+volte_status_t voice_get_volte_status(struct voice_manager *voice)
+{
+    return voice->volte_status;
+}
+
+int voice_get_samplingrate(struct voice_manager *voice)
+{
+    return voice->voice_samplingrate;
+}
+
+int voice_get_vowifi_band(struct voice_manager *voice)
+{
+    return voice->vowifi_band;
+}
+
+int voice_get_cur_indevice_id(struct voice_manager *voice)
+{
+    return voice->in_device_id;
+}
+
+
+/*
+ * Other Functions
+ */
+int voice_set_loopback_device(struct voice_manager *voice, int mode, int rx_dev, int tx_dev)
+{
+    int ret = 0;
+    if (voice) {
+        voice->loopback_mode = mode;
+        if (rx_dev == (AUDIO_DEVICE_OUT_EARPIECE | AUDIO_DEVICE_OUT_SPEAKER)) {
+            ALOGI("%s: Set loopback rx path as RCV (Speaker2)", __func__);
+            rx_dev = AUDIO_DEVICE_OUT_EARPIECE; // set rcv as speaker2
+        }
+        SitRilSetLoopback(mode, rx_dev, tx_dev);
+    }
+    return ret;
+}
+
+void voice_ril_dump(int fd __unused)
+{
+    SitRilDump(fd);
+}
+
+int voice_get_volume_index(struct voice_manager *voice, float volume)
+{
+    return (int)(volume * voice->volume_steps_max);
+}
+
+int voice_set_tty_mode(struct voice_manager *voice, int ttymode)
+{
+    int ret = 0;
+    if (voice) {
+        SitRilSetTTYMode(ttymode);
+    }
+    return ret;
+}
+
+int voice_callback(void * handle, int event, const void *data, unsigned int datalen)
+{
+    struct voice_manager *voice = (struct voice_manager *)handle;
+    int (*funcp)(int, const void *, unsigned int) = NULL;
+
+    ALOGD("vm-%s: Called Callback Function from RIL Audio Client!", __func__);
+    if (voice) {
+#if 0
+        switch (event) {
+            case VOICE_AUDIO_EVENT_RINGBACK_STATE_CHANGED:
+                ALOGD("vm-%s: Received RINGBACK_STATE_CHANGED event!", __func__);
+                break;
+
+            case VOICE_AUDIO_EVENT_IMS_SRVCC_HANDOVER:
+                ALOGD("vm-%s: Received IMS_SRVCC_HANDOVER event!", __func__);
+                break;
+
+            default:
+                ALOGD("vm-%s: Received Unsupported event (%d)!", __func__, event);
+                return 0;
+        }
+#endif
+        funcp = voice->callback;
+        funcp(event, data, datalen);
+    }
+
+    return 0;
+}
+
+void voice_deinit(struct voice_manager *voice)
+{
+    if (voice) {
+        /* RIL */
+        SitRilClose();
+        free(voice);
+    }
+
+    return ;
+}
+
+struct voice_manager* voice_init(void)
+{
+    struct voice_manager *voice = NULL;
+    char property[PROPERTY_VALUE_MAX];
+    int ret = 0;
+
+    voice = calloc(1, sizeof(struct voice_manager));
+    if (voice) {
+
+        // At initial time, try to connect to AudioRIL
+        ret = SitRilOpen();
+        if (ret == 0)
+            voice->call_status = CALL_STATUS_CONNECTED;
+        else
+            voice->call_status = CALL_STATUS_INVALID;
+
+        // Variables
+        voice->realcall = false;
+        voice->csvtcall = false;
+        voice->keep_call_mode = false;
+
+        voice->out_device = AUDIO_DEVICE_NONE;
+        voice->in_device_id = DEVICE_INVALID;
+        voice->bluetooth_nrec = BT_NREC_INITIALIZED;
+        voice->bluetooth_samplerate = NB_SAMPLING_RATE;
+        voice->tty_mode = TTY_MODE_OFF;
+        voice->call_forwarding = false;
+        voice->mute_voice = false;
+        voice->cur_modem = CP1;
+        voice->extra_volume = false;
+
+        voice->voice_samplingrate = VOICE_SR_NB;
+        voice->loopback_mode = FACTORY_LOOPBACK_OFF;
+
+        // VoIP
+        voice->voip_wificalling = false;
+        voice->voip_rx_active = false;
+        voice->vowifi_band = WB;
+
+        // VoLTE
+        voice->volte_status = VOLTE_OFF;
+        voice->previous_volte_status = VOLTE_OFF;
+
+        property_get(VOLUME_STEPS_PROPERTY, property, VOLUME_STEPS_DEFAULT);
+        voice->volume_steps_max = atoi(property);
+        /* this catches the case where VOLUME_STEPS_PROPERTY does not contain an integer */
+        if (voice->volume_steps_max == 0)
+            voice->volume_steps_max = atoi(VOLUME_STEPS_DEFAULT);
+
+        voice->callback = NULL;
+    }
+
+    return voice;
+}
diff --git a/libaudio/audiohal/voice_manager.h b/libaudio/audiohal/voice_manager.h
new file mode 100644
index 0000000..da51419
--- /dev/null
+++ b/libaudio/audiohal/voice_manager.h
@@ -0,0 +1,131 @@
+/*
+ * 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_VOICE_SERVICE_H__
+#define __EXYNOS_VOICE_SERVICE_H__
+
+#include <system/audio.h>
+#include <hardware/audio.h>
+
+#include "voice_definition.h"
+
+
+enum {
+    VOICE_SR_NB     = 0,            // Narrow Band
+    VOICE_SR_WB,                    // Wide Band
+    VOICE_SR_SWB                    // Super Wide Band
+};
+
+typedef enum {
+    VOLTE_OFF = 0,
+    VOLTE_VOICE,
+    VOLTE_VIDEO
+} volte_status_t;
+
+typedef enum {
+    CALL_STATUS_INVALID    = 0,     // RIL Audio Client is not connected yet
+    CALL_STATUS_CONNECTED,          // RIL Audio Client is connected, but it is not IN_CALL Mode
+    CALL_STATUS_INCALLMODE,         // RIL Audio Client is connected and it is IN_CALL Mode, but Voice is not working
+    CALL_STATUS_ACTIVE              // RIL Audio Client is connected, it is IN_CALL Mode and Voice is working
+} call_status_t;
+
+
+struct voice_manager {
+    // Call Status
+    call_status_t call_status;           // Current Call Status
+    bool realcall;
+    bool csvtcall;
+    bool keep_call_mode;
+
+    audio_devices_t out_device;
+    int  in_device_id; /* for disable cur path */
+    int  bluetooth_nrec;
+    int  bluetooth_samplerate;
+    int  tty_mode;
+    int  hac_mode;
+    bool call_forwarding;
+    bool mute_voice;
+    int  cur_modem;
+    bool extra_volume;
+
+    int voice_samplingrate;
+    int loopback_mode;
+
+    // VoIP
+    int  vowifi_band;
+    bool voip_rx_active;
+    bool voip_wificalling;
+
+    // VoLTE
+    volte_status_t volte_status;
+    volte_status_t previous_volte_status;
+
+    int volume_steps_max;       // Voice Volume maximum steps
+
+    int (*callback)(int, const void *, unsigned int); // Callback Function Pointer
+};
+
+struct audio_device;
+
+/* Local Functions */
+//int  voice_check_ril_connection(struct voice_manager *voice);
+//void voice_check_multisim(struct voice_manager *voice);
+//int  voice_set_current_modem(struct voice_manager *voice, int cur_modem);
+//int  voice_set_wb_amr(struct voice_manager *voice, bool on);
+//int  voice_set_sco_solution(struct voice_manager *voice, bool echo_cancel, int sample_rate);
+//int  voice_set_dha_solution(struct voice_manager *voice, const char *data);
+//int  voice_set_cover_status(struct voice_manager *voice, bool status);
+//int  voice_set_volte_status(struct voice_manager *voice, int status);
+//int  voice_set_hac_mode(struct voice_manager *voice, bool hac_flag);
+
+/* Status Check Functions */
+bool voice_is_call_mode (struct voice_manager *voice);
+bool voice_is_call_active (struct voice_manager *voice);
+//bool voice_is_in_voip(struct audio_device *adev); // Deprecated
+
+/* Set Functions */
+int  voice_set_call_mode(struct voice_manager *voice, bool on);
+int  voice_set_call_active (struct voice_manager *voice, bool on);
+int  voice_set_audio_mode(struct voice_manager *voice, int mode, bool status);
+int  voice_set_volume(struct voice_manager *voice, float volume);
+int  voice_set_extra_volume(struct voice_manager *voice, bool on);
+int  voice_set_path(struct voice_manager * voice, audio_devices_t devices);
+int  voice_set_mic_mute(struct voice_manager *voice, bool status);
+int  voice_set_rx_mute(struct voice_manager *voice, bool status);
+int  voice_set_usb_mic(struct voice_manager *voice, bool status);
+void voice_set_call_forwarding(struct voice_manager *voice, bool callfwd);
+void voice_set_cur_indevice_id(struct voice_manager *voice, int device);
+void voice_set_parameters(struct audio_device *adev, struct str_parms *parms);
+
+/* Get Functions */
+volte_status_t voice_get_volte_status(struct voice_manager *voice);
+int  voice_get_samplingrate(struct voice_manager *voice);
+int  voice_get_vowifi_band(struct voice_manager *voice);
+int  voice_get_cur_indevice_id(struct voice_manager *voice);
+bool voice_get_mic_mute(struct voice_manager *voice);
+int  voice_get_volume_index(struct voice_manager *voice, float volume);
+int  voice_set_tty_mode(struct voice_manager *voice, int ttymode);
+
+/* Other Functions */
+int voice_set_loopback_device(struct voice_manager *voice, int mode, int rx_dev, int tx_dev);
+void voice_ril_dump(int fd __unused);
+int  voice_set_callback(struct voice_manager * voice, void * callback_func);
+
+/* Voice Manager related Functiuons */
+void voice_deinit(struct voice_manager *voice);
+struct voice_manager * voice_init(void);
+
+#endif  // __EXYNOS_VOICE_SERVICE_H__